@teselagen/ui 0.8.6-beta.2 → 0.8.6-beta.21

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.
@@ -8,19 +8,8 @@ export function initializeHasuraWhereAndFilter(
8
8
  if (typeof additionalFilter === "function") {
9
9
  const newWhere = additionalFilter(where, currentParams);
10
10
  if (newWhere) {
11
- where = {
12
- ...where,
13
- ...newWhere
14
- };
11
+ Object.assign(where, newWhere);
15
12
  }
16
13
  } else if (typeof additionalFilter === "object")
17
14
  where._and.push(additionalFilter);
18
15
  }
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
- };
@@ -1,14 +1,11 @@
1
1
  import queryString from "qs";
2
- import { uniqBy, clone, camelCase } from "lodash-es";
2
+ import { uniqBy, clone, camelCase, forEach } from "lodash-es";
3
3
  import {
4
4
  getFieldsMappedByCCDisplayName,
5
5
  tableQueryParamsToHasuraClauses
6
6
  } from "./tableQueryParamsToHasuraClauses";
7
7
  import { filterLocalEntitiesToHasura } from "./filterLocalEntitiesToHasura";
8
- import {
9
- addCustomColumnFilters,
10
- initializeHasuraWhereAndFilter
11
- } from "./initializeHasuraWhereAndFilter";
8
+ import { initializeHasuraWhereAndFilter } from "./initializeHasuraWhereAndFilter";
12
9
 
13
10
  const defaultPageSizes = [5, 10, 15, 25, 50, 100, 200, 400];
14
11
 
@@ -56,7 +53,6 @@ function safeParse(val) {
56
53
  return val;
57
54
  }
58
55
  }
