@teselagen/ui 0.7.31 → 0.7.33-beta.1

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 (164) hide show
  1. package/DataTable/utils/filterLocalEntitiesToHasura.d.ts +5 -0
  2. package/DataTable/utils/initializeHasuraWhereAndFilter.d.ts +2 -0
  3. package/DataTable/utils/queryParams.d.ts +8 -12
  4. package/DataTable/utils/simplifyHasuraWhere.d.ts +1 -0
  5. package/DataTable/utils/tableQueryParamsToHasuraClauses.d.ts +14 -0
  6. package/{src/DataTable/FilterAndSortMenu.js → FilterAndSortMenu.js} +27 -30
  7. package/filterLocalEntitiesToHasura.js +216 -0
  8. package/index.cjs.js +695 -968
  9. package/index.d.ts +1 -0
  10. package/index.es.js +695 -968
  11. package/initializeHasuraWhereAndFilter.js +27 -0
  12. package/{src/utils/isBeingCalledExcessively.js → isBeingCalledExcessively.js} +0 -1
  13. package/package.json +1 -1
  14. package/queryParams.js +336 -0
  15. package/simplifyHasuraWhere.js +80 -0
  16. package/tableQueryParamsToHasuraClauses.js +113 -0
  17. package/{src/DataTable/utils/withTableParams.js → withTableParams.js} +1 -14
  18. package/src/AdvancedOptions.spec.js +0 -26
  19. package/src/AsyncValidateFieldSpinner/index.js +0 -12
  20. package/src/BlueprintError/index.js +0 -14
  21. package/src/BounceLoader/index.js +0 -16
  22. package/src/BounceLoader/style.css +0 -45
  23. package/src/CollapsibleCard/index.js +0 -68
  24. package/src/CollapsibleCard/style.css +0 -23
  25. package/src/DNALoader/index.js +0 -20
  26. package/src/DNALoader/style.css +0 -251
  27. package/src/DataTable/index.js +0 -3214
  28. package/src/DataTable/style.css +0 -608
  29. package/src/DataTable/utils/index.js +0 -55
  30. package/src/DataTable/utils/queryParams.js +0 -1058
  31. package/src/DialogFooter/index.js +0 -86
  32. package/src/DialogFooter/style.css +0 -9
  33. package/src/FormComponents/index.js +0 -1266
  34. package/src/FormComponents/style.css +0 -275
  35. package/src/FormComponents/utils.js +0 -6
  36. package/src/HotkeysDialog/index.js +0 -79
  37. package/src/HotkeysDialog/style.css +0 -54
  38. package/src/InfoHelper/index.js +0 -78
  39. package/src/InfoHelper/style.css +0 -7
  40. package/src/IntentText/index.js +0 -18
  41. package/src/Loading/index.js +0 -70
  42. package/src/Loading/style.css +0 -4
  43. package/src/MenuBar/index.js +0 -423
  44. package/src/MenuBar/style.css +0 -45
  45. package/src/PromptUnsavedChanges/index.js +0 -38
  46. package/src/ResizableDraggableDialog/index.js +0 -141
  47. package/src/ResizableDraggableDialog/style.css +0 -42
  48. package/src/ScrollToTop/index.js +0 -72
  49. package/src/TagSelect/index.js +0 -69
  50. package/src/TagSelect/style.css +0 -13
  51. package/src/TgHtmlSelect/index.js +0 -20
  52. package/src/TgSelect/index.js +0 -537
  53. package/src/TgSelect/style.css +0 -61
  54. package/src/TgSuggest/index.js +0 -124
  55. package/src/Timeline/index.js +0 -15
  56. package/src/enhancers/withDialog/index.js +0 -196
  57. package/src/index.js +0 -87
  58. package/src/showConfirmationDialog/index.js +0 -148
  59. package/src/style.css +0 -265
  60. /package/{src/AdvancedOptions.js → AdvancedOptions.js} +0 -0
  61. /package/{src/AssignDefaultsModeContext.js → AssignDefaultsModeContext.js} +0 -0
  62. /package/{src/DataTable/CellDragHandle.js → CellDragHandle.js} +0 -0
  63. /package/{src/DataTable/ColumnFilterMenu.js → ColumnFilterMenu.js} +0 -0
  64. /package/{src/DataTable/Columns.js → Columns.js} +0 -0
  65. /package/{src/DataTable/DisabledLoadingComponent.js → DisabledLoadingComponent.js} +0 -0
  66. /package/{src/DataTable/DisplayOptions.js → DisplayOptions.js} +0 -0
  67. /package/{src/DropdownButton.js → DropdownButton.js} +0 -0
  68. /package/{src/DataTable/DropdownCell.js → DropdownCell.js} +0 -0
  69. /package/{src/DataTable/EditableCell.js → EditableCell.js} +0 -0
  70. /package/{src/FillWindow.css → FillWindow.css} +0 -0
  71. /package/{src/FillWindow.js → FillWindow.js} +0 -0
  72. /package/{src/FormComponents/FormSeparator.js → FormSeparator.js} +0 -0
  73. /package/{src/FormComponents/LoadingDots.js → LoadingDots.js} +0 -0
  74. /package/{src/MatchHeaders.js → MatchHeaders.js} +0 -0
  75. /package/{src/DataTable/PagingTool.js → PagingTool.js} +0 -0
  76. /package/{src/DataTable/RenderCell.js → RenderCell.js} +0 -0
  77. /package/{src/DataTable/SearchBar.js → SearchBar.js} +0 -0
  78. /package/{src/SimpleStepViz.js → SimpleStepViz.js} +0 -0
  79. /package/{src/DataTable/SortableColumns.js → SortableColumns.js} +0 -0
  80. /package/{src/DataTable/TableFormTrackerContext.js → TableFormTrackerContext.js} +0 -0
  81. /package/{src/Tag.js → Tag.js} +0 -0
  82. /package/{src/DataTable/ThComponent.js → ThComponent.js} +0 -0
  83. /package/{src/Timeline/TimelineEvent.js → TimelineEvent.js} +0 -0
  84. /package/{src/UploadCsvWizard.css → UploadCsvWizard.css} +0 -0
  85. /package/{src/UploadCsvWizard.js → UploadCsvWizard.js} +0 -0
  86. /package/{src/FormComponents/Uploader.js → Uploader.js} +0 -0
  87. /package/{src/utils/adHoc.js → adHoc.js} +0 -0
  88. /package/{src/autoTooltip.js → autoTooltip.js} +0 -0
  89. /package/{src/utils/basicHandleActionsWithFullState.js → basicHandleActionsWithFullState.js} +0 -0
  90. /package/{src/utils/browserUtils.js → browserUtils.js} +0 -0
  91. /package/{src/utils/combineReducersWithFullState.js → combineReducersWithFullState.js} +0 -0
  92. /package/{src/utils/commandControls.js → commandControls.js} +0 -0
  93. /package/{src/utils/commandUtils.js → commandUtils.js} +0 -0
  94. /package/{src/constants.js → constants.js} +0 -0
  95. /package/{src/DataTable/utils/convertSchema.js → convertSchema.js} +0 -0
  96. /package/{src/customIcons.js → customIcons.js} +0 -0
  97. /package/{src/DataTable/dataTableEnhancer.js → dataTableEnhancer.js} +0 -0
  98. /package/{src/DataTable/defaultFormatters.js → defaultFormatters.js} +0 -0
  99. /package/{src/DataTable/defaultValidators.js → defaultValidators.js} +0 -0
  100. /package/{src/utils/determineBlackOrWhiteTextColor.js → determineBlackOrWhiteTextColor.js} +0 -0
  101. /package/{src/DataTable/editCellHelper.js → editCellHelper.js} +0 -0
  102. /package/{src/DataTable/utils/formatPasteData.js → formatPasteData.js} +0 -0
  103. /package/{src/DataTable/utils/getAllRows.js → getAllRows.js} +0 -0
  104. /package/{src/DataTable/utils/getCellCopyText.js → getCellCopyText.js} +0 -0
  105. /package/{src/DataTable/utils/getCellInfo.js → getCellInfo.js} +0 -0
  106. /package/{src/DataTable/getCellVal.js → getCellVal.js} +0 -0
  107. /package/{src/utils/getDayjsFormatter.js → getDayjsFormatter.js} +0 -0
  108. /package/{src/DataTable/utils/getFieldPathToField.js → getFieldPathToField.js} +0 -0
  109. /package/{src/DataTable/utils/getIdOrCodeOrIndex.js → getIdOrCodeOrIndex.js} +0 -0
  110. /package/{src/DataTable/utils/getLastSelectedEntity.js → getLastSelectedEntity.js} +0 -0
  111. /package/{src/DataTable/utils/getNewEntToSelect.js → getNewEntToSelect.js} +0 -0
  112. /package/{src/FormComponents/getNewName.js → getNewName.js} +0 -0
  113. /package/{src/DataTable/utils/getRowCopyText.js → getRowCopyText.js} +0 -0
  114. /package/{src/DataTable/utils/getTableConfigFromStorage.js → getTableConfigFromStorage.js} +0 -0
  115. /package/{src/utils/getTextFromEl.js → getTextFromEl.js} +0 -0
  116. /package/{src/DataTable/getVals.js → getVals.js} +0 -0
  117. /package/{src/DataTable/utils/handleCopyColumn.js → handleCopyColumn.js} +0 -0
  118. /package/{src/DataTable/utils/handleCopyHelper.js → handleCopyHelper.js} +0 -0
  119. /package/{src/DataTable/utils/handleCopyRows.js → handleCopyRows.js} +0 -0
  120. /package/{src/DataTable/utils/handleCopyTable.js → handleCopyTable.js} +0 -0
  121. /package/{src/utils/handlerHelpers.js → handlerHelpers.js} +0 -0
  122. /package/{src/utils/hotkeyUtils.js → hotkeyUtils.js} +0 -0
  123. /package/{src/utils/hooks/index.js → index.js} +0 -0
  124. /package/{src/DataTable/utils/isBottomRightCornerOfRectangle.js → isBottomRightCornerOfRectangle.js} +0 -0
  125. /package/{src/DataTable/utils/isEntityClean.js → isEntityClean.js} +0 -0
  126. /package/{src/DataTable/isTruthy.js → isTruthy.js} +0 -0
  127. /package/{src/DataTable/isValueEmpty.js → isValueEmpty.js} +0 -0
  128. /package/{src/FormComponents/itemUpload.js → itemUpload.js} +0 -0
  129. /package/{src/utils/menuUtils.js → menuUtils.js} +0 -0
  130. /package/{src/utils/popoverOverflowModifiers.js → popoverOverflowModifiers.js} +0 -0
  131. /package/{src/DataTable/utils/primarySelectedValue.js → primarySelectedValue.js} +0 -0
  132. /package/{src/utils/pureNoFunc.js → pureNoFunc.js} +0 -0
  133. /package/{src/DataTable/utils/removeCleanRows.js → removeCleanRows.js} +0 -0
  134. /package/{src/utils/renderOnDoc.js → renderOnDoc.js} +0 -0
  135. /package/{src/rerenderOnWindowResize.js → rerenderOnWindowResize.js} +0 -0
  136. /package/{src/DataTable/utils/rowClick.js → rowClick.js} +0 -0
  137. /package/{src/DataTable/utils/selection.js → selection.js} +0 -0
  138. /package/{src/showAppSpinner.js → showAppSpinner.js} +0 -0
  139. /package/{src/showDialogOnDocBody.js → showDialogOnDocBody.js} +0 -0
  140. /package/{src/utils/showProgressToast.js → showProgressToast.js} +0 -0
  141. /package/{src/FormComponents/sortify.js → sortify.js} +0 -0
  142. /package/{src/Timeline/style.css → style.css} +0 -0
  143. /package/{src/utils/tagUtils.js → tagUtils.js} +0 -0
  144. /package/{src/utils/tgFormValues.js → tgFormValues.js} +0 -0
  145. /package/{src/enhancers/withDialog/tg_modalState.js → tg_modalState.js} +0 -0
  146. /package/{src/throwFormError.js → throwFormError.js} +0 -0
  147. /package/{src/toastr.js → toastr.js} +0 -0
  148. /package/{src/FormComponents/tryToMatchSchemas.js → tryToMatchSchemas.js} +0 -0
  149. /package/{src/typeToCommonType.js → typeToCommonType.js} +0 -0
  150. /package/{src/utils/hooks/useDeepEqualMemo.js → useDeepEqualMemo.js} +0 -0
  151. /package/{src/useDialog.js → useDialog.js} +0 -0
  152. /package/{src/utils/hooks/useStableReference.js → useStableReference.js} +0 -0
  153. /package/{src/DataTable/utils/useTableEntities.js → useTableEntities.js} +0 -0
  154. /package/{src/utils/useTraceUpdate.js → useTraceUpdate.js} +0 -0
  155. /package/{src/DataTable/utils/utils.js → utils.js} +0 -0
  156. /package/{src/DataTable/validateTableWideErrors.js → validateTableWideErrors.js} +0 -0
  157. /package/{src/DataTable/viewColumn.js → viewColumn.js} +0 -0
  158. /package/{src/enhancers/withField.js → withField.js} +0 -0
  159. /package/{src/enhancers/withFields.js → withFields.js} +0 -0
  160. /package/{src/enhancers/withLocalStorage.js → withLocalStorage.js} +0 -0
  161. /package/{src/utils/withSelectTableRecords.js → withSelectTableRecords.js} +0 -0
  162. /package/{src/DataTable/utils/withSelectedEntities.js → withSelectedEntities.js} +0 -0
  163. /package/{src/utils/withStore.js → withStore.js} +0 -0
  164. /package/{src/wrapDialog.js → wrapDialog.js} +0 -0
