@teselagen/ui 0.8.8 → 0.9.3

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 (43) hide show
  1. package/DataTable/utils/filterLocalEntitiesToHasura.d.ts +5 -0
  2. package/DataTable/utils/getAllRows.d.ts +1 -1
  3. package/DataTable/utils/getRowCopyText.d.ts +1 -3
  4. package/DataTable/utils/handleCopyColumn.d.ts +1 -1
  5. package/DataTable/utils/handleCopyRows.d.ts +1 -5
  6. package/DataTable/utils/handleCopyTable.d.ts +1 -1
  7. package/DataTable/utils/index.d.ts +0 -1
  8. package/DataTable/utils/initializeHasuraWhereAndFilter.d.ts +1 -0
  9. package/DataTable/utils/queryParams.d.ts +16 -12
  10. package/DataTable/utils/rowClick.d.ts +1 -1
  11. package/DataTable/utils/tableQueryParamsToHasuraClauses.d.ts +26 -0
  12. package/FormComponents/Uploader.d.ts +1 -3
  13. package/FormComponents/tryToMatchSchemas.d.ts +1 -1
  14. package/MenuBar/index.d.ts +1 -3
  15. package/README.md +1 -1
  16. package/ResizableDraggableDialog/index.d.ts +1 -3
  17. package/TagSelect/index.d.ts +1 -1
  18. package/index.cjs.js +40098 -36878
  19. package/index.d.ts +2 -0
  20. package/index.es.js +39112 -35892
  21. package/package.json +2 -4
  22. package/src/DataTable/Columns.js +2 -2
  23. package/src/DataTable/DisplayOptions.js +1 -1
  24. package/src/DataTable/FilterAndSortMenu.js +27 -30
  25. package/src/DataTable/index.js +113 -90
  26. package/src/DataTable/style.css +1 -1
  27. package/src/DataTable/utils/filterLocalEntitiesToHasura.js +356 -0
  28. package/src/DataTable/utils/filterLocalEntitiesToHasura.test.js +1285 -0
  29. package/src/DataTable/utils/getAllRows.js +2 -6
  30. package/src/DataTable/utils/handleCopyColumn.js +2 -2
  31. package/src/DataTable/utils/handleCopyTable.js +2 -2
  32. package/src/DataTable/utils/initializeHasuraWhereAndFilter.js +15 -0
  33. package/src/DataTable/utils/queryParams.js +153 -770
  34. package/src/DataTable/utils/tableQueryParamsToHasuraClauses.js +277 -0
  35. package/src/DataTable/utils/tableQueryParamsToHasuraClauses.test.js +245 -0
  36. package/src/DataTable/utils/withTableParams.js +3 -16
  37. package/src/FormComponents/index.js +2 -2
  38. package/src/TgSelect/index.js +15 -0
  39. package/src/index.js +2 -0
  40. package/src/utils/determineBlackOrWhiteTextColor.js +8 -1
  41. package/ui.css +10537 -0
  42. package/utils/determineBlackOrWhiteTextColor.d.ts +1 -2
  43. package/utils/hotkeyUtils.d.ts +1 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teselagen/ui",
3
- "version": "0.8.8",
3
+ "version": "0.9.3",
4
4
  "main": "./src/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -17,7 +17,7 @@
17
17
  "@dnd-kit/core": "^6.1.0",
18
18
  "@dnd-kit/modifiers": "^7.0.0",
19
19
  "@dnd-kit/sortable": "^8.0.0",
20
- "@teselagen/react-table": "6.10.16",
20
+ "@teselagen/react-table": "6.10.18",
21
21
  "classnames": "^2.3.2",
22
22
  "color": "^3.2.1",
23
23
  "copy-to-clipboard": "^3.3.1",
@@ -51,8 +51,6 @@
51
51
  "url-join": "^4.0.1",
52
52
  "use-deep-compare-effect": "^1.6.1",
53
53
  "write-excel-file": "^1.4.25",
54
- "cypress-real-events": "^1.13.0",
55
- "chance": "^1.1.11",
56
54
  "@dnd-kit/utilities": "3.2.2",
