-
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
Moved schema-validator logic to form engine #107
Conversation
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.
Move the validator to https://github.com/openmrs/openmrs-form-engine-lib/tree/main/src/validators
src/schema-validator.ts
Outdated
if (data.results.length) { | ||
const [resObject] = data.results; | ||
|
||
resObject.datatype.name === 'Boolean' && |
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.
Should be driven by a config
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 kindly expound on this
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.
My bad @arodidev my comment regarding the config, see.
As a good practice, I would create an enum
holding all the know datatypes to prevent hard-coding these.
const ConceptDataTypes {
Boolean: 'Boolean',
Coded: 'Coded',
Numeric: 'Numeric',
Text: 'Text'
// more...
};
// validator.js
if (concept.datatype.name === ConceptDataTypes.Boolean) {}
src/schema-validator.ts
Outdated
|
||
if (searchRef) { | ||
try { | ||
const { data } = await openmrsFetch(`/ws/rest/v1/concept?references=${searchRef}&v=${conceptRepresentation}`); |
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.
I'm concerned about the fact that we have fused the validation logic with API-specific logic. I advise reusing the existing useConcepts()
hook. This means the validator becomes a React hook:
// the validator runs if doValidate is set to true
// isValidating shows the validation status
const { errors, warnings, isValidating } = useSchemaValidationResults(doValidate, schema);
Alternatively, you can define a FormSchemaValidator
interface but ensure you fetch the concepts in one API hit with proper separation of concerns.
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 had a previous implementation of how I understood your statement here, kindly advise if this logic suffices.
src/validators/schema-validator.ts
Outdated
if ( | ||
answer.concept !== 'cf82933b-3f3f-45e7-a5ab-5d31aaee3da3' && | ||
answer.concept !== '488b58ff-64f5-4f8a-8979-fa79940b1594' |
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.
I would do something like:
if ( ![ConceptTrue, ConceptFalse].includes(answer.concept) ) {
// handle error
}
The ConceptTrue and ConceptFalse are driven by a System configuration: concept.true
and concept.false
. We need to be picking these values from the backend. On the contrary, these are currently defined as constants within the library which isn't the conventional practice. I've always wanted to address this technical debt but never got the latitude.
Ideally, we should introduce a new hook that will read this system setting. It would be great if you offered to address this otherwise you can use the already defined constants and we address this later on.
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 this is well noted. I would also like to take on the issue of the hook reading the values from the backend if possible.
src/hooks/useSchemaValidator.ts
Outdated
import { ConceptTrue, ConceptFalse } from '../constants'; | ||
import { OHRIFormField, OHRIFormSchema } from '../api/types'; | ||
|
||
export function useSchemaValidator(schema: OHRIFormSchema) { |
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.
Two things here:
- We need a trigger state (to trigger the schema validation)
- On top of the errors and warnings, it's important to return a progress state i.e..
isValidating
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.
Noted.
src/hooks/useSchemaValidator.ts
Outdated
import { OHRIFormField, OHRIFormSchema } from '../api/types'; | ||
|
||
export function useSchemaValidator(schema: OHRIFormSchema) { | ||
//initializing state |
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.
Get rid of the 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.
Noted.
src/hooks/useSchemaValidator.ts
Outdated
const [answerConceptSet, setAnswerConceptSet] = useState<Set<string>>(new Set()); | ||
const { dataTypeToRenderingMap, conceptDataTypes } = useConfig(); | ||
|
||
const unresolvedConceptsFunc = (fullArray, filteredSetArray) => { |
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.
The signature of this function can be improved, starting with the function name. Assuming it finds unresolved concepts, findUnresolvedConcepts
is more descriptive.
fullArray
: It's not straightforward to tell the kind of objects this variable holds same applies to the other param
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.
Noted.
src/hooks/useSchemaValidator.ts
Outdated
//initializing state | ||
const [errors, setErrors] = useState([]); | ||
const [warnings, setWarnings] = useState([]); | ||
const [fullArray, setFullArray] = useState<Array<OHRIFormField>>([]); |
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 you rename this variable to clearly reflect that it's holding fields?
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.
Noted.
const conceptRepresentation = | ||
'custom:(uuid,display,datatype,conceptMappings:(conceptReferenceTerm:(conceptSource:(name),code)))'; | ||
|
||
export function useDatatype(references: Set<string>) { |
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.
Assuming this returns concepts, what stops you from reusing the useConcepts()
hook?
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.
I think we had this conversation a while back to create a new custom hook that also returns a filtered set with unresolved concepts, but if need be I can revert back to using the useConcept hook and modifying it.
src/api/types.ts
Outdated
export interface ConfigObject { | ||
Numeric: Array<string>; | ||
Coded: Array<string>; | ||
Text: Array<string>; | ||
Date: Array<string>; | ||
Datetime: Array<string>; | ||
Boolean: Array<string>; | ||
Rule: Array<string>; | ||
} |
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.
This is possessing a generic name; one may assume it's the general config interface for the form-engine configuration yet I think it's a form schema validator configuration?
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.
Noted.
src/hooks/useSchemaValidator.ts
Outdated
const [answersArray, setAnswersArray] = useState([]); | ||
const [conceptSet, setConceptSet] = useState<Set<string>>(new Set()); | ||
const [answerConceptSet, setAnswerConceptSet] = useState<Set<string>>(new Set()); | ||
const { dataTypeToRenderingMap, conceptDataTypes } = useConfig(); |
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.
Have you actually tested this out? I don't see where you defined the config schema plus you would have to load this config by module name:
const { dataTypeToRenderingMap, conceptDataTypes } = useConfig({
externalModuleName: "@openmrs/openmrs-form-engine-lib",
});
Moves the form-schema validator logic to live inside the form-engine