@@ -0,0 +1,27 @@
1
+ export function initializeHasuraWhereAndFilter(
2
+ additionalFilter,
3
+ where = {},
4
+ currentParams
5
+ ) {
6
+ where._and = where._and || [];
7
+ where._or = where._or || [];
8
+ if (typeof additionalFilter === "function") {
9
+ const newWhere = additionalFilter(where, currentParams);
10
+ if (newWhere) {
11
+ where = {
12
+ ...where,
13
+ ...newWhere
14
+ };
15
+ }
16
+ } else if (typeof additionalFilter === "object")
17
+ where._and.push(additionalFilter);
18
+ }
19
+
20
+ export const addCustomColumnFilters = (where, fields, currentParams) => {
21
+ fields.forEach(field => {
22
+ const { customColumnFilter, filterDisabled } = field;
23
+ if (filterDisabled || !customColumnFilter) return;
24
+ customColumnFilter(where, currentParams);
25
+ });
26
+ };
27
+
@@ -22,4 +22,3 @@ export const isBeingCalledExcessively = ({ uniqName }) => {
22
22
  throw new Error(`isBeingCalledExcessively: ${uniqName}`);
23
23
  }
24
24
  };
25
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teselagen/ui",
3
- "version": "0.7.31",
3
+ "version": "0.7.33-beta.1",
4
4
  "main": "./src/index.js",
