DataNodeTable.tsx 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. * Copyright 2021-2024 Avaiga Private Limited
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  5. * the License. You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  10. * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
  11. * specific language governing permissions and limitations under the License.
  12. */
  13. import React, { useEffect, useState, useCallback, useMemo, MouseEvent, ChangeEvent, MutableRefObject } from "react";
  14. import BarChartOutlined from "@mui/icons-material/BarChartOutlined";
  15. import RefreshOutlined from "@mui/icons-material/RefreshOutlined";
  16. import TableChartOutlined from "@mui/icons-material/TableChartOutlined";
  17. import Box from "@mui/material/Box";
  18. import Button from "@mui/material/Button";
  19. import Checkbox from "@mui/material/Checkbox";
  20. import FormControl from "@mui/material/FormControl";
  21. import FormControlLabel from "@mui/material/FormControlLabel";
  22. import Grid from "@mui/material/Grid";
  23. import InputLabel from "@mui/material/InputLabel";
  24. import OutlinedInput from "@mui/material/OutlinedInput";
  25. import ListItemText from "@mui/material/ListItemText";
  26. import MenuItem from "@mui/material/MenuItem";
  27. import Select, { SelectChangeEvent } from "@mui/material/Select";
  28. import Switch from "@mui/material/Switch";
  29. import TextField from "@mui/material/TextField";
  30. import ToggleButton from "@mui/material/ToggleButton";
  31. import ToggleButtonGroup from "@mui/material/ToggleButtonGroup";
  32. import {
  33. ColumnDesc,
  34. Table,
  35. TraceValueType,
  36. createSendActionNameAction,
  37. getUpdateVar,
  38. useDispatch,
  39. useModule,
  40. } from "taipy-gui";
  41. import { ChartViewType, MenuProps, TableViewType, selectSx, tabularHeaderSx } from "./utils";
  42. interface DataNodeTableProps {
  43. active: boolean;
  44. nodeId?: string;
  45. configId?: string;
  46. data?: Record<string, TraceValueType>;
  47. columns?: Record<string, ColumnDesc>;
  48. updateVarName?: string;
  49. uniqid: string;
  50. onEdit?: string;
  51. onViewTypeChange: (e: MouseEvent, value?: string) => void;
  52. onLock?: string;
  53. editInProgress?: boolean;
  54. editLock: MutableRefObject<boolean>;
  55. editable: boolean;
  56. updateDnVars?: string;
  57. }
  58. const pushRightSx = { ml: "auto" };
  59. const DataNodeTable = (props: DataNodeTableProps) => {
  60. const { uniqid, configId, nodeId, columns = "", onViewTypeChange, editable, updateDnVars = "" } = props;
  61. const dispatch = useDispatch();
  62. const module = useModule();
  63. // tabular selected columns
  64. const [selectedCols, setSelectedCols] = useState<string[]>([]);
  65. const onColsChange = useCallback(
  66. (e: SelectChangeEvent<typeof selectedCols>) => {
  67. const sc = typeof e.target.value == "string" ? e.target.value.split(",") : e.target.value;
  68. localStorage && localStorage.setItem(`${configId}-selected-cols`, JSON.stringify(sc));
  69. setSelectedCols(sc);
  70. },
  71. [configId]
  72. );
  73. const resetCols = useCallback(() => {
  74. localStorage && localStorage.removeItem(`${configId}-selected-cols`);
  75. columns && setSelectedCols(Object.entries(columns).map((e) => e[1].dfid));
  76. }, [configId, columns]);
  77. useEffect(() => {
  78. if (columns) {
  79. let tc = Object.entries(columns).map((e) => e[1].dfid);
  80. const storedSel = localStorage && localStorage.getItem(`${configId}-selected-cols`);
  81. if (storedSel) {
  82. try {
  83. const storedCols = JSON.parse(storedSel);
  84. if (Array.isArray(storedCols)) {
  85. tc = tc.filter((c) => storedCols.includes(c));
  86. }
  87. } catch {
  88. // do nothing
  89. }
  90. }
  91. setSelectedCols(tc);
  92. }
  93. }, [columns, configId]);
  94. // tabular columns
  95. const [tabCols, setTabCols] = useState<Record<string, ColumnDesc>>({});
  96. useEffect(() => {
  97. if (columns) {
  98. const res = {} as Record<string, ColumnDesc>;
  99. const dfids = {} as Record<string, string>;
  100. Object.entries(columns).forEach(([k, v]) => (dfids[v.dfid] = k));
  101. selectedCols.forEach((c) => dfids[c] && (res[dfids[c]] = columns[dfids[c]]));
  102. setTabCols(res);
  103. }
  104. }, [columns, selectedCols]);
  105. const [tableEdit, setTableEdit] = useState(false);
  106. const toggleTableEdit = useCallback(
  107. () =>
  108. setTableEdit((e) => {
  109. props.editLock.current = !e;
  110. dispatch(
  111. createSendActionNameAction("", module, props.onLock, {
  112. id: nodeId,
  113. lock: !e,
  114. error_id: getUpdateVar(updateDnVars, "error_id"),
  115. })
  116. );
  117. return !e;
  118. }),
  119. [nodeId, dispatch, module, props.onLock, props.editLock, updateDnVars]
  120. );
  121. const userData = useMemo(() => {
  122. const ret: Record<string, unknown> = { dn_id: nodeId, comment: "" };
  123. const idVar = getUpdateVar(updateDnVars, "data_id");
  124. idVar && (ret.context = { [idVar]: nodeId, data_id: idVar, error_id: getUpdateVar(updateDnVars, "error_id") });
  125. return ret;
  126. }, [nodeId, updateDnVars]);
  127. const [comment, setComment] = useState("");
  128. const changeComment = useCallback(
  129. (e: ChangeEvent<HTMLInputElement>) => {
  130. setComment(e.currentTarget.value);
  131. userData.comment = e.currentTarget.value;
  132. },
  133. [userData]
  134. );
  135. return (
  136. <>
  137. <Grid container sx={tabularHeaderSx}>
  138. <Grid item>
  139. <Box className="taipy-toggle">
  140. <ToggleButtonGroup onChange={onViewTypeChange} exclusive value={TableViewType} color="primary">
  141. <ToggleButton value={TableViewType}>
  142. <TableChartOutlined />
  143. </ToggleButton>
  144. <ToggleButton value={ChartViewType}>
  145. <BarChartOutlined />
  146. </ToggleButton>
  147. </ToggleButtonGroup>
  148. </Box>
  149. </Grid>
  150. <Grid item>
  151. <FormControl sx={selectSx} fullWidth className="taipy-selector">
  152. <InputLabel id={uniqid + "-cols-label"}>Columns</InputLabel>
  153. <Select
  154. labelId={uniqid + "-cols-label"}
  155. multiple
  156. value={selectedCols}
  157. onChange={onColsChange}
  158. input={<OutlinedInput label="Columns" fullWidth />}
  159. renderValue={(selected) => selected.join(", ")}
  160. MenuProps={MenuProps}
  161. fullWidth
  162. >
  163. {Object.values(columns || {}).map((colDesc) => (
  164. <MenuItem key={colDesc.dfid} value={colDesc.dfid}>
  165. <Checkbox checked={selectedCols.includes(colDesc.dfid)} />
  166. <ListItemText primary={colDesc.dfid} />
  167. </MenuItem>
  168. ))}
  169. </Select>
  170. </FormControl>
  171. </Grid>
  172. <Grid item>
  173. <Button
  174. onClick={resetCols}
  175. variant="text"
  176. color="primary"
  177. className="taipy-button"
  178. startIcon={<RefreshOutlined />}
  179. >
  180. Reset View
  181. </Button>
  182. </Grid>
  183. {tableEdit ? (
  184. <Grid item sx={pushRightSx}>
  185. <TextField value={comment} onChange={changeComment} label="Comment"></TextField>
  186. </Grid>
  187. ) : null}
  188. <Grid item sx={tableEdit ? undefined : pushRightSx}>
  189. <FormControlLabel
  190. disabled={!props.active || !editable || !!props.editInProgress}
  191. control={<Switch color="primary" checked={tableEdit} onChange={toggleTableEdit} />}
  192. label="Edit data"
  193. labelPlacement="start"
  194. />
  195. </Grid>
  196. </Grid>
  197. <Table
  198. active={props.active}
  199. defaultColumns={JSON.stringify(tabCols)}
  200. updateVarName={props.updateVarName}
  201. data={props.data}
  202. userData={userData}
  203. onEdit={tableEdit ? props.onEdit : undefined}
  204. filter={true}
  205. libClassName="taipy-table"
  206. pageSize={25}
  207. />
  208. </>
  209. );
  210. };
  211. export default DataNodeTable;