@integry/sdk 4.6.39 → 4.6.41

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": "@integry/sdk",
3
- "version": "4.6.39",
3
+ "version": "4.6.41",
4
4
  "description": "Integry SDK",
5
5
  "main": "dist/umd/index.umd.js",
6
6
  "module": "dist/esm/index.csm.js",
@@ -9,6 +9,7 @@ interface ListBoxItemProps {
9
9
  isSelected?: boolean;
10
10
  isHighlighted?: boolean;
11
11
  onClick(): void;
12
+ icon?: string;
12
13
  }
13
14
 
14
15
  const ListBoxItem = (props: ListBoxItemProps) => {
@@ -24,7 +24,9 @@ import { FieldDropdown, Tabs } from '../TagMenu';
24
24
 
25
25
  import styles from './styles.module.scss';
26
26
 
27
- type keyValueMapper = (input: any) => { id: any; value: any }[];
27
+ type keyValueMapper = (
28
+ input: any,
29
+ ) => { id: any; value: any; icon?: any; description?: any }[];
28
30
 
29
31
  interface ListBoxProps {
30
32
  title: string;
@@ -70,6 +72,10 @@ interface ListBoxProps {
70
72
  parentFieldChanged?: boolean;
71
73
  allowWorkspaceConnectedAccounts: boolean;
72
74
  tagsTree?: any;
75
+ enableServerSideSearch?: boolean;
76
+ serverSideSearchParamName?: string;
77
+ iconKeyPath?: string;
78
+ optionDescriptionKeyPath?: string;
73
79
  }
74
80
 
75
81
  const ListBox = (props: ListBoxProps) => {
@@ -292,6 +298,15 @@ const ListBox = (props: ListBoxProps) => {
292
298
  if (allowWorkspaceConnectedAccounts) {
293
299
  data.allow_workspace_connected_accounts = true;
294
300
  }
301
+
302
+ // When server side search is available and results are paginated, then better to search the results as value might be in the next page
303
+ if (
304
+ props.enableServerSideSearch &&
305
+ props.serverSideSearchParamName &&
306
+ value
307
+ ) {
308
+ data[props.serverSideSearchParamName] = value;
309
+ }
295
310
  } catch (error) {
296
311
  data = '';
297
312
  }
@@ -311,8 +326,9 @@ const ListBox = (props: ListBoxProps) => {
311
326
  if (res) {
312
327
  setItems(dynamicResponseMapper(res));
313
328
  if (res.hasOwnProperty('_cursor') && res._cursor !== null) {
314
- let tempFilteredItems = dynamicResponseMapper(res);
329
+ const tempFilteredItems = dynamicResponseMapper(res);
315
330
  setFilteredItems(tempFilteredItems);
331
+ setSortedFilteredItems(tempFilteredItems);
316
332
  if (tempFilteredItems.length === 1) {
317
333
  setEditableTextValue(tempFilteredItems[0].value);
318
334
  onChange(tempFilteredItems[0].id, true);
@@ -381,7 +397,11 @@ const ListBox = (props: ListBoxProps) => {
381
397
  const dynamicResponseMapper: keyValueMapper = (input) => {
382
398
  const keyPath = props.optionKeyPath || 'id';
383
399
  const valuePath = props.valueKeyPath || 'value';
384
- const inputModified = input.hasOwnProperty('output') ? input.output : input;
400
+ const inputModified = Object.prototype.hasOwnProperty.call(input, 'output')
401
+ ? input.output
402
+ : Object.prototype.hasOwnProperty.call(input, 'functions')
403
+ ? input.functions
404
+ : input;
385
405
 
386
406
  // Check if inputModified is an array, if not, return an empty array
387
407
  if (!Array.isArray(inputModified)) {
@@ -414,12 +434,16 @@ const ListBox = (props: ListBoxProps) => {
414
434
  };
415
435
 
416
436
  // Resolve id and value using the helper function
417
- let id = resolveValue(keyPath);
418
- let value = resolveValue(valuePath);
437
+ const id = resolveValue(keyPath);
438
+ let optionValue = resolveValue(valuePath);
439
+ const icon = resolveValue(props.iconKeyPath || '');
440
+ const optionDescription = resolveValue(
441
+ props.optionDescriptionKeyPath || '',
442
+ );
419
443
 
420
444
  // Fallback: If 'value' is undefined or an empty string, use 'id' as the value
421
- if (typeof value === 'undefined' || value === '') {
422
- value = id;
445
+ if (typeof optionValue === 'undefined' || optionValue === '') {
446
+ optionValue = id;
423
447
  }
424
448
 
425
449
  if (id === '') {
@@ -427,13 +451,13 @@ const ListBox = (props: ListBoxProps) => {
427
451
  `${keyPath} was not found in the response for field ${fieldId}`,
428
452
  );
429
453
  }
430
- if (value === '') {
454
+ if (optionValue === '') {
431
455
  console.warn(
432
456
  `${valuePath} was not found in the response for field ${fieldId}`,
433
457
  );
434
458
  }
435
459
 
436
- return { id, value };
460
+ return { id, value: optionValue, icon, description: optionDescription };
437
461
  });
438
462
  };
439
463
 
@@ -626,6 +650,35 @@ const ListBox = (props: ListBoxProps) => {
626
650
  return index > -1 ? items[index].value : '';
627
651
  }, [items, value]);
628
652
 
653
+ const getSelectedItemIcon = useMemo(() => {
654
+ let index = -1;
655
+ if (isMultiSelect) {
656
+ let values = value ? JSON.parse(value) : [];
657
+ values = Array.isArray(values) ? values : [String(values)];
658
+ const indexes: any = [];
659
+ const selectedValues =
660
+ values.map((val: any) => {
661
+ index = items.findIndex((el) => el.id === val);
662
+ indexes.push(index);
663
+ }) || [];
664
+ if (indexes.length > 0 && items.length > 0) {
665
+ const firstItem = items[0] as ListBoxItemProps;
666
+ return firstItem.icon || undefined;
667
+ }
668
+ } else {
669
+ try {
670
+ index = items.findIndex((el) => el.id === value);
671
+ } catch (error) {
672
+ index = -1;
673
+ }
674
+ if (isMappable && selectedTab === 'AppFields') {
675
+ return index > -1 ? items[index].icon : '';
676
+ }
677
+ }
678
+
679
+ return index > -1 ? items[index].icon : '';
680
+ }, [items, value]);
681
+
629
682
  const getItemFromText = (
630
683
  textValue: string,
631
684
  ): {
@@ -696,11 +749,57 @@ const ListBox = (props: ListBoxProps) => {
696
749
  setTempPlaceholder(getSelectedItem || '');
697
750
  }
698
751
  };
699
-
700
- const onSearchChange = (e: InputEvent) => {
752
+ const debounceTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
753
+ const onSearchChange = async (e: InputEvent) => {
701
754
  if (e.currentTarget instanceof HTMLInputElement) {
702
- setSearchValue(e.currentTarget.value.trim());
703
- setQuery(e.currentTarget.value.trim());
755
+ const searchTerm = e.currentTarget.value.trim();
756
+ if (!props.enableServerSideSearch) {
757
+ setSearchValue(searchTerm);
758
+ setQuery(searchTerm);
759
+ }
760
+
761
+ if (
762
+ isSearchable &&
763
+ props.enableServerSideSearch &&
764
+ props.serverSideSearchParamName &&
765
+ endpointUrl
766
+ ) {
767
+ if (debounceTimeout.current) {
768
+ clearTimeout(debounceTimeout.current);
769
+ }
770
+ debounceTimeout.current = setTimeout(async () => {
771
+ setLoading(true);
772
+ setItems([]);
773
+ setSortedFilteredItems([]);
774
+ try {
775
+ const params = new URLSearchParams();
776
+ params.append(props.serverSideSearchParamName || '', searchTerm);
777
+ params.append('include', 'meta');
778
+
779
+ const response = await props.apiHandler.callDynamicDataEndpoint<
780
+ {
781
+ id: string;
782
+ value: string;
783
+ }[]
784
+ >(new URL(`${endpointUrl}?${params.toString()}`), {}, 'POST');
785
+
786
+ if (response) {
787
+ const serverFilteredItems = dynamicResponseMapper(response);
788
+ setItems(serverFilteredItems);
789
+ setSortedFilteredItems(serverFilteredItems);
790
+ } else {
791
+ setItems([]);
792
+ setSortedFilteredItems([]);
793
+ }
794
+ } catch (error) {
795
+ console.error('Error performing server-side search:', error);
796
+ setItems([]);
797
+ setSortedFilteredItems([]);
798
+ } finally {
799
+ setLoading(false);
800
+ }
801
+ }, 500);
802
+ }
704
803
  }
705
804
  };
706
805
 
@@ -915,6 +1014,13 @@ const ListBox = (props: ListBoxProps) => {
915
1014
  `
916
1015
  : isDropdownOpen && !isEditable
917
1016
  ? html`
1017
+ ${getSelectedItem &&
1018
+ props.iconKeyPath &&
1019
+ html`<img
1020
+ src="${getSelectedItemIcon || ''}"
1021
+ alt="icon"
1022
+ class="${styles.selectedIcon}"
1023
+ />`}
918
1024
  <input
919
1025
  ref=${(r: any) => {
920
1026
  if (r && isDropdownOpen) {
@@ -930,6 +1036,13 @@ const ListBox = (props: ListBoxProps) => {
930
1036
  />
931
1037
  `
932
1038
  : html`
1039
+ ${getSelectedItem &&
1040
+ props.iconKeyPath &&
1041
+ html`<img
1042
+ src="${getSelectedItemIcon || ''}"
1043
+ alt="icon"
1044
+ class="${styles.selectedIcon}"
1045
+ />`}
933
1046
  <input
934
1047
  ref=${(r: any) => {
935
1048
  if (r && isDropdownOpen) {
@@ -952,7 +1065,24 @@ const ListBox = (props: ListBoxProps) => {
952
1065
  />
953
1066
  `}`}
954
1067
  </span>
955
-
1068
+ <div class=${styles.chevronIcon}>
1069
+ <svg
1070
+ class="styles-module_accountFieldDropdownIcon__3161J"
1071
+ width="20"
1072
+ height="20"
1073
+ viewBox="0 0 20 20"
1074
+ fill="none"
1075
+ xmlns="http://www.w3.org/2000/svg"
1076
+ style=""
1077
+ >
1078
+ <path
1079
+ d="M15 8L10 13L5 8"
1080
+ stroke="#999999"
1081
+ stroke-width="2"
1082
+ stroke-linecap="round"
1083
+ ></path>
1084
+ </svg>
1085
+ </div>
956
1086
  <div ref=${dropdownRef} style="display: flex;">
957
1087
  ${taggedSelect &&
958
1088
  onAddTag &&
@@ -100,6 +100,11 @@
100
100
  color: #999999;
101
101
  }
102
102
  }
103
+ .selectedIcon {
104
+ width: 20px;
105
+ height: 20px;
106
+ margin-right: 8px;
107
+ }
103
108
  &.readonly {
104
109
  cursor: auto;
105
110
  }
@@ -24,6 +24,8 @@ interface Option {
24
24
  value: string;
25
25
  id: string;
26
26
  isSelected?: boolean;
27
+ icon?: string;
28
+ description?: string;
27
29
  }
28
30
  interface FieldMenuProps {
29
31
  tags: NestedObject;
@@ -279,6 +281,8 @@ const FieldDropdown = (props: FieldMenuProps) => {
279
281
  return html`
280
282
  <div
281
283
  class=${`${styles.value} ${
284
+ option.icon ? styles.valueWithIcon : ''
285
+ } ${
282
286
  selectedValues.includes(option.id)
283
287
  ? styles.selected
284
288
  : ''
@@ -294,7 +298,25 @@ const FieldDropdown = (props: FieldMenuProps) => {
294
298
  : ''
295
299
  }`}
296
300
  >
297
- ${option.value}
301
+ ${option.icon &&
302
+ html`<img
303
+ src="${option.icon}"
304
+ alt="icon"
305
+ class="${styles.icon}"
306
+ />`}
307
+ <div class="label-text">
308
+ <div
309
+ class="${option.description
310
+ ? styles.nameWithDescription
311
+ : ''}"
312
+ >
313
+ ${option.value}
314
+ </div>
315
+ ${option.description &&
316
+ html`<div class="${styles.description}">
317
+ ${option.description}
318
+ </div>`}
319
+ </div>
298
320
  </div>
299
321
 
300
322
  ${i !== arr.length - 1
@@ -45,7 +45,7 @@
45
45
  .tagMenuHeaderItem {
46
46
  padding: 6px 12px;
47
47
  background: #f2f2f2;
48
- border-radius: 100px;
48
+ border-radius: 5px;
49
49
  font-weight: 400;
50
50
  font-size: 10px;
51
51
  line-height: 12px;
@@ -75,12 +75,33 @@
75
75
  cursor: pointer;
76
76
  &:hover {
77
77
  background: rgba(66, 80, 240, 0.1);
78
- border-radius: 100px;
78
+ border-radius: 5px;
79
79
  }
80
80
  }
81
+ .valueWithIcon {
82
+ display: flex;
83
+ align-items: center;
84
+ gap: 8px; /* Adjust spacing between image and text */
85
+ height: 40px;
86
+ }
87
+ .icon {
88
+ width: 20px;
89
+ height: 20px;
90
+ }
91
+
92
+ .description {
93
+ font-size: 0.85em;
94
+ color: #666;
95
+ width: 31.5rem;
96
+ text-overflow: ellipsis;
97
+ overflow: hidden;
98
+ }
99
+ .nameWithDescription {
100
+ font-weight: 500;
101
+ }
81
102
  .selected {
82
103
  background: rgba(66, 80, 240, 0.1);
83
- border-radius: 100px;
104
+ border-radius: 5px;
84
105
  }
85
106
  }
86
107
  }
@@ -264,9 +264,9 @@ const MultipurposeField = (props: MultipurposeFieldProps) => {
264
264
  class="tagify__tag ${tagData.class ? tagData.class : ''}"
265
265
  >
266
266
  <div class="${styles.tagifyTagTemplate}">
267
- <div class="${styles.tagifyAppIcon}">
268
- <img src="${tagData.appIcon}" alt="" />
269
- </div>
267
+ <img class="${styles.tagifyAppIcon}" src="${
268
+ tagData.appIcon
269
+ }" alt="" />
270
270
  <span data-hint="${
271
271
  typeof tagData.title === 'string' ? tagData.title : ''
272
272
  }" class='tagify__tag-text'>${originText}: ${tagData.text}</span>
@@ -62,13 +62,10 @@
62
62
  align-items: center; /* Ensures vertical alignment */
63
63
  gap: 4px; /* Optional spacing between icon and text */
64
64
  .tagifyAppIcon {
65
- img {
66
- margin-right: 5px;
67
-
68
- width: 16px; /* Adjust based on your design */
69
- height: 16px;
70
- object-fit: contain;
71
- display: block;
72
- }
65
+ display: inline-block;
66
+ height: 16px;
67
+ margin-right: 3px;
68
+ border-radius: 2px;
69
+ pointer-events: none;
73
70
  }
74
71
  }
@@ -281,7 +281,7 @@
281
281
  padding: 5px 10px;
282
282
  &:hover {
283
283
  background: rgba(66, 80, 240, 0.1);
284
- border-radius: 100px;
284
+ border-radius: 5px;
285
285
  }
286
286
  }
287
287
  }