@evoke-platform/ui-components 1.10.1-dev.1 → 1.10.1-dev.3
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/dist/published/components/custom/FormField/Select/Select.js +23 -4
- package/dist/published/components/custom/FormV2/FormRenderer.d.ts +2 -2
- package/dist/published/components/custom/FormV2/FormRenderer.js +7 -1
- package/dist/published/components/custom/FormV2/FormRendererContainer.d.ts +2 -2
- package/dist/published/components/custom/FormV2/components/FormContext.d.ts +2 -2
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/ActionDialog.d.ts +2 -2
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/RepeatableField.js +12 -4
- package/dist/published/components/custom/FormV2/components/utils.d.ts +4 -1
- package/dist/published/components/custom/FormV2/components/utils.js +4 -1
- package/dist/published/components/custom/FormV2/tests/FormRendererContainer.test.js +480 -15
- package/dist/published/components/custom/FormV2/tests/test-data.js +20 -0
- package/dist/published/stories/FormRenderer.stories.d.ts +8 -8
- package/dist/published/stories/FormRendererContainer.stories.d.ts +12 -12
- package/dist/published/theme/hooks.d.ts +3 -3
- package/package.json +1 -1
|
@@ -2,12 +2,14 @@ import { createFilterOptions, List, ListSubheader } from '@mui/material';
|
|
|
2
2
|
import { uniq } from 'lodash';
|
|
3
3
|
import React, { forwardRef, useEffect, useRef, useState } from 'react';
|
|
4
4
|
import { Clear } from '../../../../icons';
|
|
5
|
+
import { useFormContext } from '../../../../theme/hooks';
|
|
5
6
|
import { Autocomplete, FormControl, FormControlLabel, IconButton, Radio, RadioGroup, TextField, Typography, } from '../../../core';
|
|
6
7
|
import { Box } from '../../../layout';
|
|
7
8
|
import InputFieldComponent from '../InputFieldComponent/InputFieldComponent';
|
|
8
9
|
const filter = createFilterOptions();
|
|
9
10
|
const Select = (props) => {
|
|
10
11
|
const { id, property, defaultValue, error, errorMessage, onBlur, onChange, readOnly, isCombobox, selectOptions, required, size, isOptionEqualToValue, renderOption, getOptionLabel, disableCloseOnSelect, additionalProps, displayOption, sortBy, } = props;
|
|
12
|
+
const { onAutosave } = useFormContext();
|
|
11
13
|
const otherInputRef = useRef(null);
|
|
12
14
|
const [isOther, setIsOther] = useState(!!isCombobox &&
|
|
13
15
|
!!defaultValue &&
|
|
@@ -32,7 +34,7 @@ const Select = (props) => {
|
|
|
32
34
|
setValue(defaultValue);
|
|
33
35
|
}, [defaultValue]);
|
|
34
36
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
|
-
const handleChange = (event, selected) => {
|
|
37
|
+
const handleChange = async (event, selected) => {
|
|
36
38
|
if (Array.isArray(selected)) {
|
|
37
39
|
const newValues = selected.map((option) => option.value ?? option);
|
|
38
40
|
setValue(uniq(newValues));
|
|
@@ -56,6 +58,12 @@ const Select = (props) => {
|
|
|
56
58
|
onChange && onChange(property.id, selected, property);
|
|
57
59
|
}
|
|
58
60
|
}
|
|
61
|
+
try {
|
|
62
|
+
await onAutosave?.(id);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
console.error('Autosave failed:', error);
|
|
66
|
+
}
|
|
59
67
|
};
|
|
60
68
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
61
69
|
const handleInputValueChange = (event, selectValue) => {
|
|
@@ -121,22 +129,29 @@ const Select = (props) => {
|
|
|
121
129
|
}
|
|
122
130
|
setIsOtherFocused(false);
|
|
123
131
|
} })))))),
|
|
124
|
-
|
|
132
|
+
onChange && !readOnly && value && (React.createElement(Box, { sx: {
|
|
125
133
|
':hover': { cursor: 'pointer' },
|
|
126
134
|
marginTop: '4px',
|
|
127
135
|
display: 'flex',
|
|
128
136
|
alignItems: 'center',
|
|
129
137
|
} },
|
|
130
|
-
React.createElement(IconButton, { "aria-label": `Clear`, onClick: () => {
|
|
138
|
+
React.createElement(IconButton, { "aria-label": `Clear`, onClick: async () => {
|
|
131
139
|
setValue('');
|
|
132
140
|
property && onChange(property.id, '');
|
|
133
141
|
setIsOther(false);
|
|
142
|
+
// Trigger autosave immediately when clearing radio selection
|
|
143
|
+
try {
|
|
144
|
+
await onAutosave?.(id);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.error('Autosave failed:', error);
|
|
148
|
+
}
|
|
134
149
|
}, sx: { padding: '3px', marginRight: '6px' } },
|
|
135
150
|
React.createElement(Clear, { sx: {
|
|
136
151
|
color: '#637381',
|
|
137
152
|
fontSize: '1.2rem',
|
|
138
153
|
} })),
|
|
139
|
-
React.createElement(Typography, { variant: "caption" }, "Clear Selection"))))) : (React.createElement(Autocomplete, { multiple: property?.type === 'array'
|
|
154
|
+
React.createElement(Typography, { variant: "caption" }, "Clear Selection"))))) : (React.createElement(Autocomplete, { multiple: property?.type === 'array', id: id, sortBy: sortBy, renderInput: (params) => (React.createElement(TextField, { ...params, value: value, fullWidth: true, onBlur: onBlur, inputProps: {
|
|
140
155
|
...params.inputProps,
|
|
141
156
|
'aria-describedby': isCombobox ? `${id}-instructions` : undefined,
|
|
142
157
|
} })), value: value ?? (property?.type === 'array' ? [] : undefined), onChange: handleChange, options: selectOptions ?? property?.enum ?? [], inputValue: inputValue ?? '', error: error, errorMessage: errorMessage, required: required, onInputChange: handleInputValueChange, size: size, filterOptions: (options, params) => {
|
|
@@ -169,6 +184,10 @@ const Select = (props) => {
|
|
|
169
184
|
'& button.MuiButtonBase-root': {
|
|
170
185
|
visibility: 'visible',
|
|
171
186
|
},
|
|
187
|
+
}, slotProps: {
|
|
188
|
+
clearIndicator: {
|
|
189
|
+
'data-testid': 'autocomplete-clear-button',
|
|
190
|
+
},
|
|
172
191
|
}, forcePopupIcon: true, ...(isCombobox ? { selectOnFocus: true, handleHomeEndKeys: true, freeSolo: true } : {}), ...(additionalProps ?? {}) }));
|
|
173
192
|
};
|
|
174
193
|
export default Select;
|
|
@@ -19,8 +19,8 @@ export type FormRendererProps = BaseProps & {
|
|
|
19
19
|
onChange: (id: string, value: unknown) => void | Promise<void>;
|
|
20
20
|
onAutosave?: (fieldId: string) => void | Promise<void>;
|
|
21
21
|
associatedObject?: {
|
|
22
|
-
instanceId
|
|
23
|
-
propertyId
|
|
22
|
+
instanceId: string;
|
|
23
|
+
propertyId: string;
|
|
24
24
|
};
|
|
25
25
|
renderHeader?: (props: HeaderProps) => React.ReactNode;
|
|
26
26
|
renderBody?: (props: BodyProps) => React.ReactNode;
|
|
@@ -171,7 +171,13 @@ const FormRendererInternal = (props) => {
|
|
|
171
171
|
async function unregisterHiddenFieldsAndSubmit() {
|
|
172
172
|
unregisterHiddenFields(entries ?? []);
|
|
173
173
|
removeUneditedProtectedValues();
|
|
174
|
-
await handleSubmit((data) =>
|
|
174
|
+
await handleSubmit((data) => {
|
|
175
|
+
if (onSubmit) {
|
|
176
|
+
onSubmit(action?.type === 'delete' ? {} : data);
|
|
177
|
+
// clear fetched options after successful submit to allow re-evaluation with the new instance data
|
|
178
|
+
setFetchedOptions({});
|
|
179
|
+
}
|
|
180
|
+
}, (errors) => onSubmitError(errors))();
|
|
175
181
|
}
|
|
176
182
|
const headerProps = {
|
|
177
183
|
title,
|
|
@@ -30,8 +30,8 @@ export type FormRendererContainerProps = BaseProps & {
|
|
|
30
30
|
onDiscardChanges?: FormRendererProps['onDiscardChanges'];
|
|
31
31
|
onSubmitError?: FormRendererProps['onSubmitError'];
|
|
32
32
|
associatedObject?: {
|
|
33
|
-
instanceId
|
|
34
|
-
propertyId
|
|
33
|
+
instanceId: string;
|
|
34
|
+
propertyId: string;
|
|
35
35
|
};
|
|
36
36
|
renderContainer?: (state: FormRendererState) => React.ReactNode;
|
|
37
37
|
renderHeader?: FormRendererProps['renderHeader'];
|
|
@@ -11,8 +11,8 @@ export type ActionDialogProps = {
|
|
|
11
11
|
relatedParameter: InputParameter;
|
|
12
12
|
relatedFormId?: string;
|
|
13
13
|
associatedObject?: {
|
|
14
|
-
instanceId
|
|
15
|
-
propertyId
|
|
14
|
+
instanceId: string;
|
|
15
|
+
propertyId: string;
|
|
16
16
|
};
|
|
17
17
|
};
|
|
18
18
|
export declare const ActionDialog: (props: ActionDialogProps) => React.JSX.Element;
|
|
@@ -249,8 +249,10 @@ const RepeatableField = (props) => {
|
|
|
249
249
|
};
|
|
250
250
|
}
|
|
251
251
|
};
|
|
252
|
-
const checkCreateAccess = (relatedObject) => {
|
|
253
|
-
if (fieldDefinition.objectId &&
|
|
252
|
+
const checkCreateAccess = useCallback((relatedObject) => {
|
|
253
|
+
if (fieldDefinition.objectId &&
|
|
254
|
+
canUpdateProperty &&
|
|
255
|
+
!fetchedOptions[`${fieldDefinition.id}HasCreateAction`]) {
|
|
254
256
|
apiServices
|
|
255
257
|
.get(getPrefixedUrl(`/objects/${fieldDefinition.objectId}/instances/checkAccess`), {
|
|
256
258
|
params: { action: 'execute', field: entry.display?.createActionId, scope: 'data' },
|
|
@@ -272,7 +274,11 @@ const RepeatableField = (props) => {
|
|
|
272
274
|
}
|
|
273
275
|
});
|
|
274
276
|
}
|
|
275
|
-
};
|
|
277
|
+
}, [fieldDefinition, canUpdateProperty, fetchedOptions, entry.display?.createActionId, instance, apiServices]);
|
|
278
|
+
useEffect(() => {
|
|
279
|
+
// Re-check create access when instance changes to re-evaluate the criteria
|
|
280
|
+
relatedObject && checkCreateAccess(relatedObject);
|
|
281
|
+
}, [relatedObject, checkCreateAccess]);
|
|
276
282
|
useEffect(() => {
|
|
277
283
|
const updatedOptions = {};
|
|
278
284
|
if ((relatedInstances && !fetchedOptions[`${fieldDefinition.id}Options`]) ||
|
|
@@ -336,7 +342,9 @@ const RepeatableField = (props) => {
|
|
|
336
342
|
? entry.display?.updateActionId
|
|
337
343
|
: entry.display?.deleteActionId));
|
|
338
344
|
// when save is called we know that fieldDefinition is a parameter and fieldDefinition.objectId is defined
|
|
339
|
-
input = await formatSubmission(input, apiServices, fieldDefinition.objectId, selectedInstanceId, action?.type === 'update' ? updateForm : undefined
|
|
345
|
+
input = await formatSubmission(input, apiServices, fieldDefinition.objectId, selectedInstanceId, action?.type === 'update' ? updateForm : undefined, undefined, instance?.id && fieldDefinition.relatedPropertyId
|
|
346
|
+
? { instanceId: instance.id, propertyId: fieldDefinition.relatedPropertyId }
|
|
347
|
+
: undefined);
|
|
340
348
|
if (action?.type === 'create' && entry.display?.createActionId) {
|
|
341
349
|
const updatedInput = {
|
|
342
350
|
...input,
|
|
@@ -86,7 +86,10 @@ export declare function formatSubmission(submission: FieldValues, apiServices?:
|
|
|
86
86
|
showAlert: boolean;
|
|
87
87
|
message?: string;
|
|
88
88
|
isError: boolean;
|
|
89
|
-
}
|
|
89
|
+
}>>, associatedObject?: {
|
|
90
|
+
instanceId: string;
|
|
91
|
+
propertyId: string;
|
|
92
|
+
}): Promise<FieldValues>;
|
|
90
93
|
export declare function filterEmptySections(entry: Sections | Columns, instance?: FieldValues, formData?: FieldValues): Sections | Columns | null;
|
|
91
94
|
export declare function assignIdsToSectionsAndRichText(entries: FormEntry[], object: Obj, parameters?: InputParameter[]): FormEntry[];
|
|
92
95
|
/**
|
|
@@ -621,7 +621,10 @@ export const deleteDocuments = async (submittedFields, requestSuccess, apiServic
|
|
|
621
621
|
*
|
|
622
622
|
* Returns the cleaned submission ready for submitting.
|
|
623
623
|
*/
|
|
624
|
-
export async function formatSubmission(submission, apiServices, objectId, instanceId, form, setSnackbarError) {
|
|
624
|
+
export async function formatSubmission(submission, apiServices, objectId, instanceId, form, setSnackbarError, associatedObject) {
|
|
625
|
+
if (associatedObject) {
|
|
626
|
+
delete submission[associatedObject.propertyId];
|
|
627
|
+
}
|
|
625
628
|
const allEntries = getUnnestedEntries(form?.entries ?? []) ?? [];
|
|
626
629
|
for (const [key, value] of Object.entries(submission)) {
|
|
627
630
|
const entry = allEntries?.find((entry) => getEntryId(entry) === key);
|
|
@@ -326,12 +326,7 @@ describe('FormRendererContainer', () => {
|
|
|
326
326
|
await user.clear(cityField);
|
|
327
327
|
await user.type(cityField, 'Cambridge');
|
|
328
328
|
await user.tab(); // Blur the field
|
|
329
|
-
|
|
330
|
-
await waitFor(() => {
|
|
331
|
-
expect(autosaveActionSpy).toHaveBeenCalled();
|
|
332
|
-
});
|
|
333
|
-
const lastCall = autosaveActionSpy.mock.lastCall?.[0];
|
|
334
|
-
expect(lastCall).toEqual(expect.objectContaining({
|
|
329
|
+
expect(autosaveActionSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
335
330
|
input: expect.objectContaining({
|
|
336
331
|
address: expect.objectContaining({
|
|
337
332
|
city: 'Cambridge',
|
|
@@ -448,15 +443,7 @@ describe('FormRendererContainer', () => {
|
|
|
448
443
|
// Wait for and select the autocomplete option
|
|
449
444
|
const autocompleteOption = await screen.findByText('456 Oak Street');
|
|
450
445
|
await user.click(autocompleteOption);
|
|
451
|
-
|
|
452
|
-
await waitFor(() => {
|
|
453
|
-
expect(autosaveActionSpy).toHaveBeenCalled();
|
|
454
|
-
});
|
|
455
|
-
// The autosave is triggered twice when selecting the autocomplete option,
|
|
456
|
-
// once by the selection and once by the onBlur event. We want to verify the last call
|
|
457
|
-
// has the correct data.
|
|
458
|
-
const lastCall = autosaveActionSpy.mock.lastCall?.[0];
|
|
459
|
-
expect(lastCall).toEqual(expect.objectContaining({
|
|
446
|
+
expect(autosaveActionSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
460
447
|
input: expect.objectContaining({
|
|
461
448
|
address: expect.objectContaining({
|
|
462
449
|
line1: '456 Oak Street',
|
|
@@ -531,6 +518,484 @@ describe('FormRendererContainer', () => {
|
|
|
531
518
|
// Verify autosave was not triggered
|
|
532
519
|
expect(autosaveActionSpy).not.toHaveBeenCalled();
|
|
533
520
|
});
|
|
521
|
+
it('should trigger autosave immediately when a radio button is selected', async () => {
|
|
522
|
+
const user = userEvent.setup();
|
|
523
|
+
const autosaveActionSpy = vi.fn();
|
|
524
|
+
// Create a form with a status field displayed as radio buttons
|
|
525
|
+
const licenseFormWithRadioButtons = {
|
|
526
|
+
id: 'licenseForm',
|
|
527
|
+
name: 'License Form',
|
|
528
|
+
objectId: 'license',
|
|
529
|
+
actionId: '_update',
|
|
530
|
+
autosaveActionId: '_autosave',
|
|
531
|
+
entries: [
|
|
532
|
+
{
|
|
533
|
+
parameterId: 'name',
|
|
534
|
+
type: 'input',
|
|
535
|
+
display: {
|
|
536
|
+
label: 'License Number',
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
parameterId: 'status',
|
|
541
|
+
type: 'input',
|
|
542
|
+
display: {
|
|
543
|
+
label: 'Status',
|
|
544
|
+
choicesDisplay: {
|
|
545
|
+
type: 'radioButton',
|
|
546
|
+
},
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
],
|
|
550
|
+
};
|
|
551
|
+
server.use(http.get('/api/data/objects/license/instances/test-license', () => {
|
|
552
|
+
return HttpResponse.json({
|
|
553
|
+
id: 'test-license',
|
|
554
|
+
name: 'RN-123456',
|
|
555
|
+
status: 'Active',
|
|
556
|
+
});
|
|
557
|
+
}), http.get('/api/data/objects/license/instances/test-license/object', () => {
|
|
558
|
+
return HttpResponse.json(licenseObject);
|
|
559
|
+
}), http.get('/api/data/forms/licenseForm', () => {
|
|
560
|
+
return HttpResponse.json(licenseFormWithRadioButtons);
|
|
561
|
+
}), http.post('/api/data/objects/license/instances/test-license/actions', async ({ request }) => {
|
|
562
|
+
const body = (await request.json());
|
|
563
|
+
autosaveActionSpy(body);
|
|
564
|
+
return HttpResponse.json({
|
|
565
|
+
id: 'test-license',
|
|
566
|
+
name: 'RN-123456',
|
|
567
|
+
status: body.input.status,
|
|
568
|
+
});
|
|
569
|
+
}));
|
|
570
|
+
render(React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' }));
|
|
571
|
+
// Wait for the form to load and the radio buttons to appear
|
|
572
|
+
const inactiveRadio = await screen.findByRole('radio', { name: 'Inactive' });
|
|
573
|
+
// Click the "Inactive" radio button
|
|
574
|
+
await user.click(inactiveRadio);
|
|
575
|
+
// Verify autosave was triggered immediately with the new status
|
|
576
|
+
await waitFor(() => {
|
|
577
|
+
expect(autosaveActionSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
578
|
+
actionId: '_autosave',
|
|
579
|
+
input: expect.objectContaining({
|
|
580
|
+
status: 'Inactive',
|
|
581
|
+
}),
|
|
582
|
+
}));
|
|
583
|
+
});
|
|
584
|
+
});
|
|
585
|
+
it('should trigger autosave when the selection is cleared', async () => {
|
|
586
|
+
const user = userEvent.setup();
|
|
587
|
+
const autosaveActionSpy = vi.fn();
|
|
588
|
+
const licenseFormWithRadioButtons = {
|
|
589
|
+
id: 'licenseForm',
|
|
590
|
+
name: 'License Form',
|
|
591
|
+
objectId: 'license',
|
|
592
|
+
actionId: '_update',
|
|
593
|
+
autosaveActionId: '_autosave',
|
|
594
|
+
entries: [
|
|
595
|
+
{
|
|
596
|
+
parameterId: 'name',
|
|
597
|
+
type: 'input',
|
|
598
|
+
display: {
|
|
599
|
+
label: 'License Number',
|
|
600
|
+
},
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
parameterId: 'status',
|
|
604
|
+
type: 'input',
|
|
605
|
+
display: {
|
|
606
|
+
label: 'Status',
|
|
607
|
+
choicesDisplay: {
|
|
608
|
+
type: 'radioButton',
|
|
609
|
+
},
|
|
610
|
+
},
|
|
611
|
+
},
|
|
612
|
+
],
|
|
613
|
+
};
|
|
614
|
+
server.use(http.get('/api/data/objects/license/instances/test-license', () => {
|
|
615
|
+
return HttpResponse.json({
|
|
616
|
+
id: 'test-license',
|
|
617
|
+
name: 'RN-123456',
|
|
618
|
+
status: 'Active',
|
|
619
|
+
});
|
|
620
|
+
}), http.get('/api/data/objects/license/instances/test-license/object', () => {
|
|
621
|
+
return HttpResponse.json(licenseObject);
|
|
622
|
+
}), http.get('/api/data/forms/licenseForm', () => {
|
|
623
|
+
return HttpResponse.json(licenseFormWithRadioButtons);
|
|
624
|
+
}), http.post('/api/data/objects/license/instances/test-license/actions', async ({ request }) => {
|
|
625
|
+
const body = (await request.json());
|
|
626
|
+
autosaveActionSpy(body);
|
|
627
|
+
return HttpResponse.json({
|
|
628
|
+
id: 'test-license',
|
|
629
|
+
name: 'RN-123456',
|
|
630
|
+
status: body.input.status,
|
|
631
|
+
});
|
|
632
|
+
}));
|
|
633
|
+
render(React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' }));
|
|
634
|
+
const clearButton = await screen.findByRole('button', { name: 'Clear' });
|
|
635
|
+
await user.click(clearButton);
|
|
636
|
+
expect(autosaveActionSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
637
|
+
actionId: '_autosave',
|
|
638
|
+
input: expect.objectContaining({
|
|
639
|
+
status: null,
|
|
640
|
+
}),
|
|
641
|
+
}));
|
|
642
|
+
});
|
|
643
|
+
it('should trigger autosave immediately when a dropdown option is selected', async () => {
|
|
644
|
+
const user = userEvent.setup();
|
|
645
|
+
const autosaveActionSpy = vi.fn();
|
|
646
|
+
const licenseFormWithDropdown = {
|
|
647
|
+
id: 'licenseForm',
|
|
648
|
+
name: 'License Form',
|
|
649
|
+
objectId: 'license',
|
|
650
|
+
actionId: '_update',
|
|
651
|
+
autosaveActionId: '_autosave',
|
|
652
|
+
entries: [
|
|
653
|
+
{
|
|
654
|
+
parameterId: 'name',
|
|
655
|
+
type: 'input',
|
|
656
|
+
display: { label: 'License Number' },
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
parameterId: 'status',
|
|
660
|
+
type: 'input',
|
|
661
|
+
display: {
|
|
662
|
+
label: 'Status',
|
|
663
|
+
choicesDisplay: { type: 'dropdown' },
|
|
664
|
+
},
|
|
665
|
+
},
|
|
666
|
+
],
|
|
667
|
+
};
|
|
668
|
+
server.use(http.get('/api/data/objects/license/instances/test-license', () => HttpResponse.json({ id: 'test-license', name: 'RN-123456', status: 'Active' })), http.get('/api/data/objects/license/instances/test-license/object', () => HttpResponse.json(licenseObject)), http.get('/api/data/forms/licenseForm', () => HttpResponse.json(licenseFormWithDropdown)), http.post('/api/data/objects/license/instances/test-license/actions', async ({ request }) => {
|
|
669
|
+
const body = (await request.json());
|
|
670
|
+
autosaveActionSpy(body);
|
|
671
|
+
return HttpResponse.json({ id: 'test-license', name: 'RN-123456', status: body.input.status });
|
|
672
|
+
}));
|
|
673
|
+
render(React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' }));
|
|
674
|
+
// Open the dropdown/combobox and choose an option
|
|
675
|
+
const combobox = await screen.findByRole('combobox', { name: 'Status' });
|
|
676
|
+
await user.click(combobox);
|
|
677
|
+
const inactiveOption = await screen.findByRole('option', { name: 'Inactive' });
|
|
678
|
+
await user.click(inactiveOption);
|
|
679
|
+
expect(autosaveActionSpy).toHaveBeenCalledWith({
|
|
680
|
+
actionId: '_autosave',
|
|
681
|
+
input: expect.objectContaining({
|
|
682
|
+
status: 'Inactive',
|
|
683
|
+
}),
|
|
684
|
+
});
|
|
685
|
+
});
|
|
686
|
+
it('should trigger autosave when dropdown selection is cleared', async () => {
|
|
687
|
+
const user = userEvent.setup();
|
|
688
|
+
const autosaveActionSpy = vi.fn();
|
|
689
|
+
const licenseFormWithDropdown = {
|
|
690
|
+
id: 'licenseForm',
|
|
691
|
+
name: 'License Form',
|
|
692
|
+
objectId: 'license',
|
|
693
|
+
actionId: '_update',
|
|
694
|
+
autosaveActionId: '_autosave',
|
|
695
|
+
entries: [
|
|
696
|
+
{
|
|
697
|
+
parameterId: 'name',
|
|
698
|
+
type: 'input',
|
|
699
|
+
display: { label: 'License Number' },
|
|
700
|
+
},
|
|
701
|
+
{
|
|
702
|
+
parameterId: 'status',
|
|
703
|
+
type: 'input',
|
|
704
|
+
display: {
|
|
705
|
+
label: 'Status',
|
|
706
|
+
choicesDisplay: { type: 'dropdown' },
|
|
707
|
+
},
|
|
708
|
+
},
|
|
709
|
+
],
|
|
710
|
+
};
|
|
711
|
+
server.use(http.get('/api/data/objects/license/instances/test-license', () => HttpResponse.json({ id: 'test-license', name: 'RN-123456', status: 'Active' })), http.get('/api/data/objects/license/instances/test-license/object', () => HttpResponse.json(licenseObject)), http.get('/api/data/forms/licenseForm', () => HttpResponse.json(licenseFormWithDropdown)), http.post('/api/data/objects/license/instances/test-license/actions', async ({ request }) => {
|
|
712
|
+
const body = (await request.json());
|
|
713
|
+
autosaveActionSpy(body);
|
|
714
|
+
return HttpResponse.json({ id: 'test-license', name: 'RN-123456', status: body.input.status });
|
|
715
|
+
}));
|
|
716
|
+
render(React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' }));
|
|
717
|
+
const combobox = await screen.findByRole('combobox', { name: 'Status' });
|
|
718
|
+
await user.click(combobox);
|
|
719
|
+
// Clear button has tabindex="-1" so find it via testid
|
|
720
|
+
const clearButton = await screen.findByTestId('autocomplete-clear-button');
|
|
721
|
+
await user.click(clearButton);
|
|
722
|
+
expect(autosaveActionSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
723
|
+
actionId: '_autosave',
|
|
724
|
+
input: expect.objectContaining({
|
|
725
|
+
status: null,
|
|
726
|
+
}),
|
|
727
|
+
}));
|
|
728
|
+
});
|
|
729
|
+
it('should trigger autosave for multi-select when selecting an option', async () => {
|
|
730
|
+
const user = userEvent.setup();
|
|
731
|
+
const autosaveActionSpy = vi.fn();
|
|
732
|
+
const licenseFormWithMultiSelect = {
|
|
733
|
+
id: 'licenseForm',
|
|
734
|
+
name: 'License Form',
|
|
735
|
+
objectId: 'license',
|
|
736
|
+
actionId: '_update',
|
|
737
|
+
autosaveActionId: '_autosave',
|
|
738
|
+
entries: [
|
|
739
|
+
{
|
|
740
|
+
parameterId: 'name',
|
|
741
|
+
type: 'input',
|
|
742
|
+
display: { label: 'License Number' },
|
|
743
|
+
},
|
|
744
|
+
{
|
|
745
|
+
type: 'inputField',
|
|
746
|
+
input: {
|
|
747
|
+
id: 'categories',
|
|
748
|
+
type: 'array',
|
|
749
|
+
enum: ['Electrical', 'Plumbing', 'Mechanical', 'Other'],
|
|
750
|
+
},
|
|
751
|
+
display: {
|
|
752
|
+
label: 'Categories',
|
|
753
|
+
choicesDisplay: { type: 'dropdown' },
|
|
754
|
+
},
|
|
755
|
+
},
|
|
756
|
+
],
|
|
757
|
+
};
|
|
758
|
+
const licenseInstanceInitial = { id: 'test-license', name: 'RN-123456' };
|
|
759
|
+
server.use(http.get('/api/data/objects/license/instances/test-license', () => HttpResponse.json(licenseInstanceInitial)), http.get('/api/data/objects/license/instances/test-license/object', () => HttpResponse.json(licenseObject)), http.get('/api/data/forms/licenseForm', () => HttpResponse.json(licenseFormWithMultiSelect)), http.post('/api/data/objects/license/instances/test-license/actions', async ({ request }) => {
|
|
760
|
+
const body = (await request.json());
|
|
761
|
+
autosaveActionSpy(body);
|
|
762
|
+
return HttpResponse.json({
|
|
763
|
+
id: 'test-license',
|
|
764
|
+
name: body.input.name ?? 'RN-123456',
|
|
765
|
+
categories: body.input.categories,
|
|
766
|
+
});
|
|
767
|
+
}));
|
|
768
|
+
render(React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' }));
|
|
769
|
+
// Open the multi-select combobox and choose an additional option
|
|
770
|
+
const combobox = await screen.findByRole('combobox', { name: 'Categories' });
|
|
771
|
+
await user.click(combobox);
|
|
772
|
+
const plumbingOption = await screen.findByRole('option', { name: 'Electrical' });
|
|
773
|
+
await user.click(plumbingOption);
|
|
774
|
+
expect(autosaveActionSpy).toHaveBeenCalledWith({
|
|
775
|
+
actionId: '_autosave',
|
|
776
|
+
input: expect.objectContaining({ categories: ['Electrical'] }),
|
|
777
|
+
});
|
|
778
|
+
});
|
|
779
|
+
it('should trigger autosave for multi-select when adding an option', async () => {
|
|
780
|
+
const user = userEvent.setup();
|
|
781
|
+
const autosaveActionSpy = vi.fn();
|
|
782
|
+
const licenseFormWithMultiSelect = {
|
|
783
|
+
id: 'licenseForm',
|
|
784
|
+
name: 'License Form',
|
|
785
|
+
objectId: 'license',
|
|
786
|
+
actionId: '_update',
|
|
787
|
+
autosaveActionId: '_autosave',
|
|
788
|
+
entries: [
|
|
789
|
+
{
|
|
790
|
+
parameterId: 'name',
|
|
791
|
+
type: 'input',
|
|
792
|
+
display: { label: 'License Number' },
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
type: 'inputField',
|
|
796
|
+
input: {
|
|
797
|
+
id: 'categories',
|
|
798
|
+
type: 'array',
|
|
799
|
+
enum: ['Electrical', 'Plumbing', 'Mechanical', 'Other'],
|
|
800
|
+
},
|
|
801
|
+
display: {
|
|
802
|
+
label: 'Categories',
|
|
803
|
+
choicesDisplay: { type: 'dropdown' },
|
|
804
|
+
},
|
|
805
|
+
},
|
|
806
|
+
],
|
|
807
|
+
};
|
|
808
|
+
const licenseInstanceInitial = { id: 'test-license', name: 'RN-123456', categories: ['Electrical'] };
|
|
809
|
+
server.use(http.get('/api/data/objects/license/instances/test-license', () => HttpResponse.json(licenseInstanceInitial)), http.get('/api/data/objects/license/instances/test-license/object', () => HttpResponse.json(licenseObject)), http.get('/api/data/forms/licenseForm', () => HttpResponse.json(licenseFormWithMultiSelect)), http.post('/api/data/objects/license/instances/test-license/actions', async ({ request }) => {
|
|
810
|
+
const body = (await request.json());
|
|
811
|
+
autosaveActionSpy(body);
|
|
812
|
+
return HttpResponse.json({
|
|
813
|
+
id: 'test-license',
|
|
814
|
+
name: body.input.name ?? 'RN-123456',
|
|
815
|
+
categories: body.input.categories,
|
|
816
|
+
});
|
|
817
|
+
}));
|
|
818
|
+
render(React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' }));
|
|
819
|
+
// Open the multi-select combobox and choose an additional option
|
|
820
|
+
const combobox = await screen.findByRole('combobox', { name: 'Categories' });
|
|
821
|
+
await user.click(combobox);
|
|
822
|
+
const plumbingOption = await screen.findByRole('option', { name: 'Plumbing' });
|
|
823
|
+
await user.click(plumbingOption);
|
|
824
|
+
expect(autosaveActionSpy).toHaveBeenCalledWith({
|
|
825
|
+
actionId: '_autosave',
|
|
826
|
+
input: expect.objectContaining({
|
|
827
|
+
categories: expect.arrayContaining(['Electrical', 'Plumbing']),
|
|
828
|
+
}),
|
|
829
|
+
});
|
|
830
|
+
});
|
|
831
|
+
it('should trigger autosave when a multi-select option is removed', async () => {
|
|
832
|
+
const user = userEvent.setup();
|
|
833
|
+
const autosaveActionSpy = vi.fn();
|
|
834
|
+
const licenseFormWithMultiSelect = {
|
|
835
|
+
id: 'licenseForm',
|
|
836
|
+
name: 'License Form',
|
|
837
|
+
objectId: 'license',
|
|
838
|
+
actionId: '_update',
|
|
839
|
+
autosaveActionId: '_autosave',
|
|
840
|
+
entries: [
|
|
841
|
+
{
|
|
842
|
+
parameterId: 'name',
|
|
843
|
+
type: 'input',
|
|
844
|
+
display: { label: 'License Number' },
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
type: 'inputField',
|
|
848
|
+
input: {
|
|
849
|
+
id: 'categories',
|
|
850
|
+
type: 'array',
|
|
851
|
+
enum: ['Electrical', 'Plumbing', 'Mechanical', 'Other'],
|
|
852
|
+
},
|
|
853
|
+
display: {
|
|
854
|
+
label: 'Categories',
|
|
855
|
+
choicesDisplay: { type: 'dropdown' },
|
|
856
|
+
},
|
|
857
|
+
},
|
|
858
|
+
],
|
|
859
|
+
};
|
|
860
|
+
server.use(http.get('/api/data/objects/license/instances/test-license', () => HttpResponse.json({
|
|
861
|
+
id: 'test-license',
|
|
862
|
+
name: 'RN-123456',
|
|
863
|
+
categories: ['Electrical', 'Plumbing'],
|
|
864
|
+
})), http.get('/api/data/objects/license/instances/test-license/object', () => HttpResponse.json(licenseObject)), http.get('/api/data/forms/licenseForm', () => HttpResponse.json(licenseFormWithMultiSelect)), http.post('/api/data/objects/license/instances/test-license/actions', async ({ request }) => {
|
|
865
|
+
const body = (await request.json());
|
|
866
|
+
autosaveActionSpy(body);
|
|
867
|
+
return HttpResponse.json({
|
|
868
|
+
id: 'test-license',
|
|
869
|
+
name: 'RN-123456',
|
|
870
|
+
categories: body.input.categories,
|
|
871
|
+
});
|
|
872
|
+
}));
|
|
873
|
+
render(React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' }));
|
|
874
|
+
const electricalChipLabel = await screen.findByRole('button', { name: 'Electrical' });
|
|
875
|
+
// Mui autoamtically provides a test id.
|
|
876
|
+
const deleteIcon = await within(electricalChipLabel).findByTestId('CancelIcon');
|
|
877
|
+
await user.click(deleteIcon);
|
|
878
|
+
// Autosave should be called with only Plumbing remaining
|
|
879
|
+
await waitFor(() => {
|
|
880
|
+
expect(autosaveActionSpy).toHaveBeenCalledWith({
|
|
881
|
+
actionId: '_autosave',
|
|
882
|
+
input: expect.objectContaining({
|
|
883
|
+
categories: ['Plumbing'],
|
|
884
|
+
}),
|
|
885
|
+
});
|
|
886
|
+
});
|
|
887
|
+
});
|
|
888
|
+
it('should trigger autosave when a single multi-select option is removed via the dropdown', async () => {
|
|
889
|
+
const user = userEvent.setup();
|
|
890
|
+
const autosaveActionSpy = vi.fn();
|
|
891
|
+
const licenseFormWithMultiSelect = {
|
|
892
|
+
id: 'licenseForm',
|
|
893
|
+
name: 'License Form',
|
|
894
|
+
objectId: 'license',
|
|
895
|
+
actionId: '_update',
|
|
896
|
+
autosaveActionId: '_autosave',
|
|
897
|
+
entries: [
|
|
898
|
+
{
|
|
899
|
+
parameterId: 'name',
|
|
900
|
+
type: 'input',
|
|
901
|
+
display: { label: 'License Number' },
|
|
902
|
+
},
|
|
903
|
+
{
|
|
904
|
+
type: 'inputField',
|
|
905
|
+
input: {
|
|
906
|
+
id: 'categories',
|
|
907
|
+
type: 'array',
|
|
908
|
+
enum: ['Electrical', 'Plumbing', 'Mechanical', 'Other'],
|
|
909
|
+
},
|
|
910
|
+
display: {
|
|
911
|
+
label: 'Categories',
|
|
912
|
+
choicesDisplay: { type: 'dropdown' },
|
|
913
|
+
},
|
|
914
|
+
},
|
|
915
|
+
],
|
|
916
|
+
};
|
|
917
|
+
server.use(http.get('/api/data/objects/license/instances/test-license', () => HttpResponse.json({
|
|
918
|
+
id: 'test-license',
|
|
919
|
+
name: 'RN-123456',
|
|
920
|
+
categories: ['Electrical', 'Plumbing'],
|
|
921
|
+
})), http.get('/api/data/objects/license/instances/test-license/object', () => HttpResponse.json(licenseObject)), http.get('/api/data/forms/licenseForm', () => HttpResponse.json(licenseFormWithMultiSelect)), http.post('/api/data/objects/license/instances/test-license/actions', async ({ request }) => {
|
|
922
|
+
const body = (await request.json());
|
|
923
|
+
autosaveActionSpy(body);
|
|
924
|
+
return HttpResponse.json({
|
|
925
|
+
id: 'test-license',
|
|
926
|
+
name: 'RN-123456',
|
|
927
|
+
categories: body.input.categories,
|
|
928
|
+
});
|
|
929
|
+
}));
|
|
930
|
+
render(React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' }));
|
|
931
|
+
// Open the multi-select combobox and unselect the 'Plumbing' option
|
|
932
|
+
const combobox = await screen.findByRole('combobox', { name: 'Categories' });
|
|
933
|
+
await user.click(combobox);
|
|
934
|
+
// Click the option to toggle/unselect it (initially selected)
|
|
935
|
+
const plumbingOption = await screen.findByRole('option', { name: 'Plumbing' });
|
|
936
|
+
await user.click(plumbingOption);
|
|
937
|
+
// Expect autosave called with categories array no longer containing 'Plumbing'
|
|
938
|
+
expect(autosaveActionSpy).toHaveBeenCalledWith({
|
|
939
|
+
actionId: '_autosave',
|
|
940
|
+
input: expect.objectContaining({ categories: ['Electrical'] }),
|
|
941
|
+
});
|
|
942
|
+
});
|
|
943
|
+
it('should trigger autosave when multi-select is cleared', async () => {
|
|
944
|
+
const user = userEvent.setup();
|
|
945
|
+
const autosaveActionSpy = vi.fn();
|
|
946
|
+
const licenseFormWithMultiSelect = {
|
|
947
|
+
id: 'licenseForm',
|
|
948
|
+
name: 'License Form',
|
|
949
|
+
objectId: 'license',
|
|
950
|
+
actionId: '_update',
|
|
951
|
+
autosaveActionId: '_autosave',
|
|
952
|
+
entries: [
|
|
953
|
+
{
|
|
954
|
+
parameterId: 'name',
|
|
955
|
+
type: 'input',
|
|
956
|
+
display: { label: 'License Number' },
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
type: 'inputField',
|
|
960
|
+
input: {
|
|
961
|
+
id: 'categories',
|
|
962
|
+
type: 'array',
|
|
963
|
+
enum: ['Electrical', 'Plumbing', 'Mechanical', 'Other'],
|
|
964
|
+
},
|
|
965
|
+
display: {
|
|
966
|
+
label: 'Categories',
|
|
967
|
+
choicesDisplay: { type: 'dropdown' },
|
|
968
|
+
},
|
|
969
|
+
},
|
|
970
|
+
],
|
|
971
|
+
};
|
|
972
|
+
server.use(http.get('/api/data/objects/license/instances/test-license', () => HttpResponse.json({
|
|
973
|
+
id: 'test-license',
|
|
974
|
+
name: 'RN-123456',
|
|
975
|
+
categories: ['Electrical', 'Plumbing'],
|
|
976
|
+
})), http.get('/api/data/objects/license/instances/test-license/object', () => HttpResponse.json(licenseObject)), http.get('/api/data/forms/licenseForm', () => HttpResponse.json(licenseFormWithMultiSelect)), http.post('/api/data/objects/license/instances/test-license/actions', async ({ request }) => {
|
|
977
|
+
const body = (await request.json());
|
|
978
|
+
autosaveActionSpy(body);
|
|
979
|
+
return HttpResponse.json({
|
|
980
|
+
id: 'test-license',
|
|
981
|
+
name: 'RN-123456',
|
|
982
|
+
categories: body.input.categories,
|
|
983
|
+
});
|
|
984
|
+
}));
|
|
985
|
+
render(React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' }));
|
|
986
|
+
// Open the multi-select combobox and click the clear button
|
|
987
|
+
const combobox = await screen.findByRole('combobox', { name: 'Categories' });
|
|
988
|
+
await user.click(combobox);
|
|
989
|
+
// Clear button has tabindex="-1" so find via testid
|
|
990
|
+
const clearButton = await screen.findByTestId('autocomplete-clear-button');
|
|
991
|
+
await user.click(clearButton);
|
|
992
|
+
expect(autosaveActionSpy).toHaveBeenCalledWith({
|
|
993
|
+
actionId: '_autosave',
|
|
994
|
+
input: expect.objectContaining({
|
|
995
|
+
categories: expect.arrayContaining([]),
|
|
996
|
+
}),
|
|
997
|
+
});
|
|
998
|
+
});
|
|
534
999
|
});
|
|
535
1000
|
it('should display a submit button', async () => {
|
|
536
1001
|
const form = {
|
|
@@ -160,6 +160,12 @@ export const licenseObject = {
|
|
|
160
160
|
type: 'string',
|
|
161
161
|
enum: ['Active', 'Inactive'],
|
|
162
162
|
},
|
|
163
|
+
{
|
|
164
|
+
id: 'categories',
|
|
165
|
+
name: 'Categories',
|
|
166
|
+
type: 'array',
|
|
167
|
+
enum: ['Electrical', 'Plumbing', 'Mechanical', 'Other'],
|
|
168
|
+
},
|
|
163
169
|
{
|
|
164
170
|
id: 'licenseType',
|
|
165
171
|
name: 'License Type',
|
|
@@ -188,6 +194,13 @@ export const licenseObject = {
|
|
|
188
194
|
id: 'status',
|
|
189
195
|
name: 'Status',
|
|
190
196
|
type: 'string',
|
|
197
|
+
enum: ['Active', 'Inactive'],
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
id: 'categories',
|
|
201
|
+
name: 'Categories',
|
|
202
|
+
type: 'array',
|
|
203
|
+
enum: ['Electrical', 'Plumbing', 'Mechanical', 'Other'],
|
|
191
204
|
},
|
|
192
205
|
{
|
|
193
206
|
id: 'address.line1',
|
|
@@ -236,6 +249,13 @@ export const licenseObject = {
|
|
|
236
249
|
id: 'status',
|
|
237
250
|
name: 'Status',
|
|
238
251
|
type: 'string',
|
|
252
|
+
enum: ['Active', 'Inactive'],
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
id: 'categories',
|
|
256
|
+
name: 'Categories',
|
|
257
|
+
type: 'array',
|
|
258
|
+
enum: ['Electrical', 'Plumbing', 'Mechanical', 'Other'],
|
|
239
259
|
},
|
|
240
260
|
{
|
|
241
261
|
id: 'address.line1',
|
|
@@ -12,8 +12,8 @@ declare const _default: import("@storybook/types").ComponentAnnotations<import("
|
|
|
12
12
|
onChange: (id: string, value: unknown) => void | Promise<void>;
|
|
13
13
|
onAutosave?: ((fieldId: string) => void | Promise<void>) | undefined;
|
|
14
14
|
associatedObject?: {
|
|
15
|
-
instanceId
|
|
16
|
-
propertyId
|
|
15
|
+
instanceId: string;
|
|
16
|
+
propertyId: string;
|
|
17
17
|
} | undefined;
|
|
18
18
|
renderHeader?: ((props: import("../components/custom").HeaderProps) => React.ReactNode) | undefined;
|
|
19
19
|
renderBody?: ((props: import("../components/custom").BodyProps) => React.ReactNode) | undefined;
|
|
@@ -33,8 +33,8 @@ export declare const Editable: import("@storybook/types").AnnotatedStoryFn<impor
|
|
|
33
33
|
onChange: (id: string, value: unknown) => void | Promise<void>;
|
|
34
34
|
onAutosave?: ((fieldId: string) => void | Promise<void>) | undefined;
|
|
35
35
|
associatedObject?: {
|
|
36
|
-
instanceId
|
|
37
|
-
propertyId
|
|
36
|
+
instanceId: string;
|
|
37
|
+
propertyId: string;
|
|
38
38
|
} | undefined;
|
|
39
39
|
renderHeader?: ((props: import("../components/custom").HeaderProps) => React.ReactNode) | undefined;
|
|
40
40
|
renderBody?: ((props: import("../components/custom").BodyProps) => React.ReactNode) | undefined;
|
|
@@ -53,8 +53,8 @@ export declare const NoButtons: import("@storybook/types").AnnotatedStoryFn<impo
|
|
|
53
53
|
onChange: (id: string, value: unknown) => void | Promise<void>;
|
|
54
54
|
onAutosave?: ((fieldId: string) => void | Promise<void>) | undefined;
|
|
55
55
|
associatedObject?: {
|
|
56
|
-
instanceId
|
|
57
|
-
propertyId
|
|
56
|
+
instanceId: string;
|
|
57
|
+
propertyId: string;
|
|
58
58
|
} | undefined;
|
|
59
59
|
renderHeader?: ((props: import("../components/custom").HeaderProps) => React.ReactNode) | undefined;
|
|
60
60
|
renderBody?: ((props: import("../components/custom").BodyProps) => React.ReactNode) | undefined;
|
|
@@ -73,8 +73,8 @@ export declare const DocumentForm: import("@storybook/types").AnnotatedStoryFn<i
|
|
|
73
73
|
onChange: (id: string, value: unknown) => void | Promise<void>;
|
|
74
74
|
onAutosave?: ((fieldId: string) => void | Promise<void>) | undefined;
|
|
75
75
|
associatedObject?: {
|
|
76
|
-
instanceId
|
|
77
|
-
propertyId
|
|
76
|
+
instanceId: string;
|
|
77
|
+
propertyId: string;
|
|
78
78
|
} | undefined;
|
|
79
79
|
renderHeader?: ((props: import("../components/custom").HeaderProps) => React.ReactNode) | undefined;
|
|
80
80
|
renderBody?: ((props: import("../components/custom").BodyProps) => React.ReactNode) | undefined;
|
|
@@ -16,8 +16,8 @@ declare const _default: import("@storybook/types").ComponentAnnotations<import("
|
|
|
16
16
|
onDiscardChanges?: (() => void) | undefined;
|
|
17
17
|
onSubmitError?: import("react-hook-form").SubmitErrorHandler<import("react-hook-form").FieldValues> | undefined;
|
|
18
18
|
associatedObject?: {
|
|
19
|
-
instanceId
|
|
20
|
-
propertyId
|
|
19
|
+
instanceId: string;
|
|
20
|
+
propertyId: string;
|
|
21
21
|
} | undefined;
|
|
22
22
|
renderContainer?: ((state: import("../components/custom/FormV2/FormRendererContainer").FormRendererState) => React.ReactNode) | undefined;
|
|
23
23
|
renderHeader?: ((props: import("../components/custom").HeaderProps) => React.ReactNode) | undefined;
|
|
@@ -43,8 +43,8 @@ export declare const Editable: import("@storybook/types").AnnotatedStoryFn<impor
|
|
|
43
43
|
onDiscardChanges?: (() => void) | undefined;
|
|
44
44
|
onSubmitError?: import("react-hook-form").SubmitErrorHandler<import("react-hook-form").FieldValues> | undefined;
|
|
45
45
|
associatedObject?: {
|
|
46
|
-
instanceId
|
|
47
|
-
propertyId
|
|
46
|
+
instanceId: string;
|
|
47
|
+
propertyId: string;
|
|
48
48
|
} | undefined;
|
|
49
49
|
renderContainer?: ((state: import("../components/custom/FormV2/FormRendererContainer").FormRendererState) => React.ReactNode) | undefined;
|
|
50
50
|
renderHeader?: ((props: import("../components/custom").HeaderProps) => React.ReactNode) | undefined;
|
|
@@ -69,8 +69,8 @@ export declare const DefaultForm: import("@storybook/types").AnnotatedStoryFn<im
|
|
|
69
69
|
onDiscardChanges?: (() => void) | undefined;
|
|
70
70
|
onSubmitError?: import("react-hook-form").SubmitErrorHandler<import("react-hook-form").FieldValues> | undefined;
|
|
71
71
|
associatedObject?: {
|
|
72
|
-
instanceId
|
|
73
|
-
propertyId
|
|
72
|
+
instanceId: string;
|
|
73
|
+
propertyId: string;
|
|
74
74
|
} | undefined;
|
|
75
75
|
renderContainer?: ((state: import("../components/custom/FormV2/FormRendererContainer").FormRendererState) => React.ReactNode) | undefined;
|
|
76
76
|
renderHeader?: ((props: import("../components/custom").HeaderProps) => React.ReactNode) | undefined;
|
|
@@ -95,8 +95,8 @@ export declare const NoButtons: import("@storybook/types").AnnotatedStoryFn<impo
|
|
|
95
95
|
onDiscardChanges?: (() => void) | undefined;
|
|
96
96
|
onSubmitError?: import("react-hook-form").SubmitErrorHandler<import("react-hook-form").FieldValues> | undefined;
|
|
97
97
|
associatedObject?: {
|
|
98
|
-
instanceId
|
|
99
|
-
propertyId
|
|
98
|
+
instanceId: string;
|
|
99
|
+
propertyId: string;
|
|
100
100
|
} | undefined;
|
|
101
101
|
renderContainer?: ((state: import("../components/custom/FormV2/FormRendererContainer").FormRendererState) => React.ReactNode) | undefined;
|
|
102
102
|
renderHeader?: ((props: import("../components/custom").HeaderProps) => React.ReactNode) | undefined;
|
|
@@ -121,8 +121,8 @@ export declare const DocumentForm: import("@storybook/types").AnnotatedStoryFn<i
|
|
|
121
121
|
onDiscardChanges?: (() => void) | undefined;
|
|
122
122
|
onSubmitError?: import("react-hook-form").SubmitErrorHandler<import("react-hook-form").FieldValues> | undefined;
|
|
123
123
|
associatedObject?: {
|
|
124
|
-
instanceId
|
|
125
|
-
propertyId
|
|
124
|
+
instanceId: string;
|
|
125
|
+
propertyId: string;
|
|
126
126
|
} | undefined;
|
|
127
127
|
renderContainer?: ((state: import("../components/custom/FormV2/FormRendererContainer").FormRendererState) => React.ReactNode) | undefined;
|
|
128
128
|
renderHeader?: ((props: import("../components/custom").HeaderProps) => React.ReactNode) | undefined;
|
|
@@ -147,8 +147,8 @@ export declare const FormWithSections: import("@storybook/types").AnnotatedStory
|
|
|
147
147
|
onDiscardChanges?: (() => void) | undefined;
|
|
148
148
|
onSubmitError?: import("react-hook-form").SubmitErrorHandler<import("react-hook-form").FieldValues> | undefined;
|
|
149
149
|
associatedObject?: {
|
|
150
|
-
instanceId
|
|
151
|
-
propertyId
|
|
150
|
+
instanceId: string;
|
|
151
|
+
propertyId: string;
|
|
152
152
|
} | undefined;
|
|
153
153
|
renderContainer?: ((state: import("../components/custom/FormV2/FormRendererContainer").FormRendererState) => React.ReactNode) | undefined;
|
|
154
154
|
renderHeader?: ((props: import("../components/custom").HeaderProps) => React.ReactNode) | undefined;
|
|
@@ -153,9 +153,9 @@ export declare function useFormContext(): {
|
|
|
153
153
|
triggerFieldReset?: boolean | undefined;
|
|
154
154
|
showSubmitError?: boolean | undefined;
|
|
155
155
|
associatedObject?: {
|
|
156
|
-
instanceId
|
|
157
|
-
propertyId
|
|
158
|
-
} | undefined;
|
|
156
|
+
instanceId: string;
|
|
157
|
+
propertyId: string; /** Extra large screens (1536px and up) */
|
|
158
|
+
} | undefined; /** Extra large screens (1536px and up) */
|
|
159
159
|
form?: import("@evoke-platform/context").EvokeForm | undefined;
|
|
160
160
|
width: number;
|
|
161
161
|
};
|