@openmrs/esm-form-engine-lib 3.3.1-pre.2179 → 3.3.1-pre.2185

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "Visit Form",
3
+ "pages": [
4
+ {
5
+ "label": "Page 1",
6
+ "sections": [
7
+ {
8
+ "label": "Section 1",
9
+ "isExpanded": "true",
10
+ "questions": [
11
+ {
12
+ "label": "Encounter Date",
13
+ "type": "encounterDatetime",
14
+ "id": "encounterDate",
15
+ "questionOptions": {
16
+ "rendering": "date",
17
+ "calculate": {
18
+ "calculateExpression": "visit && visit?.startDatetime ? new Date(visit?.startDatetime) : null"
19
+ }
20
+ }
21
+ }
22
+ ]
23
+ }
24
+ ]
25
+ }
26
+ ],
27
+ "uuid": "form-visit-test",
28
+ "encounterType": "b9c1f50f-f77d-42e2-ad2a-d29304dde2fv"
29
+ }
@@ -40,6 +40,7 @@ export { default as uiSelectExtForm } from './sample-ui-select-ext.json';
40
40
  export { default as unspecifiedForm } from './sample-unspecified-form.json';
41
41
  export { default as viralLoadStatusForm } from './viral-load-status-form.json';
42
42
  export { default as weightForHeightZscoreTestSchema } from './zscore-weight-height-form.json';
43
+ export { default as expressionVisitObjectTestSchema } from './expression-visit-object-test.json';
43
44
 
44
45
  export { obsList } from './obs-list-data';
45
46
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-form-engine-lib",
3
- "version": "3.3.1-pre.2179",
3
+ "version": "3.3.1-pre.2185",
4
4
  "description": "React Form Engine for O3",
5
5
  "browser": "dist/openmrs-esm-form-engine-lib.js",
6
6
  "main": "src/index.ts",
@@ -19,7 +19,7 @@ export function handleFieldLogic(field: FormField, context: FormContextProps) {
19
19
  }
20
20
 
21
21
  function evaluateFieldAnswerDisabled(field: FormField, values: Record<string, any>, context: FormContextProps) {
22
- const { sessionMode, formFields, patient } = context;
22
+ const { sessionMode, formFields, patient, visit } = context;
23
23
  field.questionOptions.answers.forEach((answer) => {
24
24
  const disableExpression = answer.disable?.disableWhenExpression;
25
25
  if (disableExpression && disableExpression.includes('myValue')) {
@@ -31,6 +31,7 @@ function evaluateFieldAnswerDisabled(field: FormField, values: Record<string, an
31
31
  {
32
32
  mode: sessionMode,
33
33
  patient,
34
+ visit,
34
35
  },
35
36
  );
36
37
  }
@@ -47,6 +48,7 @@ function evaluateFieldDependents(field: FormField, values: any, context: FormCon
47
48
  methods: { setValue },
48
49
  updateFormField,
49
50
  setForm,
51
+ visit,
50
52
  } = context;
51
53
 
52
54
  let shouldUpdateForm = false;
@@ -64,6 +66,7 @@ function evaluateFieldDependents(field: FormField, values: any, context: FormCon
64
66
  {
65
67
  mode: sessionMode,
66
68
  patient,
69
+ visit,
67
70
  },
68
71
  )
69
72
  .then((result) => {
@@ -169,6 +172,7 @@ function evaluateFieldDependents(field: FormField, values: any, context: FormCon
169
172
  {
170
173
  mode: sessionMode,
171
174
  patient,
175
+ visit,
172
176
  },
173
177
  );
174
178
  });
@@ -184,6 +188,7 @@ function evaluateFieldDependents(field: FormField, values: any, context: FormCon
184
188
  {
185
189
  mode: sessionMode,
186
190
  patient,
191
+ visit,
187
192
  },
188
193
  );
189
194
  });
@@ -197,6 +202,7 @@ function evaluateFieldDependents(field: FormField, values: any, context: FormCon
197
202
  {
198
203
  mode: sessionMode,
199
204
  patient,
205
+ visit,
200
206
  },
201
207
  );
202
208
  }
@@ -210,6 +216,7 @@ function evaluateFieldDependents(field: FormField, values: any, context: FormCon
210
216
  {
211
217
  mode: sessionMode,
212
218
  patient,
219
+ visit,
213
220
  },
214
221
  );
