@integry/sdk 4.6.93 → 4.6.95

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.93",
3
+ "version": "4.6.95",
4
4
  "description": "Integry SDK",
5
5
  "main": "dist/umd/index.umd.js",
6
6
  "module": "dist/esm/index.csm.js",
@@ -5,7 +5,6 @@ import { TemplateField, NestedObject } from '@/interfaces';
5
5
  import AppContext from '@/contexts/AppContext';
6
6
  import { StoreType } from '@/types/store';
7
7
  // import { Input } from '@/components/Input';
8
- import { LargeLoader } from '@/components/LargeLoader';
9
8
  import { Loader } from '@/components/Loader';
10
9
  import { MultipurposeField } from '@/components/MultipurposeField';
11
10
  import { actionFunctions } from '@/store';
@@ -141,7 +140,13 @@ const DynamicFields = (props: DynamicFieldsProps) => {
141
140
 
142
141
  useEffect(() => {
143
142
  fetchDynamicFields();
144
- }, [dynamicField, endpointData, selectedAuthId, parentFieldChanged]);
143
+ }, [parentFieldChanged]);
144
+
145
+ useEffect(() => {
146
+ if (!onChangeCallback) {
147
+ fetchDynamicFields();
148
+ }
149
+ }, [dynamicField, endpointData, selectedAuthId]);
145
150
 
146
151
  const getPlaceholder = () => {
147
152
  let placeHolderValue = 'Enter text or map to fields...';
@@ -166,13 +171,19 @@ const DynamicFields = (props: DynamicFieldsProps) => {
166
171
  });
167
172
 