59
-
60
56
  export function getCurrentParamsFromUrl(location, isSimple) {
61
57
  let { search } = location;
62
58
  if (isSimple) {
@@ -242,9 +238,30 @@ export function makeDataTableHandlers({
242
238
  };
243
239
  }
244
240
 
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
+ });
260
+ }
261
+
245
262
  export function getQueryParams({
246
263
  currentParams,
247
- // urlConnected,
264
+ urlConnected,
248
265
  defaults,
249
266
  schema,
250
267
  isInfinite,
@@ -253,98 +270,166 @@ export function getQueryParams({
253
270
  additionalFilter,
254
271
  doNotCoercePageSize,
255
272
  noOrderError,
256
- // isCodeModel,
273
+ isCodeModel,
257
274
  ownProps
258
275
  }) {
259
- Object.keys(currentParams).forEach(function (key) {
260
- if (currentParams[key] === undefined) {
261
- delete currentParams[key]; //we want to use the default value if any of these are undefined
262
- }
263
- });
264
- const tableQueryParams = {
265
- ...defaults,
266
- ...currentParams
267
- };
268
- let { page, pageSize, searchTerm, filters, order } = tableQueryParams;
269
- if (page <= 0 || isNaN(page)) {
270
- page = undefined;
271
- }
272
- if (isInfinite) {
273
- page = undefined;
274
- pageSize = undefined;
275
- }
276
- if (pageSize !== undefined && !doNotCoercePageSize) {
277
- //pageSize might come in as an unexpected number so we coerce it to be one of the nums in our pageSizes array
278
- const closest = clone(window.tgPageSizes || defaultPageSizes).sort(
279
- (a, b) => Math.abs(pageSize - a) - Math.abs(pageSize - b)
280
- )[0];
281
- pageSize = closest;
282
- }
276
+ let errorParsingUrlString;
283
277
 
284
- const cleanedOrder = [];
285
- if (order && order.length) {
286
- const ccFields = getFieldsMappedByCCDisplayName(schema);
287
- order.forEach(orderVal => {
288
- const ccDisplayName = orderVal.replace(/^-/gi, "");
289
- const schemaForField = ccFields[ccDisplayName];
290
- if (schemaForField) {
291
- const { path } = schemaForField;
292
- const reversed = ccDisplayName !== orderVal;
293
- const prefix = reversed ? "-" : "";
294
- cleanedOrder.push(prefix + path);
295
- } else {
296
- !noOrderError &&
297
- console.error(
298
- "No schema for field found!",
299
- ccDisplayName,
300
- JSON.stringify(schema.fields, null, 2)
301
- );
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
302
282
  }
303
283
  });
304
- }
284
+ const tableQueryParams = {
285
+ ...defaults,
286
+ ...currentParams
287
+ };
288
+ let { page, pageSize, searchTerm, filters, order } = tableQueryParams;
289
+ const ccFields = getFieldsMappedByCCDisplayName(schema);
305
290
 
306
- let toRet = {
307
- //these are values that might be generally useful for the wrapped component
308
- page,
309
- pageSize: ownProps.controlled_pageSize || pageSize,
310
- order: cleanedOrder,
311
- filters,
312
- searchTerm
313
- };
291
+ cleanupFilters({ filters, ccFields });
314
292
 
315
- const { where, order_by, limit, offset } = tableQueryParamsToHasuraClauses({
316
- page,
317
- pageSize,
318
- searchTerm,
319
- filters,
320
- order: cleanedOrder,
321
- schema
322
- });
323
- initializeHasuraWhereAndFilter(additionalFilter, where, currentParams);
324
- addCustomColumnFilters(where, schema.fields, currentParams);
325
- if (isLocalCall) {
326
- //if the table is local (aka not directly connected to a db) then we need to
327
- //handle filtering/paging/sorting all on the front end
328
- toRet = {
329
- ...toRet,
330
- ...filterLocalEntitiesToHasura(entities, {
331
- where,
332
- order_by,
333
- limit,
334
- offset,
335
- isInfinite
336
- })
293
+ if (page <= 0 || isNaN(page)) {
294
+ page = undefined;
295
+ }
296
+ if (isInfinite) {
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;
306
+ }
307
+
308
+ const cleanedOrder = [];
309
+ if (order && order.length) {
310
+ order.forEach(orderVal => {
311
+ const ccDisplayName = orderVal.replace(/^-/gi, "");
312
+ const schemaForField = ccFields[ccDisplayName];
313
+ if (schemaForField) {
314
+ const { path } = schemaForField;
315
+ const reversed = ccDisplayName !== orderVal;
316
+ const prefix = reversed ? "-" : "";
317
+ cleanedOrder.push(prefix + path);
318
+ } else {
319
+ !noOrderError &&
320
+ console.error(
321
+ "No schema for field found!",
322
+ ccDisplayName,
323
+ JSON.stringify(schema.fields, null, 2)
324
+ );
325
+ }
326
+ });
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
337
335
  };
338
- return toRet;
339
- } else {
340
- return {
341
- ...toRet,
342
- variables: {
343
- where,
344
- order_by,
345
- limit,
346
- offset
336
+
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 newEnts = 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
+ );
369
+
370
+ toRet = {
371
+ ...toRet,
372
+ ...newEnts
373
+ };
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" });
347
380
  }
348
- };
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: "desc" } : { [window.__sortId || "id"]: "desc" }
385
+ );
386
+
387
+ return {
388
+ ...toRet,
389
+ variables: {
390
+ where,
391
+ order_by,
392
+ limit,
393
+ offset
394
+ }
395
+ };
396
+ }
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
403
+ );
404
+ return {
405
+ errorParsingUrlString,
406
+ variables: {
407
+ where: {},
408
+ order_by: [],
409
+ limit: 0,
410
+ offset: 0
411
+ }
412
+ };
413
+ } else {
414
+ console.error("Error building query params from filter:");
415
+ throw e;
416
+ }
349
417
  }
350
418
  }
419
+
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 newEnt = { ...entity };
424
+ // Apply any necessary transformations using ccFields
425
+ forEach(ccFields, ({ getValueToFilterOn, path }) => {
426
+ if (getValueToFilterOn) {
427
+ newEnt["___original___" + path] = newEnt[path];
428
+ const value = getValueToFilterOn(newEnt);
429
+ newEnt[path] = value;
430
+ }
431
+ });
432
+ return newEnt;
433
+ });
434
+ return r;
435
+ }