-
Notifications
You must be signed in to change notification settings - Fork 0
validation custom forms #21
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
Open
idelcano
wants to merge
24
commits into
development
Choose a base branch
from
feature/validate_improve_customforms
base: development
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
ff9ad1b
empty validation custom forms
idelcano e108dfc
added modules load
idelcano 849e20b
WIP
idelcano cdd073d
create validation logic
idelcano 3a87d03
Added progress bar when validation is running
idelcano 3278e99
updated isnull check methods and strings
idelcano 550eda6
clean code and draw items with \n
idelcano 6d0b91a
remove unused file
idelcano 6a74c10
Added translations
idelcano 40148ba
fixed most of reviews
idelcano b5decf6
Added trnslations and some function
idelcano 6285f02
wip
idelcano a52fa26
change report variant name
idelcano 6de8ef7
refactor
idelcano b123ce2
remove warning
idelcano acfe448
use d2 interface
idelcano 22b5387
rename repository
idelcano 5ee628c
prettify
idelcano b60d18b
Testing code
tokland 49277b1
clean code but found regexp bug, wip
idelcano d7b7ef2
change match metod by split
idelcano 775d0dd
refactor: pretiffy and remove unnecesary code
idelcano 3d88fd7
refactor following loadsh oop style
idelcano 9ab4e97
Minor refactors/best-practices on ValidateCustomFormsReport
tokland File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| import _ from "lodash"; | ||
| import { DataSetsRepository } from "../domain/validatecustomforms/repositories/DataSetsRepository"; | ||
| import i18n from "../locales"; | ||
| import { D2Api } from "../types/d2-api"; | ||
|
|
||
| export class DataSetsDefaultRepository implements DataSetsRepository { | ||
| constructor(private api: D2Api) {} | ||
|
|
||
| async validate(id: string): Promise<string[]> { | ||
| const metadata$ = this.api.metadata.get({ | ||
| dataSets: { | ||
| fields: { | ||
| id: true, | ||
| displayName: true, | ||
| dataEntryForm: { htmlCode: true }, | ||
| dataSetElements: { | ||
| dataElement: { id: true, categoryCombo: { id: true } }, | ||
| }, | ||
| }, | ||
| }, | ||
| dataElements: { | ||
| fields: { id: true, categoryCombo: { id: true } }, | ||
| }, | ||
| categoryCombos: { | ||
| fields: { id: true, categoryOptionCombos: { id: true } }, | ||
| }, | ||
| }); | ||
|
|
||
| const { dataSets, categoryCombos, dataElements } = await metadata$.getData(); | ||
|
|
||
| const dataSet = dataSets.find(dataset => dataset.id === id); | ||
| const htmlCode = dataSet?.dataEntryForm.htmlCode; | ||
| const newRegExp = new RegExp(/(([a-zA-Z0-9]){11})-(([A-Za-zA-Z0-9]){11})-(val)/g); | ||
|
|
||
| const matches = htmlCode?.match(newRegExp); | ||
| const customFormIds = _(matches).map(item => { | ||
| return { dataElementId: item.split("-")[0] ?? "-", categoryOptionComboId: item.split("-")[1] ?? "-" }; | ||
| }).commit().value(); | ||
|
|
||
| const categoryCombosById = _.keyBy(categoryCombos, cc => cc.id); | ||
| const dataElementsDataSetById = _.keyBy(dataSet?.dataSetElements, cc => cc.dataElement.id); | ||
| const dataElementsById = _.keyBy(dataElements, cc => cc.id); | ||
|
|
||
| const errors = _.map(customFormIds, dataElementFromCustomForm => { | ||
| const dataElement = dataElementsDataSetById[dataElementFromCustomForm.dataElementId]?.dataElement; | ||
| if (dataElement) { | ||
| const categoryCombo = | ||
| dataElement.categoryCombo.id ?? | ||
| dataElementsById[dataElementFromCustomForm.dataElementId]?.categoryCombo.id; | ||
| const isValid = categoryCombosById[categoryCombo ?? ""]?.categoryOptionCombos.find( | ||
| coc => coc.id === dataElementFromCustomForm.categoryOptionComboId | ||
| ); | ||
| if (!isValid) { | ||
| return ( | ||
| i18n.t("ERROR Dataelement with UID:") + | ||
| " " + | ||
| dataElementFromCustomForm["dataElementId"] + | ||
| " " + | ||
| i18n.t("is not associated with CategoryOptionComboID:") + | ||
| " " + | ||
| dataElementFromCustomForm["categoryOptionComboId"] | ||
| ); | ||
| } | ||
| } else { | ||
| return i18n.t( | ||
| "ERROR Dataelement with UID '{{dataElementId}}' does not exist in dataset with UID '{{dataSetId}}'", | ||
| { dataElementId: dataElementFromCustomForm.dataElementId, dataSetId: id, nsSeparator: false } | ||
| ); | ||
| } | ||
| }); | ||
| const newerror = _.compact(errors); | ||
|
|
||
| return _.uniq(newerror); | ||
| } | ||
| } | ||
3 changes: 3 additions & 0 deletions
3
src/domain/validatecustomforms/repositories/DataSetsRepository.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| export interface DataSetsRepository { | ||
| validate(id: string): Promise<string[]>; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. validateCustomForm |
||
| } | ||
10 changes: 10 additions & 0 deletions
10
src/domain/validatecustomforms/usecases/GetValidatedDataSetsUseCase.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import { DataSetsRepository } from "../repositories/DataSetsRepository"; | ||
|
|
||
| export class GetValidatedDataSetsUseCase { | ||
| constructor(private dataSetsRepository: DataSetsRepository) {} | ||
|
|
||
| execute(id: string): Promise<string[]> { | ||
| // FUTURE: Return a Future-like instead, to allow better error handling and cancellation. | ||
| return this.dataSetsRepository.validate(id); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| import { | ||
| FormControl, | ||
| InputLabel, | ||
| MenuItem, | ||
| Select as MuiSelect, | ||
| SelectProps as MuiSelectProps, | ||
| } from "@material-ui/core"; | ||
| import { createStyles, makeStyles } from "@material-ui/core/styles"; | ||
| import _ from "lodash"; | ||
| import React, { useMemo, useState } from "react"; | ||
|
|
||
| export type SelectOption = { value: string; label: string }; | ||
|
|
||
| export interface SelectProps extends Omit<MuiSelectProps, "onChange"> { | ||
| placeholder?: string; | ||
| options: Array<SelectOption>; | ||
| onChange: (option: SelectOption) => void; | ||
| defaultValue?: SelectOption; | ||
| value?: string; | ||
| allowEmpty?: boolean; | ||
| emptyLabel?: string; | ||
| } | ||
|
|
||
| export const Select: React.FC<SelectProps> = ({ | ||
| placeholder, | ||
| options, | ||
| onChange, | ||
| defaultValue, | ||
| value, | ||
| allowEmpty = false, | ||
| emptyLabel = "", | ||
| ...rest | ||
| }) => { | ||
| const classes = useStyles(); | ||
| const [stateValue, setValue] = useState(defaultValue ? defaultValue.value : ""); | ||
| const optionsByValue = useMemo(() => _.keyBy(options, option => option.value), [options]); | ||
| const defaultOption = allowEmpty ? { label: "", value: "" } : undefined; | ||
|
|
||
| const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => { | ||
| const newValue = event.target.value as string; | ||
| const option = _(optionsByValue).get(newValue, defaultOption); | ||
| setValue(newValue); | ||
| if (option) onChange(option); | ||
| }; | ||
|
|
||
| const defaultLabel = allowEmpty ? emptyLabel : placeholder; | ||
|
|
||
| return ( | ||
| <div> | ||
| <FormControl className={classes.formControl}> | ||
| {!!placeholder && <InputLabel id="demo-simple-select-label">{placeholder}</InputLabel>} | ||
| <MuiSelect onChange={handleChange} value={value ?? stateValue} autoWidth={true} {...rest}> | ||
| {!!defaultLabel && ( | ||
| <MenuItem value="" disabled={!allowEmpty} className={classes.menuItem}> | ||
| {defaultLabel} | ||
| </MenuItem> | ||
| )} | ||
| {options.map(option => ( | ||
| <MenuItem key={option.value} value={option.value} className={classes.menuItem}> | ||
| {option.label} | ||
| </MenuItem> | ||
| ))} | ||
| </MuiSelect> | ||
| </FormControl> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| const useStyles = makeStyles(() => | ||
| createStyles({ | ||
| formControl: { | ||
| margin: 0, | ||
| display: "flex", | ||
| }, | ||
| menuItem: { | ||
| minHeight: 35, | ||
| }, | ||
| }) | ||
| ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
i18n.t interpolation with {{ var }}