@openmrs/esm-form-engine-lib 2.1.0-pre.1362
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/.editorconfig +12 -0
- package/.eslintignore +2 -0
- package/.eslintrc +58 -0
- package/.husky/pre-commit +6 -0
- package/.husky/pre-push +6 -0
- package/.prettierignore +4 -0
- package/LICENSE.txt +401 -0
- package/README.md +136 -0
- package/__mocks__/concepts.mock.json +140 -0
- package/__mocks__/forms/afe-forms/component_art.json +38 -0
- package/__mocks__/forms/afe-forms/component_preclinic-review.json +38 -0
- package/__mocks__/forms/afe-forms/demo_hts-form.json +62 -0
- package/__mocks__/forms/afe-forms/form-component.json +38 -0
- package/__mocks__/forms/afe-forms/mini-form.json +31 -0
- package/__mocks__/forms/afe-forms/nested-form1.json +38 -0
- package/__mocks__/forms/afe-forms/nested-form2.json +38 -0
- package/__mocks__/forms/afe-forms/test-orders.json +72 -0
- package/__mocks__/forms/afe-forms/test-schema-transformer-form.json +88 -0
- package/__mocks__/forms/rfe-forms/age-validation-form.json +58 -0
- package/__mocks__/forms/rfe-forms/bmi-test-form.json +69 -0
- package/__mocks__/forms/rfe-forms/bsa-test-form.json +69 -0
- package/__mocks__/forms/rfe-forms/component_art.json +1705 -0
- package/__mocks__/forms/rfe-forms/component_preclinic-review.json +480 -0
- package/__mocks__/forms/rfe-forms/conditional-answered-form.json +97 -0
- package/__mocks__/forms/rfe-forms/conditional-required-form.json +281 -0
- package/__mocks__/forms/rfe-forms/demo_hts-form.json +346 -0
- package/__mocks__/forms/rfe-forms/edd-test-form.json +88 -0
- package/__mocks__/forms/rfe-forms/external_data_source_form.json +43 -0
- package/__mocks__/forms/rfe-forms/filter-answer-options-test-form.json +87 -0
- package/__mocks__/forms/rfe-forms/form-component.json +43 -0
- package/__mocks__/forms/rfe-forms/forms-loader.test.schema.ts +209 -0
- package/__mocks__/forms/rfe-forms/historical-expressions-form.json +170 -0
- package/__mocks__/forms/rfe-forms/labour_and_delivery_test_form.json +374 -0
- package/__mocks__/forms/rfe-forms/mini-form.json +29 -0
- package/__mocks__/forms/rfe-forms/mockHistoricalvisitsEncounter.json +89 -0
- package/__mocks__/forms/rfe-forms/months-on-art-form.json +90 -0
- package/__mocks__/forms/rfe-forms/multi-select-form.json +86 -0
- package/__mocks__/forms/rfe-forms/nested-form1.json +43 -0
- package/__mocks__/forms/rfe-forms/nested-form2.json +43 -0
- package/__mocks__/forms/rfe-forms/next-visit-test-form.json +78 -0
- package/__mocks__/forms/rfe-forms/obs-group-test_form.json +137 -0
- package/__mocks__/forms/rfe-forms/obs-list-data.ts +37 -0
- package/__mocks__/forms/rfe-forms/post-submission-test-form.json +116 -0
- package/__mocks__/forms/rfe-forms/reference-by-mapping-form.json +54 -0
- package/__mocks__/forms/rfe-forms/required-form.json +50 -0
- package/__mocks__/forms/rfe-forms/sample_fields.json +36 -0
- package/__mocks__/forms/rfe-forms/test-enrolment-form.json +241 -0
- package/__mocks__/forms/rfe-forms/treatment-end-date-test-form.json +121 -0
- package/__mocks__/forms/rfe-forms/viral-load-status-form.json +75 -0
- package/__mocks__/forms/rfe-forms/zscore-bmi-for-age-form.json +79 -0
- package/__mocks__/forms/rfe-forms/zscore-height-for-age-form.json +79 -0
- package/__mocks__/forms/rfe-forms/zscore-weight-height-form.json +77 -0
- package/__mocks__/packages/hiv/forms/hts_poc/1.0.json +8 -0
- package/__mocks__/packages/hiv/forms/hts_poc/1.1.json +91 -0
- package/__mocks__/packages/test-forms-registry.ts +12 -0
- package/__mocks__/patient.mock.ts +173 -0
- package/__mocks__/react-i18next.js +49 -0
- package/__mocks__/react-markdown.tsx +5 -0
- package/__mocks__/session.mock.ts +117 -0
- package/__mocks__/single-spa-react.js +11 -0
- package/__mocks__/use-initial-values/encounter.mock.json +963 -0
- package/__mocks__/use-initial-values/patient.mock.json +73 -0
- package/__mocks__/visit.mock.ts +19 -0
- package/dist/openmrs-esm-form-engine-lib.js +1 -0
- package/jest.config.js +30 -0
- package/package.json +104 -0
- package/prettier.config.js +8 -0
- package/readme/form-engine.jpeg +0 -0
- package/src/adapters/control-adapter.ts +29 -0
- package/src/adapters/encounter-datetime-adapter.ts +38 -0
- package/src/adapters/encounter-location-adapter.ts +39 -0
- package/src/adapters/encounter-provider-adapter.ts +48 -0
- package/src/adapters/encounter-role-adapter.ts +54 -0
- package/src/adapters/inline-date-adapter.ts +58 -0
- package/src/adapters/obs-adapter.ts +280 -0
- package/src/adapters/obs-comment-adapter.ts +60 -0
- package/src/adapters/orders-adapter.ts +75 -0
- package/src/adapters/patient-identifier-adapter.ts +40 -0
- package/src/adapters/program-state-adapter.ts +52 -0
- package/src/api/index.ts +178 -0
- package/src/components/error/error-modal.component.tsx +37 -0
- package/src/components/error/error.scss +4 -0
- package/src/components/extension/extension-parcel.component.tsx +32 -0
- package/src/components/field-label/field-label.component.tsx +32 -0
- package/src/components/field-label/field-label.scss +11 -0
- package/src/components/group/obs-group.component.tsx +29 -0
- package/src/components/group/obs-group.scss +12 -0
- package/src/components/inputs/content-switcher/content-switcher.component.tsx +71 -0
- package/src/components/inputs/content-switcher/content-switcher.scss +55 -0
- package/src/components/inputs/date/date.component.tsx +149 -0
- package/src/components/inputs/date/date.scss +36 -0
- package/src/components/inputs/file/camera/camera.component.tsx +34 -0
- package/src/components/inputs/file/camera/camera.scss +3 -0
- package/src/components/inputs/file/file.component.tsx +159 -0
- package/src/components/inputs/file/file.scss +101 -0
- package/src/components/inputs/fixed-value/fixed-value.component.tsx +19 -0
- package/src/components/inputs/markdown/markdown-wrapper.component.tsx +14 -0
- package/src/components/inputs/markdown/markdown.component.tsx +8 -0
- package/src/components/inputs/multi-select/multi-select.component.tsx +151 -0
- package/src/components/inputs/multi-select/multi-select.scss +25 -0
- package/src/components/inputs/multi-select/multi-select.test.tsx +90 -0
- package/src/components/inputs/number/number.component.tsx +69 -0
- package/src/components/inputs/number/number.scss +15 -0
- package/src/components/inputs/radio/radio.component.tsx +79 -0
- package/src/components/inputs/radio/radio.scss +36 -0
- package/src/components/inputs/select/dropdown.component.tsx +73 -0
- package/src/components/inputs/select/dropdown.scss +11 -0
- package/src/components/inputs/select/dropdown.test.tsx +120 -0
- package/src/components/inputs/text/text.component.tsx +65 -0
- package/src/components/inputs/text/text.scss +15 -0
- package/src/components/inputs/text/text.test.tsx +104 -0
- package/src/components/inputs/text-area/text-area.component.tsx +63 -0
- package/src/components/inputs/text-area/text-area.scss +11 -0
- package/src/components/inputs/toggle/toggle.component.tsx +66 -0
- package/src/components/inputs/toggle/toggle.scss +12 -0
- package/src/components/inputs/tooltip/tooltip.component.tsx +23 -0
- package/src/components/inputs/tooltip/tooltip.scss +8 -0
- package/src/components/inputs/ui-select-extended/ui-select-extended.component.tsx +187 -0
- package/src/components/inputs/ui-select-extended/ui-select-extended.scss +15 -0
- package/src/components/inputs/ui-select-extended/ui-select-extended.test.tsx +211 -0
- package/src/components/inputs/unspecified/unspecified.component.tsx +74 -0
- package/src/components/inputs/unspecified/unspecified.scss +7 -0
- package/src/components/inputs/unspecified/unspecified.test.tsx +95 -0
- package/src/components/inputs/workspace-launcher/workspace-launcher.component.tsx +35 -0
- package/src/components/inputs/workspace-launcher/workspace-launcher.scss +15 -0
- package/src/components/label/label.component.tsx +20 -0
- package/src/components/label/label.scss +11 -0
- package/src/components/loaders/loader.component.tsx +16 -0
- package/src/components/loaders/loader.scss +20 -0
- package/src/components/patient-banner/patient-banner.component.tsx +20 -0
- package/src/components/patient-banner/patient-banner.scss +12 -0
- package/src/components/previous-value-review/previous-value-review.component.tsx +49 -0
- package/src/components/previous-value-review/previous-value-review.scss +36 -0
- package/src/components/processor-factory/form-processor-factory.component.tsx +127 -0
- package/src/components/renderer/custom-hooks-renderer.component.tsx +30 -0
- package/src/components/renderer/field/fieldLogic.ts +214 -0
- package/src/components/renderer/field/form-field-renderer.component.tsx +281 -0
- package/src/components/renderer/field/form-field-renderer.scss +5 -0
- package/src/components/renderer/form/form-renderer.component.tsx +89 -0
- package/src/components/renderer/form/state.ts +54 -0
- package/src/components/renderer/page/page.renderer.component.tsx +50 -0
- package/src/components/renderer/page/page.renderer.scss +36 -0
- package/src/components/renderer/section/section-renderer.component.tsx +21 -0
- package/src/components/renderer/section/section-renderer.scss +19 -0
- package/src/components/repeat/helpers.test.ts +29 -0
- package/src/components/repeat/helpers.ts +68 -0
- package/src/components/repeat/repeat-controls.component.tsx +38 -0
- package/src/components/repeat/repeat-controls.scss +7 -0
- package/src/components/repeat/repeat.component.tsx +201 -0
- package/src/components/repeat/repeat.scss +30 -0
- package/src/components/repeat/repeat.test.ts +29 -0
- package/src/components/sidebar/sidebar.component.tsx +134 -0
- package/src/components/sidebar/sidebar.scss +121 -0
- package/src/components/value/value.component.tsx +27 -0
- package/src/components/value/value.scss +17 -0
- package/src/components/value/view/field-value-view.component.tsx +33 -0
- package/src/components/value/view/field-value-view.scss +31 -0
- package/src/constants.ts +12 -0
- package/src/datasources/concept-data-source.ts +42 -0
- package/src/datasources/data-source.ts +23 -0
- package/src/datasources/encounter-role-datasource.ts +15 -0
- package/src/datasources/historical-data-source.ts +11 -0
- package/src/datasources/location-data-source.ts +27 -0
- package/src/datasources/provider-datasource.ts +15 -0
- package/src/datasources/select-concept-answers-datasource.ts +15 -0
- package/src/declarations.d.ts +4 -0
- package/src/external-function-context.tsx +8 -0
- package/src/form-context.tsx +42 -0
- package/src/form-engine.component.tsx +178 -0
- package/src/form-engine.scss +140 -0
- package/src/form-engine.test.tsx +817 -0
- package/src/globals.ts +1 -0
- package/src/hooks/useClobData.tsx +21 -0
- package/src/hooks/useConcepts.tsx +55 -0
- package/src/hooks/useDatasourceDependentValue.ts +16 -0
- package/src/hooks/useEncounter.tsx +32 -0
- package/src/hooks/useEncounterRole.tsx +15 -0
- package/src/hooks/useEvaluateFormFieldExpressions.ts +138 -0
- package/src/hooks/useFieldValidationResults.ts +18 -0
- package/src/hooks/useFormCollapse.tsx +36 -0
- package/src/hooks/useFormFieldValidators.ts +22 -0
- package/src/hooks/useFormFieldValueAdapters.ts +24 -0
- package/src/hooks/useFormFields.ts +37 -0
- package/src/hooks/useFormFieldsMeta.ts +48 -0
- package/src/hooks/useFormJson.test.tsx +173 -0
- package/src/hooks/useFormJson.tsx +237 -0
- package/src/hooks/useFormStateHelpers.ts +50 -0
- package/src/hooks/useFormsConfig.tsx +27 -0
- package/src/hooks/useInitialValues.ts +38 -0
- package/src/hooks/usePatientData.tsx +32 -0
- package/src/hooks/usePatientPrograms.ts +32 -0
- package/src/hooks/usePostSubmissionActions.test.tsx +42 -0
- package/src/hooks/usePostSubmissionActions.ts +31 -0
- package/src/hooks/useProcessorDependencies.ts +30 -0
- package/src/hooks/useRestMaxResultsCount.ts +5 -0
- package/src/hooks/useSystemSetting.ts +36 -0
- package/src/hooks/useWorkspaceLayout.ts +29 -0
- package/src/index.ts +12 -0
- package/src/lifecycle.ts +33 -0
- package/src/post-submission-actions/program-enrollment-action.ts +138 -0
- package/src/processors/encounter/encounter-form-processor.ts +337 -0
- package/src/processors/encounter/encounter-processor-helper.ts +320 -0
- package/src/processors/form-processor.ts +41 -0
- package/src/provider/form-factory-helper.ts +100 -0
- package/src/provider/form-factory-provider.tsx +169 -0
- package/src/provider/form-provider.tsx +37 -0
- package/src/registry/inbuilt-components/InbuiltPostSubmissionActions.ts +9 -0
- package/src/registry/inbuilt-components/control-templates.ts +57 -0
- package/src/registry/inbuilt-components/inbuiltControls.ts +99 -0
- package/src/registry/inbuilt-components/inbuiltDataSources.ts +41 -0
- package/src/registry/inbuilt-components/inbuiltFieldValueAdapters.ts +64 -0
- package/src/registry/inbuilt-components/inbuiltTransformers.ts +10 -0
- package/src/registry/inbuilt-components/inbuiltValidators.ts +33 -0
- package/src/registry/inbuilt-components/template-component-map.ts +28 -0
- package/src/registry/registry.test.ts +20 -0
- package/src/registry/registry.ts +261 -0
- package/src/routes.json +1 -0
- package/src/setupI18n.ts +16 -0
- package/src/setupTests.ts +5 -0
- package/src/transformers/default-schema-transformer.test.ts +155 -0
- package/src/transformers/default-schema-transformer.ts +239 -0
- package/src/types/domain.ts +129 -0
- package/src/types/index.ts +130 -0
- package/src/types/schema.ts +238 -0
- package/src/typings.d.ts +9 -0
- package/src/utils/boolean-utils.ts +25 -0
- package/src/utils/common-expression-helpers.ts +503 -0
- package/src/utils/common-utils.test.ts +136 -0
- package/src/utils/common-utils.ts +55 -0
- package/src/utils/error-utils.ts +37 -0
- package/src/utils/expression-parser.test.ts +308 -0
- package/src/utils/expression-parser.ts +158 -0
- package/src/utils/expression-runner.test.ts +387 -0
- package/src/utils/expression-runner.ts +219 -0
- package/src/utils/form-helper.test.ts +482 -0
- package/src/utils/form-helper.ts +210 -0
- package/src/utils/form-page-utils.ts +13 -0
- package/src/utils/forms-loader.test.ts +323 -0
- package/src/utils/forms-loader.ts +306 -0
- package/src/utils/post-submission-action-helper.ts +71 -0
- package/src/utils/test-utils.ts +54 -0
- package/src/utils/zscore-service.ts +59 -0
- package/src/validators/conditional-answered-validator.test.ts +61 -0
- package/src/validators/conditional-answered-validator.ts +17 -0
- package/src/validators/date-validator.test.ts +46 -0
- package/src/validators/date-validator.ts +19 -0
- package/src/validators/default-value-validator.test.ts +90 -0
- package/src/validators/default-value-validator.ts +36 -0
- package/src/validators/form-validator.test.ts +188 -0
- package/src/validators/form-validator.ts +95 -0
- package/src/validators/js-expression-validator.test.ts +118 -0
- package/src/validators/js-expression-validator.ts +44 -0
- package/src/validators/schema.ts +34 -0
- package/src/zscore/bfa_boys_5_above.json +2522 -0
- package/src/zscore/bfa_girls_5_above.json +2522 -0
- package/src/zscore/hfa_boys_5_above.json +2186 -0
- package/src/zscore/hfa_boys_below5.json +22286 -0
- package/src/zscore/hfa_girls_5_above.json +2186 -0
- package/src/zscore/hfa_girls_below5.json +22286 -0
- package/src/zscore/wfl_boys_below5.json +7814 -0
- package/src/zscore/wfl_girls_below5.json +7814 -0
- package/src/zscore-tests/bmi-age.test.tsx +88 -0
- package/src/zscore-tests/height-age.test.tsx +96 -0
- package/src/zscore-tests/weight-height.test.tsx +87 -0
- package/tools/i18next-parser.config.js +93 -0
- package/translations/en.json +47 -0
- package/translations/es.json +38 -0
- package/translations/fr.json +38 -0
- package/translations/km.json +38 -0
- package/tsconfig.json +19 -0
- package/turbo.json +15 -0
- package/webpack.config.js +1 -0
@@ -0,0 +1,237 @@
|
|
1
|
+
import { useEffect, useState } from 'react';
|
2
|
+
import { type FormSchemaTransformer, type FormSchema, type FormSection, type ReferencedForm } from '../types';
|
3
|
+
import { isTrue } from '../utils/boolean-utils';
|
4
|
+
import { applyFormIntent } from '../utils/forms-loader';
|
5
|
+
import { fetchOpenMRSForm, fetchClobData } from '../api';
|
6
|
+
import { getRegisteredFormSchemaTransformers } from '../registry/registry';
|
7
|
+
import { moduleName } from '../globals';
|
8
|
+
|
9
|
+
export function useFormJson(formUuid: string, rawFormJson: any, encounterUuid: string, formSessionIntent: string) {
|
10
|
+
const [formJson, setFormJson] = useState<FormSchema>(null);
|
11
|
+
const [error, setError] = useState(validateFormsArgs(formUuid, rawFormJson));
|
12
|
+
useEffect(() => {
|
13
|
+
const setFormJsonWithTranslations = (formJson: FormSchema) => {
|
14
|
+
if (formJson?.translations) {
|
15
|
+
const language = window.i18next.language;
|
16
|
+
window.i18next.addResourceBundle(language, moduleName, formJson.translations, true, true);
|
17
|
+
}
|
18
|
+
setFormJson(formJson);
|
19
|
+
};
|
20
|
+
loadFormJson(formUuid, rawFormJson, formSessionIntent)
|
21
|
+
.then((formJson) => {
|
22
|
+
setFormJsonWithTranslations({ ...formJson, encounter: encounterUuid });
|
23
|
+
})
|
24
|
+
.catch((error) => {
|
25
|
+
console.error(error);
|
26
|
+
setError(new Error('Error loading form JSON: ' + error.message));
|
27
|
+
});
|
28
|
+
}, [formSessionIntent, formUuid, rawFormJson, encounterUuid]);
|
29
|
+
|
30
|
+
return {
|
31
|
+
formJson,
|
32
|
+
isLoading: !formJson,
|
33
|
+
formError: error,
|
34
|
+
};
|
35
|
+
}
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Fetches a form JSON schema from OpenMRS and recursively fetches its subForms if they available.
|
39
|
+
*
|
40
|
+
* If `rawFormJson` is provided, it will be used as the raw form JSON object. Otherwise, the form JSON will be fetched from OpenMRS using the `formIdentifier` parameter.
|
41
|
+
*
|
42
|
+
* @param rawFormJson The raw form JSON object to be used if `formIdentifier` is not provided.
|
43
|
+
* @param formIdentifier The UUID or name of the form to be fetched from OpenMRS if `rawFormJson` is not provided.
|
44
|
+
* @param formSessionIntent An optional parameter that represents the current intent.
|
45
|
+
* @returns A well-built form object that might include subForms.
|
46
|
+
*/
|
47
|
+
export async function loadFormJson(
|
48
|
+
formIdentifier: string,
|
49
|
+
rawFormJson?: FormSchema,
|
50
|
+
formSessionIntent?: string,
|
51
|
+
): Promise<FormSchema> {
|
52
|
+
const openmrsFormResponse = await fetchOpenMRSForm(formIdentifier);
|
53
|
+
const clobDataResponse = await fetchClobData(openmrsFormResponse);
|
54
|
+
const transformers = await getRegisteredFormSchemaTransformers();
|
55
|
+
const formJson: FormSchema = clobDataResponse
|
56
|
+
? { ...clobDataResponse, uuid: openmrsFormResponse.uuid }
|
57
|
+
: parseFormJson(rawFormJson);
|
58
|
+
|
59
|
+
// Sub forms
|
60
|
+
const subFormRefs = extractSubFormRefs(formJson);
|
61
|
+
const subForms = await loadSubForms(subFormRefs, formSessionIntent);
|
62
|
+
updateFormJsonWithSubForms(formJson, subForms);
|
63
|
+
|
64
|
+
// Form components
|
65
|
+
const formComponentsRefs = getReferencedForms(formJson);
|
66
|
+
const resolvedFormComponents = await loadFormComponents(formComponentsRefs);
|
67
|
+
const formNameToAliasMap = formComponentsRefs.reduce((acc, form) => {
|
68
|
+
acc[form.formName] = form.alias;
|
69
|
+
return acc;
|
70
|
+
}, {});
|
71
|
+
|
72
|
+
const formComponents = mapFormComponents(resolvedFormComponents);
|
73
|
+
updateFormJsonWithComponents(formJson, formComponents, formNameToAliasMap);
|
74
|
+
return refineFormJson(formJson, transformers, formSessionIntent);
|
75
|
+
}
|
76
|
+
|
77
|
+
function extractSubFormRefs(formJson: FormSchema): string[] {
|
78
|
+
return formJson.pages
|
79
|
+
.filter((page) => page.isSubform && !page.subform.form && page.subform?.name)
|
80
|
+
.map((page) => page.subform?.name);
|
81
|
+
}
|
82
|
+
|
83
|
+
async function loadSubForms(subFormRefs: string[], formSessionIntent?: string): Promise<FormSchema[]> {
|
84
|
+
return Promise.all(subFormRefs.map((subForm) => loadFormJson(subForm, null, formSessionIntent)));
|
85
|
+
}
|
86
|
+
|
87
|
+
function updateFormJsonWithSubForms(formJson: FormSchema, subForms: FormSchema[]): void {
|
88
|
+
subForms.forEach((subForm) => {
|
89
|
+
const matchingPage = formJson.pages.find((page) => page.subform?.name === subForm.name);
|
90
|
+
if (matchingPage) {
|
91
|
+
matchingPage.subform.form = subForm;
|
92
|
+
}
|
93
|
+
});
|
94
|
+
}
|
95
|
+
|
96
|
+
function validateFormsArgs(formUuid: string, rawFormJson: any): Error {
|
97
|
+
if (!formUuid && !rawFormJson) {
|
98
|
+
return new Error('InvalidArgumentsErr: Neither formUuid nor formJson was provided');
|
99
|
+
}
|
100
|
+
if (formUuid && rawFormJson) {
|
101
|
+
return new Error('InvalidArgumentsErr: Both formUuid and formJson cannot be provided at the same time.');
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
/**
|
106
|
+
* Refines the input form JSON object by parsing it, removing inline sub forms, applying form schema transformers, setting the encounter type, and applying form intents if provided.
|
107
|
+
* @param {any} formJson - The input form JSON object or string.
|
108
|
+
* @param {string} [formSessionIntent] - The optional form session intent.
|
109
|
+
* @returns {FormSchema} - The refined form JSON object of type FormSchema.
|
110
|
+
*/
|
111
|
+
function refineFormJson(
|
112
|
+
formJson: any,
|
113
|
+
schemaTransformers: FormSchemaTransformer[] = [],
|
114
|
+
formSessionIntent?: string,
|
115
|
+
): FormSchema {
|
116
|
+
removeInlineSubForms(formJson, formSessionIntent);
|
117
|
+
// apply form schema transformers
|
118
|
+
schemaTransformers.reduce((draftForm, transformer) => transformer.transform(draftForm), formJson);
|
119
|
+
setEncounterType(formJson);
|
120
|
+
return applyFormIntent(formSessionIntent, formJson);
|
121
|
+
}
|
122
|
+
|
123
|
+
/**
|
124
|
+
* Parses the input form JSON and returns a deep copy of the object.
|
125
|
+
* @param {any} formJson - The input form JSON object or string.
|
126
|
+
* @returns {FormSchema} - The parsed form JSON object of type FormSchema.
|
127
|
+
*/
|
128
|
+
function parseFormJson(formJson: any): FormSchema {
|
129
|
+
return typeof formJson === 'string' ? JSON.parse(formJson) : JSON.parse(JSON.stringify(formJson));
|
130
|
+
}
|
131
|
+
|
132
|
+
/**
|
133
|
+
* Removes inline sub forms from the form JSON and replaces them with their pages if the encounter type matches.
|
134
|
+
* @param {FormSchema} formJson - The input form JSON object of type FormSchema.
|
135
|
+
* @param {string} formSessionIntent - The form session intent.
|
136
|
+
*/
|
137
|
+
function removeInlineSubForms(formJson: FormSchema, formSessionIntent: string): void {
|
138
|
+
for (let i = formJson.pages.length - 1; i >= 0; i--) {
|
139
|
+
const page = formJson.pages[i];
|
140
|
+
if (
|
141
|
+
isTrue(page.isSubform) &&
|
142
|
+
!isTrue(page.isHidden) &&
|
143
|
+
page.subform?.form?.encounterType === formJson.encounterType
|
144
|
+
) {
|
145
|
+
const nonSubformPages = page.subform.form.pages.filter((page) => !isTrue(page.isSubform));
|
146
|
+
formJson.pages.splice(i, 1, ...refineFormJson(page.subform.form, [], formSessionIntent).pages);
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
/**
|
152
|
+
* Sets the encounter type for the form JSON if it's provided through the `encounter` attribute.
|
153
|
+
* @param {FormSchema} formJson - The input form JSON object of type FormSchema.
|
154
|
+
*/
|
155
|
+
function setEncounterType(formJson: FormSchema): void {
|
156
|
+
if (formJson.encounter && typeof formJson.encounter === 'string' && !formJson.encounterType) {
|
157
|
+
formJson.encounterType = formJson.encounter;
|
158
|
+
delete formJson.encounter;
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
/**
|
163
|
+
* Functions to support reusable Form Components
|
164
|
+
*/
|
165
|
+
function getReferencedForms(formJson: FormSchema): Array<ReferencedForm> {
|
166
|
+
const referencedForms: Array<any> = formJson?.referencedForms;
|
167
|
+
if (!referencedForms) {
|
168
|
+
return [];
|
169
|
+
}
|
170
|
+
return referencedForms;
|
171
|
+
}
|
172
|
+
|
173
|
+
async function loadFormComponents(formComponentRefs: Array<ReferencedForm>): Promise<FormSchema[]> {
|
174
|
+
return Promise.all(formComponentRefs.map((formComponent) => loadFormJson(formComponent.formName, null, null)));
|
175
|
+
}
|
176
|
+
|
177
|
+
function mapFormComponents(formComponents: Array<FormSchema>): Map<string, FormSchema> {
|
178
|
+
const formComponentsMap: Map<string, FormSchema> = new Map();
|
179
|
+
|
180
|
+
formComponents.forEach((formComponent) => {
|
181
|
+
formComponentsMap.set(formComponent.name, formComponent);
|
182
|
+
});
|
183
|
+
|
184
|
+
return formComponentsMap;
|
185
|
+
}
|
186
|
+
|
187
|
+
function updateFormJsonWithComponents(
|
188
|
+
formJson: FormSchema,
|
189
|
+
formComponents: Map<string, FormSchema>,
|
190
|
+
formNameToAliasMap: Record<string, string>,
|
191
|
+
): void {
|
192
|
+
formComponents.forEach((component, targetFormName) => {
|
193
|
+
//loop through pages and search sections for reference key
|
194
|
+
formJson.pages.forEach((page) => {
|
195
|
+
if (page.sections) {
|
196
|
+
page.sections.forEach((section) => {
|
197
|
+
if (
|
198
|
+
section.reference &&
|
199
|
+
(section.reference.form === targetFormName || section.reference.form === formNameToAliasMap[targetFormName])
|
200
|
+
) {
|
201
|
+
// resolve referenced component section
|
202
|
+
let resolvedFormSection = getReferencedFormSection(section, component);
|
203
|
+
// add resulting referenced component section to section
|
204
|
+
Object.assign(section, resolvedFormSection);
|
205
|
+
}
|
206
|
+
});
|
207
|
+
}
|
208
|
+
});
|
209
|
+
});
|
210
|
+
}
|
211
|
+
|
212
|
+
function getReferencedFormSection(formSection: FormSection, formComponent: FormSchema): FormSection {
|
213
|
+
let referencedFormSection: FormSection;
|
214
|
+
|
215
|
+
// search for component page and section reference from component
|
216
|
+
let matchingComponentPage = formComponent.pages.filter((page) => page.label === formSection.reference.page);
|
217
|
+
if (matchingComponentPage.length > 0) {
|
218
|
+
let matchingComponentSection = matchingComponentPage[0].sections.filter(
|
219
|
+
(componentSection) => componentSection.label === formSection.reference.section,
|
220
|
+
);
|
221
|
+
if (matchingComponentSection.length > 0) {
|
222
|
+
referencedFormSection = matchingComponentSection[0];
|
223
|
+
}
|
224
|
+
}
|
225
|
+
|
226
|
+
return filterExcludedQuestions(referencedFormSection, formSection.reference);
|
227
|
+
}
|
228
|
+
|
229
|
+
function filterExcludedQuestions(formSection: FormSection, reference: any): FormSection {
|
230
|
+
if (reference?.excludeQuestions) {
|
231
|
+
const excludeQuestions = reference.excludeQuestions;
|
232
|
+
formSection.questions = formSection.questions.filter((question) => {
|
233
|
+
return !excludeQuestions.includes(question.id);
|
234
|
+
});
|
235
|
+
}
|
236
|
+
return formSection;
|
237
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import { type Dispatch, useCallback } from 'react';
|
2
|
+
import { type FormSchema, type FormField } from '../types';
|
3
|
+
import { type Action } from '../components/renderer/form/state';
|
4
|
+
|
5
|
+
export function useFormStateHelpers(dispatch: Dispatch<Action>, formFields: FormField[]) {
|
6
|
+
const addFormField = useCallback((field: FormField) => {
|
7
|
+
dispatch({ type: 'ADD_FORM_FIELD', value: field });
|
8
|
+
}, []);
|
9
|
+
const updateFormField = useCallback((field: FormField) => {
|
10
|
+
dispatch({ type: 'UPDATE_FORM_FIELD', value: field });
|
11
|
+
}, []);
|
12
|
+
|
13
|
+
const getFormField = useCallback(
|
14
|
+
(fieldId: string) => {
|
15
|
+
return formFields.find((field) => field.id === fieldId);
|
16
|
+
},
|
17
|
+
[formFields.length],
|
18
|
+
);
|
19
|
+
|
20
|
+
const removeFormField = useCallback((fieldId: string) => {
|
21
|
+
dispatch({ type: 'REMOVE_FORM_FIELD', value: fieldId });
|
22
|
+
}, []);
|
23
|
+
|
24
|
+
const setInvalidFields = useCallback((fields: FormField[]) => {
|
25
|
+
dispatch({ type: 'SET_INVALID_FIELDS', value: fields });
|
26
|
+
}, []);
|
27
|
+
|
28
|
+
const addInvalidField = useCallback((field: FormField) => {
|
29
|
+
dispatch({ type: 'ADD_INVALID_FIELD', value: field });
|
30
|
+
}, []);
|
31
|
+
|
32
|
+
const removeInvalidField = useCallback((fieldId: string) => {
|
33
|
+
dispatch({ type: 'REMOVE_INVALID_FIELD', value: fieldId });
|
34
|
+
}, []);
|
35
|
+
|
36
|
+
const setForm = useCallback((formJson: FormSchema) => {
|
37
|
+
dispatch({ type: 'SET_FORM_JSON', value: formJson });
|
38
|
+
}, []);
|
39
|
+
|
40
|
+
return {
|
41
|
+
addFormField,
|
42
|
+
updateFormField,
|
43
|
+
getFormField,
|
44
|
+
removeFormField,
|
45
|
+
setInvalidFields,
|
46
|
+
addInvalidField,
|
47
|
+
removeInvalidField,
|
48
|
+
setForm,
|
49
|
+
};
|
50
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { useEffect, useState } from 'react';
|
2
|
+
import get from 'lodash-es/get';
|
3
|
+
import { getConfig } from '@openmrs/esm-framework';
|
4
|
+
import { ConceptTrue, ConceptFalse } from '../constants';
|
5
|
+
|
6
|
+
export interface FormsConfig {
|
7
|
+
conceptTrue: string;
|
8
|
+
conceptFalse: string;
|
9
|
+
}
|
10
|
+
const defaultOptions: FormsConfig = {
|
11
|
+
conceptTrue: ConceptTrue,
|
12
|
+
conceptFalse: ConceptFalse,
|
13
|
+
};
|
14
|
+
|
15
|
+
export function useFormsConfig(moduleName: string, configPath: string) {
|
16
|
+
const [config, setConfig] = useState<FormsConfig>(defaultOptions);
|
17
|
+
|
18
|
+
useEffect(() => {
|
19
|
+
if (moduleName && configPath) {
|
20
|
+
getConfig(moduleName).then((c) => {
|
21
|
+
setConfig({ config, ...get(c, configPath, config) });
|
22
|
+
});
|
23
|
+
}
|
24
|
+
}, [moduleName, configPath, config]);
|
25
|
+
|
26
|
+
return config;
|
27
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import { useEffect, useState } from 'react';
|
2
|
+
import { type FormProcessorContextProps } from '../types';
|
3
|
+
import { type FormProcessor } from '../processors/form-processor';
|
4
|
+
|
5
|
+
const useInitialValues = (
|
6
|
+
formProcessor: FormProcessor,
|
7
|
+
isLoadingContextDependencies: boolean,
|
8
|
+
context: FormProcessorContextProps,
|
9
|
+
) => {
|
10
|
+
const [isLoadingInitialValues, setIsLoadingInitialValues] = useState(true);
|
11
|
+
const [initialValues, setInitialValues] = useState({});
|
12
|
+
const [error, setError] = useState(null);
|
13
|
+
|
14
|
+
useEffect(() => {
|
15
|
+
if (
|
16
|
+
formProcessor &&
|
17
|
+
!isLoadingContextDependencies &&
|
18
|
+
context.formFields?.length &&
|
19
|
+
Object.keys(context.formFieldAdapters).length &&
|
20
|
+
!Object.keys(initialValues).length
|
21
|
+
) {
|
22
|
+
formProcessor
|
23
|
+
.getInitialValues(context)
|
24
|
+
.then((values) => {
|
25
|
+
setInitialValues(values);
|
26
|
+
setIsLoadingInitialValues(false);
|
27
|
+
})
|
28
|
+
.catch((error) => {
|
29
|
+
console.error(error);
|
30
|
+
setError(error);
|
31
|
+
});
|
32
|
+
}
|
33
|
+
}, [formProcessor, isLoadingContextDependencies, context]);
|
34
|
+
|
35
|
+
return { isLoadingInitialValues, initialValues, error };
|
36
|
+
};
|
37
|
+
|
38
|
+
export default useInitialValues;
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { usePatient } from '@openmrs/esm-framework';
|
2
|
+
|
3
|
+
function calculateAge(birthDate: Date): number {
|
4
|
+
const today = new Date();
|
5
|
+
const yearsDiff = today.getFullYear() - birthDate.getFullYear();
|
6
|
+
if (
|
7
|
+
today.getMonth() < birthDate.getMonth() ||
|
8
|
+
(today.getMonth() === birthDate.getMonth() && today.getDate() < birthDate.getDate())
|
9
|
+
) {
|
10
|
+
// subtract one year if the current date is before the birth date this year
|
11
|
+
return yearsDiff - 1;
|
12
|
+
} else {
|
13
|
+
return yearsDiff;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
const patientGenderMap = {
|
18
|
+
female: 'F',
|
19
|
+
male: 'M',
|
20
|
+
other: 'O',
|
21
|
+
unknown: 'U',
|
22
|
+
};
|
23
|
+
|
24
|
+
export const usePatientData = (patientUuid) => {
|
25
|
+
const { patient, isLoading: isLoadingPatient, error: patientError } = usePatient(patientUuid);
|
26
|
+
if (patient && !isLoadingPatient) {
|
27
|
+
// This is to support backward compatibility with the AMPATH JSON format
|
28
|
+
patient['age'] = calculateAge(new Date(patient?.birthDate));
|
29
|
+
patient['sex'] = patientGenderMap[patient.gender] ?? 'U';
|
30
|
+
}
|
31
|
+
return { patient, isLoadingPatient, patientError };
|
32
|
+
};
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
2
|
+
import { useEffect, useState } from 'react';
|
3
|
+
import { type FormSchema, type PatientProgram } from '../types';
|
4
|
+
const customRepresentation = `custom:(uuid,display,program:(uuid,name,allWorkflows),dateEnrolled,dateCompleted,location:(uuid,display),states:(startDate,endDate,state:(uuid,name,retired,concept:(uuid),programWorkflow:(uuid)))`;
|
5
|
+
|
6
|
+
export const usePatientPrograms = (patientUuid: string, formJson: FormSchema) => {
|
7
|
+
const [patientPrograms, setPatientPrograms] = useState<Array<PatientProgram>>([]);
|
8
|
+
const [isLoading, setIsLoading] = useState(true);
|
9
|
+
const [error, setError] = useState(null);
|
10
|
+
|
11
|
+
useEffect(() => {
|
12
|
+
if (formJson.meta?.programs?.hasProgramFields) {
|
13
|
+
openmrsFetch(`${restBaseUrl}/programenrollment?patient=${patientUuid}&v=${customRepresentation}`)
|
14
|
+
.then((response) => {
|
15
|
+
setPatientPrograms(response.data.results.filter((enrollment) => enrollment.dateCompleted === null));
|
16
|
+
setIsLoading(false);
|
17
|
+
})
|
18
|
+
.catch((error) => {
|
19
|
+
setError(error);
|
20
|
+
setIsLoading(false);
|
21
|
+
});
|
22
|
+
} else {
|
23
|
+
setIsLoading(false);
|
24
|
+
}
|
25
|
+
}, [formJson]);
|
26
|
+
|
27
|
+
return {
|
28
|
+
patientPrograms,
|
29
|
+
error,
|
30
|
+
isLoading,
|
31
|
+
};
|
32
|
+
};
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { renderHook, act } from '@testing-library/react';
|
2
|
+
import { usePostSubmissionActions } from './usePostSubmissionActions';
|
3
|
+
|
4
|
+
// Mock the getRegisteredPostSubmissionAction function
|
5
|
+
jest.mock('../registry/registry', () => ({
|
6
|
+
getRegisteredPostSubmissionAction: jest.fn(),
|
7
|
+
}));
|
8
|
+
|
9
|
+
describe('usePostSubmissionActions', () => {
|
10
|
+
// Mock the actual post-submission action function
|
11
|
+
const mockPostAction = jest.fn();
|
12
|
+
|
13
|
+
// Sample action references
|
14
|
+
const actionRefs = [
|
15
|
+
{ actionId: 'action1', config: { param1: 'value1' } },
|
16
|
+
{ actionId: 'action2', config: { param2: 'value2' } },
|
17
|
+
];
|
18
|
+
|
19
|
+
// Set up the mock implementation for getRegisteredPostSubmissionAction
|
20
|
+
beforeEach(() => {
|
21
|
+
jest.clearAllMocks();
|
22
|
+
jest.spyOn(global.console, 'error').mockImplementation(() => {});
|
23
|
+
jest.requireMock('../registry/registry').getRegisteredPostSubmissionAction.mockImplementation((actionId) => {
|
24
|
+
if (actionId === 'action1') {
|
25
|
+
return Promise.resolve(mockPostAction);
|
26
|
+
}
|
27
|
+
return Promise.resolve(null);
|
28
|
+
});
|
29
|
+
});
|
30
|
+
|
31
|
+
it('should fetch post-submission actions and return them', async () => {
|
32
|
+
const { result } = renderHook(() => usePostSubmissionActions(actionRefs));
|
33
|
+
|
34
|
+
// Wait for the effect to complete
|
35
|
+
await act(async () => {});
|
36
|
+
|
37
|
+
expect(result.current).toEqual([
|
38
|
+
{ postAction: mockPostAction, config: { param1: 'value1' }, actionId: 'action1' },
|
39
|
+
{ postAction: null, config: { param2: 'value2' }, actionId: 'action2' },
|
40
|
+
]);
|
41
|
+
});
|
42
|
+
});
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import { useEffect, useState } from 'react';
|
2
|
+
import { getRegisteredPostSubmissionAction } from '../registry/registry';
|
3
|
+
import { type PostSubmissionAction } from '../types';
|
4
|
+
|
5
|
+
export interface PostSubmissionActionMeta {
|
6
|
+
postAction: PostSubmissionAction;
|
7
|
+
actionId: string;
|
8
|
+
config: Record<string, any>;
|
9
|
+
enabled?: string;
|
10
|
+
}
|
11
|
+
|
12
|
+
export function usePostSubmissionActions(
|
13
|
+
actionRefs: Array<{ actionId: string; enabled?: string; config?: Record<string, any> }>,
|
14
|
+
): Array<PostSubmissionActionMeta> {
|
15
|
+
const [actions, setActions] = useState<Array<PostSubmissionActionMeta>>([]);
|
16
|
+
|
17
|
+
useEffect(() => {
|
18
|
+
const actionArray: Array<PostSubmissionActionMeta> = [];
|
19
|
+
if (actionRefs?.length) {
|
20
|
+
actionRefs.map((ref) => {
|
21
|
+
const actionId = typeof ref === 'string' ? ref : ref.actionId;
|
22
|
+
getRegisteredPostSubmissionAction(actionId)?.then((action) =>
|
23
|
+
actionArray.push({ postAction: action, config: ref.config, actionId: actionId, enabled: ref.enabled }),
|
24
|
+
);
|
25
|
+
});
|
26
|
+
}
|
27
|
+
setActions(actionArray);
|
28
|
+
}, [actionRefs]);
|
29
|
+
|
30
|
+
return actions;
|
31
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { useState, useEffect } from 'react';
|
2
|
+
import { type FormProcessorContextProps } from '../types';
|
3
|
+
import { type FormProcessor } from '../processors/form-processor';
|
4
|
+
|
5
|
+
const useProcessorDependencies = (
|
6
|
+
formProcessor: FormProcessor,
|
7
|
+
context: Partial<FormProcessorContextProps>,
|
8
|
+
setContext: (context: FormProcessorContextProps) => void,
|
9
|
+
) => {
|
10
|
+
const [isLoading, setIsLoading] = useState(false);
|
11
|
+
const [error, setError] = useState('');
|
12
|
+
const { loadDependencies } = formProcessor;
|
13
|
+
|
14
|
+
useEffect(() => {
|
15
|
+
if (loadDependencies) {
|
16
|
+
setIsLoading(true);
|
17
|
+
loadDependencies(context, setContext)
|
18
|
+
.then((results) => {
|
19
|
+
setIsLoading(false);
|
20
|
+
})
|
21
|
+
.catch((error) => {
|
22
|
+
setError(error);
|
23
|
+
});
|
24
|
+
}
|
25
|
+
}, []);
|
26
|
+
|
27
|
+
return { isLoading, error };
|
28
|
+
};
|
29
|
+
|
30
|
+
export default useProcessorDependencies;
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import { openmrsFetch, restBaseUrl, showSnackbar } from '@openmrs/esm-framework';
|
2
|
+
import { useEffect } from 'react';
|
3
|
+
import { useTranslation } from 'react-i18next';
|
4
|
+
import useSWRImmutable from 'swr/immutable';
|
5
|
+
|
6
|
+
export interface SystemSetting {
|
7
|
+
uuid: string;
|
8
|
+
property: string;
|
9
|
+
value: string;
|
10
|
+
}
|
11
|
+
|
12
|
+
export default function useSystemSetting(setting: string) {
|
13
|
+
const { t } = useTranslation();
|
14
|
+
const apiUrl = `${restBaseUrl}/systemsetting/${setting}?v=custom:(value)`;
|
15
|
+
const { data, error, isLoading } = useSWRImmutable<{ data: SystemSetting }, Error>(apiUrl, openmrsFetch);
|
16
|
+
|
17
|
+
useEffect(() => {
|
18
|
+
if (error) {
|
19
|
+
showSnackbar({
|
20
|
+
title: t('error', 'Error'),
|
21
|
+
subtitle: error?.message,
|
22
|
+
kind: 'error',
|
23
|
+
isLowContrast: false,
|
24
|
+
});
|
25
|
+
}
|
26
|
+
}, [error]);
|
27
|
+
|
28
|
+
return {
|
29
|
+
systemSetting: data?.data,
|
30
|
+
error: error,
|
31
|
+
isLoading: isLoading,
|
32
|
+
isValueUuid:
|
33
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(data?.data?.value) ||
|
34
|
+
/^[0-9a-f]{36}$/i.test(data?.data?.value),
|
35
|
+
};
|
36
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import { useLayoutEffect, useState } from 'react';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* This hook evaluates the layout of the current workspace based on the width of the container element
|
5
|
+
*/
|
6
|
+
export function useWorkspaceLayout(rootRef): 'minimized' | 'maximized' {
|
7
|
+
const [layout, setLayout] = useState<'minimized' | 'maximized'>('minimized');
|
8
|
+
const TABLET_MAX = 1023;
|
9
|
+
useLayoutEffect(() => {
|
10
|
+
const handleResize = () => {
|
11
|
+
const containerWidth = rootRef.current?.parentElement?.offsetWidth;
|
12
|
+
containerWidth && setLayout(containerWidth > TABLET_MAX ? 'maximized' : 'minimized');
|
13
|
+
};
|
14
|
+
handleResize();
|
15
|
+
const resizeObserver = new ResizeObserver((entries) => {
|
16
|
+
handleResize();
|
17
|
+
});
|
18
|
+
|
19
|
+
if (rootRef.current) {
|
20
|
+
resizeObserver.observe(rootRef.current?.parentElement);
|
21
|
+
}
|
22
|
+
|
23
|
+
return () => {
|
24
|
+
resizeObserver.disconnect();
|
25
|
+
};
|
26
|
+
}, [rootRef]);
|
27
|
+
|
28
|
+
return layout;
|
29
|
+
}
|
package/src/index.ts
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
export * from './types';
|
2
|
+
export * from './utils/forms-loader';
|
3
|
+
export * from './registry/registry';
|
4
|
+
export * from './constants';
|
5
|
+
export * from './utils/boolean-utils';
|
6
|
+
export * from './validators/form-validator';
|
7
|
+
export * from './utils/form-helper';
|
8
|
+
export * from './form-context';
|
9
|
+
export * from './components/value/view/field-value-view.component';
|
10
|
+
export * from './components/previous-value-review/previous-value-review.component';
|
11
|
+
export * from './hooks/useFormJson';
|
12
|
+
export { default as FormEngine } from './form-engine.component';
|
package/src/lifecycle.ts
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
import setupFormEngineLibI18n from './setupI18n';
|
2
|
+
import { type FormFieldValueAdapter } from './types';
|
3
|
+
|
4
|
+
const formFieldAdapters = new Set<FormFieldValueAdapter>();
|
5
|
+
|
6
|
+
export function registerFormFieldAdaptersForCleanUp(formFieldAdaptersMap: Record<string, FormFieldValueAdapter>) {
|
7
|
+
if (formFieldAdaptersMap) {
|
8
|
+
Object.values(formFieldAdaptersMap).forEach((adapter) => {
|
9
|
+
formFieldAdapters.add(adapter);
|
10
|
+
});
|
11
|
+
}
|
12
|
+
}
|
13
|
+
/**
|
14
|
+
* Invoked on mounting the "FormEngine" component
|
15
|
+
*/
|
16
|
+
export function init() {
|
17
|
+
// Setting up the i18n for the form engine library
|
18
|
+
setupFormEngineLibI18n();
|
19
|
+
}
|
20
|
+
|
21
|
+
/**
|
22
|
+
* Invoked on unmounting the "FormEngine" component
|
23
|
+
*/
|
24
|
+
export function teardown() {
|
25
|
+
formFieldAdapters.forEach((adapter) => {
|
26
|
+
try {
|
27
|
+
adapter.tearDown();
|
28
|
+
} catch (error) {
|
29
|
+
// pass
|
30
|
+
}
|
31
|
+
});
|
32
|
+
formFieldAdapters.clear();
|
33
|
+
}
|