@teselagen/ui 0.8.6-beta.12 → 0.8.6-beta.14

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/index.cjs.js CHANGED
@@ -22228,13 +22228,31 @@ function applyOrderBy(records, _order_by) {
22228
22228
  directions.push(direction);
22229
22229
  iteratees.push((record) => {
22230
22230
  const value = record[field];
22231
+ if (isNull(value) || value === void 0) {
22232
+ return direction === "asc" ? -Infinity : -Infinity;
22233
+ }
22231
22234
  if (isString$1(value) && /\d/.test(value)) {
22232
22235
  return value.replace(/(\d+)/g, (num) => num.padStart(10, "0"));
22233
22236
  }
22234
22237
  return value;
22235
22238
  });
22236
22239
  });
22237
- records = orderBy$1(records, iteratees, directions);
22240
+ let sortedRecords = orderBy$1(records, iteratees, directions);
22241
+ order_by.forEach((item) => {
22242
+ const field = Object.keys(item)[0];
22243
+ const direction = item[field];
22244
+ if (direction === "desc") {
22245
+ sortedRecords = [
22246
+ ...sortedRecords.filter(
22247
+ (record) => !isNull(record[field]) && record[field] !== void 0
22248
+ ),
22249
+ ...sortedRecords.filter(
22250
+ (record) => isNull(record[field]) || record[field] === void 0
22251
+ )
22252
+ ];
22253
+ }
22254
+ });
22255
+ records = sortedRecords;
22238
22256
  }
22239
22257
  return records;
22240
22258
  }
