@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,57 @@
|
|
1
|
+
import { type ControlTemplate } from '../../types';
|
2
|
+
|
3
|
+
export const controlTemplates: Array<ControlTemplate> = [
|
4
|
+
{
|
5
|
+
name: 'drug',
|
6
|
+
datasource: {
|
7
|
+
name: 'drug_datasource',
|
8
|
+
config: {
|
9
|
+
class: '8d490dfc-c2cc-11de-8d13-0010c6dffd0f',
|
10
|
+
},
|
11
|
+
},
|
12
|
+
},
|
13
|
+
{
|
14
|
+
name: 'select-concept-answers',
|
15
|
+
datasource: {
|
16
|
+
name: 'select_concept_answers_datasource',
|
17
|
+
config: {
|
18
|
+
concept: '',
|
19
|
+
},
|
20
|
+
},
|
21
|
+
},
|
22
|
+
{
|
23
|
+
name: 'encounter-provider',
|
24
|
+
datasource: {
|
25
|
+
name: 'provider_datasource',
|
26
|
+
},
|
27
|
+
},
|
28
|
+
{
|
29
|
+
name: 'encounter-role',
|
30
|
+
datasource: {
|
31
|
+
name: 'encounter_role_datasource',
|
32
|
+
},
|
33
|
+
},
|
34
|
+
{
|
35
|
+
name: 'encounter-location',
|
36
|
+
datasource: {
|
37
|
+
name: 'location_datasource',
|
38
|
+
},
|
39
|
+
},
|
40
|
+
{
|
41
|
+
name: 'problem',
|
42
|
+
datasource: {
|
43
|
+
name: 'problem_datasource',
|
44
|
+
config: {
|
45
|
+
class: [
|
46
|
+
'8d4918b0-c2cc-11de-8d13-0010c6dffd0f',
|
47
|
+
'8d492954-c2cc-11de-8d13-0010c6dffd0f',
|
48
|
+
'8d492b2a-c2cc-11de-8d13-0010c6dffd0f',
|
49
|
+
],
|
50
|
+
},
|
51
|
+
},
|
52
|
+
},
|
53
|
+
];
|
54
|
+
|
55
|
+
export const getControlTemplate = (name: string) => {
|
56
|
+
return controlTemplates.find((template) => template.name === name);
|
57
|
+
};
|
@@ -0,0 +1,99 @@
|
|
1
|
+
import ObsGroup from '../../components/group/obs-group.component';
|
2
|
+
import ContentSwitcher from '../../components/inputs/content-switcher/content-switcher.component';
|
3
|
+
import DateField from '../../components/inputs/date/date.component';
|
4
|
+
import FixedValue from '../../components/inputs/fixed-value/fixed-value.component';
|
5
|
+
import Markdown from '../../components/inputs/markdown/markdown.component';
|
6
|
+
import MultiSelect from '../../components/inputs/multi-select/multi-select.component';
|
7
|
+
import NumberField from '../../components/inputs/number/number.component';
|
8
|
+
import Radio from '../../components/inputs/radio/radio.component';
|
9
|
+
import Dropdown from '../../components/inputs/select/dropdown.component';
|
10
|
+
import TextArea from '../../components/inputs/text-area/text-area.component';
|
11
|
+
import TextField from '../../components/inputs/text/text.component';
|
12
|
+
import Toggle from '../../components/inputs/toggle/toggle.component';
|
13
|
+
import UiSelectExtended from '../../components/inputs/ui-select-extended/ui-select-extended.component';
|
14
|
+
import WorkspaceLauncher from '../../components/inputs/workspace-launcher/workspace-launcher.component';
|
15
|
+
import Repeat from '../../components/repeat/repeat.component';
|
16
|
+
import File from '../../components/inputs/file/file.component';
|
17
|
+
import { type FormFieldInputProps } from '../../types';
|
18
|
+
import { type RegistryItem } from '../registry';
|
19
|
+
import { controlTemplates } from './control-templates';
|
20
|
+
import { templateToComponentMap } from './template-component-map';
|
21
|
+
|
22
|
+
/**
|
23
|
+
* @internal
|
24
|
+
*/
|
25
|
+
|
26
|
+
export const inbuiltControls: Array<RegistryItem<React.ComponentType<FormFieldInputProps>>> = [
|
27
|
+
{
|
28
|
+
name: 'text',
|
29
|
+
component: TextField,
|
30
|
+
},
|
31
|
+
{
|
32
|
+
name: 'textarea',
|
33
|
+
component: TextArea,
|
34
|
+
},
|
35
|
+
{
|
36
|
+
name: 'select',
|
37
|
+
component: Dropdown,
|
38
|
+
},
|
39
|
+
{
|
40
|
+
name: 'checkbox',
|
41
|
+
component: MultiSelect,
|
42
|
+
},
|
43
|
+
{
|
44
|
+
name: 'radio',
|
45
|
+
component: Radio,
|
46
|
+
},
|
47
|
+
{
|
48
|
+
name: 'date',
|
49
|
+
component: DateField,
|
50
|
+
},
|
51
|
+
{
|
52
|
+
name: 'datetime',
|
53
|
+
component: DateField,
|
54
|
+
},
|
55
|
+
{
|
56
|
+
name: 'number',
|
57
|
+
component: NumberField,
|
58
|
+
},
|
59
|
+
{
|
60
|
+
name: 'content-switcher',
|
61
|
+
component: ContentSwitcher,
|
62
|
+
},
|
63
|
+
{
|
64
|
+
name: 'toggle',
|
65
|
+
component: Toggle,
|
66
|
+
},
|
67
|
+
{
|
68
|
+
name: 'workspace-launcher',
|
69
|
+
component: WorkspaceLauncher,
|
70
|
+
},
|
71
|
+
{
|
72
|
+
name: 'group',
|
73
|
+
component: ObsGroup,
|
74
|
+
},
|
75
|
+
{
|
76
|
+
name: 'repeating',
|
77
|
+
component: Repeat,
|
78
|
+
},
|
79
|
+
{
|
80
|
+
name: 'markdown',
|
81
|
+
component: Markdown,
|
82
|
+
},
|
83
|
+
{
|
84
|
+
name: 'fixed-value',
|
85
|
+
component: FixedValue,
|
86
|
+
},
|
87
|
+
{
|
88
|
+
name: 'ui-select-extended',
|
89
|
+
component: UiSelectExtended,
|
90
|
+
},
|
91
|
+
{
|
92
|
+
name: 'file',
|
93
|
+
component: File,
|
94
|
+
},
|
95
|
+
...controlTemplates.map((template) => ({
|
96
|
+
name: template.name,
|
97
|
+
component: templateToComponentMap.find((component) => component.name === template.name).baseControlComponent,
|
98
|
+
})),
|
99
|
+
];
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import { type DataSource } from '../../types';
|
2
|
+
import { type RegistryItem } from '../registry';
|
3
|
+
import { ConceptDataSource } from '../../datasources/concept-data-source';
|
4
|
+
import { LocationDataSource } from '../../datasources/location-data-source';
|
5
|
+
import { ProviderDataSource } from '../../datasources/provider-datasource';
|
6
|
+
import { SelectConceptAnswersDatasource } from '../../datasources/select-concept-answers-datasource';
|
7
|
+
import { EncounterRoleDataSource } from '../../datasources/encounter-role-datasource';
|
8
|
+
|
9
|
+
/**
|
10
|
+
* @internal
|
11
|
+
*/
|
12
|
+
export const inbuiltDataSources: Array<RegistryItem<DataSource<any>>> = [
|
13
|
+
{
|
14
|
+
name: 'location_datasource',
|
15
|
+
component: new LocationDataSource(),
|
16
|
+
},
|
17
|
+
{
|
18
|
+
name: 'drug_datasource',
|
19
|
+
component: new ConceptDataSource(),
|
20
|
+
},
|
21
|
+
{
|
22
|
+
name: 'problem_datasource',
|
23
|
+
component: new ConceptDataSource(),
|
24
|
+
},
|
25
|
+
{
|
26
|
+
name: 'select_concept_answers_datasource',
|
27
|
+
component: new SelectConceptAnswersDatasource(),
|
28
|
+
},
|
29
|
+
{
|
30
|
+
name: 'provider_datasource',
|
31
|
+
component: new ProviderDataSource(),
|
32
|
+
},
|
33
|
+
{
|
34
|
+
name: 'encounter_role_datasource',
|
35
|
+
component: new EncounterRoleDataSource(),
|
36
|
+
},
|
37
|
+
];
|
38
|
+
|
39
|
+
export const validateInbuiltDatasource = (name: string) => {
|
40
|
+
return inbuiltDataSources.some((datasource) => datasource.name === name);
|
41
|
+
};
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import { type RegistryItem } from '../..';
|
2
|
+
import { ControlAdapter } from '../../adapters/control-adapter';
|
3
|
+
import { EncounterDatetimeAdapter } from '../../adapters/encounter-datetime-adapter';
|
4
|
+
import { EncounterLocationAdapter } from '../../adapters/encounter-location-adapter';
|
5
|
+
import { EncounterProviderAdapter } from '../../adapters/encounter-provider-adapter';
|
6
|
+
import { EncounterRoleAdapter } from '../../adapters/encounter-role-adapter';
|
7
|
+
import { InlineDateAdapter } from '../../adapters/inline-date-adapter';
|
8
|
+
import { ObsAdapter } from '../../adapters/obs-adapter';
|
9
|
+
import { ObsCommentAdapter } from '../../adapters/obs-comment-adapter';
|
10
|
+
import { OrdersAdapter } from '../../adapters/orders-adapter';
|
11
|
+
import { PatientIdentifierAdapter } from '../../adapters/patient-identifier-adapter';
|
12
|
+
import { ProgramStateAdapter } from '../../adapters/program-state-adapter';
|
13
|
+
import { type FormFieldValueAdapter } from '../../types';
|
14
|
+
|
15
|
+
export const inbuiltFieldValueAdapters: RegistryItem<FormFieldValueAdapter>[] = [
|
16
|
+
{
|
17
|
+
type: 'obs',
|
18
|
+
component: ObsAdapter,
|
19
|
+
},
|
20
|
+
{
|
21
|
+
type: 'control',
|
22
|
+
component: ControlAdapter,
|
23
|
+
},
|
24
|
+
{
|
25
|
+
type: 'obsGroup',
|
26
|
+
component: ObsAdapter,
|
27
|
+
},
|
28
|
+
{
|
29
|
+
type: 'testOrder',
|
30
|
+
component: OrdersAdapter,
|
31
|
+
},
|
32
|
+
{
|
33
|
+
type: 'programState',
|
34
|
+
component: ProgramStateAdapter,
|
35
|
+
},
|
36
|
+
{
|
37
|
+
type: 'encounterLocation',
|
38
|
+
component: EncounterLocationAdapter,
|
39
|
+
},
|
40
|
+
{
|
41
|
+
type: 'encounterProvider',
|
42
|
+
component: EncounterProviderAdapter,
|
43
|
+
},
|
44
|
+
{
|
45
|
+
type: 'encounterRole',
|
46
|
+
component: EncounterRoleAdapter,
|
47
|
+
},
|
48
|
+
{
|
49
|
+
type: 'obsComment',
|
50
|
+
component: ObsCommentAdapter,
|
51
|
+
},
|
52
|
+
{
|
53
|
+
type: 'encounterDatetime',
|
54
|
+
component: EncounterDatetimeAdapter,
|
55
|
+
},
|
56
|
+
{
|
57
|
+
type: 'inlineDate',
|
58
|
+
component: InlineDateAdapter,
|
59
|
+
},
|
60
|
+
{
|
61
|
+
type: 'patientIdentifier',
|
62
|
+
component: PatientIdentifierAdapter,
|
63
|
+
},
|
64
|
+
];
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { DefaultFormSchemaTransformer } from '../../transformers/default-schema-transformer';
|
2
|
+
import { type FormSchemaTransformer } from '../../types';
|
3
|
+
import { type RegistryItem } from '../registry';
|
4
|
+
|
5
|
+
export const inbuiltFormTransformers: Array<RegistryItem<FormSchemaTransformer>> = [
|
6
|
+
{
|
7
|
+
name: 'DefaultFormSchemaTransformer',
|
8
|
+
component: DefaultFormSchemaTransformer,
|
9
|
+
},
|
10
|
+
];
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import { conditionalAnsweredValidator } from '../../validators/conditional-answered-validator';
|
2
|
+
import { type FormFieldValidator } from '../../types';
|
3
|
+
import { DateValidator } from '../../validators/date-validator';
|
4
|
+
import { DefaultValueValidator } from '../../validators/default-value-validator';
|
5
|
+
import { FieldValidator } from '../../validators/form-validator';
|
6
|
+
import { ExpressionValidator } from '../../validators/js-expression-validator';
|
7
|
+
import { type RegistryItem } from '../registry';
|
8
|
+
|
9
|
+
/**
|
10
|
+
* @internal
|
11
|
+
*/
|
12
|
+
export const inbuiltValidators: Array<RegistryItem<FormFieldValidator>> = [
|
13
|
+
{
|
14
|
+
name: 'default_value',
|
15
|
+
component: DefaultValueValidator,
|
16
|
+
},
|
17
|
+
{
|
18
|
+
name: 'form_field',
|
19
|
+
component: FieldValidator,
|
20
|
+
},
|
21
|
+
{
|
22
|
+
name: 'date',
|
23
|
+
component: DateValidator,
|
24
|
+
},
|
25
|
+
{
|
26
|
+
name: 'js_expression',
|
27
|
+
component: ExpressionValidator,
|
28
|
+
},
|
29
|
+
{
|
30
|
+
name: 'conditionalAnswered',
|
31
|
+
component: conditionalAnsweredValidator,
|
32
|
+
},
|
33
|
+
];
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import UiSelectExtended from '../../components/inputs/ui-select-extended/ui-select-extended.component';
|
2
|
+
|
3
|
+
export const templateToComponentMap = [
|
4
|
+
{
|
5
|
+
name: 'drug',
|
6
|
+
baseControlComponent: UiSelectExtended,
|
7
|
+
},
|
8
|
+
{
|
9
|
+
name: 'problem',
|
10
|
+
baseControlComponent: UiSelectExtended,
|
11
|
+
},
|
12
|
+
{
|
13
|
+
name: 'encounter-provider',
|
14
|
+
baseControlComponent: UiSelectExtended,
|
15
|
+
},
|
16
|
+
{
|
17
|
+
name: 'encounter-location',
|
18
|
+
baseControlComponent: UiSelectExtended,
|
19
|
+
},
|
20
|
+
{
|
21
|
+
name: 'select-concept-answers',
|
22
|
+
baseControlComponent: UiSelectExtended,
|
23
|
+
},
|
24
|
+
{
|
25
|
+
name: 'encounter-role',
|
26
|
+
baseControlComponent: UiSelectExtended,
|
27
|
+
},
|
28
|
+
];
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { getRegisteredControl } from './registry';
|
2
|
+
import MultiSelect from '../components/inputs/multi-select/multi-select.component';
|
3
|
+
import Number from '../components/inputs/number/number.component';
|
4
|
+
|
5
|
+
describe.skip('registry', () => {
|
6
|
+
it('should load the NumberField component with alias "numeric"', async () => {
|
7
|
+
const result = await getRegisteredControl('numeric');
|
8
|
+
expect(result).toEqual(Number);
|
9
|
+
});
|
10
|
+
|
11
|
+
it('should load the MultiSelect component with alias "multiCheckbox"', async () => {
|
12
|
+
const result = await getRegisteredControl('multiCheckbox');
|
13
|
+
expect(result).toEqual(MultiSelect);
|
14
|
+
});
|
15
|
+
|
16
|
+
it('should return undefined if no matching component is found', async () => {
|
17
|
+
const result = await getRegisteredControl('unknown');
|
18
|
+
expect(result).toBeUndefined();
|
19
|
+
});
|
20
|
+
});
|
@@ -0,0 +1,261 @@
|
|
1
|
+
import {
|
2
|
+
type DataSource,
|
3
|
+
type FormFieldValidator,
|
4
|
+
type FormSchemaTransformer,
|
5
|
+
type PostSubmissionAction,
|
6
|
+
} from '../types';
|
7
|
+
import { getGlobalStore } from '@openmrs/esm-framework';
|
8
|
+
import { FormsStore } from '../constants';
|
9
|
+
import { inbuiltControls } from './inbuilt-components/inbuiltControls';
|
10
|
+
import { inbuiltValidators } from './inbuilt-components/inbuiltValidators';
|
11
|
+
import { inbuiltDataSources } from './inbuilt-components/inbuiltDataSources';
|
12
|
+
import { getControlTemplate } from './inbuilt-components/control-templates';
|
13
|
+
import { inbuiltPostSubmissionActions } from './inbuilt-components/InbuiltPostSubmissionActions';
|
14
|
+
import { inbuiltFormTransformers } from './inbuilt-components/inbuiltTransformers';
|
15
|
+
import { type FormFieldInputProps, type FormFieldValueAdapter } from '../types';
|
16
|
+
import { inbuiltFieldValueAdapters } from './inbuilt-components/inbuiltFieldValueAdapters';
|
17
|
+
|
18
|
+
/**
|
19
|
+
* @internal
|
20
|
+
*/
|
21
|
+
export interface RegistryItem<T> {
|
22
|
+
// Do we need this?
|
23
|
+
name?: string;
|
24
|
+
component: T;
|
25
|
+
type?: string;
|
26
|
+
/**
|
27
|
+
* @deprecated
|
28
|
+
*/
|
29
|
+
alias?: string;
|
30
|
+
}
|
31
|
+
|
32
|
+
export interface ComponentRegistration<T> {
|
33
|
+
name: string;
|
34
|
+
load: () => Promise<{ default: T }>;
|
35
|
+
}
|
36
|
+
|
37
|
+
export interface CustomControlRegistration extends ComponentRegistration<React.ComponentType<FormFieldInputProps>> {
|
38
|
+
type: string;
|
39
|
+
alias?: string;
|
40
|
+
}
|
41
|
+
|
42
|
+
export interface FieldValueAdapterRegistration extends ComponentRegistration<FormFieldValueAdapter> {
|
43
|
+
type: string;
|
44
|
+
}
|
45
|
+
|
46
|
+
export interface FormsRegistryStoreState {
|
47
|
+
controls: CustomControlRegistration[];
|
48
|
+
fieldValidators: ComponentRegistration<FormFieldValidator>[];
|
49
|
+
fieldValueAdapters: FieldValueAdapterRegistration[];
|
50
|
+
postSubmissionActions: ComponentRegistration<PostSubmissionAction>[];
|
51
|
+
dataSources: ComponentRegistration<DataSource<any>>[];
|
52
|
+
expressionHelpers: Record<string, Function>;
|
53
|
+
formSchemaTransformers: ComponentRegistration<FormSchemaTransformer>[];
|
54
|
+
}
|
55
|
+
|
56
|
+
interface FormRegistryCache {
|
57
|
+
validators: Record<string, FormFieldValidator>;
|
58
|
+
controls: Record<string, React.ComponentType<FormFieldInputProps>>;
|
59
|
+
fieldValueAdapters: Record<string, FormFieldValueAdapter>;
|
60
|
+
postSubmissionActions: Record<string, PostSubmissionAction>;
|
61
|
+
dataSources: Record<string, DataSource<any>>;
|
62
|
+
formSchemaTransformers: Record<string, FormSchemaTransformer>;
|
63
|
+
}
|
64
|
+
|
65
|
+
const registryCache: FormRegistryCache = {
|
66
|
+
validators: {},
|
67
|
+
controls: {},
|
68
|
+
fieldValueAdapters: {},
|
69
|
+
postSubmissionActions: {},
|
70
|
+
dataSources: {},
|
71
|
+
formSchemaTransformers: {},
|
72
|
+
};
|
73
|
+
|
74
|
+
// Registers
|
75
|
+
|
76
|
+
export function registerControl(registration: CustomControlRegistration) {
|
77
|
+
getFormsStore().controls.push(registration);
|
78
|
+
}
|
79
|
+
|
80
|
+
export function registerPostSubmissionAction(registration: ComponentRegistration<PostSubmissionAction>) {
|
81
|
+
getFormsStore().postSubmissionActions.push(registration);
|
82
|
+
}
|
83
|
+
|
84
|
+
export function registerFieldValueAdapter(registration: FieldValueAdapterRegistration) {
|
85
|
+
getFormsStore().fieldValueAdapters.push(registration);
|
86
|
+
}
|
87
|
+
|
88
|
+
export function registerFieldValidator(registration: ComponentRegistration<FormFieldValidator>) {
|
89
|
+
getFormsStore().fieldValidators.push(registration);
|
90
|
+
}
|
91
|
+
|
92
|
+
export function registerCustomDataSource(registration: ComponentRegistration<DataSource<any>>) {
|
93
|
+
getFormsStore().dataSources.push(registration);
|
94
|
+
}
|
95
|
+
|
96
|
+
export function registerExpressionHelper(name: string, fn: Function) {
|
97
|
+
getFormsStore().expressionHelpers[name] = fn;
|
98
|
+
}
|
99
|
+
|
100
|
+
export function registerFormSchemaTransformers(registration: ComponentRegistration<FormSchemaTransformer>) {
|
101
|
+
const store = getFormsStore();
|
102
|
+
const existingIndex = store.formSchemaTransformers.findIndex((reg) => reg.name === registration.name);
|
103
|
+
|
104
|
+
if (existingIndex !== -1) {
|
105
|
+
// If registration with the same name exists, override it
|
106
|
+
store.formSchemaTransformers[existingIndex] = registration;
|
107
|
+
} else {
|
108
|
+
store.formSchemaTransformers.push(registration);
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
// Getters
|
113
|
+
|
114
|
+
/**
|
115
|
+
* A convenience function that returns the appropriate control for a given rendering type.
|
116
|
+
*/
|
117
|
+
export async function getRegisteredControl(renderType: string) {
|
118
|
+
if (registryCache.controls[renderType]) {
|
119
|
+
return registryCache.controls[renderType];
|
120
|
+
}
|
121
|
+
let component = inbuiltControls.find(
|
122
|
+
(control) => control.name === renderType || control?.alias === renderType,
|
123
|
+
)?.component;
|
124
|
+
// if undefined, try serching through the registered custom controls
|
125
|
+
if (!component) {
|
126
|
+
const importedControl = await getFormsStore()
|
127
|
+
.controls.find((control) => control.name === renderType || control?.alias === renderType)
|
128
|
+
?.load?.();
|
129
|
+
component = importedControl?.default;
|
130
|
+
}
|
131
|
+
registryCache.controls[renderType] = component;
|
132
|
+
return component;
|
133
|
+
}
|
134
|
+
|
135
|
+
export async function getRegisteredFieldValueAdapter(type: string): Promise<FormFieldValueAdapter> {
|
136
|
+
if (registryCache.fieldValueAdapters[type]) {
|
137
|
+
return registryCache.fieldValueAdapters[type];
|
138
|
+
}
|
139
|
+
let adapter = inbuiltFieldValueAdapters.find((adapter) => adapter.type === type)?.component;
|
140
|
+
// if undefined, try searching through the registered custom handlers
|
141
|
+
if (!adapter) {
|
142
|
+
const adapterImport = await getFormsStore()
|
143
|
+
.fieldValueAdapters.find((adapter) => adapter.type === type)
|
144
|
+
?.load?.();
|
145
|
+
adapter = adapterImport?.default;
|
146
|
+
}
|
147
|
+
registryCache.fieldValueAdapters[type] = adapter;
|
148
|
+
return adapter;
|
149
|
+
}
|
150
|
+
|
151
|
+
export async function getRegisteredFormSchemaTransformers(): Promise<FormSchemaTransformer[]> {
|
152
|
+
const transformers = [];
|
153
|
+
|
154
|
+
const cachedTransformers = registryCache.formSchemaTransformers;
|
155
|
+
if (Object.keys(cachedTransformers).length) {
|
156
|
+
return Object.values(cachedTransformers);
|
157
|
+
}
|
158
|
+
|
159
|
+
const formTransformersFromStore = getFormsStore().formSchemaTransformers || [];
|
160
|
+
const customTransformers = await Promise.all(
|
161
|
+
formTransformersFromStore.map(async (transformer) => {
|
162
|
+
const transformerImport = await transformer.load?.();
|
163
|
+
return transformerImport?.default;
|
164
|
+
}),
|
165
|
+
);
|
166
|
+
transformers.push(...customTransformers.filter((transformer) => transformer !== undefined));
|
167
|
+
|
168
|
+
transformers.push(...inbuiltFormTransformers.map((inbuiltTransformer) => inbuiltTransformer.component));
|
169
|
+
|
170
|
+
transformers.forEach((transformer) => {
|
171
|
+
const inbuiltTransformer = inbuiltFormTransformers.find((t) => t.component === transformer);
|
172
|
+
registryCache.formSchemaTransformers[inbuiltTransformer.name] = transformer;
|
173
|
+
});
|
174
|
+
|
175
|
+
return transformers;
|
176
|
+
}
|
177
|
+
|
178
|
+
export async function getRegisteredPostSubmissionAction(actionId: string) {
|
179
|
+
const cachedAction = registryCache.postSubmissionActions[actionId];
|
180
|
+
if (cachedAction) {
|
181
|
+
return cachedAction;
|
182
|
+
}
|
183
|
+
|
184
|
+
const inbuiltRegistration = inbuiltPostSubmissionActions.find((registration) => registration.name === actionId);
|
185
|
+
|
186
|
+
if (inbuiltRegistration) {
|
187
|
+
const lazy = inbuiltRegistration.load;
|
188
|
+
const actionImport = await lazy();
|
189
|
+
registryCache.postSubmissionActions[actionId] = actionImport.default;
|
190
|
+
return actionImport.default;
|
191
|
+
}
|
192
|
+
|
193
|
+
const formsStoreRegistration = getFormsStore().postSubmissionActions.find(
|
194
|
+
(registration) => registration.name === actionId,
|
195
|
+
);
|
196
|
+
|
197
|
+
if (formsStoreRegistration) {
|
198
|
+
const lazy = formsStoreRegistration.load;
|
199
|
+
const actionImport = await lazy();
|
200
|
+
registryCache.postSubmissionActions[actionId] = actionImport.default;
|
201
|
+
return actionImport.default;
|
202
|
+
} else {
|
203
|
+
console.error(`No loader found for PostSubmissionAction registration of id: ${actionId}`);
|
204
|
+
}
|
205
|
+
|
206
|
+
return null;
|
207
|
+
}
|
208
|
+
|
209
|
+
export async function getRegisteredValidator(name: string): Promise<FormFieldValidator> {
|
210
|
+
if (registryCache.validators[name]) {
|
211
|
+
return registryCache.validators[name];
|
212
|
+
}
|
213
|
+
let validator = inbuiltValidators.find((validator) => validator.name === name)?.component;
|
214
|
+
if (!validator) {
|
215
|
+
const validatorImport = await getFormsStore()
|
216
|
+
.fieldValidators.find((validator) => validator.name === name)
|
217
|
+
?.load?.();
|
218
|
+
validator = validatorImport?.default;
|
219
|
+
}
|
220
|
+
registryCache.validators[name] = validator;
|
221
|
+
return validator;
|
222
|
+
}
|
223
|
+
|
224
|
+
export async function getRegisteredDataSource(name: string): Promise<DataSource<any>> {
|
225
|
+
if (registryCache.dataSources[name]) {
|
226
|
+
return registryCache.dataSources[name];
|
227
|
+
}
|
228
|
+
let ds = inbuiltDataSources.find((dataSource) => dataSource.name === name)?.component;
|
229
|
+
if (!ds) {
|
230
|
+
const template = getControlTemplate(name);
|
231
|
+
if (template) {
|
232
|
+
ds = inbuiltDataSources.find((dataSource) => dataSource.name === template.datasource.name)?.component;
|
233
|
+
} else {
|
234
|
+
const dataSourceImport = await getFormsStore()
|
235
|
+
.dataSources.find((ds) => ds.name === name)
|
236
|
+
?.load?.();
|
237
|
+
if (!dataSourceImport) {
|
238
|
+
throw new Error('Datasource not found');
|
239
|
+
}
|
240
|
+
ds = dataSourceImport.default;
|
241
|
+
}
|
242
|
+
}
|
243
|
+
registryCache.dataSources[name] = ds;
|
244
|
+
return ds;
|
245
|
+
}
|
246
|
+
|
247
|
+
export function getRegisteredExpressionHelpers() {
|
248
|
+
return getFormsStore().expressionHelpers;
|
249
|
+
}
|
250
|
+
|
251
|
+
function getFormsStore(): FormsRegistryStoreState {
|
252
|
+
return getGlobalStore<FormsRegistryStoreState>(FormsStore, {
|
253
|
+
controls: [],
|
254
|
+
postSubmissionActions: [],
|
255
|
+
expressionHelpers: {},
|
256
|
+
fieldValidators: [],
|
257
|
+
fieldValueAdapters: [],
|
258
|
+
dataSources: [],
|
259
|
+
formSchemaTransformers: [],
|
260
|
+
}).getState();
|
261
|
+
}
|
package/src/routes.json
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{}
|
package/src/setupI18n.ts
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
import { moduleName } from './globals';
|
2
|
+
|
3
|
+
function loadResourcesFromFile() {
|
4
|
+
const lang = window.i18next.language;
|
5
|
+
import(/* webpackMode: "lazy" */ `../translations/${lang}.json`)
|
6
|
+
.then((json) => {
|
7
|
+
const data = json ?? {};
|
8
|
+
window?.i18next?.addResourceBundle?.(lang, moduleName, data);
|
9
|
+
})
|
10
|
+
.catch((err) => console.error(err));
|
11
|
+
}
|
12
|
+
|
13
|
+
export default function setupFormEngineLibI18n() {
|
14
|
+
loadResourcesFromFile();
|
15
|
+
window.i18next?.on?.('languageChanged', loadResourcesFromFile);
|
16
|
+
}
|