@teselagen/ui 0.8.6-beta.5 → 0.8.6-beta.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teselagen/ui",
3
- "version": "0.8.6-beta.5",
3
+ "version": "0.8.6-beta.7",
4
4
  "main": "./src/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -55,7 +55,8 @@
55
55
  "chance": "^1.1.11",
56
56
  "@dnd-kit/utilities": "3.2.2",
57
57
  "@teselagen/file-utils": "0.3.20",
58
- "@blueprintjs/icons": "3.33.0"
58
+ "@blueprintjs/icons": "3.33.0",
59
+ "jszip": "3.10.1"
59
60
  },
60
61
  "license": "MIT"
61
62
  }
@@ -1,3 +1,4 @@
1
+ import {} from "jszip";
1
2
  import {
2
3
  isEmpty,
3
4
  every,
@@ -225,12 +226,27 @@ function applyWhereClause(records, where) {
225
226
  return records.filter(record => applyFilter(record, where));
226
227
  }
227
228
 
228
- function applyOrderBy(records, order_by) {
229
- const keys = Object.keys(order_by);
230
- if (keys.length > 0) {
231
- const field = keys[0];
232
- const direction = order_by[field] === "asc" ? "asc" : "desc";
233
- return orderBy(records, [field], [direction]);
229
+ // takes in an array of records and an order_by clause
230
+ // order_by looks like this: [{ some_field: "asc" }, { some_other_field: "desc" }] or {some_field: "asc"}
231
+ // returns the records sorted by the order_by clause
232
+ function applyOrderBy(records, _order_by) {
233
+ const order_by = isArray(_order_by)
234
+ ? _order_by
235
+ : isEmpty(_order_by)
236
+ ? []
237
+ : [_order_by];
238
+
239
+ if (order_by.length > 0) {
240
+ const fields = [];
241
+ const directions = [];
242
+ order_by.forEach(item => {
243
+ // Hasura-style: { field: "asc" }
244
+ const field = Object.keys(item)[0];
245
+ const direction = item[field];
246
+ fields.push(field);
247
+ directions.push(direction);
248
+ });
249
+ records = orderBy(records, fields, directions);
234
250
  }
235
251
  return records;
236
252
  }
@@ -536,7 +536,25 @@ describe("filterLocalEntitiesToHasura", () => {
536
536
  expect(result.entitiesAcrossPages).toEqual([records[0], records[2]]);
537
537
  expect(result.entityCount).toBe(2);
538
538
  });
539
-
539
+ it("should order by multiple fields (age asc, name desc)", () => {
540
+ // Make two of the ages the same for testing secondary sort
541
+ const modifiedRecords = [
542
+ records[1], // Jane Smith, age 25
543
+ { ...records[0], age: 25 }, // John Doe, age 25
544
+ records[2], // Alice Johnson, age 35
545
+ records[3] // Bob Williams, age 20
546
+ ];
547
+ const result = filterLocalEntitiesToHasura(modifiedRecords, {
548
+ order_by: [{ age: "asc" }, { name: "desc" }]
549
+ });
550
+ expect(result.entities).toEqual([
551
+ modifiedRecords[3], // age 20, name "Bob Williams"
552
+ modifiedRecords[1], // age 25, name "John Doe" (name desc)
553
+ modifiedRecords[0], // age 25, name "Jane Smith"
554
+ modifiedRecords[2] // age 35, name "Alice Johnson"
555
+ ]);
556
+ expect(result.entityCount).toBe(4);
557
+ });
540
558
  it("should apply limit and offset to filtered and ordered results", () => {
541
559
  const result = filterLocalEntitiesToHasura(records, {
542
560
  where: { city: { _eq: "London" } },
@@ -244,7 +244,7 @@ export function makeDataTableHandlers({
244
244
 
245
245
  export function getQueryParams({
246
246
  currentParams,
247
- // urlConnected,
247
+ urlConnected,
248
248
  defaults,
249
249
  schema,
250
250
  isInfinite,
@@ -253,98 +253,130 @@ export function getQueryParams({
253
253
  additionalFilter,
254
254
  doNotCoercePageSize,
255
255
  noOrderError,
256
- // isCodeModel,
256
+ isCodeModel,
257
257
  ownProps
258
258
  }) {
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
- }
259
+ let errorParsingUrlString;
283
260
 
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
- );
261
+ try {
262
+ Object.keys(currentParams).forEach(function (key) {
263
+ if (currentParams[key] === undefined) {
264
+ delete currentParams[key]; //we want to use the default value if any of these are undefined
302
265
  }
303
266
  });
304
- }
267
+ const tableQueryParams = {
268
+ ...defaults,
269
+ ...currentParams
270
+ };
271
+ let { page, pageSize, searchTerm, filters, order } = tableQueryParams;
272
+ if (page <= 0 || isNaN(page)) {
273
+ page = undefined;
274
+ }
275
+ if (isInfinite) {
276
+ page = undefined;
277
+ pageSize = undefined;
278
+ }
279
+ if (pageSize !== undefined && !doNotCoercePageSize) {
280
+ //pageSize might come in as an unexpected number so we coerce it to be one of the nums in our pageSizes array
281
+ const closest = clone(window.tgPageSizes || defaultPageSizes).sort(
282
+ (a, b) => Math.abs(pageSize - a) - Math.abs(pageSize - b)
283
+ )[0];
284
+ pageSize = closest;
285
+ }
305
286
 
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
- };
287
+ const cleanedOrder = [];
288
+ if (order && order.length) {
289
+ const ccFields = getFieldsMappedByCCDisplayName(schema);
290
+ order.forEach(orderVal => {
291
+ const ccDisplayName = orderVal.replace(/^-/gi, "");
292
+ const schemaForField = ccFields[ccDisplayName];
293
+ if (schemaForField) {
294
+ const { path } = schemaForField;
295
+ const reversed = ccDisplayName !== orderVal;
296
+ const prefix = reversed ? "-" : "";
297
+ cleanedOrder.push(prefix + path);
298
+ } else {
299
+ !noOrderError &&
300
+ console.error(
301
+ "No schema for field found!",
302
+ ccDisplayName,
303
+ JSON.stringify(schema.fields, null, 2)
304
+ );
305
+ }
306
+ });
307
+ }
308
+ // by default make sort by updated at
309
+ if (!cleanedOrder.length) {
310
+ cleanedOrder.push("-updatedAt");
311
+ }
314
312
 
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
- })
337
- };
338
- return toRet;
339
- } else {
340
- return {
341
- ...toRet,
342
- variables: {
343
- where,
344
- order_by,
345
- limit,
346
- offset
347
- }
313
+ // in case entries that have the same value in the column being sorted on
314
+ // fall back to id as a secondary sort to make sure ordering happens correctly
315
+ cleanedOrder.push(isCodeModel ? "code" : window.__sortId || "id");
316
+
317
+ let toRet = {
318
+ //these are values that might be generally useful for the wrapped component
319
+ page,
320
+ pageSize: ownProps.controlled_pageSize || pageSize,
321
+ order: cleanedOrder,
322
+ filters,
323
+ searchTerm
348
324
  };
325
+
326
+ const { where, order_by, limit, offset } = tableQueryParamsToHasuraClauses({
327
+ page,
328
+ pageSize,
329
+ searchTerm,
330
+ filters,
331
+ order: cleanedOrder,
332
+ schema
333
+ });
334
+ initializeHasuraWhereAndFilter(additionalFilter, where, currentParams);
335
+ addCustomColumnFilters(where, schema.fields, currentParams);
336
+ if (isLocalCall) {
337
+ //if the table is local (aka not directly connected to a db) then we need to
338
+ //handle filtering/paging/sorting all on the front end
339
+ toRet = {
340
+ ...toRet,
341
+ ...filterLocalEntitiesToHasura(entities, {
342
+ where,
343
+ order_by,
344
+ limit,
345
+ offset,
346
+ isInfinite
347
+ })
348
+ };
349
+ return toRet;
350
+ } else {
351
+ return {
352
+ ...toRet,
353
+ variables: {
354
+ where,
355
+ order_by,
356
+ limit,
357
+ offset
358
+ }
359
+ };
360
+ }
361
+ } catch (e) {
362
+ if (urlConnected) {
363
+ errorParsingUrlString = e;
364
+ console.error(
365
+ "The following error occurred when trying to build the query params. This is probably due to a malformed URL:",
366
+ e
367
+ );
368
+ return {
369
+ errorParsingUrlString,
370
+ variables: {
371
+ where: {},
372
+ order_by: [],
373
+ limit: 0,
374
+ offset: 0
375
+ }
376
+ };
377
+ } else {
378
+ console.error("Error building query params from filter:");
379
+ throw e;
380
+ }
349
381
  }
350
382
  }
@@ -11,7 +11,7 @@ export function tableQueryParamsToHasuraClauses({
11
11
  }) {
12
12
  const ccFields = getFieldsMappedByCCDisplayName(schema);
13
13
  let where = {};
14
- const order_by = {};
14
+ const order_by = [];
15
15
  const limit = pageSize || 25;
16
16
  const offset = page && pageSize ? (page - 1) * pageSize : 0;
17
17
 
@@ -108,7 +108,7 @@ export function tableQueryParamsToHasuraClauses({
108
108
  case "contains":
109
109
  return { [filterOn]: { _ilike: `%${filterValue}%` } };
110
110
  case "notContains":
111
- return { [filterOn]: { _not_ilike: `%${filterValue}%` } };
111
+ return { [filterOn]: { _nilike: `%${filterValue}%` } };
112
112
  case "isExactly":
113
113
  return { [filterOn]: { _eq: filterValue } };
114
114
  case "isEmpty":
@@ -224,7 +224,7 @@ export function tableQueryParamsToHasuraClauses({
224
224
  order.forEach(item => {
225
225
  const field = item.startsWith("-") ? item.substring(1) : item;
226
226
  const direction = item.startsWith("-") ? "desc" : "asc";
227
- order_by[field] = direction;
227
+ order_by.push({ [field]: direction });
228
228
  });
229
229
  }
230
230
 
@@ -14,7 +14,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
14
14
  const result = tableQueryParamsToHasuraClauses({});
15
15
  expect(result).toEqual({
16
16
  where: {},
17
- order_by: {},
17
+ order_by: [],
18
18
  limit: 25,
19
19
  offset: 0
20
20
  });
@@ -24,7 +24,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
24
24
  const result = tableQueryParamsToHasuraClauses({ page: 2, pageSize: 10 });
25
25
  expect(result).toEqual({
26
26
  where: {},
27
- order_by: {},
27
+ order_by: [],
28
28
  limit: 10,
29
29
  offset: 10
30
30
  });
@@ -39,7 +39,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
39
39
  where: {
40
40
  _or: [{ name: { _ilike: "%test%" } }, { email: { _ilike: "%test%" } }]
41
41
  },
42
- order_by: {},
42
+ order_by: [],
43
43
  limit: 25,
44
44
  offset: 0
45
45
  });
@@ -58,7 +58,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
58
58
  { email: { _ilike: "%30%" } }
59
59
  ]
60
60
  },
61
- order_by: {},
61
+ order_by: [],
62
62
  limit: 25,
63
63
  offset: 0
64
64
  });
@@ -77,7 +77,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
77
77
  { email: { _ilike: "%true%" } }
78
78
  ]
79
79
  },
80
- order_by: {},
80
+ order_by: [],
81
81
  limit: 25,
82
82
  offset: 0
83
83
  });
