@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.
@@ -0,0 +1,749 @@
1
+ import { html } from 'htm/preact';
2
+ import { useState, useRef, useEffect } from 'preact/hooks';
3
+ import { ListBox } from '@/components/MultipurposeField/Dropdown';
4
+ import FunctionForm from '@/features/common/FunctionForm';
5
+ import AuthSelectorV2 from '@/features/common/AuthSelectorV2';
6
+ import { LargeLoader } from '@/components/LargeLoader';
7
+ import { Hint } from '@/components/Tooltip';
8
+ import styles from './styles.module.scss';
9
+
10
+ // Types for our component
11
+ type Authorization = {
12
+ id: number;
13
+ display_name: string;
14
+ };
15
+
16
+ type FunctionFieldProps = {
17
+ onChange: (value: any) => void;
18
+ value?: any;
19
+ label?: string;
20
+ name: string;
21
+ description?: string;
22
+ field: Record<string, any>;
23
+ apiHandler?: any;
24
+ isArray?: boolean; // New prop for array support
25
+ };
26
+
27
+ const FunctionField = (props: FunctionFieldProps) => {
28
+ const { value, label, description, field, isArray = false } = props;
29
+ const [isOpen, setIsOpen] = useState(false);
30
+ const [editingIndex, setEditingIndex] = useState<number | null>(null);
31
+ const [selectedFunction, setSelectedFunction] = useState<string>('');
32
+ const [activeTab, setActiveTab] = useState('authorization');
33
+ const [functionDetails, setFunctionDetails] = useState<any>(null);
34
+ const [loadingFunctionDetails, setLoadingFunctionDetails] = useState<boolean>(
35
+ false,
36
+ );
37
+ const [connectedAccountId, setConnectedAccountId] = useState<number | null>(
38
+ null,
39
+ );
40
+ const [connectedAccounts, setConnectedAccounts] = useState<any>([]);
41
+ const [visibleFields, setVisibleFields] = useState<any>([]);
42
+
43
+ // Modified to support array of values
44
+ const [functionValues, setFunctionValues] = useState<any[]>(() => {
45
+ if (isArray && Array.isArray(value)) {
46
+ return value;
47
+ }
48
+ if (value) {
49
+ return [value];
50
+ }
51
+ return [];
52
+ });
53
+
54
+ const [formHasInvalidFields, setFormHasInvalidFields] = useState<boolean>(
55
+ false,
56
+ );
57
+ const [userFilledData, setUserFilledData] = useState<any>({});
58
+
59
+ const modalRef = useRef<HTMLDivElement | null>(null);
60
+ const FUNCTIONS_LIST_URL = `https://api.integry.io/functions/list/`;
61
+
62
+ // Reset state when opening modal for a new action
63
+ const resetModalState = () => {
64
+ setSelectedFunction('');
65
+ setActiveTab('authorization');
66
+ setFunctionDetails(null);
67
+ setConnectedAccountId(null);
68
+ setUserFilledData({});
69
+ setFormHasInvalidFields(false);
70
+ };
71
+
72
+ // Handle clicking outside the modal to close it
73
+ useEffect(() => {
74
+ function handleClickOutside(event: MouseEvent) {
75
+ if (
76
+ modalRef.current &&
77
+ !modalRef.current.contains(event.target as Node)
78
+ ) {
79
+ setIsOpen(false);
80
+ }
81
+ }
82
+
83
+ if (isOpen) {
84
+ document.addEventListener('mousedown', handleClickOutside);
85
+ }
86
+
87
+ return () => {
88
+ document.removeEventListener('mousedown', handleClickOutside);
89
+ };
90
+ }, [isOpen]);
91
+
92
+ // Open modal for adding a new action
93
+ const handleOpenModal = () => {
94
+ resetModalState();
95
+ setEditingIndex(null);
96
+ setIsOpen(true);
97
+ };
98
+
99
+ const getVisibleFields = (properties: any[]) => {
100
+ const response: any[] = [];
101
+
102
+ Object.entries(properties).forEach(([key, property]) => {
103
+ if (property.meta?.ui?.is_visible) {
104
+ response.push({ key, ...property });
105
+ }
106
+ });
107
+
108
+ return response;
109
+ };
110
+
111
+ const getInvalidFields = (properties: any[]) => {
112
+ const response: any[] = [];
113
+
114
+ Object.entries(properties).forEach(([key, property]) => {
115
+ if (
116
+ property.meta?.ui?.is_visible &&
117
+ property.meta?.is_required &&
118
+ !userFilledData[key]
119
+ ) {
120
+ response.push({ key, ...property });
121
+ }
122
+ });
123
+
124
+ return response;
125
+ };
126
+
127
+ // Open modal for editing an existing action
128
+ const handleEditAction = (index: number) => {
129
+ const actionToEdit = functionValues[index];
130
+ setEditingIndex(index);
131
+ setSelectedFunction(actionToEdit?.json_schema?.function.name || '');
132
+ setUserFilledData(actionToEdit?.default_arguments || {});
133
+
134
+ // Load function details for the selected function
135
+ setLoadingFunctionDetails(true);
136
+ props.apiHandler
137
+ .getFunctionDetails(actionToEdit?.json_schema?.function.name, {})
138
+ .then((response: any) => {
139
+ setFunctionDetails(response);
140
+ setLoadingFunctionDetails(false);
141
+ setConnectedAccounts(response?.meta?.app?.connected_accounts || []);
142
+ setVisibleFields(
143
+ getVisibleFields(response?.parameters?.properties || []),
144
+ );
145
+ setFormHasInvalidFields(
146
+ getInvalidFields(response?.parameters?.properties || []).length > 0,
147
+ );
148
+ setConnectedAccountId(actionToEdit?.meta?.connected_account_id || null);
149
+ setActiveTab('authorization');
150
+ });
151
+
152
+ setIsOpen(true);
153
+ };
154
+
155
+ const handleCloseModal = () => {
156
+ setIsOpen(false);
157
+ };
158
+
159
+ const handleFunctionSelect = (val: any) => {
160
+ setSelectedFunction(val);
161
+ setActiveTab('authorization');
162
+ setLoadingFunctionDetails(true);
163
+ props.apiHandler.getFunctionDetails(val, {}).then((response: any) => {
164
+ setFunctionDetails(response);
165
+ setLoadingFunctionDetails(false);
166
+ setConnectedAccounts(response?.meta?.app?.connected_accounts || []);
167
+ setVisibleFields(
168
+ getVisibleFields(response?.parameters?.properties || []),
169
+ );
170
+ setFormHasInvalidFields(
171
+ getInvalidFields(response?.parameters?.properties || []).length > 0,
172
+ );
173
+ if (response && response.meta?.app?.connected_accounts?.length > 0) {
174
+ setConnectedAccountId(response.meta.app.connected_accounts[0].id);
175
+ } else {
176
+ setConnectedAccountId(null);
177
+ }
178
+ });
179
+ };
180
+
181
+ const removeMeta = (obj: any): any => {
182
+ if (Array.isArray(obj)) {
183
+ return obj.map(removeMeta);
184
+ }
185
+ if (typeof obj === 'object' && obj !== null) {
186
+ const newObj: any = {};
187
+ Object.keys(obj).forEach((key) => {
188
+ if (key !== 'meta') {
189
+ newObj[key] = removeMeta(obj[key]);
190
+ }
191
+ });
192
+ return newObj;
193
+ }
194
+ return obj;
195
+ };
196
+
197
+ // Modified to handle array of values
198
+ const handleSave = () => {
199
+ if (selectedFunction && functionDetails) {
200
+ const schema = {
201
+ json_schema: {
202
+ type: 'function',
203
+ function: removeMeta(functionDetails),
204
+ },
205
+ meta: {
206
+ id: functionDetails.meta.id,
207
+ version: functionDetails.meta.version,
208
+ connected_account_id: connectedAccountId,
209
+ form_page_machine_name: null,
210
+ name: functionDetails.name,
211
+ title: functionDetails.meta.ui.title,
212
+ app_name: functionDetails.meta.app.title,
213
+ app_icon_url: functionDetails.meta.app.icon_url,
214
+ },
215
+ default_arguments: userFilledData,
216
+ parameters_visible_to_user: {},
217
+ };
218
+
219
+ // Update or add the function value
220
+ let updatedValues;
221
+ if (editingIndex !== null) {
222
+ // Update existing action
223
+ updatedValues = [...functionValues];
224
+ updatedValues[editingIndex] = schema;
225
+ } else {
226
+ // Add new action
227
+ updatedValues = [...functionValues, schema];
228
+ }
229
+
230
+ setFunctionValues(updatedValues);
231
+
232
+ // Call onChange with the updated values
233
+ if (props.onChange) {
234
+ props.onChange(isArray ? updatedValues : updatedValues[0]);
235
+ }
236
+
237
+ setIsOpen(false);
238
+ }
239
+ };
240
+
241
+ // Delete a specific action from the array
242
+ const handleDeleteAction = (index: number) => {
243
+ const updatedValues = functionValues.filter((_, i) => i !== index);
244
+ setFunctionValues(updatedValues);
245
+
246
+ // Call onChange with the updated values
247
+ if (props.onChange) {
248
+ props.onChange(isArray ? updatedValues : updatedValues[0] || null);
249
+ }
250
+ };
251
+
252
+ const handleAuthCreated = (auth: Authorization) => {
253
+ setActiveTab('input');
254
+ const existingAuth = connectedAccounts.find(
255
+ (account: Authorization) => account.id === auth.id,
256
+ );
257
+ if (!existingAuth) {
258
+ setConnectedAccounts((prev: Authorization[]) => [...prev, auth]);
259
+ setConnectedAccountId(auth.id);
260
+ }
261
+ };
262
+
263
+ const handleAuthDeleted = (authId: number) => {
264
+ setConnectedAccounts((prev: Authorization[]) =>
265
+ prev.filter((account: Authorization) => account.id !== authId),
266
+ );
267
+ setConnectedAccountId(null);
268
+ };
269
+
270
+ const handleCustomaSave = (customSaveResponse: any) => {
271
+ setFormHasInvalidFields(customSaveResponse.hasInvalidFields);
272
+ setUserFilledData(customSaveResponse.data);
273
+ };
274
+
275
+ const handleNextTab = () => {
276
+ setActiveTab('input');
277
+ };
278
+
279
+ const loadAuthorizationTabContent = () => {
280
+ let content;
281
+
282
+ if (loadingFunctionDetails) {
283
+ content = html`
284
+ <div class=${styles.loader || 'function-field-loader'}>
285
+ <${LargeLoader} />
286
+ </div>
287
+ `;
288
+ } else if (functionDetails) {
289
+ const selectedAuthId =
290
+ connectedAccountId ||
291
+ (functionDetails.meta.app.connected_accounts.length > 0
292
+ ? functionDetails.meta.app.connected_accounts[0]?.id
293
+ : null);
294
+
295
+ content = html`
296
+ <${AuthSelectorV2}
297
+ authorizations=${connectedAccounts}
298
+ appName=${functionDetails.meta.app.title}
299
+ apiHandler=${props.apiHandler}
300
+ onAuthSelected=${(authId: number) => {
301
+ setConnectedAccountId(authId);
302
+ }}
303
+ onAuthCreated=${handleAuthCreated}
304
+ onAuthDeleted=${handleAuthDeleted}
305
+ selectedAuthId=${selectedAuthId}
306
+ loginUrl=${functionDetails.meta.app.login_url}
307
+ />
308
+ `;
309
+ }
310
+
311
+ return content;
312
+ };
313
+
314
+ return html`
315
+ <div class=${styles.functionFieldContainer || 'function-field-container'}>
316
+ ${label
317
+ ? html`
318
+ <label class=${styles.functionFieldLabel || 'function-field-label'}>
319
+ ${label}
320
+ ${description
321
+ ? html`
322
+ <div
323
+ class=${styles.functionFieldDescription ||
324
+ 'function-field-description'}
325
+ >
326
+ ${description}
327
+ </div>
328
+ `
329
+ : null}
330
+ </label>
331
+ `
332
+ : null}
333
+ ${isArray && functionValues.length > 0
334
+ ? html`
335
+ <div class=${styles.functionFieldArray || 'function-field-array'}>
336
+ ${functionValues.map(
337
+ (functionValue, index) => html`
338
+ <div
339
+ key=${index}
340
+ class=${styles.functionFieldSummary ||
341
+ 'function-field-summary'}
342
+ style="margin-bottom: 8px;"
343
+ >
344
+ <div
345
+ class=${styles.functionFieldSelected ||
346
+ 'function-field-selected'}
347
+ >
348
+ <div
349
+ class=${styles.functionFieldInfo ||
350
+ 'function-field-info'}
351
+ >
352
+ <img
353
+ src=${functionValue?.meta?.app_icon_url}
354
+ alt=${functionValue.meta?.app_name || 'App'}
355
+ class=${styles.functionFieldAppIcon ||
356
+ 'function-field-app-icon'}
357
+ />
358
+ <div
359
+ class=${styles.functionFieldNameContainer ||
360
+ 'function-field-name-container'}
361
+ >
362
+ <span
363
+ class=${styles.functionFieldName ||
364
+ 'function-field-name'}
365
+ >
366
+ ${functionValue.meta?.title || 'Function'}
367
+ </span>
368
+ <span
369
+ class=${styles.functionFieldAppName ||
370
+ 'function-field-app-name'}
371
+ >
372
+ ${functionValue.meta?.name || ''}
373
+ </span>
374
+ </div>
375
+ </div>
376
+ <div
377
+ class=${styles.functionFieldActions ||
378
+ 'function-field-actions'}
379
+ >
380
+ <button
381
+ type="button"
382
+ class=${styles.functionFieldDeleteBtn ||
383
+ 'function-field-delete-btn'}
384
+ onClick=${(e: any) => {
385
+ e.stopPropagation();
386
+ handleDeleteAction(index);
387
+ }}
388
+ aria-label="Delete"
389
+ >
390
+ <svg
391
+ width="16"
392
+ height="16"
393
+ viewBox="0 0 24 24"
394
+ fill="none"
395
+ xmlns="http://www.w3.org/2000/svg"
396
+ >
397
+ <path
398
+ d="M3 6H5H21"
399
+ stroke="currentColor"
400
+ stroke-width="2"
401
+ stroke-linecap="round"
402
+ stroke-linejoin="round"
403
+ />
404
+ <path
405
+ d="M8 6V4C8 3.46957 8.21071 2.96086 8.58579 2.58579C8.96086 2.21071 9.46957 2 10 2H14C14.5304 2 15.0391 2.21071 15.4142 2.58579C15.7893 2.96086 16 3.46957 16 4V6M19 6V20C19 20.5304 18.7893 21.0391 18.4142 21.4142C18.0391 21.7893 17.5304 22 17 22H7C6.46957 22 5.96086 21.7893 5.58579 21.4142C5.21071 21.0391 5 20.5304 5 20V6H19Z"
406
+ stroke="currentColor"
407
+ stroke-width="2"
408
+ stroke-linecap="round"
409
+ stroke-linejoin="round"
410
+ />
411
+ </svg>
412
+ </button>
413
+ <button
414
+ type="button"
415
+ class=${styles.functionFieldEditBtn ||
416
+ 'function-field-edit-btn'}
417
+ onClick=${() => handleEditAction(index)}
418
+ >
419
+ Edit
420
+ </button>
421
+ </div>
422
+ </div>
423
+ </div>
424
+ `,
425
+ )}
426
+ </div>
427
+ `
428
+ : null}
429
+ ${!isArray && functionValues.length > 0
430
+ ? html`
431
+ <div
432
+ class=${styles.functionFieldSummary || 'function-field-summary'}
433
+ >
434
+ <div
435
+ class=${styles.functionFieldSelected ||
436
+ 'function-field-selected'}
437
+ >
438
+ <div class=${styles.functionFieldInfo || 'function-field-info'}>
439
+ <img
440
+ src=${functionValues[0]?.meta?.app_icon_url}
441
+ alt=${functionValues[0].meta?.app_name || 'App'}
442
+ class=${styles.functionFieldAppIcon ||
443
+ 'function-field-app-icon'}
444
+ />
445
+ <div
446
+ class=${styles.functionFieldNameContainer ||
447
+ 'function-field-name-container'}
448
+ >
449
+ <span
450
+ class=${styles.functionFieldName || 'function-field-name'}
451
+ >
452
+ ${functionValues[0].meta?.title || 'Function'}
453
+ </span>
454
+ <span
455
+ class=${styles.functionFieldAppName ||
456
+ 'function-field-app-name'}
457
+ >
458
+ ${functionValues[0].meta?.name || ''}
459
+ </span>
460
+ </div>
461
+ </div>
462
+ <div
463
+ class=${styles.functionFieldActions ||
464
+ 'function-field-actions'}
465
+ >
466
+ <button
467
+ type="button"
468
+ class=${styles.functionFieldDeleteBtn ||
469
+ 'function-field-delete-btn'}
470
+ onClick=${(e: any) => {
471
+ e.stopPropagation();
472
+ handleDeleteAction(0);
473
+ }}
474
+ aria-label="Delete"
475
+ >
476
+ <svg
477
+ width="16"
478
+ height="16"
479
+ viewBox="0 0 24 24"
480
+ fill="none"
481
+ xmlns="http://www.w3.org/2000/svg"
482
+ >
483
+ <path
484
+ d="M3 6H5H21"
485
+ stroke="currentColor"
486
+ stroke-width="2"
487
+ stroke-linecap="round"
488
+ stroke-linejoin="round"
489
+ />
490
+ <path
491
+ d="M8 6V4C8 3.46957 8.21071 2.96086 8.58579 2.58579C8.96086 2.21071 9.46957 2 10 2H14C14.5304 2 15.0391 2.21071 15.4142 2.58579C15.7893 2.96086 16 3.46957 16 4V6M19 6V20C19 20.5304 18.7893 21.0391 18.4142 21.4142C18.0391 21.7893 17.5304 22 17 22H7C6.46957 22 5.96086 21.7893 5.58579 21.4142C5.21071 21.0391 5 20.5304 5 20V6H19Z"
492
+ stroke="currentColor"
493
+ stroke-width="2"
494
+ stroke-linecap="round"
495
+ stroke-linejoin="round"
496
+ />
497
+ </svg>
498
+ </button>
499
+ <button
500
+ type="button"
501
+ class=${styles.functionFieldEditBtn ||
502
+ 'function-field-edit-btn'}
503
+ onClick=${() => handleEditAction(0)}
504
+ >
505
+ Edit
506
+ </button>
507
+ </div>
508
+ </div>
509
+ </div>
510
+ `
511
+ : null}
512
+ ${isArray || functionValues.length === 0
513
+ ? html`
514
+ <div
515
+ class=${styles.functionFieldActions || 'function-field-actions'}
516
+ style="margin-top: ${functionValues.length > 0 ? '8px' : '0'}"
517
+ >
518
+ <button
519
+ type="button"
520
+ class=${styles.functionFieldAddBtn || 'function-field-add-btn'}
521
+ onClick=${handleOpenModal}
522
+ >
523
+ ${isArray && functionValues.length > 0
524
+ ? 'Add another'
525
+ : 'Add action'}
526
+ </button>
527
+ </div>
528
+ `
529
+ : null}
530
+ ${isOpen
531
+ ? html`
532
+ <div
533
+ class=${styles.functionFieldOverlay || 'function-field-overlay'}
534
+ >
535
+ <div
536
+ class=${styles.functionFieldModal || 'function-field-modal'}
537
+ ref=${modalRef}
538
+ >
539
+ <div
540
+ class=${styles.functionFieldModalHeader ||
541
+ 'function-field-modal-header'}
542
+ >
543
+ <h3
544
+ class=${styles.functionFieldModalTitle ||
545
+ 'function-field-modal-title'}
546
+ >
547
+ ${editingIndex !== null ? 'Edit action' : 'Add action'}
548
+ </h3>
549
+ <p
550
+ class=${styles.functionFieldModalDescription ||
551
+ 'function-field-modal-description'}
552
+ >
553
+ The AI will use this action
554
+ </p>
555
+ <button
556
+ type="button"
557
+ class=${styles.functionFieldCloseBtn ||
558
+ 'function-field-close-btn'}
559
+ onClick=${handleCloseModal}
560
+ >
561
+ ×
562
+ </button>
563
+ </div>
564
+
565
+ <div
566
+ class=${styles.functionFieldModalBody ||
567
+ 'function-field-modal-body'}
568
+ >
569
+ <div
570
+ class=${styles.functionFieldInlineGroup ||
571
+ 'function-field-inline-group'}
572
+ >
573
+ <${ListBox}
574
+ key=${field.activity_field?.id}
575
+ fieldId=${field.activity_field?.id ||
576
+ field.id ||
577
+ field?.activity_field?.machine_name}
578
+ title=${`Action`}
579
+ placeholder=${`Select an action to use`}
580
+ isRequired=${true}
581
+ isHidden=${false}
582
+ isSearchable=${true}
583
+ value=${selectedFunction}
584
+ onChange=${handleFunctionSelect}
585
+ isDynamic=${true}
586
+ endpointUrl=${FUNCTIONS_LIST_URL}
587
+ endpointData=${`{"include": "meta"}`}
588
+ apiHandler=${props.apiHandler}
589
+ optionKeyPath=${`name`}
590
+ valueKeyPath=${`meta.ui.title`}
591
+ enableServerSideSearch=${true}
592
+ serverSideSearchParamName=${`search`}
593
+ iconKeyPath=${`meta.app.icon_url`}
594
+ optionDescriptionKeyPath=${`description`}
595
+ />
596
+ </div>
597
+
598
+ ${selectedFunction
599
+ ? html`
600
+ <div class=${
601
+ styles.functionFieldConfig || 'function-field-config'
602
+ }>
603
+ <div class=${
604
+ styles.functionFieldTabs || 'function-field-tabs'
605
+ }>
606
+ <button
607
+ type="button"
608
+ class=${`${
609
+ styles.functionFieldTab || 'function-field-tab'
610
+ } ${
611
+ activeTab === 'authorization'
612
+ ? styles.functionFieldTabActive ||
613
+ 'function-field-tab-active'
614
+ : ''
615
+ }`}
616
+ onClick=${() => setActiveTab('authorization')}
617
+ >
618
+ Authorization
619
+ </button>
620
+ <${Hint} dismissOnClick=${false} position="top" deltaY=${0}>
621
+ <button
622
+ data-hint=${
623
+ connectedAccountId
624
+ ? ''
625
+ : `Please connect your account to proceed.`
626
+ }
627
+ type="button"
628
+ class=${`${
629
+ styles.functionFieldTab || 'function-field-tab'
630
+ } ${
631
+ activeTab === 'input'
632
+ ? styles.functionFieldTabActive ||
633
+ 'function-field-tab-active'
634
+ : ''
635
+ } ${connectedAccountId ? '' : styles.disabled}`}
636
+ onClick=${() => {
637
+ if (connectedAccountId) {
638
+ setActiveTab('input');
639
+ }
640
+ }}
641
+ >
642
+ Input
643
+ ${
644
+ visibleFields.length > 0
645
+ ? ` (${visibleFields.length})`
646
+ : ''
647
+ }
648
+ </button>
649
+ </${Hint}>
650
+ </div>
651
+
652
+ <div class=${
653
+ styles.functionFieldTabContent ||
654
+ 'function-field-tab-content'
655
+ }>
656
+ ${
657
+ activeTab === 'authorization'
658
+ ? html`
659
+ <div
660
+ class=${styles.functionFieldAuthContent ||
661
+ 'function-field-auth-content'}
662
+ >
663
+ ${html`${loadAuthorizationTabContent()}`}
664
+ </div>
665
+ `
666
+ : html`
667
+ <div
668
+ class=${styles.functionFieldInputContent ||
669
+ 'function-field-input-content'}
670
+ >
671
+ <${FunctionForm}
672
+ functionName=${selectedFunction}
673
+ apiHandler=${props.apiHandler}
674
+ functionArguments=${userFilledData}
675
+ connectedAccountId=${connectedAccountId}
676
+ customSaveCallback=${handleCustomaSave}
677
+ />
678
+ </div>
679
+ `
680
+ }
681
+ </div>
682
+ </div>
683
+ `
684
+ : null}
685
+ </div>
686
+
687
+ ${activeTab === 'input'
688
+ ? html`
689
+ <div
690
+ class=${styles.functionFieldModalFooter ||
691
+ 'function-field-modal-footer'}
692
+ >
693
+ <button
694
+ type="button"
695
+ class=${styles.functionFieldCancelBtn ||
696
+ 'function-field-cancel-btn'}
697
+ onClick=${handleCloseModal}
698
+ >
699
+ Cancel
700
+ </button>
701
+ <button
702
+ type="button"
703
+ class=${styles.functionFieldSaveBtn ||
704
+ 'function-field-save-btn'}
705
+ onClick=${handleSave}
706
+ disabled=${!selectedFunction ||
707
+ formHasInvalidFields ||
708
+ !connectedAccountId}
709
+ >
710
+ Save
711
+ </button>
712
+ </div>
713
+ `
714
+ : null}
715
+ ${activeTab === 'authorization' && selectedFunction
716
+ ? html`
717
+ <div
718
+ class=${styles.functionFieldModalFooter ||
719
+ 'function-field-modal-footer'}
720
+ >
721
+ <button
722
+ type="button"
723
+ class=${styles.functionFieldCancelBtn ||
724
+ 'function-field-cancel-btn'}
725
+ onClick=${handleCloseModal}
726
+ >
727
+ Cancel
728
+ </button>
729
+ <button
730
+ type="button"
731
+ class=${styles.functionFieldSaveBtn ||
732
+ 'function-field-save-btn'}
733
+ onClick=${handleNextTab}
734
+ disabled=${!selectedFunction || !connectedAccountId}
735
+ >
736
+ Next
737
+ </button>
738
+ </div>
739
+ `
740
+ : null}
741
+ </div>
742
+ </div>
743
+ `
744
+ : null}
745
+ </div>
746
+ `;
747
+ };
748
+
749
+ export { FunctionField, FunctionFieldProps };