168
173
  if (onChangeCallback && objectValue !== null) {
169
- const data = {
170
- ...customFieldsData,
171
- [machineName]: val,
172
- };
173
- setCustomFieldsData(data);
174
+ // Use the functional update form of setState to ensure we're working with the latest state
175
+ setCustomFieldsData((prevData: any) => {
176
+ const updatedData = {
177
+ ...prevData,
178
+ [machineName]: val,
179
+ };
174
180
 
175
- onChangeCallback(JSON.stringify(data));
181
+ // Call the callback with the updated data
182
+ onChangeCallback(JSON.stringify(updatedData));
183
+
184
+ // Return the updated data to set the state
185
+ return updatedData;
186
+ });
176
187
  } else {
177
188
  props.setStepMappingData({
178
189
  stepId,
@@ -38,7 +38,7 @@ export type DynamicFieldsProps = {
38
38
  isDisabled?: boolean;
39
39
  onChangeCallback?: (val: any) => void;
40
40
  dependsOn?: string[];
41
- isArray?: boolean; // New prop to determine if the output should be an array
41
+ isArray?: boolean;
42
42
  } & StoreType;
43
43
 
44
44
  interface DynamicDataItem {
@@ -69,16 +69,37 @@ const DynamicTypedFields = (props: DynamicFieldsProps) => {
69
69
  isDisabled = false,
70
70
  onChangeCallback = () => null,
71
71
  dependsOn = [],
72
- isArray = false, // Default to false for backward compatibility
72
+ isArray = false,
73
73
  } = props;
74
+
74
75
  const [dynamicItems, setDynamicItems] = useState<DynamicDataItem[]>([]);
75
76
  const [loading, setLoading] = useState<boolean>(true);
77
+
78
+ // For array mode, we'll track multiple sets of field data
79
+ const [fieldSets, setFieldSets] = useState<any[]>(() => {
80
+ if (value) {
81
+ const parsedValue = typeof value === 'string' ? JSON.parse(value) : value;
82
+
83
+ if (isArray) {
84
+ // If it's already an array, use it
85
+ if (Array.isArray(parsedValue)) {
86
+ return parsedValue;
87
+ }
88
+ // If it's an object, wrap it in an array
89
+ return [parsedValue];
90
+ }
91
+
92
+ // For non-array mode, we still initialize with a single object
93
+ return [parsedValue];
94
+ }
95
+ return [{}]; // Start with one empty object
96
+ });
97
+
98
+ // For backward compatibility, maintain customFieldsData for the first set
76
99
  const [customFieldsData, setCustomFieldsData] = useState<any>(() => {
77
- // Initialize from value prop if available
78
100
  if (value) {
79
101
  const parsedValue = typeof value === 'string' ? JSON.parse(value) : value;
80
102
 
81
- // If isArray is true and the value is an array, extract the first object
82
103
  if (isArray && Array.isArray(parsedValue) && parsedValue.length > 0) {
83
104
  return parsedValue[0];
84
105
  }
@@ -87,6 +108,7 @@ const DynamicTypedFields = (props: DynamicFieldsProps) => {
87
108
  }
88
109
  return {};
89
110
  });
111
+
90
112
  const [
91
113
  isErrorOnLoadingCustomFields,
92
114
  setIsErrorOnLoadingCustomFields,
@@ -135,13 +157,13 @@ const DynamicTypedFields = (props: DynamicFieldsProps) => {
135
157
  if (Array.isArray(res)) {
136
158
  transformedItems = res;
137
159
  } else if (res.output && Array.isArray(res.output)) {
138
- const { idKeyPath, titleKeyPath, typeKeyPath } = props; // Assuming these are passed as part of dynamicField prop
160
+ const { idKeyPath, titleKeyPath, typeKeyPath } = props;
139
161
 
140
162
  if (idKeyPath && titleKeyPath) {
141
163
  transformedItems = res.output.map((item: any) => ({
142
- id: resolveValue(idKeyPath, item), // Use idKeyPath to access the ID
143
- title: resolveValue(titleKeyPath, item), // Use titleKeyPath to access the title
144
- type: 'TEXTFIELD', // Use typeKeyPath to access the type
164
+ id: resolveValue(idKeyPath, item),
165
+ title: resolveValue(titleKeyPath, item),
166
+ type: 'TEXTFIELD',
145
167
  }));
146
168
  } else {
147
169
  setDynamicItems([]);
@@ -164,9 +186,8 @@ const DynamicTypedFields = (props: DynamicFieldsProps) => {
164
186
  }
165
187
  };
166
188
 
167
- // Split the effects - one for fetching fields, one for handling value changes
189
+ // Effect for fetching fields
168
190
  useEffect(() => {
169
- // Only fetch fields on initial mount or when parentFieldsChanged changes
170
191
  if (dependsOn.length > 0 && !parentFieldsChanged) {
171
192
  setLoading(false);
172
193
  setIsErrorOnLoadingCustomFields(false);
@@ -176,51 +197,115 @@ const DynamicTypedFields = (props: DynamicFieldsProps) => {
176
197
  fetchDynamicFields();
177
198
  fieldsHaveBeenFetched.current = true;
178
199
  }
179
- }, [parentFieldsChanged]); // Remove value from dependencies
200
+ }, [parentFieldsChanged]);
180
201
 
181
- // Separate effect for handling external value changes
202
+ // Effect for handling external value changes
182
203
  useEffect(() => {
183
- // Only update from props if the value is different from current state
184
- // AND it's not coming from our own onChange (which would cause a loop)
185
204
  if (value && !loading) {
186
- let parsedValue = typeof value === 'string' ? JSON.parse(value) : value;
205
+ const parsedValue = typeof value === 'string' ? JSON.parse(value) : value;
187
206
 
188
- // If isArray is true and the value is an array, extract the first object for internal state
189
- if (isArray && Array.isArray(parsedValue) && parsedValue.length > 0) {
190
- [parsedValue] = parsedValue;
191
- }
207
+ if (isArray) {
208
+ // Handle array values
209
+ const newFieldSets = Array.isArray(parsedValue)
210
+ ? parsedValue
211
+ : [parsedValue];
192
212
 
193
- // Compare if the value is actually different to avoid unnecessary updates
194
- const currentValueStr = JSON.stringify(customFieldsData);
195
- const newValueStr = JSON.stringify(parsedValue);
213
+ // Update fieldSets
214
+ setFieldSets(newFieldSets);
196
215
 
197
- if (currentValueStr !== newValueStr) {
216
+ // Update customFieldsData with the first item for backward compatibility
217
+ if (newFieldSets.length > 0) {
218
+ setCustomFieldsData(newFieldSets[0]);
219
+ }
220
+ } else {
221
+ // Handle single object value
198
222
  setCustomFieldsData(parsedValue);
223
+ setFieldSets([parsedValue]);
199
224
  }
200
225
  }
201
226
  }, [value, loading, isArray]);
202
227
 
203
- // Modify the onFieldChange function to handle array output if isArray is true
204
- const onFieldChange = (id: string, val: string, type: string) => {
205
- // Update local state immediately
206
- setCustomFieldsData((prevData: any) => {
207
- const newData = {
208
- ...prevData,
209
- [id]: val,
228
+ // Function to add a new empty set of fields
229
+ const addNewFieldSet = () => {
230
+ setFieldSets((prev) => {
231
+ const newFieldSets = [...prev, {}];
232
+
233
+ // Call parent callbacks with the updated array
234
+ if (onChange) {
235
+ onChange(newFieldSets);
236
+ }
237
+ if (onChangeCallback) {
238
+ onChangeCallback(JSON.stringify(newFieldSets));
239
+ }
240
+
241
+ return newFieldSets;
242
+ });
243
+ };
244
+
245
+ // Function to remove a field set
246
+ const removeFieldSet = (index: number) => {
247
+ if (fieldSets.length <= 1) return; // Don't remove the last set
248
+
249
+ setFieldSets((prev) => {
250
+ const newFieldSets = prev.filter((_, i) => i !== index);
251
+
252
+ // Update customFieldsData if we're removing the first set
253
+ if (index === 0 && newFieldSets.length > 0) {
254
+ setCustomFieldsData(newFieldSets[0]);
255
+ }
256
+
257
+ // Call parent callbacks with the updated array
258
+ if (onChange) {
259
+ onChange(newFieldSets);
260
+ }
261
+ if (onChangeCallback) {
262
+ onChangeCallback(JSON.stringify(newFieldSets));
263
+ }
264
+
265
+ return newFieldSets;
266
+ });
267
+ };
268
+
269
+ // Function to update a specific field in a specific set
270
+ const onFieldSetChange = (
271
+ setIndex: number,
272
+ fieldId: string,
273
+ val: string,
274
+ type: string,
275
+ ) => {
276
+ setFieldSets((prev) => {
277
+ const newFieldSets = [...prev];
278
+
279
+ // Create or update the field in the specified set
280
+ newFieldSets[setIndex] = {
281
+ ...newFieldSets[setIndex],
282
+ [fieldId]: val,
210
283
  };
211
284
 
212
- // Call parent callbacks with the new data, wrapping in array if isArray is true
285
+ // If this is the first set, also update customFieldsData for backward compatibility
286
+ if (setIndex === 0) {
287
+ setCustomFieldsData(newFieldSets[0]);
288
+ }
289
+
290
+ // Call parent callbacks with the updated array
213
291
  if (onChange) {
214
- onChange(isArray ? [newData] : newData);
292
+ onChange(isArray ? newFieldSets : newFieldSets[0]);
215
293
  }
216
294
  if (onChangeCallback) {
217
- onChangeCallback(JSON.stringify(isArray ? [newData] : newData));
295
+ onChangeCallback(
296
+ JSON.stringify(isArray ? newFieldSets : newFieldSets[0]),
297
+ );
218
298
  }
219
299
 
220
- return newData;
300
+ return newFieldSets;
221
301
  });
222
302
  };
223
303
 
304
+ // For backward compatibility, maintain the original onFieldChange function
305
+ const onFieldChange = (id: string, val: string, type: string) => {
306
+ onFieldSetChange(0, id, val, type);
307
+ };
308
+
224
309
  return html`
225
310
  <div>
226
311
  ${loading
@@ -231,31 +316,111 @@ const DynamicTypedFields = (props: DynamicFieldsProps) => {
231
316
  Loading custom fields...
232
317
  </div> `
233
318
  : html`
234
- ${dynamicItems.map(
235
- (el) => html`
236
- <div class=${styles.dynamicTypedFieldWrapper} key=${el.id}>
237
- <${MultipurposeField}
238
- id="${el.id}"
239
- title="${el.title}"
240
- placeholder="${dynamicField.placeholder}"
241
- isRequired="${dynamicField.is_required}"
242
- isEditable="${dynamicField.is_editable}"
243
- fieldId=${el.id}
244
- onChange=${(val: any) => {
245
- onFieldChange(el.id, val, el.type || 'string');
246
- }}
247
- value=${customFieldsData[el.id] || ''}
248
- activityOutputData=${activityOutputData}
249
- activityOutputDataRaw=${activityOutputDataRaw}
250
- type=${el.type || 'TEXTFIELD'}
251
- isMappable=${Object.entries(activityOutputData || {})
252
- .length > 0}
253
- allowTagsInText=${true}
254
- isDisabled=${isDisabled}
255
- ><//>
256
- </div>
257
- `,
258
- )}
319
+ ${isArray
320
+ ? dynamicItems.length > 0 &&
321
+ html`
322
+ ${fieldSets.map(
323
+ (fieldSet, setIndex) => html`
324
+ <div
325
+ class=${styles.dynamicTypedFieldSetContainer}
326
+ key=${`fieldset-${setIndex}`}
327
+ >
328
+ <div class=${styles.fieldSetHeader}>
329
+ <h4>${dynamicField.title} ${setIndex + 1}</h4>
330
+ ${setIndex > 0 &&
331
+ html`
332
+ <button
333
+ type="button"
334
+ class=${styles.removeButton}
335
+ onClick=${() => removeFieldSet(setIndex)}
336
+ disabled=${isDisabled}
337
+ >
338
+ Remove
339
+ </button>
340
+ `}
341
+ </div>
342
+ ${dynamicItems.map(
343
+ (el) => html`
344
+ <div
345
+ class=${styles.dynamicTypedFieldWrapper}
346
+ key=${`${setIndex}-${el.id}`}
347
+ >
348
+ <${MultipurposeField}
349
+ id="${`${setIndex}_${el.id}`}"
350
+ title="${el.title}"
351
+ placeholder="${dynamicField.placeholder}"
352
+ isRequired="${dynamicField.is_required}"
353
+ isEditable="${dynamicField.is_editable}"
354
+ fieldId=${`${setIndex}_${el.id}`}
355
+ onChange=${(val: any) => {
356
+ onFieldSetChange(
357
+ setIndex,
358
+ el.id,
359
+ val,
360
+ el.type || 'string',
361
+ );
362
+ }}
363
+ value=${fieldSet[el.id] || ''}
364
+ activityOutputData=${activityOutputData}
365
+ activityOutputDataRaw=${activityOutputDataRaw}
366
+ type=${el.type || 'TEXTFIELD'}
367
+ isMappable=${Object.entries(
368
+ activityOutputData || {},
369
+ ).length > 0}
370
+ allowTagsInText=${true}
371
+ isDisabled=${isDisabled}
372
+ ><//>
373
+ </div>
374
+ `,
375
+ )}
376
+ ${setIndex === fieldSets.length - 1 &&
377
+ html`
378
+ <div class=${styles.addButtonContainer}>
379
+ <button
380
+ type="button"
381
+ class=${styles.addButton}
382
+ onClick=${addNewFieldSet}
383
+ disabled=${isDisabled}
384
+ >
385
+ + Add Another ${dynamicField.title}
386
+ </button>
387
+ </div>
388
+ `}
389
+ </div>
390
+ `,
391
+ )}
392
+ `
393
+ : dynamicItems.length > 0 &&
394
+ html`
395
+ ${dynamicItems.map(
396
+ (el) => html`
397
+ <div
398
+ class=${styles.dynamicTypedFieldWrapper}
399
+ key=${el.id}
400
+ >
401
+ <${MultipurposeField}
402
+ id="${el.id}"
403
+ title="${el.title}"
404
+ placeholder="${dynamicField.placeholder}"
405
+ isRequired="${dynamicField.is_required}"
406
+ isEditable="${dynamicField.is_editable}"
407
+ fieldId=${el.id}
408
+ onChange=${(val: any) => {
409
+ onFieldChange(el.id, val, el.type || 'string');
410
+ }}
411
+ value=${customFieldsData[el.id] || ''}
412
+ activityOutputData=${activityOutputData}
413
+ activityOutputDataRaw=${activityOutputDataRaw}
414
+ type=${el.type || 'TEXTFIELD'}
415
+ isMappable=${Object.entries(activityOutputData || {})
416
+ .length > 0}
417
+ allowTagsInText=${true}
418
+ isDisabled=${isDisabled}
419
+ ><//>
420
+ </div>
421
+ `,
422
+ )}
423
+ `}
259
424
  `}
260
425
  ${!isErrorOnLoadingCustomFields
261
426
  ? ''
@@ -71,3 +71,65 @@ a.optionsRefresh {
71
71
  height: 37px;
72
72
  }
73
73
  }
74
+
75
+ // New styles for field sets
76
+ .dynamicTypedFieldSetContainer {
77
+ margin-bottom: 20px;
78
+ padding: 15px;
79
+ border: 1px solid #e0e0e0;
80
+ border-radius: 4px;
81
+ background-color: #f9f9f9;
82
+
83
+ .fieldSetHeader {
84
+ display: flex;
85
+ justify-content: space-between;
86
+ align-items: center;
87
+ margin-bottom: 10px;
88
+ padding-bottom: 10px;
89
+ border-bottom: 1px solid #e0e0e0;
90
+
91
+ h4 {
92
+ margin: 0;
93
+ font-size: 12px;
94
+ font-weight: 500;
95
+ }
96
+ }
97
+
98
+ .removeButton {
99
+ background-color: #f44336;
100
+ color: white;
101
+ border: none;
102
+ border-radius: 4px;
103
+ padding: 5px 10px;
104
+ cursor: pointer;
105
+ font-size: 12px;
106
+
107
+ &:hover {
108
+ background-color: #d32f2f;
109
+ }
110
+
111
+ &:disabled {
112
+ background-color: #cccccc;
113
+ cursor: not-allowed;
114
+ }
115
+ }
116
+
117
+ .addButtonContainer {
118
+ margin-top: 15px;
119
+ }
120
+
121
+ .addButton {
122
+ background-color: unset;
123
+ color: #007bff;
124
+ border: none;
125
+ border-radius: 4px;
126
+ padding: 8px 16px;
127
+ cursor: pointer;
128
+ font-size: 12px;
129
+
130
+ &:disabled {
131
+ background-color: #cccccc;
132
+ cursor: not-allowed;
133
+ }
134
+ }
135
+ }