215
222
  }
@@ -35,6 +35,7 @@ const Repeat: React.FC<FormFieldInputProps> = ({ field }) => {
35
35
  removeFormField,
36
36
  deletedFields,
37
37
  setDeletedFields,
38
+ visit,
38
39
  } = context;
39
40
 
40
41
  useEffect(() => {
@@ -61,6 +62,7 @@ const Repeat: React.FC<FormFieldInputProps> = ({ field }) => {
61
62
  {
62
63
  mode: sessionMode,
63
64
  patient: patient,
65
+ visit,
64
66
  },
65
67
  );
66
68
  }
@@ -73,6 +75,7 @@ const Repeat: React.FC<FormFieldInputProps> = ({ field }) => {
73
75
  {
74
76
  mode: sessionMode,
75
77
  patient: patient,
78
+ visit,
76
79
  },
77
80
  ).then((result) => {
78
81
  if (!isEmpty(result)) {
@@ -45,6 +45,7 @@ import {
45
45
  sampleFieldsForm,
46
46
  testEnrolmentForm,
47
47
  viralLoadStatusForm,
48
+ expressionVisitObjectTestSchema,
48
49
  } from '__mocks__/forms';
49
50
  import { type FormSchema, type OpenmrsEncounter, type SessionMode } from './types';
50
51
  import { useEncounter } from './hooks/useEncounter';
@@ -1260,6 +1261,20 @@ describe('Form engine component', () => {
1260
1261
  });
1261
1262
  });
1262
1263
  });
1264
+ describe('Form calculate expression integration', () => {
1265
+ it('should calculate encounter date from visit startDatetime', async () => {
1266
+ await act(async () => {
1267
+ return renderForm(null, expressionVisitObjectTestSchema, 'enter', 'enter', null);
1268
+ });
1269
+
1270
+ await waitFor(() => {
1271
+ const dateInput = screen.getByLabelText('Encounter Date') as HTMLInputElement;
1272
+ expect(dateInput).toBeInTheDocument();
1273
+
1274
+ expect(dateInput.value).toContain('28/07/2020');
1275
+ });
1276
+ });
1277
+ });
1263
1278
 