@@ -61163,7 +61181,7 @@ const DataTable = /* @__PURE__ */ __name((_I) => {
61163
61181
  try {
61164
61182
  const allEntities = yield safeQuery(fragment, {
61165
61183
  variables: {
61166
- filter: variables.filter,
61184
+ where: variables.where,
61167
61185
  sort: variables.sort
61168
61186
  },
61169
61187
  canCancel: true
package/index.es.js CHANGED
@@ -22210,13 +22210,31 @@ function applyOrderBy(records, _order_by) {
22210
22210
  directions.push(direction);
22211
22211
  iteratees.push((record) => {
22212
22212
  const value = record[field];
22213
+ if (isNull(value) || value === void 0) {
22214
+ return direction === "asc" ? -Infinity : -Infinity;
22215
+ }
22213
22216
  if (isString$1(value) && /\d/.test(value)) {
22214
22217
  return value.replace(/(\d+)/g, (num) => num.padStart(10, "0"));
22215
22218
  }
22216
22219
  return value;
22217
22220
  });
22218
22221
  });
22219
- records = orderBy$1(records, iteratees, directions);
22222
+ let sortedRecords = orderBy$1(records, iteratees, directions);
22223
+ order_by.forEach((item) => {
22224
+ const field = Object.keys(item)[0];
22225
+ const direction = item[field];
22226
+ if (direction === "desc") {
22227
+ sortedRecords = [
22228
+ ...sortedRecords.filter(
22229
+ (record) => !isNull(record[field]) && record[field] !== void 0
22230
+ ),
22231
+ ...sortedRecords.filter(
22232
+ (record) => isNull(record[field]) || record[field] === void 0
22233
+ )
22234
+ ];
22235
+ }
22236
+ });
22237
+ records = sortedRecords;
22220
22238
  }
22221
22239
  return records;
22222
22240
  }
@@ -61145,7 +61163,7 @@ const DataTable = /* @__PURE__ */ __name((_I) => {
61145
61163
  try {
61146
61164
  const allEntities = yield safeQuery(fragment, {
61147
61165
  variables: {
61148
- filter: variables.filter,
61166
+ where: variables.where,
61149
61167
  sort: variables.sort
61150
61168
  },
61151
61169
  canCancel: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teselagen/ui",
3
- "version": "0.8.6-beta.12",
3
+ "version": "0.8.6-beta.14",
4
4
  "main": "./src/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -3078,7 +3078,7 @@ const DataTable = ({
3078
3078
  try {
3079
3079
  const allEntities = await safeQuery(fragment, {
3080
3080
  variables: {
3081
- filter: variables.filter,
3081
+ where: variables.where,
3082
3082
  sort: variables.sort
3083
3083
  },
3084
3084
  canCancel: true
@@ -251,6 +251,10 @@ function applyOrderBy(records, _order_by) {
251
251
  // Create a custom iteratee function for natural sorting
252
252
  iteratees.push(record => {
253
253
  const value = record[field];
254
+ // Handle null values based on sort direction
255
+ if (isNull(value) || value === undefined) {
256
+ return direction === "asc" ? -Infinity : -Infinity;
257
+ }
254
258
  // Use natural sorting only for strings that contain numbers
255
259
  if (isString(value) && /\d/.test(value)) {
256
260
  // Return the value in a format that can be naturally sorted
@@ -261,8 +265,29 @@ function applyOrderBy(records, _order_by) {
261
265
  });
262
266
  });
263
267
 
264
- // Use the custom iteratees for natural sorting
265
- records = orderBy(records, iteratees, directions);
268
+ // First sort normally
269
+ let sortedRecords = orderBy(records, iteratees, directions);
270
+
271
+ // Then ensure entries with a value for the field come before entries without a value
272
+ // for any field sorted in descending order
273
+ order_by.forEach(item => {
274
+ const field = Object.keys(item)[0];
275
+ const direction = item[field];
276
+
277
+ if (direction === "desc") {
278
+ // For descending sorts, we want entries with values to appear before entries without values
279
+ sortedRecords = [
280
+ ...sortedRecords.filter(
281
+ record => !isNull(record[field]) && record[field] !== undefined
282
+ ),
283
+ ...sortedRecords.filter(
284
+ record => isNull(record[field]) || record[field] === undefined
285
+ )
286
+ ];
287
+ }
288
+ });
289
+
290
+ records = sortedRecords;
266
291
  }
267
292
  return records;
268
293
  }
@@ -379,42 +379,152 @@ describe("filterLocalEntitiesToHasura", () => {
379
379
  ]);
380
380
  expect(result.entityCount).toBe(3);
381
381
  });
382
- it("should order by age ascending", () => {
383
- const result = filterLocalEntitiesToHasura(records, {
384
- order_by: { age: "asc" }
385
- });
382
+ it("should order by age ascending and put null vals last by default", () => {
383
+ const result = filterLocalEntitiesToHasura(
384
+ [{ id: 111, name: "Null Age", age: null, city: "Unknown" }, ...records],
385
+ {
386
+ order_by: { age: "asc" }
387
+ }
388
+ );
386
389
  expect(result.entities).toEqual([
387
390
  records[3],
388
391
  records[1],
389
392
  records[0],
390
- records[2]
393
+ records[2],
394
+ { id: 111, name: "Null Age", age: null, city: "Unknown" }
391
395
  ]);
392
396
  expect(result.entitiesAcrossPages).toEqual([
393
397
  records[3],
394
398
  records[1],
395
399
  records[0],
396
- records[2]
400
+ records[2],
401
+ { id: 111, name: "Null Age", age: null, city: "Unknown" }
397
402
  ]);
398
- expect(result.entityCount).toBe(4);
403
+ expect(result.entityCount).toBe(5);
399
404
  });
400
-
401
- it("should order by age descending", () => {
402
- const result = filterLocalEntitiesToHasura(records, {
403
- order_by: { age: "desc" }
404
- });
405
+ it("should order by age desc and put null/undefined vals last by default", () => {
406
+ const result = filterLocalEntitiesToHasura(
407
+ [
408
+ { id: 111, name: "Null Age", age: null, city: "Unknown" },
409
+ { id: 1121, name: "Undefined Age", age: undefined, city: "Unknown" },
410
+ ...records
411
+ ],
412
+ {
413
+ order_by: { age: "desc" }
414
+ }
415
+ );
405
416
  expect(result.entities).toEqual([
406
417
  records[2],
407
418
  records[0],
408
419
  records[1],
409
- records[3]
420
+ records[3],
421
+ { id: 111, name: "Null Age", age: null, city: "Unknown" },
422
+ { id: 1121, name: "Undefined Age", age: undefined, city: "Unknown" }
410
423
  ]);
411
- expect(result.entitiesAcrossPages).toEqual([
424
+ expect(result.entityCount).toBe(6);
425
+ });
426
+
427
+ it.only("should order by updatedAt descending, putting null/undefined vals last ", () => {
428
+ const result = filterLocalEntitiesToHasura(
429
+ [
430
+ {
431
+ name: "-10_signal",
432
+ color: "#4ECDC4",
433
+ isGenbankStandardType: true,
434
+ __typename: "featureTypeOverride"
435
+ },
436
+ {
437
+ name: "-35_signal",
438
+ color: "#F7FFF7",
439
+ isGenbankStandardType: true,
440
+ __typename: "featureTypeOverride"
441
+ },
442
+ {
443
+ name: "3'clip",
444
+ color: "#FF6B6B",
445
+ isGenbankStandardType: true,
446
+ __typename: "featureTypeOverride"
447
+ },
448
+ {
449
+ name: "3'UTR",
450
+ color: "#FFE66D",
451
+ isGenbankStandardType: true,
452
+ __typename: "featureTypeOverride"
453
+ },
454
+
455
+ {
456
+ __typename: "featureTypeOverride",
457
+ id: "33a90fcb-fc26-406f-a6d5-41ac4ba8ea64",
458
+ name: "lalala",
459
+ description: null,
460
+ color: "#81bb41",
461
+ genbankEquivalentType: null,
462
+ updatedAt: "2025-06-03T01:02:24.737499+00:00",
463
+ isHidden: false,
464
+ isCustomType: true
465
+ }
466
+ ],
467
+ {
468
+ order_by: [{ updatedAt: "desc" }]
469
+ }
470
+ );
471
+ expect(result.entities).toEqual([
472
+ {
473
+ __typename: "featureTypeOverride",
474
+ id: "33a90fcb-fc26-406f-a6d5-41ac4ba8ea64",
475
+ name: "lalala",
476
+ description: null,
477
+ color: "#81bb41",
478
+ genbankEquivalentType: null,
479
+ updatedAt: "2025-06-03T01:02:24.737499+00:00",
480
+ isHidden: false,
481
+ isCustomType: true
482
+ },
483
+ {
484
+ name: "-10_signal",
485
+ color: "#4ECDC4",
486
+ isGenbankStandardType: true,
487
+ __typename: "featureTypeOverride"
488
+ },
489
+ {
490
+ name: "-35_signal",
491
+ color: "#F7FFF7",
492
+ isGenbankStandardType: true,
493
+ __typename: "featureTypeOverride"
494
+ },
495
+ {
496
+ name: "3'clip",
497
+ color: "#FF6B6B",
498
+ isGenbankStandardType: true,
499
+ __typename: "featureTypeOverride"
500
+ },
501
+ {
502
+ name: "3'UTR",
503
+ color: "#FFE66D",
504
+ isGenbankStandardType: true,
505
+ __typename: "featureTypeOverride"
506
+ }
507
+ ]);
508
+ });
509
+ it("should order by age descending, putting null/undefined vals last ", () => {
510
+ const result = filterLocalEntitiesToHasura(
511
+ [
512
+ { id: 111, name: "Null Age", age: null, city: "Unknown" },
513
+ { id: 1121, name: "Undefined Age", age: undefined, city: "Unknown" },
514
+ ...records
515
+ ],
516
+ {
517
+ order_by: { age: "desc" }
518
+ }
519
+ );
520
+ expect(result.entities).toEqual([
412
521
  records[2],
413
522
  records[0],
414
523
  records[1],
415
- records[3]
524
+ records[3],
525
+ { id: 111, name: "Null Age", age: null, city: "Unknown" },
526
+ { id: 1121, name: "Undefined Age", age: undefined, city: "Unknown" }
416
527
  ]);
417
- expect(result.entityCount).toBe(4);
418
528
  });
419
529
 
420
530
  it("should order by name ascending", () => {
@@ -21,18 +21,18 @@ export function tableQueryParamsToHasuraClauses({
21
21
  const uniqueFieldsByPath = {};
22
22
 
23
23
  // Split the search term by comma to support multi-term searching
24
- const searchTerms = searchTerm.split(',');
24
+ const searchTerms = searchTerm.split(",");
25
25
 
26
26
  schema.fields.forEach(field => {
27
27
  const { type, path, searchDisabled } = field;
28
28
  if (uniqueFieldsByPath[path]) return; // Skip if already added
29
29
  uniqueFieldsByPath[path] = true;
30
30
  if (searchDisabled || field.filterDisabled || type === "color") return;
31
-
31
+
32
32
  // Process each search term
33
33
  searchTerms.forEach(term => {
34
34
  const filterValue = term.trim(); // Trim the term to handle spaces after commas
35
-
35
+
36
36
  if (type === "string" || type === "lookup") {
37
37
  const o = set({}, path, { _ilike: `%${filterValue}%` });
38
38
  searchTermFilters.push(o);