5
5
  "type": "module",
6
6
  "exports": {
package/queryParams.js ADDED
@@ -0,0 +1,336 @@
1
+ import queryString from "qs";
2
+ import { uniqBy, clone, camelCase } from "lodash-es";
3
+ import { tableQueryParamsToHasuraClauses } from "./tableQueryParamsToHasuraClauses";
4
+ import { filterLocalEntitiesToHasura } from "./filterLocalEntitiesToHasura";
5
+ import {
6
+ addCustomColumnFilters,
7
+ initializeHasuraWhereAndFilter
8
+ } from "./initializeHasuraWhereAndFilter";
9
+
10
+ const defaultPageSizes = [5, 10, 15, 25, 50, 100, 200, 400];
11
+
12
+ export { defaultPageSizes };
13
+
14
+ export function getMergedOpts(topLevel = {}, instanceLevel = {}) {
15
+ const merged = {
16
+ ...topLevel,
17
+ ...instanceLevel
18
+ };
19
+ return {
20
+ formName: "tgDataTable",
21
+ ...merged,
22
+ pageSize: merged.controlled_pageSize || merged.pageSize,
23
+ defaults: {
24
+ pageSize: merged.controlled_pageSize || 25,
25
+ order: [], //[-name, statusCode] //an array of camelCase display names with - sign to denote reverse
26
+ searchTerm: "",
27
+ page: 1,
28
+ filters: [
29
+ //filters look like this:
30
+ // {
31
+ // selectedFilter: 'textContains', //camel case
32
+ // filterOn: ccDisplayName, //camel case display name if available and string, otherwise path
33
+ // filterValue: 'thomas',
34
+ // }
35
+ ],
36
+ ...(topLevel.defaults || {}),
37
+ ...(instanceLevel.defaults || {})
38
+ }
39
+ };
40
+ }
41
+
42
+ function safeStringify(val) {
43
+ if (val !== null && typeof val === "object") {
44
+ return JSON.stringify(val);
45
+ }
46
+ return val;
47
+ }
48
+
49
+ function safeParse(val) {
50
+ try {
51
+ return JSON.parse(val);
52
+ } catch (e) {
53
+ return val;
54
+ }
55
+ }
56
+
57
+ /**
58
+ *
59
+ * @param {object} field
60
+ * @returns the camelCase display name of the field, to be used for filters, sorting, etc
61
+ */
62
+ export function getCCDisplayName(field) {
63
+ return camelCase(
64
+ typeof field.displayName === "string" ? field.displayName : field.path
65
+ );
66
+ }
67
+
68
+ export function getCurrentParamsFromUrl(location, isSimple) {
69
+ let { search } = location;
70
+ if (isSimple) {
71
+ search = window.location.href.split("?")[1] || "";
72
+ }
73
+
74
+ return parseFilters(queryString.parse(search, { ignoreQueryPrefix: true }));
75
+ }
76
+
77
+ export function setCurrentParamsOnUrl(newParams, replace, isSimple) {
78
+ const stringifiedFilters = stringifyFilters(newParams);
79
+ const search = `?${queryString.stringify(stringifiedFilters)}`;
80
+ if (isSimple) {
81
+ return window.location.replace(
82
+ `${window.location.href.split("?")[0]}${search}`
83
+ );
84
+ }
85
+ replace({
86
+ search
87
+ });
88
+ }
89
+
90
+ function stringifyFilters(newParams) {
91
+ let filters;
92
+ if (newParams.filters && newParams.filters.length) {
93
+ filters = newParams.filters.reduce(
94
+ (acc, { filterOn, selectedFilter, filterValue }, index) => {
95
+ acc +=
96
+ (index > 0 ? "::" : "") +
97
+ `${filterOn}__${camelCase(selectedFilter)}__${safeStringify(
98
+ Array.isArray(filterValue) ? filterValue.join(";") : filterValue
99
+ )}`;
100
+ return acc;
101
+ },
102
+ ""
103
+ );
104
+ }
105
+ let order;
106
+ if (newParams.order && newParams.order.length) {
107
+ order = newParams.order.reduce((acc, order, index) => {
108
+ acc += (index > 0 ? "___" : "") + order;
109
+ return acc;
110
+ }, "");
111
+ }
112
+ return {
113
+ ...newParams,
114
+ filters,
115
+ order
116
+ };
117
+ }
118
+ function parseFilters(newParams) {
119
+ return {
120
+ ...newParams,
121
+ order: newParams.order && newParams.order.split("___"),
122
+ filters:
123
+ newParams.filters &&
124
+ newParams.filters.split("::").map(filter => {
125
+ const splitFilter = filter.split("__");
126
+ const [filterOn, selectedFilter, filterValue] = splitFilter;
127
+ const parseFilterValue = filterValue => {
128
+ if (selectedFilter === "inList" || selectedFilter === "notInList") {
129
+ return filterValue.split(";");
130
+ }
131
+ if (
132
+ selectedFilter === "inRange" ||
133
+ selectedFilter === "outsideRange"
134
+ ) {
135
+ return filterValue.split(";").map(Number);
136
+ }
137
+ return safeParse(filterValue);
138
+ };
139
+ return {
140
+ filterOn,
141
+ selectedFilter,
142
+ filterValue: parseFilterValue(filterValue)
143
+ };
144
+ })
145
+ };
146
+ }
147
+
148
+ export function makeDataTableHandlers({
149
+ setNewParams,
150
+ defaults,
151
+ onlyOneFilter
152
+ }) {
153
+ //all of these actions have currentParams bound to them as their last arg in withTableParams
154
+ const setSearchTerm = searchTerm => {
155
+ setNewParams(prev => ({
156
+ ...(prev ?? {}),
157
+ page: undefined, //set page undefined to return the table to page 1
158
+ searchTerm: searchTerm === defaults.searchTerm ? undefined : searchTerm
159
+ }));
160
+ onlyOneFilter && clearFilters();
161
+ };
162
+
163
+ const addFilters = newFilters => {
164
+ if (!newFilters) return;
165
+ setNewParams(prev => {
166
+ const filters = uniqBy(
167
+ [...newFilters, ...(onlyOneFilter ? [] : prev?.filters || [])],
168
+ "filterOn"
169
+ );
170
+ return {
171
+ ...(prev ?? {}),
172
+ page: undefined, //set page undefined to return the table to page 1
173
+ filters
174
+ };
175
+ });
176
+ };
177
+
178
+ const removeSingleFilter = filterOn =>
179
+ setNewParams(prev => {
180
+ const filters = prev?.filters
181
+ ? prev.filters.filter(filter => {
182
+ return filter.filterOn !== filterOn;
183
+ })
184
+ : undefined;
185
+ return { ...(prev ?? {}), filters };
186
+ });
187
+
188
+ const clearFilters = (additionalFilterKeys = []) => {
189
+ const toClear = {
190
+ filters: undefined,
191
+ searchTerm: undefined,
192
+ tags: undefined
193
+ };
194
+ additionalFilterKeys.forEach(key => {
195
+ toClear[key] = undefined;
196
+ });
197
+ setNewParams(toClear);
198
+ };
199
+
200
+ const setPageSize = pageSize =>
201
+ setNewParams(prev => ({
202
+ ...(prev ?? {}),
203
+ pageSize: pageSize === defaults.pageSize ? undefined : pageSize,
204
+ page: undefined //set page undefined to return the table to page 1
205
+ }));
206
+
207
+ const setOrder = (order, isRemove, shiftHeld) =>
208
+ setNewParams(prev => {
209
+ let newOrder = [];
210
+ if (shiftHeld) {
211
+ //first remove the old order
212
+ newOrder = [...(prev?.order || [])].filter(value => {
213
+ const shouldRemove =
214
+ value.replace(/^-/, "") === order.replace(/^-/, "");
215
+ return !shouldRemove;
216
+ });
217
+ //then, if we are adding, pop the order onto the array
218
+ if (!isRemove) {
219
+ newOrder.push(order);
220
+ }
221
+ } else {
222
+ if (isRemove) {
223
+ newOrder = [];
224
+ } else {
225
+ newOrder = [order];
226
+ }
227
+ }
228
+ return {
229
+ ...(prev ?? {}),
230
+ order: newOrder
231
+ };
232
+ });
233
+
234
+ const setPage = page => {
235
+ setNewParams(prev => ({
236
+ ...(prev ?? {}),
237
+ page: page === defaults.page ? undefined : page
238
+ }));
239
+ };
240
+
241
+ return {
242
+ setSearchTerm,
243
+ addFilters,
244
+ clearFilters,
245
+ removeSingleFilter,
246
+ setPageSize,
247
+ setPage,
248
+ setOrder,
249
+ setNewParams
250
+ };
251
+ }
252
+
253
+ export function getQueryParams({
254
+ currentParams,
255
+ // urlConnected,
256
+ defaults,
257
+ schema,
258
+ isInfinite,
259
+ entities,
260
+ isLocalCall,
261
+ additionalFilter,
262
+ doNotCoercePageSize,
263
+ // noOrderError,
264
+ // isCodeModel,
265
+ ownProps
266
+ }) {
267
+ Object.keys(currentParams).forEach(function (key) {
268
+ if (currentParams[key] === undefined) {
269
+ delete currentParams[key]; //we want to use the default value if any of these are undefined
270
+ }
271
+ });
272
+ const tableQueryParams = {
273
+ ...defaults,
274
+ ...currentParams
275
+ };
276
+ let { page, pageSize, searchTerm, filters, order } = tableQueryParams;
277
+ if (page <= 0 || isNaN(page)) {
278
+ page = undefined;
279
+ }
280
+ if (isInfinite) {
281
+ page = undefined;
282
+ pageSize = undefined;
283
+ }
284
+ if (pageSize !== undefined && !doNotCoercePageSize) {
285
+ //pageSize might come in as an unexpected number so we coerce it to be one of the nums in our pageSizes array
286
+ const closest = clone(window.tgPageSizes || defaultPageSizes).sort(
287
+ (a, b) => Math.abs(pageSize - a) - Math.abs(pageSize - b)
288
+ )[0];
289
+ pageSize = closest;
290
+ }
291
+ const toReturn = {
292
+ //these are values that might be generally useful for the wrapped component
293
+ page,
294
+ pageSize: ownProps.controlled_pageSize || pageSize,
295
+ order,
296
+ filters,
297
+ searchTerm
298
+ };
299
+ // tnwtodo: need to make sure ignoreSearchTerm still works
300
+ // if (additionalOrFilterToUse && additionalOrFilterToUse.ignoreSearchTerm) {
301
+ // searchTerm = "";
302
+ // additionalOrFilterToUse = additionalOrFilterToUse.additionalOrFilterToUse;
303
+ // }
304
+
305
+ const { where, order_by, limit, offset } = tableQueryParamsToHasuraClauses({
306
+ page,
307
+ pageSize,
308
+ searchTerm,
309
+ filters,
310
+ order,
311
+ schema
312
+ });
313
+ initializeHasuraWhereAndFilter(additionalFilter, where, currentParams);
314
+ addCustomColumnFilters(where, schema.fields, currentParams);
315
+ if (isLocalCall) {
316
+ //if the table is local (aka not directly connected to a db) then we need to
317
+ //handle filtering/paging/sorting all on the front end
318
+ return filterLocalEntitiesToHasura(entities, {
319
+ where,
320
+ order_by,
321
+ limit,
322
+ offset,
323
+ isInfinite
324
+ });
325
+ } else {
326
+ return {
327
+ ...toReturn,
328
+ variables: {
329
+ where,
330
+ order_by,
331
+ limit,
332
+ offset
333
+ }
334
+ };
335
+ }
336
+ }
@@ -0,0 +1,80 @@
1
+ export function simplifyHasuraWhere(whereClause) {
2
+ const simplifiedWhere = {};
3
+
4
+ for (const key in whereClause) {
5
+ // eslint-disable-next-line no-prototype-builtins
6
+ if (whereClause.hasOwnProperty(key)) {
7
+ const value = whereClause[key];
8
+
9
+ if (
10
+ typeof value === "object" &&
11
+ value !== null &&
12
+ !Array.isArray(value)
13
+ ) {
14
+ if (key.includes(".")) {
15
+ // Handle dot-nested where clauses
16
+ const keys = key.split(".");
17
+ let currentObj = simplifiedWhere;
18
+ for (let i = 0; i < keys.length - 1; i++) {
19
+ const nestedKey = keys[i];
20
+ if (!currentObj[nestedKey]) {
21
+ currentObj[nestedKey] = {};
22
+ }
23
+ currentObj = currentObj[nestedKey];
24
+ }
25
+ if (typeof value === "object" && value !== null && "_eq" in value) {
26
+ currentObj[keys[keys.length - 1]] = value;
27
+ } else {
28
+ currentObj[keys[keys.length - 1]] = { _eq: value };
29
+ }
30
+ } else {
31
+ // Handle regular Hasura operators or already nested objects.
32
+ if (
33
+ typeof value === "object" &&
34
+ value !== null &&
35
+ !("_eq" in value) &&
36
+ !("_gt" in value) &&
37
+ !("_lt" in value) &&
38
+ !("_gte" in value) &&
39
+ !("_lte" in value) &&
40
+ !("_in" in value) &&
41
+ !("_nin" in value) &&
42
+ !("_neq" in value) &&
43
+ !("_like" in value) &&
44
+ !("_nlike" in value) &&
45
+ !("_ilike" in value) &&
46
+ !("_nilike" in value) &&
47
+ !("_similar" in value) &&
48
+ !("_nsimilar" in value) &&
49
+ !("_regex" in value) &&
50
+ !("_nregex" in value) &&
51
+ !("_iregex" in value) &&
52
+ !("_niregex" in value)
53
+ ) {
54
+ simplifiedWhere[key] = simplifyHasuraWhere(value);
55
+ } else {
56
+ simplifiedWhere[key] = value;
57
+ }
58
+ }
59
+ } else {
60
+ // Handle simplified _eq where clauses
61
+ if (key.includes(".")) {
62
+ const keys = key.split(".");
63
+ let currentObj = simplifiedWhere;
64
+ for (let i = 0; i < keys.length - 1; i++) {
65
+ const nestedKey = keys[i];
66
+ if (!currentObj[nestedKey]) {
67
+ currentObj[nestedKey] = {};
68
+ }
69
+ currentObj = currentObj[nestedKey];
70
+ }
71
+ currentObj[keys[keys.length - 1]] = { _eq: value };
72
+ } else {
73
+ simplifiedWhere[key] = { _eq: value };
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ return simplifiedWhere;
80
+ }
@@ -0,0 +1,113 @@
1
+ export function tableQueryParamsToHasuraClauses({
2
+ page,
3
+ pageSize,
4
+ searchTerm,
5
+ filters,
6
+ order,
7
+ schema, // Add schema as a parameter
8
+ additionalFilter
9
+ }) {
10
+ let where = {};
11
+ const order_by = {};
12
+ const limit = pageSize || 25;
13
+ const offset = page && pageSize ? (page - 1) * pageSize : 0;
14
+
15
+ if (searchTerm) {
16
+ const searchTermFilters = [];
17
+ schema.fields.forEach(field => {
18
+ const { type, path, searchDisabled } = field;
19
+ if (searchDisabled || field.filterDisabled || type === "color") return;
20
+ const filterValue = searchTerm; // No cleaning needed here, we're using _ilike
21
+
22
+ if (type === "string" || type === "lookup") {
23
+ searchTermFilters.push({
24
+ [path]: { _ilike: `%${filterValue}%` }
25
+ });
26
+ } else if (type === "boolean") {
27
+ let regex;
28
+ try {
29
+ regex = new RegExp("^" + searchTerm, "ig");
30
+ } catch (error) {
31
+ //ignore
32
+ }
33
+ if (regex) {
34
+ if ("true".replace(regex, "") !== "true") {
35
+ searchTermFilters.push({
36
+ [path]: { _eq: true }
37
+ });
38
+ } else if ("false".replace(regex, "") !== "false") {
39
+ searchTermFilters.push({
40
+ [path]: { _eq: false }
41
+ });
42
+ }
43
+ }
44
+ } else if (
45
+ (type === "number" || type === "integer") &&
46
+ !isNaN(filterValue)
47
+ ) {
48
+ searchTermFilters.push({
49
+ [path]: { _eq: parseFloat(filterValue) }
50
+ });
51
+ }
52
+ });
53
+ if (searchTermFilters.length > 0) {
54
+ if (Object.keys(where).length > 0) {
55
+ where = { _and: [where, { _or: searchTermFilters }] };
56
+ } else {
57
+ where = { _or: searchTermFilters };
58
+ }
59
+ }
60
+ }
61
+
62
+ if (filters && filters.length > 0) {
63
+ const filterClauses = filters.map(filter => {
64
+ const { selectedFilter, filterOn, filterValue } = filter;
65
+ switch (selectedFilter) {
66
+ case "textContains":
67
+ return { [filterOn]: { _ilike: `%${filterValue}%` } };
68
+ case "textEquals":
69
+ return { [filterOn]: { _eq: filterValue } };
70
+ case "textNotEquals":
71
+ return { [filterOn]: { _neq: filterValue } };
72
+ case "numberEquals":
73
+ return { [filterOn]: { _eq: parseFloat(filterValue) } };
74
+ case "numberGreaterThan":
75
+ return { [filterOn]: { _gt: parseFloat(filterValue) } };
76
+ case "numberLessThan":
77
+ return { [filterOn]: { _lt: parseFloat(filterValue) } };
78
+ case "numberGreaterThanEquals":
79
+ return { [filterOn]: { _gte: parseFloat(filterValue) } };
80
+ case "numberLessThanEquals":
81
+ return { [filterOn]: { _lte: parseFloat(filterValue) } };
82
+ case "isNull":
83
+ return { [filterOn]: { _is_null: true } };
84
+ case "isNotNull":
85
+ return { [filterOn]: { _is_null: false } };
86
+ default:
87
+ console.warn(`Unsupported filter type: ${selectedFilter}`);
88
+ return {};
89
+ }
90
+ });
91
+
92
+ if (filterClauses.length > 0) {
93
+ if (Object.keys(where).length > 0) {
94
+ where = { _and: [where, ...filterClauses] };
95
+ } else {
96
+ where = { _and: filterClauses };
97
+ }
98
+ }
99
+ }
100
+
101
+ if (order && order.length > 0) {
102
+ order.forEach(item => {
103
+ const field = item.startsWith("-") ? item.substring(1) : item;
104
+ const direction = item.startsWith("-") ? "desc" : "asc";
105
+ order_by[field] = direction;
106
+ });
107
+ }
108
+
109
+ if (additionalFilter) {
110
+ where = { _and: [where, additionalFilter] };
111
+ }
112
+ return { where, order_by, limit, offset };
113
+ }
@@ -32,7 +32,6 @@ import { branch, compose } from "recompose";
32
32
  export const useTableParams = props => {
33
33
  const {
34
34
  additionalFilter,
35
- additionalOrFilter,
36
35
  controlled_pageSize,
37
36
  defaults: _defaults,
38
37
  doNotCoercePageSize,
@@ -166,16 +165,6 @@ export const useTableParams = props => {
166
165
  );
167
166
 
168
167
  const queryParams = useMemo(() => {
169
- const additionalFilterToUse =
170
- typeof additionalFilter === "function"
171
- ? additionalFilter
172
- : () => additionalFilter;
173
-
174
- const additionalOrFilterToUse =
175
- typeof additionalOrFilter === "function"
176
- ? additionalOrFilter
177
- : () => additionalOrFilter;
178
-
179
168
  return getQueryParams({
180
169
  doNotCoercePageSize,
181
170
  currentParams,
@@ -185,8 +174,7 @@ export const useTableParams = props => {
185
174
  schema: convertedSchema,
186
175
  isInfinite: isInfinite || (isSimple && !withPaging),
187
176
  isLocalCall,
188
- additionalFilter: additionalFilterToUse,
189
- additionalOrFilter: additionalOrFilterToUse,
177
+ additionalFilter,
190
178
  noOrderError,
191
179
  isCodeModel,
192
180
  ownProps: passingProps
@@ -194,7 +182,6 @@ export const useTableParams = props => {
194
182
  }, [
195
183
  additionalFilter,
196
184
  passingProps,
197
- additionalOrFilter,
198
185
  doNotCoercePageSize,
199
186
  currentParams,
200
187
  entities,
@@ -1,26 +0,0 @@
1
- import React from "react";
2
- import { render, fireEvent } from "@testing-library/react";
3
- import AdvancedOptions from "./AdvancedOptions";
4
-
5
- describe("AdvancedOptions", () => {
6
- test("renders correctly with given props and default state", () => {
7
- const { queryByText, container } = render(
8
- <AdvancedOptions label="Test Label" content="Test Content" />
9
- );
10
- expect(queryByText("Test Label")).toBeInTheDocument();
11
- expect(queryByText("Test Content")).not.toBeInTheDocument();
12
-
13
- expect(
14
- container.querySelector(".bp3-icon-caret-right")
15
- ).toBeInTheDocument();
16
- });
17
-
18
- test("toggles content when clicked", () => {
19
- const { getByText, queryByText, container } = render(
20
- <AdvancedOptions label="Test Label" content="Test Content" />
21
- );
22
- fireEvent.click(getByText("Test Label"));
23
- expect(queryByText("Test Content")).toBeInTheDocument();
24
- expect(container.querySelector(".bp3-icon-caret-down")).toBeInTheDocument();
25
- });
26
- });
@@ -1,12 +0,0 @@
1
- /* Copyright (C) 2018 TeselaGen Biotechnology, Inc. */
2
-
3
- import React from "react";
4
- import { Spinner } from "@blueprintjs/core";
5
-
6
- export default function AsyncValidateFieldSpinner({ validating }) {
7
- if (validating) {
8
- return <Spinner size="18" />;
9
- } else {
10
- return null;
11
- }
12
- }
@@ -1,14 +0,0 @@
1
- import React from "react";
2
- import { Classes } from "@blueprintjs/core";
3
- import classNames from "classnames";
4
-
5
- export default function BlueprintError({ error }) {
6
- if (!error) return null;
7
- return (
8
- <div className={classNames(Classes.FORM_GROUP, Classes.INTENT_DANGER)}>
9
- <div className={classNames(Classes.FORM_HELPER_TEXT, "preserve-newline")}>
10
- {error}
11
- </div>
12
- </div>
13
- );
14
- }
@@ -1,16 +0,0 @@
1
- /* taken from http://tobiasahlin.com/spinkit/ */
2
- import React from "react";
3
- import classNames from "classnames";
4
- import "./style.css";
5
-
6
- export function BounceLoader({ style, className }) {
7
- return (
8
- <div className={classNames("tg-bounce-loader", className)} style={style}>
9
- <div className="rect1" />
10
- <div className="rect2" />
11
- <div className="rect3" />
12
- <div className="rect4" />
13
- <div className="rect5" />
14
- </div>
15
- );
16
- }