box-ui-elements 24.0.0-beta.4 → 24.0.0-beta.6

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.
Files changed (113) hide show
  1. package/dist/explorer.css +1 -1
  2. package/dist/explorer.js +1 -1
  3. package/dist/openwith.js +1 -1
  4. package/dist/picker.js +1 -1
  5. package/dist/preview.js +1 -1
  6. package/dist/sharing.js +1 -1
  7. package/dist/sidebar.js +1 -1
  8. package/dist/uploader.js +1 -1
  9. package/es/api/Metadata.js +98 -13
  10. package/es/api/Metadata.js.flow +110 -12
  11. package/es/api/Metadata.js.map +1 -1
  12. package/es/elements/common/messages.js +16 -0
  13. package/es/elements/common/messages.js.flow +25 -0
  14. package/es/elements/common/messages.js.map +1 -1
  15. package/es/elements/content-explorer/Content.js +5 -2
  16. package/es/elements/content-explorer/Content.js.map +1 -1
  17. package/es/elements/content-explorer/ContentExplorer.js +31 -6
  18. package/es/elements/content-explorer/ContentExplorer.js.map +1 -1
  19. package/es/elements/content-explorer/MetadataQueryAPIHelper.js +164 -10
  20. package/es/elements/content-explorer/MetadataQueryAPIHelper.js.map +1 -1
  21. package/es/elements/content-explorer/MetadataQueryBuilder.js +115 -0
  22. package/es/elements/content-explorer/MetadataQueryBuilder.js.map +1 -0
  23. package/es/elements/content-explorer/MetadataSidePanel.js +40 -14
  24. package/es/elements/content-explorer/MetadataSidePanel.js.map +1 -1
  25. package/es/elements/content-explorer/MetadataViewContainer.js +133 -36
  26. package/es/elements/content-explorer/MetadataViewContainer.js.map +1 -1
  27. package/es/elements/content-explorer/stories/MetadataView.stories.js +3 -25
  28. package/es/elements/content-explorer/stories/MetadataView.stories.js.map +1 -1
  29. package/es/elements/content-explorer/stories/tests/MetadataView-visual.stories.js +65 -29
  30. package/es/elements/content-explorer/stories/tests/MetadataView-visual.stories.js.map +1 -1
  31. package/es/elements/content-explorer/utils.js +140 -12
  32. package/es/elements/content-explorer/utils.js.map +1 -1
  33. package/es/src/elements/common/__mocks__/mockMetadata.d.ts +8 -24
  34. package/es/src/elements/content-explorer/Content.d.ts +4 -3
  35. package/es/src/elements/content-explorer/ContentExplorer.d.ts +19 -6
  36. package/es/src/elements/content-explorer/MetadataQueryAPIHelper.d.ts +22 -3
  37. package/es/src/elements/content-explorer/MetadataQueryBuilder.d.ts +27 -0
  38. package/es/src/elements/content-explorer/MetadataSidePanel.d.ts +6 -3
  39. package/es/src/elements/content-explorer/MetadataViewContainer.d.ts +10 -4
  40. package/es/src/elements/content-explorer/__tests__/MetadataQueryBuilder.test.d.ts +1 -0
  41. package/es/src/elements/content-explorer/stories/tests/MetadataView-visual.stories.d.ts +1 -0
  42. package/es/src/elements/content-explorer/utils.d.ts +9 -3
  43. package/i18n/bn-IN.js +4 -0
  44. package/i18n/bn-IN.properties +12 -0
  45. package/i18n/da-DK.js +4 -0
  46. package/i18n/da-DK.properties +12 -0
  47. package/i18n/de-DE.js +5 -1
  48. package/i18n/de-DE.properties +12 -0
  49. package/i18n/en-AU.js +4 -0
  50. package/i18n/en-AU.properties +12 -0
  51. package/i18n/en-CA.js +4 -0
  52. package/i18n/en-CA.properties +12 -0
  53. package/i18n/en-GB.js +4 -0
  54. package/i18n/en-GB.properties +12 -0
  55. package/i18n/en-US.js +4 -0
  56. package/i18n/en-US.properties +8 -0
  57. package/i18n/en-x-pseudo.js +4 -0
  58. package/i18n/es-419.js +5 -1
  59. package/i18n/es-419.properties +12 -0
  60. package/i18n/es-ES.js +5 -1
  61. package/i18n/es-ES.properties +12 -0
  62. package/i18n/fi-FI.js +4 -0
  63. package/i18n/fi-FI.properties +12 -0
  64. package/i18n/fr-CA.js +4 -0
  65. package/i18n/fr-CA.properties +12 -0
  66. package/i18n/fr-FR.js +4 -0
  67. package/i18n/fr-FR.properties +12 -0
  68. package/i18n/hi-IN.js +4 -0
  69. package/i18n/hi-IN.properties +12 -0
  70. package/i18n/it-IT.js +4 -0
  71. package/i18n/it-IT.properties +12 -0
  72. package/i18n/ja-JP.js +6 -2
  73. package/i18n/ja-JP.properties +14 -2
  74. package/i18n/ko-KR.js +4 -0
  75. package/i18n/ko-KR.properties +12 -0
  76. package/i18n/nb-NO.js +4 -0
  77. package/i18n/nb-NO.properties +12 -0
  78. package/i18n/nl-NL.js +4 -0
  79. package/i18n/nl-NL.properties +12 -0
  80. package/i18n/pl-PL.js +4 -0
  81. package/i18n/pl-PL.properties +12 -0
  82. package/i18n/pt-BR.js +4 -0
  83. package/i18n/pt-BR.properties +12 -0
  84. package/i18n/ru-RU.js +5 -1
  85. package/i18n/ru-RU.properties +12 -0
  86. package/i18n/sv-SE.js +4 -0
  87. package/i18n/sv-SE.properties +12 -0
  88. package/i18n/tr-TR.js +5 -1
  89. package/i18n/tr-TR.properties +12 -0
  90. package/i18n/zh-CN.js +4 -0
  91. package/i18n/zh-CN.properties +12 -0
  92. package/i18n/zh-TW.js +4 -0
  93. package/i18n/zh-TW.properties +12 -0
  94. package/package.json +3 -3
  95. package/src/api/Metadata.js +110 -12
  96. package/src/api/__tests__/Metadata.test.js +120 -0
  97. package/src/elements/common/__mocks__/mockMetadata.ts +7 -11
  98. package/src/elements/common/messages.js +25 -0
  99. package/src/elements/content-explorer/Content.tsx +9 -2
  100. package/src/elements/content-explorer/ContentExplorer.tsx +71 -17
  101. package/src/elements/content-explorer/MetadataQueryAPIHelper.ts +199 -8
  102. package/src/elements/content-explorer/MetadataQueryBuilder.ts +159 -0
  103. package/src/elements/content-explorer/MetadataSidePanel.tsx +55 -14
  104. package/src/elements/content-explorer/MetadataViewContainer.tsx +164 -29
  105. package/src/elements/content-explorer/__tests__/Content.test.tsx +1 -0
  106. package/src/elements/content-explorer/__tests__/ContentExplorer.test.tsx +38 -7
  107. package/src/elements/content-explorer/__tests__/MetadataQueryAPIHelper.test.ts +428 -12
  108. package/src/elements/content-explorer/__tests__/MetadataQueryBuilder.test.ts +419 -0
  109. package/src/elements/content-explorer/__tests__/MetadataSidePanel.test.tsx +145 -3
  110. package/src/elements/content-explorer/__tests__/MetadataViewContainer.test.tsx +413 -9
  111. package/src/elements/content-explorer/stories/MetadataView.stories.tsx +3 -21
  112. package/src/elements/content-explorer/stories/tests/MetadataView-visual.stories.tsx +56 -21
  113. package/src/elements/content-explorer/utils.ts +150 -13