1264
1279
  function renderForm(formUUID, formJson, intent?: string, mode?: SessionMode, encounterUUID?: string) {
1265
1280
  render(
@@ -11,7 +11,7 @@ export const useEvaluateFormFieldExpressions = (
11
11
  formValues: Record<string, any>,
12
12
  factoryContext: FormProcessorContextProps,
13
13
  ) => {
14
- const { formFields, patient, sessionMode } = factoryContext;
14
+ const { formFields, patient, sessionMode, visit } = factoryContext;
15
15
  const [evaluatedFormJson, setEvaluatedFormJson] = useState(factoryContext.formJson);
16
16
  const [evaluatedPagesVisibility, setEvaluatedPagesVisibility] = useState(false);
17
17
 
@@ -21,6 +21,7 @@ export const useEvaluateFormFieldExpressions = (
21
21
  const runnerContext = {
22
22
  patient,
23
23
  mode: sessionMode,
24
+ visit,
24
25
  };
25
26
  // evaluate hide
26
27
  if (field.hide?.hideWhenExpression) {
@@ -330,6 +330,7 @@ export class EncounterFormProcessor extends FormProcessor {
330
330
  methods: { getValues },
331
331
  formFieldAdapters,
332
332
  previousDomainObjectValue,
333
+ visit,
333
334
  } = context;
334
335
  const node: FormNode = { value: field, type: 'field' };
335
336
  const adapter = formFieldAdapters[field.type];
@@ -338,6 +339,7 @@ export class EncounterFormProcessor extends FormProcessor {
338
339
  mode: sessionMode,
339
340
  patient: patient,
340
341
  previousEncounter: previousDomainObjectValue,
342
+ visit,
341
343
  });
342
344
  return value ? extractObsValueAndDisplay(field, value) : null;
343
345
  }
@@ -353,12 +355,13 @@ async function evaluateCalculateExpression(
353
355
  values: Record<string, any>,
354
356
  formContext: FormProcessorContextProps,
355
357
  ) {
356
- const { formFields, sessionMode, patient } = formContext;
358
+ const { formFields, sessionMode, patient, visit } = formContext;
357
359
  const expression = field.questionOptions.calculate.calculateExpression;
358
360
  const node: FormNode = { value: field, type: 'field' };
359
361
  const context = {
360
362
  mode: sessionMode,
361
363
  patient: patient,
364
+ visit,
362
365
  };
363
366
  const value = await evaluateAsyncExpression(expression, node, formFields, values, context);
364
367
  if (!isEmpty(value)) {
@@ -8,6 +8,7 @@ import {
8
8
  showSnackbar,
9
9
  showToast,
10
10
  type ToastDescriptor,
11
+ Visit,
11
12
  } from '@openmrs/esm-framework';
12
13
  import { type FormProcessorConstructor } from '../processors/form-processor';
13
14
  import { type FormContextProps } from './form-provider';
@@ -24,7 +25,7 @@ interface FormFactoryProviderContextProps {
24
25
  formProcessors: Record<string, FormProcessorConstructor>;
25
26
  layoutType: LayoutType;
26
27
  workspaceLayout: 'minimized' | 'maximized';
27
- visit: OpenmrsResource;
28
+ visit: Visit;
28
29
  location: OpenmrsResource;
29
30
  provider: OpenmrsResource;
30
31
  isFormExpanded: boolean;
@@ -42,7 +43,7 @@ interface FormFactoryProviderProps {
42
43
  workspaceLayout: 'minimized' | 'maximized';
43
44
  location: OpenmrsResource;
44
45
  provider: OpenmrsResource;
45
- visit: OpenmrsResource;
46
+ visit: Visit;
46
47
  isFormExpanded: boolean;
47
48
  children: React.ReactNode;
48
49
  formSubmissionProps: {
@@ -1,4 +1,4 @@
1
- import { type LayoutType, type OpenmrsResource } from '@openmrs/esm-framework';
1
+ import { type Visit, type LayoutType, type OpenmrsResource } from '@openmrs/esm-framework';
2
2
  import { type FormProcessor } from '../processors/form-processor';
3
3
  import { type FormContextProps } from '../provider/form-provider';
4
4
  import { type FormField, type FormSchema } from './schema';
@@ -9,7 +9,7 @@ export type SessionMode = 'edit' | 'enter' | 'view' | 'embedded-view';
9
9
  export interface FormProcessorContextProps {
10
10
  patient: fhir.Patient;
11
11
  formJson: FormSchema;
12
- visit: OpenmrsResource;
12
+ visit: Visit;
13
13
  sessionMode: SessionMode;
14
14
  sessionDate: Date;
15
15
  location: OpenmrsResource;
@@ -55,7 +55,6 @@ export function evaluateExpression(
55
55
  const compiledExpression = getExpressionAst(expression);
56
56
  // track dependencies
57
57
  trackFieldDependencies(compiledExpression, node, fields);
58
-
59
58
  try {
60
59
  return evaluateAsType(compiledExpression, getEvaluationContext(node, fields, fieldValues, context), typePredicate);
61
60
  } catch (error) {
@@ -74,6 +73,7 @@ export async function evaluateAsyncExpression(
74
73
  if (!expression?.trim()) {
75
74
  return null;
76
75
  }
76
+
77
77
  const compiledExpression = getExpressionAst(expression);
78
78
  // track dependencies
79
79
  trackFieldDependencies(compiledExpression, node, fields);
@@ -110,7 +110,8 @@ function getEvaluationContext(
110
110
  },
111
111
  });
112
112
 
113
- const visitType = context.visit?.visitType || { uuid: '' };
113
+ const visit: Visit = context?.visit ?? ({} as Visit);
114
+ const visitType = visit?.visitType || { uuid: '' };
114
115
  const visitTypeUuid = visitType.uuid ?? '';
115
116
 
116
117
  const _ = {
@@ -127,6 +128,7 @@ function getEvaluationContext(
127
128
  sex,
128
129
  age,
129
130
  HD,
131
+ visit,
130
132
  visitType,
131
133
  visitTypeUuid,
132
134
  _,
@@ -160,6 +162,7 @@ export function trackFieldDependencies(
160
162
  allFields: FormField[],
161
163
  ) {
162
164
  const variables = extractVariableNames(expression);
165
+
163
166
  for (const variable of variables) {
164
167
  const field = allFields.find((field) => field.id === variable);
165
168
  if (field) {