@teselagen/ui 0.8.8 → 0.9.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/getAllRows.d.ts +1 -1
- package/DataTable/utils/getRowCopyText.d.ts +1 -3
- package/DataTable/utils/handleCopyColumn.d.ts +1 -1
- package/DataTable/utils/handleCopyRows.d.ts +1 -5
- package/DataTable/utils/handleCopyTable.d.ts +1 -1
- package/DataTable/utils/index.d.ts +0 -1
- package/DataTable/utils/initializeHasuraWhereAndFilter.d.ts +1 -0
- package/DataTable/utils/queryParams.d.ts +16 -12
- package/DataTable/utils/rowClick.d.ts +1 -1
- package/DataTable/utils/tableQueryParamsToHasuraClauses.d.ts +26 -0
- package/FormComponents/Uploader.d.ts +1 -3
- package/FormComponents/tryToMatchSchemas.d.ts +1 -1
- package/MenuBar/index.d.ts +1 -3
- package/README.md +1 -1
- package/ResizableDraggableDialog/index.d.ts +1 -3
- package/TagSelect/index.d.ts +1 -1
- package/index.cjs.js +39715 -36506
- package/index.d.ts +2 -0
- package/index.es.js +38714 -35505
- package/package.json +2 -2
- package/src/DataTable/Columns.js +2 -2
- package/src/DataTable/DisplayOptions.js +1 -1
- package/src/DataTable/FilterAndSortMenu.js +27 -30
- package/src/DataTable/index.js +101 -84
- package/src/DataTable/style.css +1 -1
- package/src/DataTable/utils/filterLocalEntitiesToHasura.js +356 -0
- package/src/DataTable/utils/filterLocalEntitiesToHasura.test.js +1285 -0
- package/src/DataTable/utils/getAllRows.js +2 -6
- package/src/DataTable/utils/handleCopyColumn.js +2 -2
- package/src/DataTable/utils/handleCopyTable.js +2 -2
- package/src/DataTable/utils/initializeHasuraWhereAndFilter.js +15 -0
- package/src/DataTable/utils/queryParams.js +153 -770
- package/src/DataTable/utils/tableQueryParamsToHasuraClauses.js +277 -0
- package/src/DataTable/utils/tableQueryParamsToHasuraClauses.test.js +245 -0
- package/src/DataTable/utils/withTableParams.js +3 -16
- package/src/FormComponents/index.js +2 -2
- package/src/TgSelect/index.js +15 -0
- package/src/index.js +2 -0
- package/src/utils/determineBlackOrWhiteTextColor.js +8 -1
- package/ui.css +10537 -0
- package/utils/determineBlackOrWhiteTextColor.d.ts +1 -2
- package/utils/hotkeyUtils.d.ts +1 -3
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
import queryString from "qs";
|
|
2
|
+
import { uniqBy, clone, camelCase, forEach } from "lodash-es";
|
|
2
3
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
startsWith,
|
|
9
|
-
endsWith,
|
|
10
|
-
last,
|
|
11
|
-
orderBy,
|
|
12
|
-
take,
|
|
13
|
-
drop,
|
|
14
|
-
isEmpty,
|
|
15
|
-
isInteger
|
|
16
|
-
} from "lodash-es";
|
|
17
|
-
import dayjs from "dayjs";
|
|
18
|
-
import { flatMap } from "lodash-es";
|
|
4
|
+
getFieldsMappedByCCDisplayName,
|
|
5
|
+
tableQueryParamsToHasuraClauses
|
|
6
|
+
} from "./tableQueryParamsToHasuraClauses";
|
|
7
|
+
import { filterLocalEntitiesToHasura } from "./filterLocalEntitiesToHasura";
|
|
8
|
+
import { initializeHasuraWhereAndFilter } from "./initializeHasuraWhereAndFilter";
|
|
19
9
|
|
|
20
10
|
const defaultPageSizes = [5, 10, 15, 25, 50, 100, 200, 400];
|
|
21
11
|
|
|
@@ -63,448 +53,6 @@ function safeParse(val) {
|
|
|
63
53
|
return val;
|
|
64
54
|
}
|
|
65
55
|
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
*
|
|
69
|
-
* @param {object} field
|
|
70
|
-
* @returns the camelCase display name of the field, to be used for filters, sorting, etc
|
|
71
|
-
*/
|
|
72
|
-
export function getCCDisplayName(field) {
|
|
73
|
-
return camelCase(
|
|
74
|
-
typeof field.displayName === "string" ? field.displayName : field.path
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Takes a schema and returns an object with the fields mapped by their camelCased display name.
|
|
80
|
-
* If the displayName is not set or is a jsx element, the path is used instead.
|
|
81
|
-
* The same conversion must be done when using the result of this method
|
|
82
|
-
*/
|
|
83
|
-
function getFieldsMappedByCCDisplayName(schema) {
|
|
84
|
-
return schema.fields.reduce((acc, field) => {
|
|
85
|
-
const ccDisplayName = getCCDisplayName(field);
|
|
86
|
-
acc[ccDisplayName] = field;
|
|
87
|
-
return acc;
|
|
88
|
-
}, {});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function orderEntitiesLocal(orderArray, entities, schema, ownProps) {
|
|
92
|
-
if (orderArray?.length) {
|
|
93
|
-
const orderFuncs = [];
|
|
94
|
-
const ascOrDescArray = [];
|
|
95
|
-
orderArray.forEach(order => {
|
|
96
|
-
const ccDisplayName = order.replace(/^-/gi, ""); // "-updatedAt" => "updatedAt"
|
|
97
|
-
const ccFields = getFieldsMappedByCCDisplayName(schema);
|
|
98
|
-
const field = ccFields[ccDisplayName];
|
|
99
|
-
if (!field) {
|
|
100
|
-
throw new Error(
|
|
101
|
-
"Ruh roh, there should have been a column to sort on for " +
|
|
102
|
-
order +
|
|
103
|
-
" but none was found in " +
|
|
104
|
-
schema.fields
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
const { path, getValueToFilterOn, sortFn } = field;
|
|
108
|
-
if (field.type === "timestamp") {
|
|
109
|
-
//with the timestamp logic below, make sure empty dates always end up on the bottom of the stack
|
|
110
|
-
ascOrDescArray.push("desc");
|
|
111
|
-
}
|
|
112
|
-
ascOrDescArray.push(ccDisplayName === order ? "asc" : "desc");
|
|
113
|
-
//push the actual sorting function
|
|
114
|
-
if (field.type === "timestamp") {
|
|
115
|
-
//with the timestamp logic above, make sure empty dates always end up on the bottom of the stack
|
|
116
|
-
orderFuncs.push(r => {
|
|
117
|
-
const val = get(r, path);
|
|
118
|
-
return !!val;
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
if (path && endsWith(path.toLowerCase(), "id")) {
|
|
122
|
-
orderFuncs.push(o => {
|
|
123
|
-
return parseInt(get(o, path), 10);
|
|
124
|
-
});
|
|
125
|
-
} else if (sortFn) {
|
|
126
|
-
const toOrder = Array.isArray(sortFn) ? sortFn : [sortFn];
|
|
127
|
-
orderFuncs.push(...toOrder);
|
|
128
|
-
} else if (getValueToFilterOn) {
|
|
129
|
-
orderFuncs.push(o => {
|
|
130
|
-
return getValueToFilterOn(o, ownProps);
|
|
131
|
-
});
|
|
132
|
-
} else {
|
|
133
|
-
orderFuncs.push(r => {
|
|
134
|
-
const val = get(r, path);
|
|
135
|
-
return val && val.toLowerCase ? val.toLowerCase() : val;
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
entities = orderBy(entities, orderFuncs, ascOrDescArray);
|
|
140
|
-
}
|
|
141
|
-
return entities;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function getAndAndOrFilters(allFilters) {
|
|
145
|
-
const orFilters = [];
|
|
146
|
-
const andFilters = [];
|
|
147
|
-
const otherOrFilters = [];
|
|
148
|
-
|
|
149
|
-
allFilters.forEach(filter => {
|
|
150
|
-
if (
|
|
151
|
-
filter.isOrFilter &&
|
|
152
|
-
typeof filter.filterValue === "string" &&
|
|
153
|
-
filter.filterValue.includes(",")
|
|
154
|
-
) {
|
|
155
|
-
// handle comma separated filters by adding more orWheres
|
|
156
|
-
const allFilterValues = filter.filterValue.split(",");
|
|
157
|
-
allFilterValues.forEach((filterValue, i) => {
|
|
158
|
-
filterValue = filterValue.trim();
|
|
159
|
-
if (!filterValue) return;
|
|
160
|
-
const newFilter = {
|
|
161
|
-
...filter,
|
|
162
|
-
filterValue
|
|
163
|
-
};
|
|
164
|
-
if (i === 0) {
|
|
165
|
-
orFilters.push(newFilter);
|
|
166
|
-
} else {
|
|
167
|
-
const iMinus = i - 1;
|
|
168
|
-
if (!otherOrFilters[iMinus]) otherOrFilters[iMinus] = [];
|
|
169
|
-
otherOrFilters[iMinus].push(newFilter);
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
} else if (filter.isOrFilter) {
|
|
173
|
-
orFilters.push(filter);
|
|
174
|
-
} else {
|
|
175
|
-
andFilters.push(filter);
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
return {
|
|
179
|
-
orFilters,
|
|
180
|
-
andFilters,
|
|
181
|
-
otherOrFilters
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function filterEntitiesLocal(
|
|
186
|
-
filters = [],
|
|
187
|
-
searchTerm,
|
|
188
|
-
entities,
|
|
189
|
-
schema,
|
|
190
|
-
ownProps
|
|
191
|
-
) {
|
|
192
|
-
const allFilters = getAllFilters(filters, searchTerm, schema);
|
|
193
|
-
|
|
194
|
-
if (allFilters.length) {
|
|
195
|
-
const ccFields = getFieldsMappedByCCDisplayName(schema);
|
|
196
|
-
const { andFilters, orFilters, otherOrFilters } =
|
|
197
|
-
getAndAndOrFilters(allFilters);
|
|
198
|
-
//filter ands first
|
|
199
|
-
andFilters.forEach(filter => {
|
|
200
|
-
entities = getEntitiesForGivenFilter(
|
|
201
|
-
entities,
|
|
202
|
-
filter,
|
|
203
|
-
ccFields,
|
|
204
|
-
ownProps
|
|
205
|
-
);
|
|
206
|
-
});
|
|
207
|
-
//then filter ors
|
|
208
|
-
if (orFilters.length) {
|
|
209
|
-
let orEntities = [];
|
|
210
|
-
orFilters.concat(...otherOrFilters).forEach(filter => {
|
|
211
|
-
orEntities = orEntities.concat(
|
|
212
|
-
getEntitiesForGivenFilter(entities, filter, ccFields, ownProps)
|
|
213
|
-
);
|
|
214
|
-
});
|
|
215
|
-
entities = uniq(orEntities);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return entities;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function cleanFilterValue(_filterValue, type) {
|
|
222
|
-
let filterValue = _filterValue;
|
|
223
|
-
if (type === "number" || type === "integer") {
|
|
224
|
-
filterValue = Array.isArray(filterValue)
|
|
225
|
-
? filterValue.map(val => Number(val))
|
|
226
|
-
: Number(filterValue);
|
|
227
|
-
}
|
|
228
|
-
return filterValue;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function getEntitiesForGivenFilter(entities, filter, ccFields, ownProps) {
|
|
232
|
-
const { filterOn, filterValue: _filterValue, selectedFilter } = filter;
|
|
233
|
-
const field = ccFields[filterOn];
|
|
234
|
-
const { path, getValueToFilterOn } = field;
|
|
235
|
-
const filterValue = cleanFilterValue(_filterValue, field.type);
|
|
236
|
-
const subFilter = getSubFilter(false, selectedFilter, filterValue);
|
|
237
|
-
entities = entities.filter(entity => {
|
|
238
|
-
const fieldVal = getValueToFilterOn
|
|
239
|
-
? getValueToFilterOn(entity, ownProps)
|
|
240
|
-
: get(entity, path);
|
|
241
|
-
const shouldKeep = subFilter(fieldVal);
|
|
242
|
-
return shouldKeep;
|
|
243
|
-
});
|
|
244
|
-
return entities;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function getFiltersFromSearchTerm(searchTerm, schema) {
|
|
248
|
-
const searchTermFilters = [];
|
|
249
|
-
if (searchTerm) {
|
|
250
|
-
const sharedFields = {
|
|
251
|
-
isOrFilter: true,
|
|
252
|
-
isSearchTermFilter: true
|
|
253
|
-
};
|
|
254
|
-
schema.fields.forEach(field => {
|
|
255
|
-
const { type, searchDisabled } = field;
|
|
256
|
-
if (searchDisabled || field.filterDisabled || type === "color") return;
|
|
257
|
-
const ccDisplayName = getCCDisplayName(field);
|
|
258
|
-
const filterValue = cleanFilterValue(searchTerm, type);
|
|
259
|
-
if (type === "string" || type === "lookup") {
|
|
260
|
-
searchTermFilters.push({
|
|
261
|
-
...sharedFields,
|
|
262
|
-
filterOn: ccDisplayName,
|
|
263
|
-
filterValue: searchTerm,
|
|
264
|
-
selectedFilter: "contains"
|
|
265
|
-
});
|
|
266
|
-
} else if (type === "boolean") {
|
|
267
|
-
let regex;
|
|
268
|
-
try {
|
|
269
|
-
regex = new RegExp("^" + searchTerm, "ig");
|
|
270
|
-
} catch (error) {
|
|
271
|
-
//ignore
|
|
272
|
-
}
|
|
273
|
-
if (regex) {
|
|
274
|
-
if ("true".replace(regex, "") !== "true") {
|
|
275
|
-
searchTermFilters.push({
|
|
276
|
-
...sharedFields,
|
|
277
|
-
filterOn: ccDisplayName,
|
|
278
|
-
filterValue: true,
|
|
279
|
-
selectedFilter: "true"
|
|
280
|
-
});
|
|
281
|
-
} else if ("false".replace(regex, "") !== "false") {
|
|
282
|
-
searchTermFilters.push({
|
|
283
|
-
...sharedFields,
|
|
284
|
-
filterOn: ccDisplayName,
|
|
285
|
-
filterValue: false,
|
|
286
|
-
selectedFilter: "false"
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
} else if (
|
|
291
|
-
(type === "number" || type === "integer") &&
|
|
292
|
-
!isNaN(filterValue)
|
|
293
|
-
) {
|
|
294
|
-
if (type === "integer" && !isInteger(filterValue)) {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
searchTermFilters.push({
|
|
298
|
-
...sharedFields,
|
|
299
|
-
filterOn: ccDisplayName,
|
|
300
|
-
filterValue: filterValue,
|
|
301
|
-
selectedFilter: "equalTo"
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
return searchTermFilters;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
function getSubFilter(
|
|
310
|
-
qb, //if no qb is passed, it means we are filtering locally and want to get a function back that can be used in an array filter
|
|
311
|
-
selectedFilter,
|
|
312
|
-
filterValue
|
|
313
|
-
) {
|
|
314
|
-
const ccSelectedFilter = camelCase(selectedFilter);
|
|
315
|
-
let stringFilterValue =
|
|
316
|
-
filterValue && filterValue.toString ? filterValue.toString() : filterValue;
|
|
317
|
-
if (stringFilterValue === false) {
|
|
318
|
-
// we still want to be able to search for the string "false" which will get parsed to false
|
|
319
|
-
stringFilterValue = "false";
|
|
320
|
-
} else {
|
|
321
|
-
stringFilterValue = stringFilterValue || "";
|
|
322
|
-
}
|
|
323
|
-
const filterValLower =
|
|
324
|
-
stringFilterValue.toLowerCase && stringFilterValue.toLowerCase();
|
|
325
|
-
const arrayFilterValue = Array.isArray(filterValue)
|
|
326
|
-
? filterValue
|
|
327
|
-
: stringFilterValue.split(";");
|
|
328
|
-
if (ccSelectedFilter === "startsWith") {
|
|
329
|
-
return qb
|
|
330
|
-
? qb.startsWith(stringFilterValue) //filter using qb (aka we're backend connected)
|
|
331
|
-
: fieldVal => {
|
|
332
|
-
//filter using plain old javascript (aka we've got a local table that isn't backend connected)
|
|
333
|
-
if (!fieldVal || !fieldVal.toLowerCase) return false;
|
|
334
|
-
return startsWith(fieldVal.toLowerCase(), filterValLower);
|
|
335
|
-
};
|
|
336
|
-
} else if (ccSelectedFilter === "endsWith") {
|
|
337
|
-
return qb
|
|
338
|
-
? qb.endsWith(stringFilterValue) //filter using qb (aka we're backend connected)
|
|
339
|
-
: fieldVal => {
|
|
340
|
-
//filter using plain old javascript (aka we've got a local table that isn't backend connected)
|
|
341
|
-
if (!fieldVal || !fieldVal.toLowerCase) return false;
|
|
342
|
-
return endsWith(fieldVal.toLowerCase(), filterValLower);
|
|
343
|
-
};
|
|
344
|
-
} else if (
|
|
345
|
-
ccSelectedFilter === "contains" ||
|
|
346
|
-
ccSelectedFilter === "notContains"
|
|
347
|
-
) {
|
|
348
|
-
return qb
|
|
349
|
-
? ccSelectedFilter === "contains"
|
|
350
|
-
? qb.contains(stringFilterValue.replace(/_/g, "\\_"))
|
|
351
|
-
: qb.notContains(stringFilterValue.replace(/_/g, "\\_"))
|
|
352
|
-
: fieldVal => {
|
|
353
|
-
if (!fieldVal || !fieldVal.toLowerCase) return false;
|
|
354
|
-
return ccSelectedFilter === "contains"
|
|
355
|
-
? fieldVal.toLowerCase().replace(filterValLower, "") !==
|
|
356
|
-
fieldVal.toLowerCase()
|
|
357
|
-
: fieldVal.toLowerCase().replace(filterValLower, "") ===
|
|
358
|
-
fieldVal.toLowerCase();
|
|
359
|
-
};
|
|
360
|
-
} else if (ccSelectedFilter === "inList") {
|
|
361
|
-
return qb
|
|
362
|
-
? qb.inList(arrayFilterValue) //filter using qb (aka we're backend connected)
|
|
363
|
-
: fieldVal => {
|
|
364
|
-
//filter using plain old javascript (aka we've got a local table that isn't backend connected)
|
|
365
|
-
if (!fieldVal?.toString) return false;
|
|
366
|
-
return (
|
|
367
|
-
arrayFilterValue
|
|
368
|
-
.map(val => {
|
|
369
|
-
if (val) {
|
|
370
|
-
if (val.toString) return val.toString().toLowerCase();
|
|
371
|
-
return val.toLowerCase();
|
|
372
|
-
}
|
|
373
|
-
return undefined;
|
|
374
|
-
})
|
|
375
|
-
.indexOf(fieldVal.toString().toLowerCase()) > -1
|
|
376
|
-
);
|
|
377
|
-
};
|
|
378
|
-
} else if (ccSelectedFilter === "notInList") {
|
|
379
|
-
return qb
|
|
380
|
-
? qb.notInList(arrayFilterValue) //filter using qb (aka we're backend connected)
|
|
381
|
-
: fieldVal => {
|
|
382
|
-
//filter using plain old javascript (aka we've got a local table that isn't backend connected)
|
|
383
|
-
if (!fieldVal?.toString) return false;
|
|
384
|
-
return (
|
|
385
|
-
arrayFilterValue
|
|
386
|
-
.map(val => {
|
|
387
|
-
if (val) {
|
|
388
|
-
if (val.toString) return val.toString().toLowerCase();
|
|
389
|
-
return val.toLowerCase();
|
|
390
|
-
}
|
|
391
|
-
return undefined;
|
|
392
|
-
})
|
|
393
|
-
.indexOf(fieldVal.toString().toLowerCase()) === -1
|
|
394
|
-
);
|
|
395
|
-
};
|
|
396
|
-
} else if (ccSelectedFilter === "isEmpty") {
|
|
397
|
-
return qb
|
|
398
|
-
? qb.isEmpty()
|
|
399
|
-
: fieldVal => {
|
|
400
|
-
return !fieldVal;
|
|
401
|
-
};
|
|
402
|
-
} else if (ccSelectedFilter === "notEmpty") {
|
|
403
|
-
return qb
|
|
404
|
-
? [qb.notNull(), qb.notEquals("")]
|
|
405
|
-
: fieldVal => {
|
|
406
|
-
return !!fieldVal;
|
|
407
|
-
};
|
|
408
|
-
} else if (ccSelectedFilter === "isExactly") {
|
|
409
|
-
return qb
|
|
410
|
-
? filterValue
|
|
411
|
-
: fieldVal => {
|
|
412
|
-
return fieldVal === filterValue;
|
|
413
|
-
};
|
|
414
|
-
} else if (ccSelectedFilter === "true") {
|
|
415
|
-
return qb
|
|
416
|
-
? qb.equals(true) //filter using qb (aka we're backend connected)
|
|
417
|
-
: fieldVal => {
|
|
418
|
-
//filter using plain old javascript (aka we've got a local table that isn't backend connected)
|
|
419
|
-
return !!fieldVal;
|
|
420
|
-
};
|
|
421
|
-
} else if (ccSelectedFilter === "false") {
|
|
422
|
-
return qb
|
|
423
|
-
? qb.equals(false) //filter using qb (aka we're backend connected)
|
|
424
|
-
: fieldVal => {
|
|
425
|
-
//filter using plain old javascript (aka we've got a local table that isn't backend connected)
|
|
426
|
-
return !fieldVal;
|
|
427
|
-
};
|
|
428
|
-
} else if (ccSelectedFilter === "isBetween") {
|
|
429
|
-
return qb
|
|
430
|
-
? qb.between(
|
|
431
|
-
new Date(arrayFilterValue[0]),
|
|
432
|
-
new Date(new Date(arrayFilterValue[1]).setHours(23, 59)) // set end of day for more accurate filtering
|
|
433
|
-
)
|
|
434
|
-
: fieldVal => {
|
|
435
|
-
return (
|
|
436
|
-
dayjs(arrayFilterValue[0]).valueOf() <= dayjs(fieldVal).valueOf() &&
|
|
437
|
-
dayjs(fieldVal).valueOf() <= dayjs(arrayFilterValue[1]).valueOf()
|
|
438
|
-
);
|
|
439
|
-
};
|
|
440
|
-
} else if (ccSelectedFilter === "notBetween") {
|
|
441
|
-
return qb
|
|
442
|
-
? qb.notBetween(
|
|
443
|
-
new Date(arrayFilterValue[0]),
|
|
444
|
-
new Date(new Date(arrayFilterValue[1]).setHours(23, 59)) // set end of day for more accurate filtering
|
|
445
|
-
)
|
|
446
|
-
: fieldVal => {
|
|
447
|
-
return (
|
|
448
|
-
dayjs(arrayFilterValue[0]).valueOf() > dayjs(fieldVal).valueOf() ||
|
|
449
|
-
dayjs(fieldVal).valueOf() > dayjs(arrayFilterValue[1]).valueOf()
|
|
450
|
-
);
|
|
451
|
-
};
|
|
452
|
-
} else if (ccSelectedFilter === "isBefore") {
|
|
453
|
-
return qb
|
|
454
|
-
? qb.lessThan(new Date(filterValue))
|
|
455
|
-
: fieldVal => {
|
|
456
|
-
return dayjs(fieldVal).valueOf() < dayjs(filterValue).valueOf();
|
|
457
|
-
};
|
|
458
|
-
} else if (ccSelectedFilter === "isAfter") {
|
|
459
|
-
return qb
|
|
460
|
-
? qb.greaterThan(new Date(new Date(filterValue).setHours(23, 59))) // set end of day for more accurate filtering
|
|
461
|
-
: fieldVal => {
|
|
462
|
-
return dayjs(fieldVal).valueOf() > dayjs(filterValue).valueOf();
|
|
463
|
-
};
|
|
464
|
-
} else if (ccSelectedFilter === "greaterThan") {
|
|
465
|
-
return qb
|
|
466
|
-
? qb.greaterThan(filterValue)
|
|
467
|
-
: fieldVal => {
|
|
468
|
-
return fieldVal > filterValue;
|
|
469
|
-
};
|
|
470
|
-
} else if (ccSelectedFilter === "lessThan") {
|
|
471
|
-
return qb
|
|
472
|
-
? qb.lessThan(filterValue)
|
|
473
|
-
: fieldVal => {
|
|
474
|
-
return fieldVal < filterValue;
|
|
475
|
-
};
|
|
476
|
-
} else if (ccSelectedFilter === "inRange") {
|
|
477
|
-
return qb
|
|
478
|
-
? qb.between(filterValue[0], filterValue[1])
|
|
479
|
-
: fieldVal => {
|
|
480
|
-
return filterValue[0] <= fieldVal && fieldVal <= filterValue[1];
|
|
481
|
-
};
|
|
482
|
-
} else if (ccSelectedFilter === "outsideRange") {
|
|
483
|
-
return qb
|
|
484
|
-
? qb.notBetween(filterValue[0], filterValue[1])
|
|
485
|
-
: fieldVal => {
|
|
486
|
-
return filterValue[0] > fieldVal || fieldVal > filterValue[1];
|
|
487
|
-
};
|
|
488
|
-
} else if (ccSelectedFilter === "equalTo") {
|
|
489
|
-
return qb
|
|
490
|
-
? filterValue
|
|
491
|
-
: fieldVal => {
|
|
492
|
-
return fieldVal === filterValue;
|
|
493
|
-
};
|
|
494
|
-
} else if (ccSelectedFilter === "regex") {
|
|
495
|
-
return qb
|
|
496
|
-
? qb.matchesRegex(filterValue)
|
|
497
|
-
: fieldVal => {
|
|
498
|
-
new RegExp(filterValue).test(fieldVal);
|
|
499
|
-
return fieldVal;
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
throw new Error(
|
|
504
|
-
`Unsupported filter ${selectedFilter}. Please make a new filter if you need one`
|
|
505
|
-
);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
56
|
export function getCurrentParamsFromUrl(location, isSimple) {
|
|
509
57
|
let { search } = location;
|
|
510
58
|
if (isSimple) {
|
|
@@ -585,23 +133,6 @@ function parseFilters(newParams) {
|
|
|
585
133
|
};
|
|
586
134
|
}
|
|
587
135
|
|
|
588
|
-
function buildRef(qb, reference, searchField, expression) {
|
|
589
|
-
if (reference.reference) {
|
|
590
|
-
// qb[reference.target] = {}
|
|
591
|
-
return qb.related(reference.target).whereAny({
|
|
592
|
-
[reference.sourceField]: buildRef(
|
|
593
|
-
qb,
|
|
594
|
-
reference.reference,
|
|
595
|
-
searchField,
|
|
596
|
-
expression
|
|
597
|
-
)
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
|
-
return qb.related(reference.target).whereAny({
|
|
601
|
-
[searchField]: expression
|
|
602
|
-
});
|
|
603
|
-
}
|
|
604
|
-
|
|
605
136
|
export function makeDataTableHandlers({
|
|
606
137
|
setNewParams,
|
|
607
138
|
defaults,
|
|
@@ -707,34 +238,25 @@ export function makeDataTableHandlers({
|
|
|
707
238
|
};
|
|
708
239
|
}
|
|
709
240
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
...filters,
|
|
730
|
-
...getFiltersFromSearchTerm(searchTerm, schema)
|
|
731
|
-
];
|
|
732
|
-
|
|
733
|
-
allFilters = allFilters.filter(val => {
|
|
734
|
-
return val !== "";
|
|
735
|
-
}); //get rid of erroneous filters
|
|
736
|
-
|
|
737
|
-
return allFilters.map(cleanupFilter);
|
|
241
|
+
function cleanupFilters({ filters, ccFields }) {
|
|
242
|
+
(filters || []).forEach(filter => {
|
|
243
|
+
const { filterOn, filterValue } = filter;
|
|
244
|
+
const field = ccFields[filterOn];
|
|
245
|
+
if (field.type === "number" || field.type === "integer") {
|
|
246
|
+
filter.filterValue = Array.isArray(filterValue)
|
|
247
|
+
? filterValue.map(val => Number(val))
|
|
248
|
+
: Number(filterValue);
|
|
249
|
+
}
|
|
250
|
+
if (
|
|
251
|
+
filter.selectedFilter === "inList" &&
|
|
252
|
+
typeof filter.filterValue === "number"
|
|
253
|
+
) {
|
|
254
|
+
// if an inList value only has two items like
|
|
255
|
+
// 2.3 then it will get parsed to a number and
|
|
256
|
+
// break, convert it back to a string here
|
|
257
|
+
filter.filterValue = filter.filterValue.toString();
|
|
258
|
+
}
|
|
259
|
+
});
|
|
738
260
|
}
|
|
739
261
|
|
|
740
262
|
export function getQueryParams({
|
|
@@ -746,115 +268,53 @@ export function getQueryParams({
|
|
|
746
268
|
entities,
|
|
747
269
|
isLocalCall,
|
|
748
270
|
additionalFilter,
|
|
749
|
-
additionalOrFilter,
|
|
750
271
|
doNotCoercePageSize,
|
|
751
272
|
noOrderError,
|
|
752
273
|
isCodeModel,
|
|
753
274
|
ownProps
|
|
754
275
|
}) {
|
|
755
|
-
|
|
756
|
-
if (currentParams[key] === undefined) {
|
|
757
|
-
delete currentParams[key]; //we want to use the default value if any of these are undefined
|
|
758
|
-
}
|
|
759
|
-
});
|
|
760
|
-
const tableQueryParams = {
|
|
761
|
-
...defaults,
|
|
762
|
-
...currentParams
|
|
763
|
-
};
|
|
764
|
-
let { page, pageSize, searchTerm, filters, order } = tableQueryParams;
|
|
765
|
-
if (page <= 0 || isNaN(page)) {
|
|
766
|
-
page = undefined;
|
|
767
|
-
}
|
|
768
|
-
if (isInfinite) {
|
|
769
|
-
page = undefined;
|
|
770
|
-
pageSize = undefined;
|
|
771
|
-
}
|
|
772
|
-
if (pageSize !== undefined && !doNotCoercePageSize) {
|
|
773
|
-
//pageSize might come in as an unexpected number so we coerce it to be one of the nums in our pageSizes array
|
|
774
|
-
const closest = clone(window.tgPageSizes || defaultPageSizes).sort(
|
|
775
|
-
(a, b) => Math.abs(pageSize - a) - Math.abs(pageSize - b)
|
|
776
|
-
)[0];
|
|
777
|
-
pageSize = closest;
|
|
778
|
-
}
|
|
779
|
-
const toReturn = {
|
|
780
|
-
//these are values that might be generally useful for the wrapped component
|
|
781
|
-
page,
|
|
782
|
-
pageSize: ownProps.controlled_pageSize || pageSize,
|
|
783
|
-
order,
|
|
784
|
-
filters,
|
|
785
|
-
searchTerm
|
|
786
|
-
};
|
|
276
|
+
let errorParsingUrlString;
|
|
787
277
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
278
|
+
try {
|
|
279
|
+
Object.keys(currentParams).forEach(function (key) {
|
|
280
|
+
if (currentParams[key] === undefined) {
|
|
281
|
+
delete currentParams[key]; //we want to use the default value if any of these are undefined
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
const tableQueryParams = {
|
|
285
|
+
...defaults,
|
|
286
|
+
...currentParams
|
|
287
|
+
};
|
|
288
|
+
let { page, pageSize, searchTerm, filters, order } = tableQueryParams;
|
|
289
|
+
const ccFields = getFieldsMappedByCCDisplayName(schema);
|
|
800
290
|
|
|
801
|
-
|
|
291
|
+
cleanupFilters({ filters, ccFields });
|
|
802
292
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
if (!isInfinite && !ownProps.controlled_pageSize) {
|
|
806
|
-
const offset = (page - 1) * pageSize;
|
|
807
|
-
newEntities = take(drop(newEntities, offset), pageSize);
|
|
293
|
+
if (page <= 0 || isNaN(page)) {
|
|
294
|
+
page = undefined;
|
|
808
295
|
}
|
|
809
|
-
toReturn.entities = newEntities;
|
|
810
|
-
toReturn.entitiesAcrossPages = entitiesAcrossPages;
|
|
811
|
-
toReturn.entityCount = newEntityCount;
|
|
812
|
-
//if this call is being made by a local-data only connected datatable component,
|
|
813
|
-
//we don't want to do the following gql stuff
|
|
814
|
-
return toReturn;
|
|
815
|
-
} else {
|
|
816
|
-
const graphqlQueryParams = {
|
|
817
|
-
// need to make sure sort exists because of https://github.com/apollographql/apollo-client/issues/3077
|
|
818
|
-
sort: []
|
|
819
|
-
};
|
|
820
296
|
if (isInfinite) {
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
297
|
+
page = undefined;
|
|
298
|
+
pageSize = undefined;
|
|
299
|
+
}
|
|
300
|
+
if (pageSize !== undefined && !doNotCoercePageSize) {
|
|
301
|
+
//pageSize might come in as an unexpected number so we coerce it to be one of the nums in our pageSizes array
|
|
302
|
+
const closest = clone(window.tgPageSizes || defaultPageSizes).sort(
|
|
303
|
+
(a, b) => Math.abs(pageSize - a) - Math.abs(pageSize - b)
|
|
304
|
+
)[0];
|
|
305
|
+
pageSize = closest;
|
|
827
306
|
}
|
|
828
307
|
|
|
829
|
-
const
|
|
830
|
-
if (
|
|
831
|
-
|
|
832
|
-
// qb = qb.filter('user')
|
|
833
|
-
// qb = qb.whereAny({
|
|
834
|
-
// userStatus: qb.related('userStatus').whereAny({
|
|
835
|
-
// code: qb.contains('pending')
|
|
836
|
-
// })
|
|
837
|
-
// })
|
|
838
|
-
// qb = qb.andWhere({
|
|
839
|
-
// age: qb.lessThan(12)
|
|
840
|
-
// })
|
|
841
|
-
// qb.toJSON()
|
|
842
|
-
// let filterBuilder = qb.filter(model); //start filter on model
|
|
843
|
-
|
|
844
|
-
const ccFields = getFieldsMappedByCCDisplayName(schema);
|
|
845
|
-
|
|
846
|
-
if (tableQueryParams.order && tableQueryParams.order.length) {
|
|
847
|
-
tableQueryParams.order.forEach(orderVal => {
|
|
308
|
+
const cleanedOrder = [];
|
|
309
|
+
if (order && order.length) {
|
|
310
|
+
order.forEach(orderVal => {
|
|
848
311
|
const ccDisplayName = orderVal.replace(/^-/gi, "");
|
|
849
312
|
const schemaForField = ccFields[ccDisplayName];
|
|
850
313
|
if (schemaForField) {
|
|
851
314
|
const { path } = schemaForField;
|
|
852
315
|
const reversed = ccDisplayName !== orderVal;
|
|
853
316
|
const prefix = reversed ? "-" : "";
|
|
854
|
-
|
|
855
|
-
...(graphqlQueryParams.sort || []),
|
|
856
|
-
prefix + path
|
|
857
|
-
];
|
|
317
|
+
cleanedOrder.push(prefix + path);
|
|
858
318
|
} else {
|
|
859
319
|
!noOrderError &&
|
|
860
320
|
console.error(
|
|
@@ -865,194 +325,117 @@ export function getQueryParams({
|
|
|
865
325
|
}
|
|
866
326
|
});
|
|
867
327
|
}
|
|
328
|
+
let toRet = {
|
|
329
|
+
//these are values that might be generally useful for the wrapped component
|
|
330
|
+
page,
|
|
331
|
+
pageSize: ownProps.controlled_pageSize || pageSize,
|
|
332
|
+
order: cleanedOrder,
|
|
333
|
+
filters,
|
|
334
|
+
searchTerm
|
|
335
|
+
};
|
|
868
336
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
}
|
|
337
|
+
const { where, order_by, limit, offset } = tableQueryParamsToHasuraClauses({
|
|
338
|
+
page,
|
|
339
|
+
pageSize,
|
|
340
|
+
searchTerm,
|
|
341
|
+
filters,
|
|
342
|
+
order: cleanedOrder,
|
|
343
|
+
schema
|
|
344
|
+
});
|
|
345
|
+
initializeHasuraWhereAndFilter(additionalFilter, where, currentParams);
|
|
346
|
+
if (isLocalCall) {
|
|
347
|
+
//if the table is local (aka not directly connected to a db) then we need to
|
|
348
|
+
//handle filtering/paging/sorting all on the front end
|
|
349
|
+
const r = filterLocalEntitiesToHasura(
|
|
350
|
+
prepEntitiesForLocalFilter({ entities, ccFields }),
|
|
351
|
+
{
|
|
352
|
+
where,
|
|
353
|
+
order_by: (Array.isArray(order_by) ? order_by : [order_by]).map(
|
|
354
|
+
obj => {
|
|
355
|
+
const path = Object.keys(obj)[0];
|
|
356
|
+
return {
|
|
357
|
+
path,
|
|
358
|
+
direction: obj[path],
|
|
359
|
+
ownProps,
|
|
360
|
+
...ccFields[path]
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
),
|
|
364
|
+
limit,
|
|
365
|
+
offset,
|
|
366
|
+
isInfinite
|
|
367
|
+
}
|
|
368
|
+
);
|
|
877
369
|
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
try {
|
|
882
|
-
const flattenFilters = filterObj => {
|
|
883
|
-
return flatMap(Object.keys(filterObj), key => {
|
|
884
|
-
return filterObj[key].map(filter => ({
|
|
885
|
-
[key]: filter
|
|
886
|
-
}));
|
|
887
|
-
});
|
|
370
|
+
toRet = {
|
|
371
|
+
...toRet,
|
|
372
|
+
...r
|
|
888
373
|
};
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
flattenFilters(otherOrFiltersObject)
|
|
896
|
-
);
|
|
897
|
-
});
|
|
898
|
-
allOrFilters.push(additionalOrFilterToUse);
|
|
899
|
-
allOrFilters = allOrFilters.filter(obj => !isEmpty(obj));
|
|
900
|
-
|
|
901
|
-
const unflattenedAndQueries = getQueries(andFilters, qb, ccFields);
|
|
902
|
-
let allAndFilters = flattenFilters(unflattenedAndQueries);
|
|
903
|
-
allAndFilters.push(additionalFilterToUse);
|
|
904
|
-
allAndFilters = allAndFilters.filter(obj => !isEmpty(obj));
|
|
905
|
-
if (allAndFilters.length) {
|
|
906
|
-
qb.whereAll(...allAndFilters);
|
|
907
|
-
}
|
|
908
|
-
if (allOrFilters.length) {
|
|
909
|
-
qb.andWhereAny(...allOrFilters);
|
|
374
|
+
return toRet;
|
|
375
|
+
} else {
|
|
376
|
+
if (!order_by.length) {
|
|
377
|
+
// if no order by is specified, we will default to sorting by updatedAt
|
|
378
|
+
// this is useful for models that do not have a code field
|
|
379
|
+
order_by.push({ updatedAt: "desc" });
|
|
910
380
|
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
381
|
+
// in case entries that have the same value in the column being sorted on
|
|
382
|
+
// fall back to id as a secondary sort to make sure ordering happens correctly
|
|
383
|
+
order_by.push(
|
|
384
|
+
isCodeModel ? { code: "asc" } : { [window.__sortId || "id"]: "asc" }
|
|
915
385
|
);
|
|
916
|
-
if (columnCustomFilters.length) {
|
|
917
|
-
qb.whereAll(...columnCustomFilters);
|
|
918
|
-
}
|
|
919
|
-
} catch (e) {
|
|
920
|
-
if (urlConnected) {
|
|
921
|
-
errorParsingUrlString = e;
|
|
922
|
-
console.error(
|
|
923
|
-
"The following error occurred when trying to build the query params. This is probably due to a malformed URL:",
|
|
924
|
-
e
|
|
925
|
-
);
|
|
926
|
-
} else {
|
|
927
|
-
console.error("Error building query params from filter:");
|
|
928
|
-
throw e;
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
386
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
387
|
+
return {
|
|
388
|
+
...toRet,
|
|
389
|
+
variables: {
|
|
390
|
+
where,
|
|
391
|
+
order_by,
|
|
392
|
+
limit,
|
|
393
|
+
offset
|
|
394
|
+
}
|
|
395
|
+
};
|
|
939
396
|
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
return {
|
|
948
|
-
...toReturn,
|
|
949
|
-
//the query params will get passed directly to as variables to the graphql query
|
|
950
|
-
variables: graphqlQueryParams,
|
|
951
|
-
errorParsingUrlString
|
|
952
|
-
};
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
function getSubFiltersAndPath(filter, qb, ccFields) {
|
|
957
|
-
const { selectedFilter, filterValue, filterOn } = filter;
|
|
958
|
-
const fieldSchema = ccFields[filterOn];
|
|
959
|
-
let filterValueToUse = filterValue;
|
|
960
|
-
|
|
961
|
-
if (fieldSchema) {
|
|
962
|
-
if (fieldSchema.normalizeFilter) {
|
|
963
|
-
filterValueToUse = fieldSchema.normalizeFilter(
|
|
964
|
-
filterValue,
|
|
965
|
-
selectedFilter,
|
|
966
|
-
filterOn
|
|
397
|
+
} catch (e) {
|
|
398
|
+
if (urlConnected) {
|
|
399
|
+
errorParsingUrlString = e;
|
|
400
|
+
console.error(
|
|
401
|
+
"The following error occurred when trying to build the query params. This is probably due to a malformed URL:",
|
|
402
|
+
e
|
|
967
403
|
);
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
404
|
+
return {
|
|
405
|
+
errorParsingUrlString,
|
|
406
|
+
variables: {
|
|
407
|
+
where: {},
|
|
408
|
+
order_by: [],
|
|
409
|
+
limit: 0,
|
|
410
|
+
offset: 0
|
|
411
|
+
}
|
|
412
|
+
};
|
|
977
413
|
} else {
|
|
978
|
-
|
|
414
|
+
console.error("Error building query params from filter:");
|
|
415
|
+
throw e;
|
|
979
416
|
}
|
|
980
|
-
} else if (filterOn === "id") {
|
|
981
|
-
filterField = filterOn;
|
|
982
|
-
} else {
|
|
983
|
-
console.error("Trying to filter on unknown field");
|
|
984
417
|
}
|
|
985
|
-
const subFiltersToUse = [];
|
|
986
|
-
const subFilters = Array.isArray(_subFilters) ? _subFilters : [_subFilters];
|
|
987
|
-
subFilters.forEach(subFilter => {
|
|
988
|
-
let subFilterToUse = subFilter;
|
|
989
|
-
if (fieldSchema) {
|
|
990
|
-
const { path, reference } = fieldSchema;
|
|
991
|
-
if (reference) {
|
|
992
|
-
subFilterToUse = buildRef(
|
|
993
|
-
qb,
|
|
994
|
-
reference,
|
|
995
|
-
last(path.split(".")),
|
|
996
|
-
subFilter
|
|
997
|
-
);
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
subFiltersToUse.push(subFilterToUse);
|
|
1001
|
-
});
|
|
1002
|
-
|
|
1003
|
-
return {
|
|
1004
|
-
path: filterField,
|
|
1005
|
-
subFilters: subFiltersToUse
|
|
1006
|
-
};
|
|
1007
418
|
}
|
|
1008
419
|
|
|
1009
|
-
function
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
return acc;
|
|
1023
|
-
}, {});
|
|
1024
|
-
return subQueries;
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
function getColumnCustomFilters(filters, qb, ccFields) {
|
|
1028
|
-
const subQueries = filters.reduce((acc, filter) => {
|
|
1029
|
-
if (!filter) {
|
|
1030
|
-
console.warn("We should always have a filter object!");
|
|
1031
|
-
return acc;
|
|
1032
|
-
}
|
|
1033
|
-
const { filterOn } = filter;
|
|
1034
|
-
const fieldSchema = ccFields[filterOn];
|
|
1035
|
-
if (filter.isSearchTermFilter || !fieldSchema?.additionalColumnFilter) {
|
|
1036
|
-
return acc;
|
|
1037
|
-
}
|
|
1038
|
-
const { path, subFilters } = getSubFiltersAndPath(filter, qb, ccFields);
|
|
1039
|
-
/* the column filters need to have access to this sub filter but also be able to add additional
|
|
1040
|
-
filter logic.
|
|
1041
|
-
ex.
|
|
1042
|
-
qb.whereAny({
|
|
1043
|
-
id: qb.related("extendedStringValueView.buildSampleId").whereAll({
|
|
1044
|
-
value: "something",
|
|
1045
|
-
extendedPropertyId: "myId"
|
|
1046
|
-
})
|
|
1047
|
-
...
|
|
1048
|
-
})
|
|
1049
|
-
|
|
1050
|
-
is possible because the returned accumulator will be passed to whereAny
|
|
1051
|
-
*/
|
|
1052
|
-
subFilters.forEach(subFilter => {
|
|
1053
|
-
acc.push(fieldSchema.additionalColumnFilter(qb, subFilter, path));
|
|
420
|
+
function prepEntitiesForLocalFilter({ entities, ccFields }) {
|
|
421
|
+
// Prepare entities for local filtering by mapping over them and applying necessary transformations
|
|
422
|
+
const r = entities.map(entity => {
|
|
423
|
+
const toSpread = {};
|
|
424
|
+
let hasChanged = false;
|
|
425
|
+
// Apply any necessary transformations using ccFields
|
|
426
|
+
forEach(ccFields, ({ getValueToFilterOn, path }) => {
|
|
427
|
+
if (getValueToFilterOn) {
|
|
428
|
+
hasChanged = true;
|
|
429
|
+
toSpread["___original___" + path] = entity[path];
|
|
430
|
+
const value = getValueToFilterOn(entity);
|
|
431
|
+
toSpread[path] = value;
|
|
432
|
+
}
|
|
1054
433
|
});
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
434
|
+
if (hasChanged) {
|
|
435
|
+
// If there are any transformations, spread them into the entity
|
|
436
|
+
return { ...entity, ...toSpread };
|
|
437
|
+
}
|
|
438
|
+
return entity;
|
|
439
|
+
});
|
|
440
|
+
return r;
|
|
1058
441
|
}
|