@teselagen/ui 0.8.6-beta.22 → 0.8.6-beta.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/DataTable/EditabelCell.d.ts +7 -0
  2. package/DataTable/defaultProps.d.ts +43 -0
  3. package/DataTable/utils/computePresets.d.ts +1 -0
  4. package/DataTable/utils/convertSchema.d.ts +22 -2
  5. package/DataTable/utils/getAllRows.d.ts +1 -1
  6. package/DataTable/utils/handleCopyColumn.d.ts +1 -1
  7. package/DataTable/utils/handleCopyTable.d.ts +1 -1
  8. package/DataTable/utils/isBottomRightCornerOfRectangle.d.ts +10 -8
  9. package/DataTable/utils/isEntityClean.d.ts +3 -1
  10. package/DataTable/utils/primarySelectedValue.d.ts +1 -1
  11. package/DataTable/utils/removeCleanRows.d.ts +11 -3
  12. package/DataTable/utils/selection.d.ts +3 -1
  13. package/DataTable/utils/useDeepEqualMemo.d.ts +1 -0
  14. package/DataTable/utils/useTableEntities.d.ts +17 -4
  15. package/DataTable/utils/useTableParams.d.ts +49 -0
  16. package/index.cjs.js +125 -109
  17. package/index.es.js +125 -109
  18. package/package.json +2 -2
  19. package/src/DataTable/Columns.jsx +945 -0
  20. package/src/DataTable/EditabelCell.js +44 -0
  21. package/src/DataTable/EditabelCell.jsx +44 -0
  22. package/src/DataTable/RenderCell.jsx +191 -0
  23. package/src/DataTable/defaultProps.js +45 -0
  24. package/src/DataTable/index.js +96 -68
  25. package/src/DataTable/utils/computePresets.js +42 -0
  26. package/src/DataTable/utils/convertSchema.ts +79 -0
  27. package/src/DataTable/utils/getAllRows.js +2 -6
  28. package/src/DataTable/utils/handleCopyColumn.js +2 -2
  29. package/src/DataTable/utils/handleCopyTable.js +2 -2
  30. package/src/DataTable/utils/isBottomRightCornerOfRectangle.ts +27 -0
  31. package/src/DataTable/utils/isEntityClean.ts +15 -0
  32. package/src/DataTable/utils/primarySelectedValue.ts +1 -0
  33. package/src/DataTable/utils/queryParams.js +1 -1
  34. package/src/DataTable/utils/removeCleanRows.ts +25 -0
  35. package/src/DataTable/utils/selection.ts +11 -0
  36. package/src/DataTable/utils/useDeepEqualMemo.js +10 -0
  37. package/src/DataTable/utils/useTableEntities.ts +60 -0
  38. package/src/DataTable/utils/useTableParams.js +361 -0
  39. package/style.css +10537 -0
