-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(feat) O3-3049: adding evaluated historical expression support #226
Conversation
Extends logic in this PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@arodidev can we have some unit tests coverage around this?
|
||
interface FieldComponentMap { | ||
fieldComponent: React.ComponentType<FormFieldProps>; | ||
fieldDescriptor: FormField; | ||
handler: SubmissionHandler; | ||
} | ||
|
||
const historicalValueTransformer = (field, obs) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes @samuelmale the logic exists within the handlers, although it exists as part of a greater process which we do not need much of, eg. pulling the obs from the encounter, while in our case we already have the obs to be evaluated. I think this approach would render the returned obs from the evaluated historical expression to be obsolete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you suggest modifying the handler to accomodate instances where the obs is already present?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@samuelmale I'm requesting some guidance on this before progressing, thanks.
const transformedHistoricalValue = historicalValue | ||
? historicalValueTransformer(fieldDescriptor, historicalValue) | ||
: null; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't treat the historicalValue
vs previousFieldValue
as separate things, we should instead do something like:
const previousFieldValue = !isEmpty(fieldDescriptor.historicalExpression)
? evaluatePreviousValueFromHD(fieldDescriptor.historicalExpression)
: pickPreviousValueFromEncounter(encounterContext.previousEncounter);
@@ -444,6 +444,17 @@ export class CommonExpressionHelpers { | |||
return Promise.resolve(lazy); | |||
}; | |||
} | |||
export class HistoricalDataSourceService { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move this to its own file? I also feel like it's valid to move the expression runner components out of the utils to a new folder "expression-runner".
src/utils/expression-runner.ts
Outdated
// register dependencies | ||
findAndRegisterReferencedFields(node, parts, fields); | ||
//adds values to the determinants |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need this comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will resolve
@arodidev is it possible to move this from draft? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@arodidev can you resolve the merge conflicts?
if (!isEmpty(previousValue)) { | ||
if (Array.isArray(previousValue)) { | ||
const valuesToSet = previousValue.map((eachItem) => eachItem.value); | ||
setFieldValue(question.id, valuesToSet); | ||
onChange(question.id, valuesToSet, setErrors, setWarnings); | ||
question.value = handler?.handleFieldSubmission(question, valuesToSet, encounterContext); | ||
} else { | ||
const valueToSet = [previousValue.value]; | ||
setFieldValue(question.id, valueToSet); | ||
onChange(question.id, valueToSet, setErrors, setWarnings); | ||
question.value = handler?.handleFieldSubmission(question, valueToSet, encounterContext); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To prevent the code duplication here, I would simply:
if (!isEmpty(previousValue) {
const previousValues = Array.isArray(previousValue) ? previousValue.map(item => item.value) : [previousValue.value];
// ....
}
src/components/section/helpers.ts
Outdated
default: | ||
return value?.display; | ||
} | ||
}; | ||
|
||
export const historicalValueTransformer = (field: FormField, obs: OpenmrsObs) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const refineHistoricalValue = (field: FormField, value: OpenmrsObs) => {
OR
const extractObsValueAndDisplay = (field: FormField, obs: OpenmrsObs) => {
return formatDate(new Date(value?.display)) || formatDate(value?.value); | ||
case 'checkbox': | ||
return Array.isArray(value) ? previousValueDisplayForCheckbox(value) : null; | ||
return Array.isArray(value) ? previousValueDisplayForCheckbox(value) : value.display; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to receive a null
or undefined
argument for value
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No it is not. The following evaluations need to be truthy before the component is called.
encounterContext?.previousEncounter && (previousFieldValue || historicalValue) && (isTrue(fieldDescriptor.questionOptions.enablePreviousValue) || fieldDescriptor.historicalExpression)Ï
src/utils/historical-data-source.ts
Outdated
@@ -0,0 +1,11 @@ | |||
export class HistoricalDataSourceService { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels wrong having a service live under "utils", since it's Datasource related, I would rather move this to the "datasource" folder.
@samuelmale All comments on this PR have been resolved, I beleive it is ready to be merged. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
* Initial commit(will remove the date bug fix) * cleanup * Getting the HD object to evaluate tt t * aligning Hxp with previous value * more cleanup * resolving logic * revamped transformer, migrated historical data source class * combine hxp and previous value logic * Added tests * PR resolutions * Fix CI build failure
Requirements
Summary
This introduces the ability for the user to get the historical value (the field's previous value) based on an evaluated expression provided on the form's schema.
Screenshots
https://www.loom.com/share/5ee375006f1b4cf4b9fdf9fcbcf78bc4
Related Issue
Other