@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.
- package/DataTable/utils/filterLocalEntitiesToHasura.d.ts +5 -0
- package/DataTable/utils/initializeHasuraWhereAndFilter.d.ts +2 -0
- package/DataTable/utils/queryParams.d.ts +8 -12
- package/DataTable/utils/simplifyHasuraWhere.d.ts +1 -0
- package/DataTable/utils/tableQueryParamsToHasuraClauses.d.ts +14 -0
- package/{src/DataTable/FilterAndSortMenu.js → FilterAndSortMenu.js} +27 -30
- package/filterLocalEntitiesToHasura.js +216 -0
- package/index.cjs.js +695 -968
- package/index.d.ts +1 -0
- package/index.es.js +695 -968
- package/initializeHasuraWhereAndFilter.js +27 -0
- package/{src/utils/isBeingCalledExcessively.js → isBeingCalledExcessively.js} +0 -1
- package/package.json +1 -1
- package/queryParams.js +336 -0
- package/simplifyHasuraWhere.js +80 -0
- package/tableQueryParamsToHasuraClauses.js +113 -0
- package/{src/DataTable/utils/withTableParams.js → withTableParams.js} +1 -14
- package/src/AdvancedOptions.spec.js +0 -26
- package/src/AsyncValidateFieldSpinner/index.js +0 -12
- package/src/BlueprintError/index.js +0 -14
- package/src/BounceLoader/index.js +0 -16
- package/src/BounceLoader/style.css +0 -45
- package/src/CollapsibleCard/index.js +0 -68
- package/src/CollapsibleCard/style.css +0 -23
- package/src/DNALoader/index.js +0 -20
- package/src/DNALoader/style.css +0 -251
- package/src/DataTable/index.js +0 -3214
- package/src/DataTable/style.css +0 -608
- package/src/DataTable/utils/index.js +0 -55
- package/src/DataTable/utils/queryParams.js +0 -1058
- package/src/DialogFooter/index.js +0 -86
- package/src/DialogFooter/style.css +0 -9
- package/src/FormComponents/index.js +0 -1266
- package/src/FormComponents/style.css +0 -275
- package/src/FormComponents/utils.js +0 -6
- package/src/HotkeysDialog/index.js +0 -79
- package/src/HotkeysDialog/style.css +0 -54
- package/src/InfoHelper/index.js +0 -78
- package/src/InfoHelper/style.css +0 -7
- package/src/IntentText/index.js +0 -18
- package/src/Loading/index.js +0 -70
- package/src/Loading/style.css +0 -4
- package/src/MenuBar/index.js +0 -423
- package/src/MenuBar/style.css +0 -45
- package/src/PromptUnsavedChanges/index.js +0 -38
- package/src/ResizableDraggableDialog/index.js +0 -141
- package/src/ResizableDraggableDialog/style.css +0 -42
- package/src/ScrollToTop/index.js +0 -72
- package/src/TagSelect/index.js +0 -69
- package/src/TagSelect/style.css +0 -13
- package/src/TgHtmlSelect/index.js +0 -20
- package/src/TgSelect/index.js +0 -537
- package/src/TgSelect/style.css +0 -61
- package/src/TgSuggest/index.js +0 -124
- package/src/Timeline/index.js +0 -15
- package/src/enhancers/withDialog/index.js +0 -196
- package/src/index.js +0 -87
- package/src/showConfirmationDialog/index.js +0 -148
- package/src/style.css +0 -265
- /package/{src/AdvancedOptions.js → AdvancedOptions.js} +0 -0
- /package/{src/AssignDefaultsModeContext.js → AssignDefaultsModeContext.js} +0 -0
- /package/{src/DataTable/CellDragHandle.js → CellDragHandle.js} +0 -0
- /package/{src/DataTable/ColumnFilterMenu.js → ColumnFilterMenu.js} +0 -0
- /package/{src/DataTable/Columns.js → Columns.js} +0 -0
- /package/{src/DataTable/DisabledLoadingComponent.js → DisabledLoadingComponent.js} +0 -0
- /package/{src/DataTable/DisplayOptions.js → DisplayOptions.js} +0 -0
- /package/{src/DropdownButton.js → DropdownButton.js} +0 -0
- /package/{src/DataTable/DropdownCell.js → DropdownCell.js} +0 -0
- /package/{src/DataTable/EditableCell.js → EditableCell.js} +0 -0
- /package/{src/FillWindow.css → FillWindow.css} +0 -0
- /package/{src/FillWindow.js → FillWindow.js} +0 -0
- /package/{src/FormComponents/FormSeparator.js → FormSeparator.js} +0 -0
- /package/{src/FormComponents/LoadingDots.js → LoadingDots.js} +0 -0
- /package/{src/MatchHeaders.js → MatchHeaders.js} +0 -0
- /package/{src/DataTable/PagingTool.js → PagingTool.js} +0 -0
- /package/{src/DataTable/RenderCell.js → RenderCell.js} +0 -0
- /package/{src/DataTable/SearchBar.js → SearchBar.js} +0 -0
- /package/{src/SimpleStepViz.js → SimpleStepViz.js} +0 -0
- /package/{src/DataTable/SortableColumns.js → SortableColumns.js} +0 -0
- /package/{src/DataTable/TableFormTrackerContext.js → TableFormTrackerContext.js} +0 -0
- /package/{src/Tag.js → Tag.js} +0 -0
- /package/{src/DataTable/ThComponent.js → ThComponent.js} +0 -0
- /package/{src/Timeline/TimelineEvent.js → TimelineEvent.js} +0 -0
- /package/{src/UploadCsvWizard.css → UploadCsvWizard.css} +0 -0
- /package/{src/UploadCsvWizard.js → UploadCsvWizard.js} +0 -0
- /package/{src/FormComponents/Uploader.js → Uploader.js} +0 -0
- /package/{src/utils/adHoc.js → adHoc.js} +0 -0
- /package/{src/autoTooltip.js → autoTooltip.js} +0 -0
- /package/{src/utils/basicHandleActionsWithFullState.js → basicHandleActionsWithFullState.js} +0 -0
- /package/{src/utils/browserUtils.js → browserUtils.js} +0 -0
- /package/{src/utils/combineReducersWithFullState.js → combineReducersWithFullState.js} +0 -0
- /package/{src/utils/commandControls.js → commandControls.js} +0 -0
- /package/{src/utils/commandUtils.js → commandUtils.js} +0 -0
- /package/{src/constants.js → constants.js} +0 -0
- /package/{src/DataTable/utils/convertSchema.js → convertSchema.js} +0 -0
- /package/{src/customIcons.js → customIcons.js} +0 -0
- /package/{src/DataTable/dataTableEnhancer.js → dataTableEnhancer.js} +0 -0
- /package/{src/DataTable/defaultFormatters.js → defaultFormatters.js} +0 -0
- /package/{src/DataTable/defaultValidators.js → defaultValidators.js} +0 -0
- /package/{src/utils/determineBlackOrWhiteTextColor.js → determineBlackOrWhiteTextColor.js} +0 -0
- /package/{src/DataTable/editCellHelper.js → editCellHelper.js} +0 -0
- /package/{src/DataTable/utils/formatPasteData.js → formatPasteData.js} +0 -0
- /package/{src/DataTable/utils/getAllRows.js → getAllRows.js} +0 -0
- /package/{src/DataTable/utils/getCellCopyText.js → getCellCopyText.js} +0 -0
- /package/{src/DataTable/utils/getCellInfo.js → getCellInfo.js} +0 -0
- /package/{src/DataTable/getCellVal.js → getCellVal.js} +0 -0
- /package/{src/utils/getDayjsFormatter.js → getDayjsFormatter.js} +0 -0
- /package/{src/DataTable/utils/getFieldPathToField.js → getFieldPathToField.js} +0 -0
- /package/{src/DataTable/utils/getIdOrCodeOrIndex.js → getIdOrCodeOrIndex.js} +0 -0
- /package/{src/DataTable/utils/getLastSelectedEntity.js → getLastSelectedEntity.js} +0 -0
- /package/{src/DataTable/utils/getNewEntToSelect.js → getNewEntToSelect.js} +0 -0
- /package/{src/FormComponents/getNewName.js → getNewName.js} +0 -0
- /package/{src/DataTable/utils/getRowCopyText.js → getRowCopyText.js} +0 -0
- /package/{src/DataTable/utils/getTableConfigFromStorage.js → getTableConfigFromStorage.js} +0 -0
- /package/{src/utils/getTextFromEl.js → getTextFromEl.js} +0 -0
- /package/{src/DataTable/getVals.js → getVals.js} +0 -0
- /package/{src/DataTable/utils/handleCopyColumn.js → handleCopyColumn.js} +0 -0
- /package/{src/DataTable/utils/handleCopyHelper.js → handleCopyHelper.js} +0 -0
- /package/{src/DataTable/utils/handleCopyRows.js → handleCopyRows.js} +0 -0
- /package/{src/DataTable/utils/handleCopyTable.js → handleCopyTable.js} +0 -0
- /package/{src/utils/handlerHelpers.js → handlerHelpers.js} +0 -0
- /package/{src/utils/hotkeyUtils.js → hotkeyUtils.js} +0 -0
- /package/{src/utils/hooks/index.js → index.js} +0 -0
- /package/{src/DataTable/utils/isBottomRightCornerOfRectangle.js → isBottomRightCornerOfRectangle.js} +0 -0
- /package/{src/DataTable/utils/isEntityClean.js → isEntityClean.js} +0 -0
- /package/{src/DataTable/isTruthy.js → isTruthy.js} +0 -0
- /package/{src/DataTable/isValueEmpty.js → isValueEmpty.js} +0 -0
- /package/{src/FormComponents/itemUpload.js → itemUpload.js} +0 -0
- /package/{src/utils/menuUtils.js → menuUtils.js} +0 -0
- /package/{src/utils/popoverOverflowModifiers.js → popoverOverflowModifiers.js} +0 -0
- /package/{src/DataTable/utils/primarySelectedValue.js → primarySelectedValue.js} +0 -0
- /package/{src/utils/pureNoFunc.js → pureNoFunc.js} +0 -0
- /package/{src/DataTable/utils/removeCleanRows.js → removeCleanRows.js} +0 -0
- /package/{src/utils/renderOnDoc.js → renderOnDoc.js} +0 -0
- /package/{src/rerenderOnWindowResize.js → rerenderOnWindowResize.js} +0 -0
- /package/{src/DataTable/utils/rowClick.js → rowClick.js} +0 -0
- /package/{src/DataTable/utils/selection.js → selection.js} +0 -0
- /package/{src/showAppSpinner.js → showAppSpinner.js} +0 -0
- /package/{src/showDialogOnDocBody.js → showDialogOnDocBody.js} +0 -0
- /package/{src/utils/showProgressToast.js → showProgressToast.js} +0 -0
- /package/{src/FormComponents/sortify.js → sortify.js} +0 -0
- /package/{src/Timeline/style.css → style.css} +0 -0
- /package/{src/utils/tagUtils.js → tagUtils.js} +0 -0
- /package/{src/utils/tgFormValues.js → tgFormValues.js} +0 -0
- /package/{src/enhancers/withDialog/tg_modalState.js → tg_modalState.js} +0 -0
- /package/{src/throwFormError.js → throwFormError.js} +0 -0
- /package/{src/toastr.js → toastr.js} +0 -0
- /package/{src/FormComponents/tryToMatchSchemas.js → tryToMatchSchemas.js} +0 -0
- /package/{src/typeToCommonType.js → typeToCommonType.js} +0 -0
- /package/{src/utils/hooks/useDeepEqualMemo.js → useDeepEqualMemo.js} +0 -0
- /package/{src/useDialog.js → useDialog.js} +0 -0
- /package/{src/utils/hooks/useStableReference.js → useStableReference.js} +0 -0
- /package/{src/DataTable/utils/useTableEntities.js → useTableEntities.js} +0 -0
- /package/{src/utils/useTraceUpdate.js → useTraceUpdate.js} +0 -0
- /package/{src/DataTable/utils/utils.js → utils.js} +0 -0
- /package/{src/DataTable/validateTableWideErrors.js → validateTableWideErrors.js} +0 -0
- /package/{src/DataTable/viewColumn.js → viewColumn.js} +0 -0
- /package/{src/enhancers/withField.js → withField.js} +0 -0
- /package/{src/enhancers/withFields.js → withFields.js} +0 -0
- /package/{src/enhancers/withLocalStorage.js → withLocalStorage.js} +0 -0
- /package/{src/utils/withSelectTableRecords.js → withSelectTableRecords.js} +0 -0
- /package/{src/DataTable/utils/withSelectedEntities.js → withSelectedEntities.js} +0 -0
- /package/{src/utils/withStore.js → withStore.js} +0 -0
- /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
|
+
|
package/package.json
CHANGED
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
|
|
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
|
-
}
|