@@ -8,9 +8,9 @@ import {
8
8
  JSON_PATCH_OP_REPLACE,
9
9
  JSON_PATCH_OP_TEST,
10
10
  } from '../../../common/constants';
11
- import { FIELD_METADATA, FIELD_NAME, FIELD_EXTENSION } from '../../../constants';
11
+ import { FIELD_METADATA, FIELD_ITEM_NAME, FIELD_EXTENSION, FIELD_PERMISSIONS } from '../../../constants';
12
12
 
13
- describe('features/metadata-based-view/MetadataQueryAPIHelper', () => {
13
+ describe('elements/content-explorer/MetadataQueryAPIHelper', () => {
14
14
  let metadataQueryAPIHelper;
15
15
  const templateScope = 'enterprise_12345';
16
16
  const templateKey = 'awesomeTemplate';
@@ -193,7 +193,7 @@ describe('features/metadata-based-view/MetadataQueryAPIHelper', () => {
193
193
  query: 'query',
194
194
  query_params: {},
195
195
  fields: [
196
- FIELD_NAME,
196
+ FIELD_ITEM_NAME,
197
197
  'metadata.enterprise_1234.templateKey.type',
198
198
  'metadata.enterprise_1234.templateKey.year',
199
199
  'metadata.enterprise_1234.templateKey.approved',
@@ -225,6 +225,29 @@ describe('features/metadata-based-view/MetadataQueryAPIHelper', () => {
225
225
  test('should return empty object when instance is not found', () => {
226
226
  expect(metadataQueryAPIHelper.flattenMetadata(undefined)).toEqual({});
227
227
  });
228
+
229
+ test('should return fields even when template fields are empty', () => {
230
+ metadataQueryAPIHelper.metadataTemplate = { ...template, fields: [] };
231
+ const result = metadataQueryAPIHelper.flattenMetadata(entries[0].metadata);
232
+ expect(result.enterprise.fields).toHaveLength(3);
233
+ expect(result.enterprise.fields[0].type).toBeUndefined();
234
+ });
235
+
236
+ test('should handle missing template field gracefully', () => {
237
+ const metadataWithMissingField = {
238
+ [templateScope]: {
239
+ [templateKey]: {
240
+ $id: metadataInstanceId1,
241
+ type: 'bill',
242
+ // year field is missing
243
+ approved: 'yes',
244
+ },
245
+ },
246
+ };
247
+ const result = metadataQueryAPIHelper.flattenMetadata(metadataWithMissingField);
248
+ expect(result.enterprise.fields).toHaveLength(3);
249
+ expect(result.enterprise.fields.find(f => f.key.includes('year'))?.value).toBeUndefined();
250
+ });
228
251
  });
229
252
 
230
253
  describe('getDataWithTypes()', () => {
@@ -234,6 +257,13 @@ describe('features/metadata-based-view/MetadataQueryAPIHelper', () => {
234
257
  expect(result).toEqual(dataWithTypes);
235
258
  expect(metadataQueryAPIHelper.metadataTemplate).toEqual(template);
236
259
  });
260
+
261
+ test('should handle undefined template schema response', () => {
262
+ metadataQueryAPIHelper.metadataQueryResponseData = metadataQueryResponse;
263
+ const result = metadataQueryAPIHelper.getDataWithTypes(undefined);
264
+ expect(result).toEqual(dataWithTypes);
265
+ expect(metadataQueryAPIHelper.metadataTemplate).toBeUndefined();
266
+ });
237
267
  });
238
268
 
239
269
  describe('getTemplateSchemaInfo()', () => {
@@ -253,6 +283,20 @@ describe('features/metadata-based-view/MetadataQueryAPIHelper', () => {
253
283
  expect(result).toBe(undefined);
254
284
  expect(metadataQueryAPIHelper.metadataQueryResponseData).toEqual(emptyEntriesResponse);
255
285
  });
286
+
287
+ test('should handle response with null entries', async () => {
288
+ const nullEntriesResponse = { entries: null, next_marker: nextMarker };
289
+ const result = await metadataQueryAPIHelper.getTemplateSchemaInfo(nullEntriesResponse);
290
+ expect(getSchemaByTemplateKeyFunc).not.toHaveBeenCalled();
291
+ expect(result).toBe(undefined);
292
+ });
293
+
294
+ test('should handle response with undefined entries', async () => {
295
+ const undefinedEntriesResponse = { next_marker: nextMarker };
296
+ const result = await metadataQueryAPIHelper.getTemplateSchemaInfo(undefinedEntriesResponse);
297
+ expect(getSchemaByTemplateKeyFunc).not.toHaveBeenCalled();
298
+ expect(result).toBe(undefined);
299
+ });
256
300
  });
257
301
 
258
302
  describe('queryMetadata()', () => {
@@ -266,6 +310,15 @@ describe('features/metadata-based-view/MetadataQueryAPIHelper', () => {
266
310
  { forceFetch: true },
267
311
  );
268
312
  });
313
+
314
+ test('should handle API errors properly', async () => {
315
+ const error = new Error('API Error');
316
+ queryMetadataFunc.mockImplementationOnce((query, resolve, reject) => {
317
+ reject(error);
318
+ });
319
+
320
+ await expect(metadataQueryAPIHelper.queryMetadata()).rejects.toThrow('API Error');
321
+ });
269
322
  });
270
323
 
271
324
  describe('fetchMetadataQueryResults()', () => {
@@ -301,6 +354,17 @@ describe('features/metadata-based-view/MetadataQueryAPIHelper', () => {
301
354
  expect(successCallback).not.toHaveBeenCalled();
302
355
  expect(errorCallback).toBeCalledWith(err);
303
356
  });
357
+
358
+ test('should handle query metadata errors', async () => {
359
+ const err = new Error('Query failed');
360
+ const successCallback = jest.fn();
361
+ const errorCallback = jest.fn();
362
+ metadataQueryAPIHelper.queryMetadata = jest.fn().mockReturnValueOnce(Promise.reject(err));
363
+
364
+ await metadataQueryAPIHelper.fetchMetadataQueryResults(mdQuery, successCallback, errorCallback);
365
+ expect(errorCallback).toBeCalledWith(err);
366
+ expect(successCallback).not.toHaveBeenCalled();
367
+ });
304
368
  });
305
369
 
306
370
  describe('createJSONPatchOperations()', () => {
@@ -345,6 +409,30 @@ describe('features/metadata-based-view/MetadataQueryAPIHelper', () => {
345
409
  const expectedResponse = ['type', 'year', 'approved'];
346
410
  expect(metadataQueryAPIHelper.getMetadataQueryFields()).toEqual(expectedResponse);
347
411
  });
412
+
413
+ test('should handle query with no metadata fields', () => {
414
+ metadataQueryAPIHelper.metadataQuery = {
415
+ ...mdQuery,
416
+ fields: [FIELD_ITEM_NAME, 'created_at'],
417
+ };
418
+ expect(metadataQueryAPIHelper.getMetadataQueryFields()).toEqual([]);
419
+ });
420
+
421
+ test('should handle query with empty fields array', () => {
422
+ metadataQueryAPIHelper.metadataQuery = {
423
+ ...mdQuery,
424
+ fields: [],
425
+ };
426
+ expect(metadataQueryAPIHelper.getMetadataQueryFields()).toEqual([]);
427
+ });
428
+
429
+ test('should handle query with undefined fields', () => {
430
+ metadataQueryAPIHelper.metadataQuery = {
431
+ ...mdQuery,
432
+ fields: undefined,
433
+ };
434
+ expect(metadataQueryAPIHelper.getMetadataQueryFields()).toEqual([]);
435
+ });
348
436
  });
349
437
 
350
438
  describe('updateMetadata()', () => {
@@ -396,21 +484,21 @@ describe('features/metadata-based-view/MetadataQueryAPIHelper', () => {
396
484
  from: 'enterprise_1234.templateKey',
397
485
  query: 'query',
398
486
  query_params: {},
399
- fields: [FIELD_NAME, 'metadata.enterprise_1234.templateKey.type'],
487
+ fields: [FIELD_ITEM_NAME, 'metadata.enterprise_1234.templateKey.type'],
400
488
  };
401
489
  const mdQueryWithoutExtensionField = {
402
490
  ancestor_folder_id: '672838458',
403
491
  from: 'enterprise_1234.templateKey',
404
492
  query: 'query',
405
493
  query_params: {},
406
- fields: [FIELD_NAME, 'metadata.enterprise_1234.templateKey.type'],
494
+ fields: [FIELD_ITEM_NAME, 'metadata.enterprise_1234.templateKey.type'],
407
495
  };
408
496
  const mdQueryWithBothFields = {
409
497
  ancestor_folder_id: '672838458',
410
498
  from: 'enterprise_1234.templateKey',
411
499
  query: 'query',
412
500
  query_params: {},
413
- fields: [FIELD_NAME, FIELD_EXTENSION, 'metadata.enterprise_1234.templateKey.type'],
501
+ fields: [FIELD_ITEM_NAME, FIELD_EXTENSION, 'metadata.enterprise_1234.templateKey.type'],
414
502
  };
415
503
  test.each`
416
504
  index | metadataQuery
@@ -424,31 +512,359 @@ describe('features/metadata-based-view/MetadataQueryAPIHelper', () => {
424
512
  ({ index, metadataQuery }) => {
425
513
  const updatedMetadataQuery = metadataQueryAPIHelper.verifyQueryFields(metadataQuery);
426
514
  expect(isArray(updatedMetadataQuery.fields)).toBe(true);
427
- expect(includes(updatedMetadataQuery.fields, FIELD_NAME)).toBe(true);
515
+ expect(includes(updatedMetadataQuery.fields, FIELD_ITEM_NAME)).toBe(true);
428
516
  expect(includes(updatedMetadataQuery.fields, FIELD_EXTENSION)).toBe(true);
517
+ expect(includes(updatedMetadataQuery.fields, FIELD_PERMISSIONS)).toBe(true);
429
518
 
430
519
  if (index === 2) {
431
- // Verify "name" and "extension" are added to pre-existing fields
520
+ // Verify "name", "extension" and "permission" are added to pre-existing fields
432
521
  expect(updatedMetadataQuery.fields).toEqual([
433
522
  ...mdQueryWithoutNameField.fields,
434
- FIELD_NAME,
523
+ FIELD_ITEM_NAME,
435
524
  FIELD_EXTENSION,
525
+ FIELD_PERMISSIONS,
436
526
  ]);
437
527
  }
438
528
 
439
529
  if (index === 4) {
440
- // Verify "extension" is added when "name" exists but "extension" doesn't
530
+ // Verify "extension" and "permission" are added when "name" exists but "extension" and "permission" don't
441
531
  expect(updatedMetadataQuery.fields).toEqual([
442
532
  ...mdQueryWithoutExtensionField.fields,
443
533
  FIELD_EXTENSION,
534
+ FIELD_PERMISSIONS,
444
535
  ]);
445
536
  }
446
537
 
447
538
  if (index === 5) {
448
- // No change, original query has all necessary fields
449
- expect(updatedMetadataQuery.fields).toEqual(mdQueryWithBothFields.fields);
539
+ // Verify "permission" is added
540
+ expect(updatedMetadataQuery.fields).toEqual([...mdQueryWithBothFields.fields, FIELD_PERMISSIONS]);
450
541
  }
451
542
  },
452
543
  );
544
+
545
+ test('should handle query with non-array fields', () => {
546
+ const mdQueryWithNonArrayFields = {
547
+ ancestor_folder_id: '672838458',
548
+ from: 'enterprise_1234.templateKey',
549
+ query: 'query',
550
+ query_params: {},
551
+ fields: 'not-an-array',
552
+ };
553
+
554
+ const updatedMetadataQuery = metadataQueryAPIHelper.verifyQueryFields(mdQueryWithNonArrayFields);
555
+ expect(isArray(updatedMetadataQuery.fields)).toBe(true);
556
+ expect(includes(updatedMetadataQuery.fields, FIELD_ITEM_NAME)).toBe(true);
557
+ expect(includes(updatedMetadataQuery.fields, FIELD_EXTENSION)).toBe(true);
558
+ });
559
+ });
560
+
561
+ describe('buildMDQueryParams()', () => {
562
+ test('should return empty result when no filters provided', () => {
563
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams({});
564
+ expect(result).toEqual({
565
+ queryParams: {},
566
+ query: '',
567
+ });
568
+ });
569
+
570
+ test('should return empty result when filters is null', () => {
571
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(null);
572
+ expect(result).toEqual({
573
+ queryParams: {},
574
+ query: '',
575
+ });
576
+ });
577
+
578
+ test('should handle date/float field with greater than filter', () => {
579
+ const filters = {
580
+ year: {
581
+ fieldType: 'float',
582
+ value: { range: { gt: 2020 } },
583
+ },
584
+ };
585
+
586
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
587
+ expect(result.query).toBe('(year >= :arg_year_1)');
588
+ expect(result.queryParams.arg_year_1).toBe(2020);
589
+ });
590
+
591
+ test('should handle date/float field with less than filter', () => {
592
+ const filters = {
593
+ year: {
594
+ fieldType: 'date',
595
+ value: { range: { lt: 2023 } },
596
+ },
597
+ };
598
+
599
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
600
+ expect(result.query).toBe('(year <= :arg_year_1)');
601
+ expect(result.queryParams.arg_year_1).toBe(2023);
602
+ });
603
+
604
+ test('should handle date/float field with range array filter', () => {
605
+ const filters = {
606
+ year: {
607
+ fieldType: 'float',
608
+ value: { range: { gt: 2020, lt: 2023 } },
609
+ },
610
+ };
611
+
612
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
613
+ expect(result.query).toBe('(year >= :arg_year_1 AND year <= :arg_year_2)');
614
+ expect(result.queryParams.arg_year_1).toBe(2020);
615
+ expect(result.queryParams.arg_year_2).toBe(2023);
616
+ });
617
+
618
+ test('should handle enum field with single value', () => {
619
+ const filters = {
620
+ status: {
621
+ fieldType: 'enum',
622
+ value: 'active',
623
+ },
624
+ };
625
+
626
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
627
+ expect(result.query).toBe('(status HASANY (:arg_status_1))');
628
+ expect(result.queryParams.arg_status_1).toBe('active');
629
+ });
630
+
631
+ test('should handle enum field with multiple values', () => {
632
+ const filters = {
633
+ status: {
634
+ fieldType: 'enum',
635
+ value: ['active', 'pending'],
636
+ },
637
+ };
638
+
639
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
640
+ expect(result.query).toBe('(status HASANY (:arg_status_1, :arg_status_2))');
641
+ expect(result.queryParams.arg_status_1).toBe('active');
642
+ expect(result.queryParams.arg_status_2).toBe('pending');
643
+ });
644
+
645
+ test('should handle multiSelect field', () => {
646
+ const filters = {
647
+ tags: {
648
+ fieldType: 'multiSelect',
649
+ value: ['tag1', 'tag2'],
650
+ },
651
+ };
652
+
653
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
654
+ expect(result.query).toBe('(tags HASANY (:arg_tags_1, :arg_tags_2))');
655
+ expect(result.queryParams.arg_tags_1).toBe('tag1');
656
+ expect(result.queryParams.arg_tags_2).toBe('tag2');
657
+ });
658
+
659
+ test('should handle string field with search value', () => {
660
+ const filters = {
661
+ name: {
662
+ fieldType: 'string',
663
+ value: ['search term'],
664
+ },
665
+ };
666
+
667
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
668
+ expect(result.query).toBe('(name ILIKE :arg_name_1)');
669
+ expect(result.queryParams.arg_name_1).toBe('%search term%');
670
+ });
671
+
672
+ test('should handle mimetype filter specifically', () => {
673
+ const filters = {
674
+ 'mimetype-filter': {
675
+ fieldType: 'enum',
676
+ value: ['pdf', 'doc'],
677
+ },
678
+ };
679
+
680
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
681
+ expect(result.query).toBe('(item.extension IN (:arg_mimetype_filter_1, :arg_mimetype_filter_2))');
682
+ expect(result.queryParams.arg_mimetype_filter_1).toBe('pdf');
683
+ expect(result.queryParams.arg_mimetype_filter_2).toBe('doc');
684
+ });
685
+
686
+ test('should handle multiple filters of different types', () => {
687
+ const filters = {
688
+ year: {
689
+ fieldType: 'float',
690
+ value: { range: { gt: 2020 } },
691
+ },
692
+ status: {
693
+ fieldType: 'enum',
694
+ value: ['active'],
695
+ },
696
+ name: {
697
+ fieldType: 'string',
698
+ value: ['search'],
699
+ },
700
+ };
701
+
702
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
703
+ expect(result.query).toBe(
704
+ '(year >= :arg_year_1) AND (status HASANY (:arg_status_2)) AND (name ILIKE :arg_name_3)',
705
+ );
706
+ expect(Object.keys(result.queryParams)).toHaveLength(3);
707
+ });
708
+
709
+ test('should handle filter with null/undefined value', () => {
710
+ const filters = {
711
+ field: {
712
+ fieldType: 'string',
713
+ value: null,
714
+ },
715
+ };
716
+
717
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
718
+ expect(result.query).toBe('');
719
+ expect(Object.keys(result.queryParams)).toHaveLength(0);
720
+ });
721
+
722
+ test('should handle filter with empty string value', () => {
723
+ const filters = {
724
+ field: {
725
+ fieldType: 'string',
726
+ value: '',
727
+ },
728
+ };
729
+
730
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
731
+ expect(result.query).toBe('');
732
+ expect(Object.keys(result.queryParams)).toHaveLength(0);
733
+ });
734
+
735
+ test('should handle unknown field type with array value', () => {
736
+ const filters = {
737
+ field: {
738
+ fieldType: 'unknown',
739
+ value: ['value1', 'value2'],
740
+ },
741
+ };
742
+
743
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
744
+ expect(result.query).toBeFalsy();
745
+ expect(result.queryParams.arg_field_1).toBeUndefined();
746
+ expect(result.queryParams.arg_field_2).toBeUndefined();
747
+ });
748
+ test('should handle empty array values for enum/multiSelect', () => {
749
+ const filters = {
750
+ status: {
751
+ fieldType: 'enum',
752
+ value: [],
753
+ },
754
+ };
755
+
756
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
757
+ expect(result.query).toBe('');
758
+ expect(Object.keys(result.queryParams)).toHaveLength(0);
759
+ });
760
+
761
+ test('should handle empty string array for string field', () => {
762
+ const filters = {
763
+ name: {
764
+ fieldType: 'string',
765
+ value: [''],
766
+ },
767
+ };
768
+
769
+ const result = metadataQueryAPIHelper.buildMetadataQueryParams(filters);
770
+ expect(result.query).toBe('');
771
+ expect(Object.keys(result.queryParams)).toHaveLength(0);
772
+ });
773
+ });
774
+
775
+ describe('verifyQueryFields with filters', () => {
776
+ test('should build query and query_params when filters are provided', () => {
777
+ const metadataQuery = {
778
+ ancestor_folder_id: '672838458',
779
+ from: 'enterprise_1234.templateKey',
780
+ fields: [FIELD_ITEM_NAME],
781
+ };
782
+
783
+ const filters = {
784
+ status: {
785
+ fieldType: 'enum',
786
+ value: ['active'],
787
+ },
788
+ };
789
+
790
+ const result = metadataQueryAPIHelper.verifyQueryFields(metadataQuery, filters);
791
+
792
+ expect(result.query).toBe('(status HASANY (:arg_status_1))');
793
+ expect(result.query_params).toEqual({
794
+ arg_status_1: 'active',
795
+ });
796
+ expect(result.fields).toContain(FIELD_ITEM_NAME);
797
+ expect(result.fields).toContain(FIELD_EXTENSION);
798
+ });
799
+
800
+ test('should handle multiple filters with AND logic', () => {
801
+ const metadataQuery = {
802
+ ancestor_folder_id: '672838458',
803
+ from: 'enterprise_1234.templateKey',
804
+ fields: [FIELD_ITEM_NAME],
805
+ };
806
+
807
+ const filters = {
808
+ status: {
809
+ fieldType: 'enum',
810
+ value: ['active'],
811
+ },
812
+ year: {
813
+ fieldType: 'float',
814
+ value: { range: { gt: 2020 } },
815
+ },
816
+ };
817
+
818
+ const result = metadataQueryAPIHelper.verifyQueryFields(metadataQuery, filters);
819
+
820
+ expect(result.query).toContain('AND');
821
+ expect(result.query).toContain('HASANY');
822
+ expect(result.query).toContain('>=');
823
+ expect(Object.keys(result.query_params)).toHaveLength(2);
824
+ });
825
+
826
+ test('should merge existing query_params with filter query params', () => {
827
+ const metadataQuery = {
828
+ ancestor_folder_id: '672838458',
829
+ from: 'enterprise_1234.templateKey',
830
+ fields: [FIELD_ITEM_NAME],
831
+ query: '(existing_field = :existing_param)',
832
+ query_params: {
833
+ existing_param: 'existing_value',
834
+ },
835
+ };
836
+
837
+ const filters = {
838
+ status: {
839
+ fieldType: 'enum',
840
+ value: ['active'],
841
+ },
842
+ };
843
+
844
+ const result = metadataQueryAPIHelper.verifyQueryFields(metadataQuery, filters);
845
+
846
+ expect(result.query).toBe('(existing_field = :existing_param) AND (status HASANY (:arg_status_1))');
847
+ expect(result.query_params).toEqual({
848
+ existing_param: 'existing_value',
849
+ arg_status_1: 'active',
850
+ });
851
+ expect(result.fields).toContain(FIELD_ITEM_NAME);
852
+ expect(result.fields).toContain(FIELD_EXTENSION);
853
+ });
854
+
855
+ test('should not modify query when no filters provided', () => {
856
+ const metadataQuery = {
857
+ ancestor_folder_id: '672838458',
858
+ from: 'enterprise_1234.templateKey',
859
+ fields: [FIELD_ITEM_NAME],
860
+ };
861
+
862
+ const result = metadataQueryAPIHelper.verifyQueryFields(metadataQuery);
863
+
864
+ expect(result.query).toBeUndefined();
865
+ expect(result.query_params).toBeUndefined();
866
+ expect(result.fields).toContain(FIELD_ITEM_NAME);
867
+ expect(result.fields).toContain(FIELD_EXTENSION);
868
+ });
453
869
  });
454
870
  });