@@ -0,0 +1,44 @@
1
+ import React, { useEffect, useRef, useState } from "react";
2
+
3
+ export const EditableCell = ({
4
+ cancelEdit,
5
+ dataTest,
6
+ finishEdit,
7
+ isNumeric,
8
+ initialValue
9
+ }) => {
10
+ const [value, setValue] = useState(initialValue);
11
+ const inputRef = useRef(null);
12
+
13
+ useEffect(() => {
14
+ if (inputRef.current) {
15
+ inputRef.current.focus();
16
+ }
17
+ }, [isNumeric]);
18
+
19
+ return (
20
+ <input
21
+ style={{
22
+ border: 0,
23
+ width: "95%",
24
+ fontSize: 12,
25
+ background: "none"
26
+ }}
27
+ ref={inputRef}
28
+ {...dataTest}
29
+ autoFocus
30
+ onKeyDown={e => {
31
+ e.stopPropagation();
32
+ if (e.key === "Enter") {
33
+ e.target.blur();
34
+ } else if (e.key === "Escape") {
35
+ cancelEdit();
36
+ }
37
+ }}
38
+ onBlur={() => finishEdit(value)}
39
+ onChange={e => setValue(e.target.value)}
40
+ type={isNumeric ? "number" : undefined}
41
+ value={value}
42
+ />
43
+ );
44
+ };
@@ -0,0 +1,44 @@
1
+ import React, { useEffect, useRef, useState } from "react";
2
+
3
+ export const EditableCell = ({
4
+ cancelEdit,
5
+ dataTest,
6
+ finishEdit,
7
+ isNumeric,
8
+ initialValue
9
+ }) => {
10
+ const [value, setValue] = useState(initialValue);
11
+ const inputRef = useRef(null);
12
+
13
+ useEffect(() => {
14
+ if (inputRef.current) {
15
+ inputRef.current.focus();
16
+ }
17
+ }, [isNumeric]);
18
+
19
+ return (
20
+ <input
21
+ style={{
22
+ border: 0,
23
+ width: "95%",
24
+ fontSize: 12,
25
+ background: "none"
26
+ }}
27
+ ref={inputRef}
28
+ {...dataTest}
29
+ autoFocus
30
+ onKeyDown={e => {
31
+ e.stopPropagation();
32
+ if (e.key === "Enter") {
33
+ e.target.blur();
34
+ } else if (e.key === "Escape") {
35
+ cancelEdit();
36
+ }
37
+ }}
38
+ onBlur={() => finishEdit(value)}
39
+ onChange={e => setValue(e.target.value)}
40
+ type={isNumeric ? "number" : undefined}
41
+ value={value}
42
+ />
43
+ );
44
+ };
@@ -0,0 +1,191 @@
1
+ import React from "react";
2
+ import { useSelector } from "react-redux";
3
+ import { Checkbox, Icon } from "@blueprintjs/core";
4
+ import {
5
+ getIdOrCodeOrIndex,
6
+ isBottomRightCornerOfRectangle,
7
+ PRIMARY_SELECTED_VAL
8
+ } from "./utils";
9
+ import { DropdownCell } from "./DropdownCell";
10
+ import { EditableCell } from "./EditabelCell";
11
+ import { getVals } from "./getVals";
12
+ import { CellDragHandle } from "./CellDragHandle";
13
+
14
+ export const RenderCell = ({
15
+ oldFunc,
16
+ getCopyTextForCell,
17
+ column,
18
+ isCellEditable,
19
+ isEntityDisabled,
20
+ finishCellEdit,
21
+ formName,
22
+ noEllipsis,
23
+ cancelCellEdit,
24
+ getCellHoverText,
25
+ selectedCells,
26
+ isSelectionARectangle,
27
+ startCellEdit,
28
+ tableRef,
29
+ onDragEnd,
30
+ args
31
+ }) => {
32
+ const editingCell = useSelector(
33
+ state => state.form?.[formName]?.values?.reduxFormEditingCell
34
+ );
35
+ const initialValue = useSelector(
36
+ state => state.form?.[formName]?.values?.reduxFormInitialValue
37
+ );
38
+
39
+ const [row] = args;
40
+ const rowId = getIdOrCodeOrIndex(row.original, row.index);
41
+ const cellId = `${rowId}:${row.column.path}`;
42
+ const isEditingCell = editingCell === cellId;
43
+ let val = oldFunc(...args);
44
+ const oldVal = val;
45
+ const text = getCopyTextForCell(val, row, column);
46
+ const dataTest = {
47
+ "data-test": "tgCell_" + column.path
48
+ };
49
+ const fullValue = row.original?.[row.column.path];
50
+
51
+ if (isEditingCell) {
52
+ if (column.type === "genericSelect") {
53
+ const GenericSelectComp = column.GenericSelectComp;
54
+
55
+ return (
56
+ <GenericSelectComp
57
+ rowId={rowId}
58
+ fullValue={fullValue}
59
+ initialValue={text}
60
+ {...dataTest}
61
+ finishEdit={(newVal, doNotStopEditing) => {
62
+ finishCellEdit(cellId, newVal, doNotStopEditing);
63
+ }}
64
+ dataTest={dataTest}
65
+ cancelEdit={cancelCellEdit}
66
+ />
67
+ );
68
+ }
69
+ if (column.type === "dropdown" || column.type === "dropdownMulti") {
70
+ return (
71
+ <DropdownCell
72
+ isMulti={dataTest.isMulti || column.type === "dropdownMulti"}
73
+ initialValue={dataTest.initialValue || text}
74
+ options={getVals(column.values)}
75
+ finishEdit={(newVal, doNotStopEditing) => {
76
+ finishCellEdit(cellId, newVal, doNotStopEditing);
77
+ }}
78
+ dataTest={dataTest}
79
+ cancelEdit={cancelCellEdit}
80
+ />
81
+ );
82
+ } else {
83
+ return (
84
+ <EditableCell
85
+ dataTest={dataTest}
86
+ cancelEdit={cancelCellEdit}
87
+ isNumeric={column.type === "number"}
88
+ initialValue={initialValue || text}
89
+ finishEdit={newVal => {
90
+ finishCellEdit(cellId, newVal);
91
+ }}
92
+ />
93
+ );
94
+ }
95
+ }
96
+
97
+ const isBool = column.type === "boolean";
98
+ if (isCellEditable && isBool) {
99
+ val = (
100
+ <Checkbox
101
+ disabled={isEntityDisabled(row.original)}
102
+ className="tg-cell-edit-boolean-checkbox"
103
+ checked={oldVal === "True"}
104
+ onChange={e => {
105
+ const checked = e.target.checked;
106
+ finishCellEdit(cellId, checked);
107
+ }}
108
+ />
109
+ );
110
+ noEllipsis = true;
111
+ }
112
+
113
+ //wrap the original tableColumn.Cell function in another div in order to add a title attribute
114
+ let title = text;
115
+ if (getCellHoverText) title = getCellHoverText(...args);
116
+ else if (column.getTitleAttr) title = column.getTitleAttr(...args);
117
+ const isSelectedCell = selectedCells?.[cellId];
118
+ const {
119
+ isRect,
120
+ selectionGrid,
121
+ lastRowIndex,
122
+ lastCellIndex,
123
+ entityMap,
124
+ pathToIndex
125
+ } = isSelectionARectangle();
126
+
127
+ return (
128
+ <>
129
+ <div
130
+ style={{
131
+ ...(!noEllipsis && {
132
+ textOverflow: "ellipsis",
133
+ overflow: "hidden"
134
+ })
135
+ }}
136
+ {...dataTest}
137
+ className="tg-cell-wrapper"
138
+ data-copy-text={text}
139
+ data-copy-json={JSON.stringify(
140
+ //tnw: eventually we'll parse these back out and use either the fullValue (for the generic selects) or the regular text vals for everything else
141
+ column.type === "genericSelect"
142
+ ? {
143
+ __strVal: fullValue,
144
+ __genSelCol: column.path
145
+ }
146
+ : { __strVal: text }
147
+ )}
148
+ title={title || undefined}
149
+ >
150
+ {val}
151
+ </div>
152
+ {isCellEditable &&
153
+ (column.type === "dropdown" ||
154
+ column.type === "dropdownMulti" ||
155
+ column.type === "genericSelect") && (
156
+ <Icon
157
+ icon="caret-down"
158
+ style={{
159
+ position: "absolute",
160
+ right: 5,
161
+ opacity: 0.3
162
+ }}
163
+ className="cell-edit-dropdown"
164
+ onClick={() => {
165
+ startCellEdit(cellId);
166
+ }}
167
+ />
168
+ )}
169
+
170
+ {isSelectedCell &&
171
+ (isRect
172
+ ? isBottomRightCornerOfRectangle({
173
+ cellId,
174
+ selectionGrid,
175
+ lastRowIndex,
176
+ lastCellIndex,
177
+ entityMap,
178
+ pathToIndex
179
+ })
180
+ : isSelectedCell === PRIMARY_SELECTED_VAL) && (
181
+ <CellDragHandle
182
+ key={cellId}
183
+ thisTable={tableRef.current.tableRef}
184
+ cellId={cellId}
185
+ isSelectionARectangle={isSelectionARectangle}
186
+ onDragEnd={onDragEnd}
187
+ />
188
+ )}
189
+ </>
190
+ );
191
+ };
@@ -0,0 +1,45 @@
1
+ import { noop } from "lodash-es";
2
+
3
+ // eslint-disable-next-line import/no-anonymous-default-export
4
+ export default {
5
+ //NOTE: DO NOT SET DEFAULTS HERE FOR PROPS THAT GET COMPUTED AS PART OF PRESET GROUPS IN computePresets
6
+ addFilters: noop,
7
+ className: "",
8
+ clearFilters: noop,
9
+ contextMenu: noop,
10
+ disabled: false,
11
+ entities: [],
12
+ extraClasses: "",
13
+ filters: [],
14
+ isCopyable: true,
15
+ isEntityDisabled: noop,
16
+ isLoading: false,
17
+ isSimple: false,
18
+ isSingleSelect: false,
19
+ maxHeight: 600,
20
+ noHeader: false,
21
+ noSelect: false,
22
+ noUserSelect: false,
23
+ onDeselect: noop,
24
+ onMultiRowSelect: noop,
25
+ onRowClick: noop,
26
+ onRowSelect: noop,
27
+ onSingleRowSelect: noop,
28
+ page: 1,
29
+ pageSize: 10,
30
+ reduxFormExpandedEntityIdMap: {},
31
+ reduxFormSearchInput: "",
32
+ reduxFormSelectedEntityIdMap: {},
33
+ removeSingleFilter: noop,
34
+ resized: [],
35
+ resizePersist: noop,
36
+ setFilter: noop,
37
+ setOrder: noop,
38
+ setPage: noop,
39
+ setPageSize: noop,
40
+ setSearchTerm: noop,
41
+ showCount: false,
42
+ style: {},
43
+ withCheckboxes: false,
44
+ withSort: true
45
+ };
@@ -43,7 +43,7 @@ import {
43
43
  import { arrayMove } from "@dnd-kit/sortable";
44
44
  import classNames from "classnames";
45
45
  import scrollIntoView from "dom-scroll-into-view";
46
- import ReactTable from "@teselagen/react-table";
46
+ import ReactTable, { VIRTUALIZE_CUTOFF_LENGTH } from "@teselagen/react-table";
47
47
  import immer, { produceWithPatches, enablePatches, applyPatches } from "immer";
48
48
  import papaparse from "papaparse";
49
49
  import { useDispatch, useSelector } from "react-redux";
@@ -141,6 +141,7 @@ const DataTable = ({
141
141
  );
142
142
  const tableRef = useRef();
143
143
  const alreadySelected = useRef(false);
144
+ const [noVirtual, setNoVirtual] = useState(false);
144
145
  const [onlyShowRowsWErrors, setOnlyShowRowsWErrors] = useState(false);
145
146
  const [entitiesUndoRedoStack, setEntitiesUndoRedoStack] = useState({
146
147
  currentVersion: 0
@@ -1145,70 +1146,94 @@ const DataTable = ({
1145
1146
  updateValidation
1146
1147
  ]);
1147
1148
 
1148
- const handleCopySelectedCells = useCallback(
1149
- e => {
1150
- // if the current selection is consecutive cells then copy with
1151
- // tabs between. if not then just select primary selected cell
1152
- if (isEmpty(selectedCells)) return;
1153
- const pathToIndex = getFieldPathToIndex(schema);
1154
- const entityIdToEntity = getEntityIdToEntity(entities);
1155
- const selectionGrid = [];
1156
- let firstRowIndex;
1157
- let firstCellIndex;
1158
- Object.keys(selectedCells).forEach(key => {
1159
- const [rowId, path] = key.split(":");
1160
- const eInfo = entityIdToEntity[rowId];
1161
- if (eInfo) {
1162
- if (firstRowIndex === undefined || eInfo.i < firstRowIndex) {
1163
- firstRowIndex = eInfo.i;
1164
- }
1165
- if (!selectionGrid[eInfo.i]) {
1166
- selectionGrid[eInfo.i] = [];
1167
- }
1168
- const cellIndex = pathToIndex[path];
1169
- if (firstCellIndex === undefined || cellIndex < firstCellIndex) {
1170
- firstCellIndex = cellIndex;
1171
- }
1172
- selectionGrid[eInfo.i][cellIndex] = true;
1149
+ const waitUntilAllRowsAreRendered = useCallback(() => {
1150
+ return new Promise(resolve => {
1151
+ const interval = setInterval(() => {
1152
+ const allRowEls =
1153
+ tableRef.current?.tableRef?.querySelectorAll(".rt-tr-group");
1154
+ if (allRowEls?.length === entities.length) {
1155
+ clearInterval(interval);
1156
+ resolve();
1173
1157
  }
1174
- });
1175
- if (firstRowIndex === undefined) return;
1176
- const allRows = getAllRows(e);
1177
- let fullCellText = "";
1178
- const fullJson = [];
1179
- times(selectionGrid.length, i => {
1180
- const row = selectionGrid[i];
1181
- if (fullCellText) {
1182
- fullCellText += "\n";
1158
+ }, 50);
1159
+ });
1160
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1161
+ }, []);
1162
+
1163
+ const handleCopySelectedCells = useCallback(async () => {
1164
+ // if the current selection is consecutive cells then copy with
1165
+ // tabs between. if not then just select primary selected cell
1166
+ if (isEmpty(selectedCells)) return;
1167
+
1168
+ // Temporarily disable virtualization for large tables
1169
+ if (entities.length > VIRTUALIZE_CUTOFF_LENGTH) {
1170
+ setNoVirtual(true);
1171
+ await waitUntilAllRowsAreRendered();
1172
+ }
1173
+
1174
+ const pathToIndex = getFieldPathToIndex(schema);
1175
+ const entityIdToEntity = getEntityIdToEntity(entities);
1176
+ const selectionGrid = [];
1177
+ let firstRowIndex;
1178
+ let firstCellIndex;
1179
+ Object.keys(selectedCells).forEach(key => {
1180
+ const [rowId, path] = key.split(":");
1181
+ const eInfo = entityIdToEntity[rowId];
1182
+ if (eInfo) {
1183
+ if (firstRowIndex === undefined || eInfo.i < firstRowIndex) {
1184
+ firstRowIndex = eInfo.i;
1183
1185
  }
1184
- if (!row) {
1185
- return;
1186
- } else {
1187
- const jsonRow = [];
1188
- // ignore header
1189
- let [rowCopyText, json] = getRowCopyText(allRows[i + 1]);
1190
- rowCopyText = rowCopyText.split("\t");
1191
- times(row.length, i => {
1192
- const cell = row[i];
1193
- if (cell) {
1194
- fullCellText += rowCopyText[i];
1195
- jsonRow.push(json[i]);
1196
- }
1197
- if (i !== row.length - 1 && i >= firstCellIndex)
1198
- fullCellText += "\t";
1199
- });
1200
- fullJson.push(jsonRow);
1186
+ if (!selectionGrid[eInfo.i]) {
1187
+ selectionGrid[eInfo.i] = [];
1201
1188
  }
1202
- });
1203
- if (!fullCellText) return window.toastr.warning("No text to copy");
1189
+ const cellIndex = pathToIndex[path];
1190
+ if (firstCellIndex === undefined || cellIndex < firstCellIndex) {
1191
+ firstCellIndex = cellIndex;
1192
+ }
1193
+ selectionGrid[eInfo.i][cellIndex] = true;
1194
+ }
1195
+ });
1196
+ if (firstRowIndex === undefined) return;
1197
+ const allRows = getAllRows(tableRef);
1198
+ let fullCellText = "";
1199
+ const fullJson = [];
1200
+ times(selectionGrid.length, i => {
1201
+ const row = selectionGrid[i];
1202
+ if (fullCellText) {
1203
+ fullCellText += "\n";
1204
+ }
1205
+ if (!row) {
1206
+ return;
1207
+ } else {
1208
+ const jsonRow = [];
1209
+ // ignore header
1210
+ let [rowCopyText, json] = getRowCopyText(allRows[i + 1]);
1211
+ rowCopyText = rowCopyText.split("\t");
1212
+ times(row.length, i => {
1213
+ const cell = row[i];
1214
+ if (cell) {
1215
+ fullCellText += rowCopyText[i];
1216
+ jsonRow.push(json[i]);
1217
+ }
1218
+ if (i !== row.length - 1 && i >= firstCellIndex) fullCellText += "\t";
1219
+ });
1220
+ fullJson.push(jsonRow);
1221
+ }
1222
+ });
1223
+ if (!fullCellText) return window.toastr.warning("No text to copy");
1204
1224
 
1205
- handleCopyHelper(fullCellText, fullJson, "Selected cells copied");
1206
- },
1207
- [entities, selectedCells, schema]
1208
- );
1225
+ handleCopyHelper(fullCellText, fullJson, "Selected cells copied");
1226
+
1227
+ // Re-enable virtualization if it was disabled
1228
+ setNoVirtual(false);
1229
+ }, [entities, selectedCells, schema, waitUntilAllRowsAreRendered]);
1209
1230
 
1210
1231
  const handleCopySelectedRows = useCallback(
1211
- (selectedRecords, e) => {
1232
+ async selectedRecords => {
1233
+ if (entities.length > VIRTUALIZE_CUTOFF_LENGTH) {
1234
+ setNoVirtual(true);
1235
+ await waitUntilAllRowsAreRendered();
1236
+ }
1212
1237
  const idToIndex = entities.reduce((acc, e, i) => {
1213
1238
  acc[e.id || e.code] = i;
1214
1239
  return acc;
@@ -1223,10 +1248,10 @@ const DataTable = ({
1223
1248
  if (!rowNumbersToCopy.length) return;
1224
1249
  rowNumbersToCopy.unshift(0); //add in the header row
1225
1250
  try {
1226
- const allRowEls = getAllRows(e);
1251
+ const allRowEls = getAllRows(tableRef);
1227
1252
  if (!allRowEls) return;
1228
1253
  const rowEls = rowNumbersToCopy.map(i => allRowEls[i]);
1229
-
1254
+ if (window.Cypress) window.Cypress.__copiedRowsLength = rowEls.length;
1230
1255
  handleCopyRows(rowEls, {
1231
1256
  onFinishMsg: "Selected rows copied"
1232
1257
  });
@@ -1234,8 +1259,9 @@ const DataTable = ({
1234
1259
  console.error(`error:`, error);
1235
1260
  window.toastr.error("Error copying rows.");
1236
1261
  }
1262
+ setNoVirtual(false);
1237
1263
  },
1238
- [entities]
1264
+ [entities, waitUntilAllRowsAreRendered]
1239
1265
  );
1240
1266
 
1241
1267
  const handleCopyHotkey = useCallback(
@@ -2096,7 +2122,7 @@ const DataTable = ({
2096
2122
  <MenuItem
2097
2123
  key="copyColumn"
2098
2124
  onClick={() => {
2099
- handleCopyColumn(e, cellWrapper);
2125
+ handleCopyColumn(tableRef, cellWrapper);
2100
2126
  }}
2101
2127
  text="Column"
2102
2128
  />
@@ -2106,7 +2132,7 @@ const DataTable = ({
2106
2132
  <MenuItem
2107
2133
  key="copyColumnSelected"
2108
2134
  onClick={() => {
2109
- handleCopyColumn(e, cellWrapper, selectedRecords);
2135
+ handleCopyColumn(tableRef, cellWrapper, selectedRecords);
2110
2136
  }}
2111
2137
  text="Column (Selected)"
2112
2138
  />
@@ -2146,7 +2172,7 @@ const DataTable = ({
2146
2172
  <MenuItem
2147
2173
  key="copyFullTableRows"
2148
2174
  onClick={() => {
2149
- handleCopyTable(e);
2175
+ handleCopyTable(tableRef);
2150
2176
  // loop through each cell in the row
2151
2177
  }}
2152
2178
  text="Table"
@@ -2754,6 +2780,7 @@ const DataTable = ({
2754
2780
  <ReactTable
2755
2781
  data={filteredEnts}
2756
2782
  ref={tableRef}
2783
+ noVirtual={noVirtual}
2757
2784
  className={classNames({
2758
2785
  isCellEditable,
2759
2786
  "tg-table-loading": isLoading,
@@ -2835,7 +2862,8 @@ const DataTable = ({
2835
2862
  resizePersist,
2836
2863
  resized,
2837
2864
  rowsToShow,
2838
- style
2865
+ style,
2866
+ noVirtual
2839
2867
  ]
2840
2868
  );
2841
2869
 
@@ -3152,8 +3180,8 @@ const DataTable = ({
3152
3180
  )}
3153
3181
  </div>
3154
3182
  <Button
3155
- onClick={e => {
3156
- handleCopyTable(e, { isDownload: true });
3183
+ onClick={() => {
3184
+ handleCopyTable(tableRef, { isDownload: true });
3157
3185
  }}
3158
3186
  data-tip="Download Table as CSV"
3159
3187
  minimal
@@ -0,0 +1,42 @@
1
+ import { omitBy, isNil } from "lodash-es";
2
+ //we use this to make adding preset prop groups simpler
3
+ export default function computePresets(props = {}) {
4
+ const { isSimple } = props;
5
+ let toReturn = omitBy(props, isNil);
6
+ toReturn.pageSize = toReturn.controlled_pageSize || toReturn.pageSize;
7
+ if (isSimple) {
8
+ //isSimplePreset
9
+ toReturn = {
10
+ noHeader: true,
11
+ noFooter: !props.withPaging,
12
+ noPadding: true,
13
+ noFullscreenButton: true,
14
+ hidePageSizeWhenPossible: !props.withPaging,
15
+ isInfinite: !props.withPaging,
16
+ hideSelectedCount: true,
17
+ withTitle: false,
18
+ withSearch: false,
19
+ compact: true,
20
+ withPaging: false,
21
+ withFilter: false,
22
+ ...toReturn
23
+ };
24
+ } else {
25
+ toReturn = {
26
+ // the usual defaults:
27
+ noFooter: false,
28
+ noPadding: false,
29
+ compact: true,
30
+ noFullscreenButton: false,
31
+ hidePageSizeWhenPossible: false,
32
+ isInfinite: false,
33
+ hideSelectedCount: false,
34
+ withTitle: true,
35
+ withSearch: true,
36
+ withPaging: true,
37
+ withFilter: true,
38
+ ...toReturn
39
+ };
40
+ }
41
+ return toReturn || {};
42
+ }
@@ -0,0 +1,79 @@
1
+ import { camelCase } from "lodash-es";
2
+ import { startCase, keyBy, map } from "lodash-es";
3
+
4
+ type Field = {
5
+ type?: string;
6
+ displayName?: string;
7
+ path?: string;
8
+ filterDisabled?: boolean;
9
+ sortDisabled?: boolean;
10
+ };
11
+
12
+ type Schema = { fields: (Field | string)[] };
13
+
14
+ type CompleteField = Field & {
15
+ type: string;
16
+ displayName: string;
17
+ path: string;
18
+ };
19
+
20
+ type CompleteSchema = {
21
+ fields: CompleteField[];
22
+ };
23
+
24
+ const convertSchema = (schema: Schema): CompleteSchema => {
25
+ let schemaToUse = schema;
26
+ if (!schemaToUse.fields && Array.isArray(schema)) {
27
+ schemaToUse = {
28
+ fields: schema
29
+ };
30
+ }
31
+ schemaToUse = {
32
+ ...schemaToUse
33
+ };
34
+ schemaToUse.fields = schemaToUse.fields.map((field, i) => {
35
+ if (typeof field === "string") {
36
+ return {
37
+ displayName: startCase(camelCase(field)),
38
+ path: field,
39
+ type: "string"
40
+ };
41
+ } else {
42
+ const fieldToUse = { ...(field as Field) };
43
+ fieldToUse.type = fieldToUse.type || "string";
44
+ fieldToUse.displayName =
45
+ fieldToUse.displayName || startCase(camelCase(fieldToUse.path || ""));
46
+ // paths are needed for column resizing
47
+ if (!fieldToUse.path) {
48
+ fieldToUse.filterDisabled = true;
49
+ fieldToUse.sortDisabled = true;
50
+ fieldToUse.path = "fake-path" + i;
51
+ }
52
+ return fieldToUse as CompleteField;
53
+ }
54
+ });
55
+ return schemaToUse as CompleteSchema;
56
+ };
57
+
58
+ export function mergeSchemas(_originalSchema: Schema, _overrideSchema: Schema) {
59
+ const originalSchema = convertSchema(_originalSchema);
60
+ const overrideSchema = convertSchema(_overrideSchema);
61
+
62
+ const overridesByKey = keyBy(overrideSchema.fields, "path");
63
+ return {
64
+ ...originalSchema,
65
+ ...overrideSchema,
66
+ fields: originalSchema.fields
67
+ .map(f => {
68
+ const override = overridesByKey[f.path];
69
+ if (override) {
70
+ delete overridesByKey[f.path];
71
+ return override;
72
+ }
73
+ return f;
74
+ })
75
+ .concat(map(overridesByKey))
76
+ };
77
+ }
78
+
79
+ export default convertSchema;