57
55
  "@teselagen/file-utils": "0.3.20",
58
56
  "@blueprintjs/icons": "3.33.0"
@@ -33,10 +33,10 @@ import getTextFromEl from "../utils/getTextFromEl";
33
33
  import rowClick, { finalizeSelection } from "./utils/rowClick";
34
34
  import { editCellHelper } from "./editCellHelper";
35
35
  import { getCellVal } from "./getCellVal";
36
- import { getCCDisplayName } from "./utils/queryParams";
37
36
  import { useDispatch } from "react-redux";
38
37
  import { change as _change } from "redux-form";
39
38
  import { RenderCell } from "./RenderCell";
39
+ import { getCCDisplayName } from "./utils/tableQueryParamsToHasuraClauses";
40
40
 
41
41
  dayjs.extend(localizedFormat);
42
42
 
@@ -104,7 +104,7 @@ const RenderColumnHeader = ({
104
104
  if (order && order.length) {
105
105
  order.forEach(order => {
106
106
  const orderField = order.replace("-", "");
107
- if (orderField === ccDisplayName) {
107
+ if (orderField === path) {
108
108
  if (orderField === order) {
109
109
  ordering = "asc";
110
110
  } else {
@@ -10,7 +10,7 @@ import {
10
10
  Popover,
11
11
  Switch
12
12
  } from "@blueprintjs/core";
13
- import { getCCDisplayName } from "./utils/queryParams";
13
+ import { getCCDisplayName } from "./utils/tableQueryParamsToHasuraClauses";
14
14
 
15
15
  const DisplayOptions = ({
16
16
  compact,
@@ -1,6 +1,6 @@
1
1
  import React, { useState } from "react";
2
2
  import { DateInput, DateRangeInput } from "@blueprintjs/datetime";
3
- import { camelCase } from "lodash-es";
3
+ import { camelCase, startCase } from "lodash-es";
4
4
  import classNames from "classnames";
5
5
  import {
6
6
  Menu,
@@ -349,43 +349,40 @@ function getFilterMenuItems(dataType) {
349
349
  let filterMenuItems = [];
350
350
  if (dataType === "string") {
351
351
  filterMenuItems = [
352
- "Contains",
353
- "Not Contains",
354
- "Starts With",
355
- "Ends With",
356
- "Is Exactly",
357
- "Regex",
358
- "In List",
359
- "Not In List",
360
- "Is Empty",
361
- "Not Empty"
352
+ "contains",
353
+ "notContains",
354
+ "startsWith",
355
+ "endsWith",
356
+ "isExactly",
357
+ "regex",
358
+ "inList",
359
+ "notInList",
360
+ "isEmpty",
361
+ "notEmpty"
362
362
  ];
363
363
  } else if (dataType === "lookup") {
364
364
  filterMenuItems = [
365
- "Contains",
366
- "Not Contains",
367
- "Starts With",
368
- "Ends With",
369
- "Is Exactly",
370
- "Regex"
365
+ "contains",
366
+ "notContains",
367
+ "startsWith",
368
+ "endsWith",
369
+ "isExactly",
370
+ "regex"
371
371
  ];
372
372
  } else if (dataType === "boolean") {
373
- filterMenuItems = ["True", "False"];
373
+ filterMenuItems = ["true", "false"];
374
374
  } else if (dataType === "number" || dataType === "integer") {
375
- // else if (dataType === "lookup") {
376
- // filterMenuItems = ["None"];
377
- // }
378
375
  filterMenuItems = [
379
- "Greater Than",
380
- "Less Than",
381
- "In Range",
382
- "Outside Range",
383
- "Equal To",
384
- "In List",
385
- "Not In List"
376
+ "greaterThan",
377
+ "lessThan",
378
+ "inRange",
379
+ "outsideRange",
380
+ "equalTo",
381
+ "inList",
382
+ "notInList"
386
383
  ];
387
384
  } else if (dataType === "timestamp") {
388
- filterMenuItems = ["Is Between", "Not Between", "Is Before", "Is After"];
385
+ filterMenuItems = ["isBetween", "notBetween", "isBefore", "isAfter"];
389
386
  }
390
- return filterMenuItems;
387
+ return filterMenuItems.map(item => startCase(item));
391
388
  }
@@ -27,7 +27,8 @@ import {
27
27
  isFunction,
28
28
  isEqual,
29
29
  every,
30
- some
30
+ some,
31
+ identity
31
32
  } from "lodash-es";
32
33
  import {
33
34
  Button,
@@ -43,7 +44,7 @@ import {
43
44
  import { arrayMove } from "@dnd-kit/sortable";
44
45
  import classNames from "classnames";
45
46
  import scrollIntoView from "dom-scroll-into-view";
46
- import ReactTable from "@teselagen/react-table";
47
+ import ReactTable, { VIRTUALIZE_CUTOFF_LENGTH } from "@teselagen/react-table";
47
48
  import immer, { produceWithPatches, enablePatches, applyPatches } from "immer";
48
49
  import papaparse from "papaparse";
49
50
  import { useDispatch, useSelector } from "react-redux";
@@ -92,10 +93,9 @@ import { viewColumn, openColumn, multiViewColumn } from "./viewColumn";
92
93
  import convertSchema from "./utils/convertSchema";
93
94
  import TableFormTrackerContext from "./TableFormTrackerContext";
94
95
  import {
95
- getCCDisplayName,
96
- getCurrentParamsFromUrl,
97
96
  getQueryParams,
98
97
  makeDataTableHandlers,
98
+ getCurrentParamsFromUrl,
99
99
  setCurrentParamsOnUrl
100
100
  } from "./utils/queryParams";
101
101
  import { useColumns } from "./Columns";
@@ -103,6 +103,7 @@ import { formValueSelector, change as _change } from "redux-form";
103
103
  import { throwFormError } from "../throwFormError";
104
104
  import { isObservableArray, toJS } from "mobx";
105
105
  import { isBeingCalledExcessively } from "../utils/isBeingCalledExcessively";
106
+ import { getCCDisplayName } from "./utils/tableQueryParamsToHasuraClauses";
106
107
 
107
108
  enablePatches();
108
109
  const IS_LINUX = window.navigator.platform.toLowerCase().search("linux") > -1;
@@ -141,6 +142,7 @@ const DataTable = ({
141
142
  );
142
143
  const tableRef = useRef();
143
144
  const alreadySelected = useRef(false);
145
+ const [noVirtual, setNoVirtual] = useState(false);
144
146
  const [onlyShowRowsWErrors, setOnlyShowRowsWErrors] = useState(false);
145
147
  const [entitiesUndoRedoStack, setEntitiesUndoRedoStack] = useState({
146
148
  currentVersion: 0
@@ -337,16 +339,6 @@ const DataTable = ({
337
339
 
338
340
  const queryParams = useMemo(() => {
339
341
  if (!isTableParamsConnected) {
340
- const additionalFilterToUse =
341
- typeof props.additionalFilter === "function"
342
- ? props.additionalFilter
343
- : () => props.additionalFilter;
344
-
345
- const additionalOrFilterToUse =
346
- typeof props.additionalOrFilter === "function"
347
- ? props.additionalOrFilter
348
- : () => props.additionalOrFilter;
349
-
350
342
  return getQueryParams({
351
343
  doNotCoercePageSize,
352
344
  currentParams,
@@ -356,8 +348,7 @@ const DataTable = ({
356
348
  schema: convertedSchema,
357
349
  isInfinite,
358
350
  isLocalCall,
359
- additionalFilter: additionalFilterToUse,
360
- additionalOrFilter: additionalOrFilterToUse,
351
+ additionalFilter: props.additionalFilter,
361
352
  noOrderError: props.noOrderError,
362
353
  isCodeModel: props.isCodeModel,
363
354
  ownProps: props
@@ -614,7 +605,7 @@ const DataTable = ({
614
605
  : !val;
615
606
  });
616
607
  }
617
- if (noValsForField) {
608
+ if (noValsForField && entities.length) {
618
609
  return {
619
610
  ...field,
620
611
  isHidden: true,
@@ -1156,70 +1147,94 @@ const DataTable = ({
1156
1147
  updateValidation
1157
1148
  ]);
1158
1149
 
1159
- const handleCopySelectedCells = useCallback(
1160
- e => {
1161
- // if the current selection is consecutive cells then copy with
1162
- // tabs between. if not then just select primary selected cell
1163
- if (isEmpty(selectedCells)) return;
1164
- const pathToIndex = getFieldPathToIndex(schema);
1165
- const entityIdToEntity = getEntityIdToEntity(entities);
1166
- const selectionGrid = [];
1167
- let firstRowIndex;
1168
- let firstCellIndex;
1169
- Object.keys(selectedCells).forEach(key => {
1170
- const [rowId, path] = key.split(":");
1171
- const eInfo = entityIdToEntity[rowId];
1172
- if (eInfo) {
1173
- if (firstRowIndex === undefined || eInfo.i < firstRowIndex) {
1174
- firstRowIndex = eInfo.i;
1175
- }
1176
- if (!selectionGrid[eInfo.i]) {
1177
- selectionGrid[eInfo.i] = [];
1178
- }
1179
- const cellIndex = pathToIndex[path];
1180
- if (firstCellIndex === undefined || cellIndex < firstCellIndex) {
1181
- firstCellIndex = cellIndex;
1182
- }
1183
- selectionGrid[eInfo.i][cellIndex] = true;
1150
+ const waitUntilAllRowsAreRendered = useCallback(() => {
1151
+ return new Promise(resolve => {
1152
+ const interval = setInterval(() => {
1153
+ const allRowEls =
1154
+ tableRef.current?.tableRef?.querySelectorAll(".rt-tr-group");
1155
+ if (allRowEls?.length === entities.length) {
1156
+ clearInterval(interval);
1157
+ resolve();
1184
1158
  }
1185
- });
1186
- if (firstRowIndex === undefined) return;
1187
- const allRows = getAllRows(e);
1188
- let fullCellText = "";
1189
- const fullJson = [];
1190
- times(selectionGrid.length, i => {
1191
- const row = selectionGrid[i];
1192
- if (fullCellText) {
1193
- fullCellText += "\n";
1159
+ }, 50);
1160
+ });
1161
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1162
+ }, []);
1163
+
1164
+ const handleCopySelectedCells = useCallback(async () => {
1165
+ // if the current selection is consecutive cells then copy with
1166
+ // tabs between. if not then just select primary selected cell
1167
+ if (isEmpty(selectedCells)) return;
1168
+
1169
+ // Temporarily disable virtualization for large tables
1170
+ if (entities.length > VIRTUALIZE_CUTOFF_LENGTH) {
1171
+ setNoVirtual(true);
1172
+ await waitUntilAllRowsAreRendered();
1173
+ }
1174
+
1175
+ const pathToIndex = getFieldPathToIndex(schema);
1176
+ const entityIdToEntity = getEntityIdToEntity(entities);
1177
+ const selectionGrid = [];
1178
+ let firstRowIndex;
1179
+ let firstCellIndex;
1180
+ Object.keys(selectedCells).forEach(key => {
1181
+ const [rowId, path] = key.split(":");
1182
+ const eInfo = entityIdToEntity[rowId];
1183
+ if (eInfo) {
1184
+ if (firstRowIndex === undefined || eInfo.i < firstRowIndex) {
1185
+ firstRowIndex = eInfo.i;
1194
1186
  }
1195
- if (!row) {
1196
- return;
1197
- } else {
1198
- const jsonRow = [];
1199
- // ignore header
1200
- let [rowCopyText, json] = getRowCopyText(allRows[i + 1]);
1201
- rowCopyText = rowCopyText.split("\t");
1202
- times(row.length, i => {
1203
- const cell = row[i];
1204
- if (cell) {
1205
- fullCellText += rowCopyText[i];
1206
- jsonRow.push(json[i]);
1207
- }
1208
- if (i !== row.length - 1 && i >= firstCellIndex)
1209
- fullCellText += "\t";
1210
- });
1211
- fullJson.push(jsonRow);
1187
+ if (!selectionGrid[eInfo.i]) {
1188
+ selectionGrid[eInfo.i] = [];
1212
1189
  }
1213
- });
1214
- if (!fullCellText) return window.toastr.warning("No text to copy");
1190
+ const cellIndex = pathToIndex[path];
1191
+ if (firstCellIndex === undefined || cellIndex < firstCellIndex) {
1192
+ firstCellIndex = cellIndex;
1193
+ }
1194
+ selectionGrid[eInfo.i][cellIndex] = true;
1195
+ }
1196
+ });
1197
+ if (firstRowIndex === undefined) return;
1198
+ const allRows = getAllRows(tableRef);
1199
+ let fullCellText = "";
1200
+ const fullJson = [];
1201
+ times(selectionGrid.length, i => {
1202
+ const row = selectionGrid[i];
1203
+ if (fullCellText) {
1204
+ fullCellText += "\n";
1205
+ }
1206
+ if (!row) {
1207
+ return;
1208
+ } else {
1209
+ const jsonRow = [];
1210
+ // ignore header
1211
+ let [rowCopyText, json] = getRowCopyText(allRows[i + 1]);
1212
+ rowCopyText = rowCopyText.split("\t");
1213
+ times(row.length, i => {
1214
+ const cell = row[i];
1215
+ if (cell) {
1216
+ fullCellText += rowCopyText[i];
1217
+ jsonRow.push(json[i]);
1218
+ }
1219
+ if (i !== row.length - 1 && i >= firstCellIndex) fullCellText += "\t";
1220
+ });
1221
+ fullJson.push(jsonRow);
1222
+ }
1223
+ });
1224
+ if (!fullCellText) return window.toastr.warning("No text to copy");
1215
1225
 
1216
- handleCopyHelper(fullCellText, fullJson, "Selected cells copied");
1217
- },
1218
- [entities, selectedCells, schema]
1219
- );
1226
+ handleCopyHelper(fullCellText, fullJson, "Selected cells copied");
1227
+
1228
+ // Re-enable virtualization if it was disabled
1229
+ setNoVirtual(false);
1230
+ }, [entities, selectedCells, schema, waitUntilAllRowsAreRendered]);
1220
1231
 
1221
1232
  const handleCopySelectedRows = useCallback(
1222
- (selectedRecords, e) => {
1233
+ async selectedRecords => {
1234
+ if (entities.length > VIRTUALIZE_CUTOFF_LENGTH) {
1235
+ setNoVirtual(true);
1236
+ await waitUntilAllRowsAreRendered();
1237
+ }
1223
1238
  const idToIndex = entities.reduce((acc, e, i) => {
1224
1239
  acc[e.id || e.code] = i;
1225
1240
  return acc;
@@ -1227,17 +1242,17 @@ const DataTable = ({
1227
1242
 
1228
1243
  //index 0 of the table is the column titles
1229
1244
  //must add 1 to rowNum
1230
- const rowNumbersToCopy = selectedRecords
1231
- .map(rec => idToIndex[rec.id || rec.code] + 1)
1232
- .sort();
1245
+ const rowNumbersToCopy = Array.from(
1246
+ new Set(selectedRecords.map(rec => idToIndex[rec.id || rec.code] + 1))
1247
+ ).sort();
1233
1248
 
1234
1249
  if (!rowNumbersToCopy.length) return;
1235
1250
  rowNumbersToCopy.unshift(0); //add in the header row
1236
1251
  try {
1237
- const allRowEls = getAllRows(e);
1252
+ const allRowEls = getAllRows(tableRef);
1238
1253
  if (!allRowEls) return;
1239
- const rowEls = rowNumbersToCopy.map(i => allRowEls[i]);
1240
-
1254
+ const rowEls = rowNumbersToCopy.map(i => allRowEls[i]).filter(identity);
1255
+ if (window.Cypress) window.Cypress.__copiedRowsLength = rowEls.length;
1241
1256
  handleCopyRows(rowEls, {
1242
1257
  onFinishMsg: "Selected rows copied"
1243
1258
  });
@@ -1245,8 +1260,9 @@ const DataTable = ({
1245
1260
  console.error(`error:`, error);
1246
1261
  window.toastr.error("Error copying rows.");
1247
1262
  }
1263
+ setNoVirtual(false);
1248
1264
  },
1249
- [entities]
1265
+ [entities, waitUntilAllRowsAreRendered]
1250
1266
  );
1251
1267
 
1252
1268
  const handleCopyHotkey = useCallback(
@@ -2107,7 +2123,7 @@ const DataTable = ({
2107
2123
  <MenuItem
2108
2124
  key="copyColumn"
2109
2125
  onClick={() => {
2110
- handleCopyColumn(e, cellWrapper);
2126
+ handleCopyColumn(tableRef, cellWrapper);
2111
2127
  }}
2112
2128
  text="Column"
2113
2129
  />
@@ -2117,7 +2133,7 @@ const DataTable = ({
2117
2133
  <MenuItem
2118
2134
  key="copyColumnSelected"
2119
2135
  onClick={() => {
2120
- handleCopyColumn(e, cellWrapper, selectedRecords);
2136
+ handleCopyColumn(tableRef, cellWrapper, selectedRecords);
2121
2137
  }}
2122
2138
  text="Column (Selected)"
2123
2139
  />
@@ -2157,7 +2173,7 @@ const DataTable = ({
2157
2173
  <MenuItem
2158
2174
  key="copyFullTableRows"
2159
2175
  onClick={() => {
2160
- handleCopyTable(e);
2176
+ handleCopyTable(tableRef);
2161
2177
  // loop through each cell in the row
2162
2178
  }}
2163
2179
  text="Table"
@@ -2765,6 +2781,7 @@ const DataTable = ({
2765
2781
  <ReactTable
2766
2782
  data={filteredEnts}
2767
2783
  ref={tableRef}
2784
+ noVirtual={noVirtual}
2768
2785
  className={classNames({
2769
2786
  isCellEditable,
2770
2787
  "tg-table-loading": isLoading,
@@ -2846,12 +2863,18 @@ const DataTable = ({
2846
2863
  resizePersist,
2847
2864
  resized,
2848
2865
  rowsToShow,
2849
- style
2866
+ style,
2867
+ noVirtual
2850
2868
  ]
2851
2869
  );
2852
2870
 
2853
2871
  return (
2854
- <div tabIndex="1" onKeyDown={handleKeyDown} onKeyUp={handleKeyUp}>
2872
+ <div
2873
+ tabIndex="1"
2874
+ style={{ height: "100%" }}
2875
+ onKeyDown={handleKeyDown}
2876
+ onKeyUp={handleKeyUp}
2877
+ >
2855
2878
  <div
2856
2879
  className={classNames(
2857
2880
  "data-table-container",
@@ -3089,7 +3112,7 @@ const DataTable = ({
3089
3112
  try {
3090
3113
  const allEntities = await safeQuery(fragment, {
3091
3114
  variables: {
3092
- filter: variables.filter,
3115
+ where: variables.where,
3093
3116
  sort: variables.sort
3094
3117
  },
3095
3118
  canCancel: true
@@ -3163,8 +3186,8 @@ const DataTable = ({
3163
3186
  )}
3164
3187
  </div>
3165
3188
  <Button
3166
- onClick={e => {
3167
- handleCopyTable(e, { isDownload: true });
3189
+ onClick={() => {
3190
+ handleCopyTable(tableRef, { isDownload: true });
3168
3191
  }}
3169
3192
  data-tip="Download Table as CSV"
3170
3193
  minimal
@@ -246,7 +246,7 @@ body:not(.drag-active)
246
246
  display: flex;
247
247
  flex-wrap: wrap;
248
248
  align-items: center;
249
- margin-top: 20px;
249
+ margin-top: 10px;
250
250
  }
251
251
 
252
252
  .ReactTable {