@evoke-platform/ui-components 1.13.0-dev.1 → 1.13.0-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/FormV2/FormRendererContainer.js +1 -1
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/RepeatableField.js +2 -2
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.js +1 -0
- package/dist/published/components/custom/FormV2/components/utils.d.ts +1 -1
- package/dist/published/components/custom/FormV2/components/utils.js +13 -3
- package/dist/published/components/custom/FormV2/tests/FormRenderer.test.js +38 -1
- package/dist/published/components/custom/FormV2/tests/test-data.js +29 -0
- package/package.json +2 -1
|
@@ -186,7 +186,7 @@ function FormRendererContainer(props) {
|
|
|
186
186
|
if (!form) {
|
|
187
187
|
return;
|
|
188
188
|
}
|
|
189
|
-
submission = await formatSubmission(submission, apiServices, objectId, instanceId, form, setSnackbarError);
|
|
189
|
+
submission = await formatSubmission(submission, apiServices, objectId, instanceId, form, setSnackbarError, undefined, parameters);
|
|
190
190
|
try {
|
|
191
191
|
if (action?.type === 'create') {
|
|
192
192
|
const response = await apiServices.post(getPrefixedUrl(`/objects/${form.objectId}/instances/actions`), {
|
|
@@ -9,7 +9,7 @@ import { Accordion, AccordionDetails, AccordionSummary, Button, IconButton, Skel
|
|
|
9
9
|
import { Box } from '../../../../../layout';
|
|
10
10
|
import { getReadableQuery } from '../../../../CriteriaBuilder';
|
|
11
11
|
import { retrieveCustomErrorMessage } from '../../../../Form/utils';
|
|
12
|
-
import { deleteDocuments, formatSubmission, getPrefixedUrl, transformToWhere } from '../../utils';
|
|
12
|
+
import { convertPropertiesToParams, deleteDocuments, formatSubmission, getPrefixedUrl, transformToWhere, } from '../../utils';
|
|
13
13
|
import { ActionDialog } from './ActionDialog';
|
|
14
14
|
import { DocumentViewerCell } from './DocumentViewerCell';
|
|
15
15
|
const styles = {
|
|
@@ -344,7 +344,7 @@ const RepeatableField = (props) => {
|
|
|
344
344
|
// when save is called we know that fieldDefinition is a parameter and fieldDefinition.objectId is defined
|
|
345
345
|
input = await formatSubmission(input, apiServices, fieldDefinition.objectId, selectedInstanceId, action?.type === 'update' ? updateForm : undefined, undefined, instance?.id && fieldDefinition.relatedPropertyId
|
|
346
346
|
? { instanceId: instance.id, propertyId: fieldDefinition.relatedPropertyId }
|
|
347
|
-
: undefined);
|
|
347
|
+
: undefined, action?.parameters ?? (relatedObject && convertPropertiesToParams(relatedObject)));
|
|
348
348
|
if (action?.type === 'create' && entry.display?.createActionId) {
|
|
349
349
|
const updatedInput = {
|
|
350
350
|
...input,
|
package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.js
CHANGED
|
@@ -57,6 +57,7 @@ export const Document = (props) => {
|
|
|
57
57
|
const handleUpload = async (files) => {
|
|
58
58
|
// Store File objects in form state - they will be uploaded during autosave via formatSubmission()
|
|
59
59
|
const newDocuments = [...(documents ?? []), ...(files ?? [])];
|
|
60
|
+
console.debug('Uploading documents:', newDocuments);
|
|
60
61
|
setDocuments(newDocuments);
|
|
61
62
|
try {
|
|
62
63
|
handleChange && (await handleChange(id, newDocuments));
|
|
@@ -84,7 +84,7 @@ export declare function formatSubmission(submission: FieldValues, apiServices?:
|
|
|
84
84
|
}>>, associatedObject?: {
|
|
85
85
|
instanceId: string;
|
|
86
86
|
propertyId: string;
|
|
87
|
-
}): Promise<FieldValues>;
|
|
87
|
+
}, parameters?: InputParameter[]): Promise<FieldValues>;
|
|
88
88
|
export declare function filterEmptySections(entry: Sections | Columns, instance?: FieldValues, formData?: FieldValues): Sections | Columns | null;
|
|
89
89
|
export declare function assignIdsToSectionsAndRichText(entries: FormEntry[], object: Obj, parameters?: InputParameter[]): FormEntry[];
|
|
90
90
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LocalDateTime } from '@js-joda/core';
|
|
2
|
-
import jsonLogic from 'json-logic-js';
|
|
2
|
+
import { jsonLogic } from 'json-logic-js-graphql';
|
|
3
3
|
import { get, isArray, isEmpty, isObject, omit, pick, startCase, transform } from 'lodash';
|
|
4
4
|
import { DateTime } from 'luxon';
|
|
5
5
|
import { nanoid } from 'nanoid';
|
|
@@ -115,6 +115,16 @@ export const getEntryId = (entry) => {
|
|
|
115
115
|
? entry.input.id
|
|
116
116
|
: undefined;
|
|
117
117
|
};
|
|
118
|
+
const getEntryType = (entry, parameters) => {
|
|
119
|
+
if (entry?.type === 'inputField') {
|
|
120
|
+
return entry?.input?.type;
|
|
121
|
+
}
|
|
122
|
+
else if (entry?.type === 'input') {
|
|
123
|
+
// For 'input' type entries, look up the parameter by parameterId
|
|
124
|
+
const parameter = parameters?.find((param) => param.id === entry.parameterId);
|
|
125
|
+
return parameter?.type;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
118
128
|
export function getPrefixedUrl(url) {
|
|
119
129
|
const wcsMatchers = ['/apps', '/pages', '/widgets'];
|
|
120
130
|
const dataMatchers = ['/objects', '/correspondenceTemplates', '/documents', '/payments', '/forms', '/locations'];
|
|
@@ -584,7 +594,7 @@ export const deleteDocuments = async (submittedFields, requestSuccess, apiServic
|
|
|
584
594
|
*
|
|
585
595
|
* Returns the cleaned submission ready for submitting.
|
|
586
596
|
*/
|
|
587
|
-
export async function formatSubmission(submission, apiServices, objectId, instanceId, form, setSnackbarError, associatedObject) {
|
|
597
|
+
export async function formatSubmission(submission, apiServices, objectId, instanceId, form, setSnackbarError, associatedObject, parameters) {
|
|
588
598
|
if (associatedObject) {
|
|
589
599
|
delete submission[associatedObject.propertyId];
|
|
590
600
|
}
|
|
@@ -596,7 +606,7 @@ export async function formatSubmission(submission, apiServices, objectId, instan
|
|
|
596
606
|
const fileInArray = value.some((item) => item instanceof File);
|
|
597
607
|
if (fileInArray && apiServices && objectId) {
|
|
598
608
|
// Determine property type from the entry
|
|
599
|
-
const propertyType = entry
|
|
609
|
+
const propertyType = getEntryType(entry, parameters);
|
|
600
610
|
try {
|
|
601
611
|
let uploadedDocuments = [];
|
|
602
612
|
if (propertyType === 'file') {
|
|
@@ -135,6 +135,44 @@ describe('FormRenderer', () => {
|
|
|
135
135
|
// Validate that specialty type dropdown renders
|
|
136
136
|
await screen.findByRole('combobox', { name: 'Specialty Type' });
|
|
137
137
|
});
|
|
138
|
+
it('shows fields based on form data using JsonLogic with a Lodash function', async () => {
|
|
139
|
+
server.use(http.get('/data/objects/license/instances/rnLicense', () => HttpResponse.json(rnLicense)));
|
|
140
|
+
const user = userEvent.setup();
|
|
141
|
+
const FormWithState = () => {
|
|
142
|
+
const [formData, setFormData] = React.useState({
|
|
143
|
+
specialtyType: { id: 'rnSpecialtyType1', name: 'RN Specialty Type #1' },
|
|
144
|
+
});
|
|
145
|
+
const handleChange = (id, value) => {
|
|
146
|
+
setFormData((prev) => {
|
|
147
|
+
const newData = { ...prev };
|
|
148
|
+
set(newData, id, value);
|
|
149
|
+
return newData;
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
try {
|
|
153
|
+
return (React.createElement(FormRenderer, { form: jsonLogicDisplayTestSpecialtyForm, value: formData, onChange: handleChange, instance: {
|
|
154
|
+
id: '123',
|
|
155
|
+
objectId: 'specialty',
|
|
156
|
+
name: 'Test Specialty Object Instance',
|
|
157
|
+
} }));
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
console.error('Render error:', err);
|
|
161
|
+
return React.createElement("div", null, "Render error");
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
render(React.createElement(FormWithState, null));
|
|
165
|
+
// Validate that Additional Training renders because specialtyType.name isn't empty
|
|
166
|
+
await screen.findByRole('textbox', { name: 'Additional Training' });
|
|
167
|
+
await screen.findByRole('combobox', { name: 'Specialty Type' });
|
|
168
|
+
// Clear the specialtyType field
|
|
169
|
+
const clearButton = screen.getByRole('button', { name: 'Clear selection' });
|
|
170
|
+
await user.click(clearButton);
|
|
171
|
+
// Validate that Additional Training is no longer visible because specialtyType.name is now empty
|
|
172
|
+
await waitFor(() => {
|
|
173
|
+
expect(screen.queryByRole('textbox', { name: 'Additional Training' })).not.toBeInTheDocument();
|
|
174
|
+
});
|
|
175
|
+
});
|
|
138
176
|
it('hides fields based on instance data using JsonLogic', async () => {
|
|
139
177
|
server.use(http.get('/data/objects/license/instances/rnLicense', () => HttpResponse.json(rnLicense)));
|
|
140
178
|
render(React.createElement(FormRenderer, { form: jsonLogicDisplayTestSpecialtyForm, onChange: () => { }, instance: {
|
|
@@ -170,7 +208,6 @@ describe('FormRenderer', () => {
|
|
|
170
208
|
expect(screen.queryByRole('combobox', { name: 'Specialty Type' })).not.toBeInTheDocument();
|
|
171
209
|
});
|
|
172
210
|
});
|
|
173
|
-
// accessibility508Form2
|
|
174
211
|
describe('508 accessibility compliance', () => {
|
|
175
212
|
it('supports keyboard navigation back and forth through Related Object dropdowns', async () => {
|
|
176
213
|
const user = userEvent.setup();
|
|
@@ -87,6 +87,25 @@ export const jsonLogicDisplayTestSpecialtyForm = {
|
|
|
87
87
|
},
|
|
88
88
|
},
|
|
89
89
|
},
|
|
90
|
+
{
|
|
91
|
+
parameterId: 'additionalTraining',
|
|
92
|
+
type: 'input',
|
|
93
|
+
display: {
|
|
94
|
+
label: 'Additional Training',
|
|
95
|
+
visibility: {
|
|
96
|
+
and: [
|
|
97
|
+
{
|
|
98
|
+
'!': {
|
|
99
|
+
_isEmpty: { var: 'data.specialtyType.name' },
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
in: [{ var: 'data.specialtyType.name' }, ['RN Specialty Type #1', 'RN Specialty Type #2']],
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
90
109
|
{
|
|
91
110
|
parameterId: 'license',
|
|
92
111
|
type: 'input',
|
|
@@ -360,6 +379,11 @@ export const specialtyObject = {
|
|
|
360
379
|
type: 'object',
|
|
361
380
|
objectId: 'license',
|
|
362
381
|
},
|
|
382
|
+
{
|
|
383
|
+
id: 'additionalTraining',
|
|
384
|
+
name: 'Additional Training',
|
|
385
|
+
type: 'string',
|
|
386
|
+
},
|
|
363
387
|
],
|
|
364
388
|
actions: [
|
|
365
389
|
{
|
|
@@ -422,6 +446,11 @@ export const specialtyObject = {
|
|
|
422
446
|
type: 'object',
|
|
423
447
|
objectId: 'license',
|
|
424
448
|
},
|
|
449
|
+
{
|
|
450
|
+
id: 'additionalTraining',
|
|
451
|
+
name: 'Additional Training',
|
|
452
|
+
type: 'string',
|
|
453
|
+
},
|
|
425
454
|
],
|
|
426
455
|
},
|
|
427
456
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evoke-platform/ui-components",
|
|
3
|
-
"version": "1.13.0-dev.
|
|
3
|
+
"version": "1.13.0-dev.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/published/index.js",
|
|
6
6
|
"module": "dist/published/index.js",
|
|
@@ -128,6 +128,7 @@
|
|
|
128
128
|
"flat": "^6.0.1",
|
|
129
129
|
"formiojs": "^4.21.7",
|
|
130
130
|
"html-react-parser": "^5.1.18",
|
|
131
|
+
"json-logic-js-graphql": "^1.2.4",
|
|
131
132
|
"luxon": "^2.5.2",
|
|
132
133
|
"nanoid": "^5.0.8",
|
|
133
134
|
"nanoid-dictionary": "^4.3.0",
|