@@ -92,7 +92,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
92
92
  where: {
93
93
  _or: [{ name: { _ilike: "%test%" } }, { email: { _ilike: "%test%" } }]
94
94
  },
95
- order_by: {},
95
+ order_by: [],
96
96
  limit: 25,
97
97
  offset: 0
98
98
  });
@@ -110,7 +110,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
110
110
  });
111
111
  expect(result).toEqual({
112
112
  where: { _and: [{ name: { _ilike: "%test%" } }] },
113
- order_by: {},
113
+ order_by: [],
114
114
  limit: 25,
115
115
  offset: 0
116
116
  });
@@ -125,7 +125,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
125
125
  });
126
126
  expect(result).toEqual({
127
127
  where: { _and: [{ age: { _eq: 30 } }] },
128
- order_by: {},
128
+ order_by: [],
129
129
  limit: 25,
130
130
  offset: 0
131
131
  });
@@ -135,7 +135,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
135
135
  const result = tableQueryParamsToHasuraClauses({ order: ["name", "-age"] });
136
136
  expect(result).toEqual({
137
137
  where: {},
138
- order_by: { name: "asc", age: "desc" },
138
+ order_by: [{ name: "asc" }, { age: "desc" }],
139
139
  limit: 25,
140
140
  offset: 0
141
141
  });
@@ -168,7 +168,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
168
168
  { age: { _gt: 30 } }
169
169
  ]
170
170
  },
171
- order_by: { name: "asc" },
171
+ order_by: [{ name: "asc" }],
172
172
  limit: 10,
173
173
  offset: 10
174
174
  });
@@ -198,7 +198,7 @@ describe("tableQueryParamsToHasuraClauses", () => {
198
198
  { age: { _gt: 30 } }
199
199
  ]
200
200
  },
201
- order_by: {},
201
+ order_by: [],
202
202
  limit: 25,
203
203
  offset: 0
204
204
  });