-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement merging of indicators
- Loading branch information
1 parent
a264d6f
commit a84ee60
Showing
4 changed files
with
240 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,90 @@ | ||
import { useDataEngine } from '@dhis2/app-runtime' | ||
import i18n from '@dhis2/d2-i18n' | ||
import React, { useMemo } from 'react' | ||
import { Form } from 'react-final-form' | ||
import { | ||
DefaultMergeFormContents, | ||
MergeComplete, | ||
StyledMergeForm, | ||
Title, | ||
} from '../../components/merge' | ||
import { getDefaults, useLocationWithState } from '../../lib' | ||
import { createFormError } from '../../lib/form/createFormError' | ||
import { IndicatorMergeFormFields } from './merge/IndicatorMergeFormFields' | ||
import { | ||
IndicatorMergeFormValues, | ||
mergeFormSchema, | ||
validate, | ||
} from './merge/IndicatorMergeSchema' | ||
|
||
export const Component = () => { | ||
const location = useLocationWithState<{ selectedModels: Set<string> }>() | ||
|
||
const dataEngine = useDataEngine() | ||
const initialValues = useMemo(() => { | ||
const defaults = { | ||
...getDefaults(mergeFormSchema), | ||
target: undefined, | ||
sources: Array.from(location.state?.selectedModels || []).map( | ||
(id) => ({ | ||
id, | ||
}) | ||
), | ||
} | ||
return defaults | ||
}, [location.state?.selectedModels]) | ||
|
||
const onSubmit = async (values: IndicatorMergeFormValues) => { | ||
try { | ||
const data = mergeFormSchema.parse(values) | ||
await dataEngine.mutate({ | ||
resource: 'indicators/merge', | ||
type: 'create', | ||
data, | ||
}) | ||
return undefined | ||
} catch (e) { | ||
console.error(e) | ||
return createFormError(e) | ||
} | ||
} | ||
|
||
return ( | ||
<Form | ||
initialValues={initialValues} | ||
onSubmit={onSubmit} | ||
validate={validate} | ||
subscription={{ | ||
values: false, | ||
submitting: true, | ||
submitSucceeded: true, | ||
}} | ||
> | ||
{({ handleSubmit }) => ( | ||
<StyledMergeForm onSubmit={handleSubmit}> | ||
<DefaultMergeFormContents | ||
title={ | ||
<Title>{i18n.t('Configure indicator merge')}</Title> | ||
} | ||
mergeCompleteElement={ | ||
<MergeComplete> | ||
<p> | ||
{i18n.t( | ||
'The indicator merge operation is complete.' | ||
)} | ||
</p> | ||
<p> | ||
{i18n.t( | ||
'All selected indicators were merged successfully.' | ||
)} | ||
</p> | ||
</MergeComplete> | ||
} | ||
> | ||
<IndicatorMergeFormFields /> | ||
</DefaultMergeFormContents> | ||
</StyledMergeForm> | ||
)} | ||
</Form> | ||
) | ||
} |
119 changes: 119 additions & 0 deletions
119
src/pages/indicators/merge/IndicatorMergeFormFields.tsx
This file contains 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,119 @@ | ||
import i18n from '@dhis2/d2-i18n' | ||
import { NoticeBox } from '@dhis2/ui' | ||
import React from 'react' | ||
import { useFormState } from 'react-final-form' | ||
import { StandardFormSectionTitle } from '../../../components' | ||
import { | ||
BaseSourcesField, | ||
BaseTargetField, | ||
MergeSourcesTargetWrapper, | ||
DeleteSourcesFields, | ||
Description, | ||
FormSection, | ||
FormSections, | ||
ConfirmationField, | ||
} from '../../../components/merge' | ||
import { IndicatorMergeFormValues } from './IndicatorMergeSchema' | ||
|
||
export const IndicatorMergeFormFields = () => { | ||
return ( | ||
<FormSections> | ||
<FormSection> | ||
<Description> | ||
<p> | ||
{i18n.t(`The merge operation will merge the source indicators into | ||
the target indicator. One or many source indicators | ||
can be specified`)} | ||
</p> | ||
<p> | ||
{i18n.t(`Only one target should be specified. The merge operation will | ||
transfer all of the indicator metadata associations to the | ||
source indicator over to the target indicator.`)} | ||
</p> | ||
</Description> | ||
<MergeSourcesTargetWrapper> | ||
<BaseSourcesField | ||
label={i18n.t('Indicators to be merged (source)')} | ||
placeholder={i18n.t('Select indicators to merge')} | ||
query={{ | ||
resource: 'indicators', | ||
params: { | ||
fields: ['id', 'displayName', 'name', 'factor'], | ||
}, | ||
}} | ||
/> | ||
<BaseTargetField | ||
label={i18n.t('Indicators to merge into (target)')} | ||
placeholder={i18n.t('Select indicator to merge into')} | ||
query={{ | ||
resource: 'indicators', | ||
params: { | ||
fields: ['id', 'displayName', 'name', 'factor'], | ||
}, | ||
}} | ||
/> | ||
</MergeSourcesTargetWrapper> | ||
</FormSection> | ||
<FormSection> | ||
<StandardFormSectionTitle> | ||
{i18n.t('Merge settings')} | ||
</StandardFormSectionTitle> | ||
|
||
<DeleteSourcesFields | ||
groupLabel={i18n.t( | ||
'What should happen to the source indicators after the merge is complete?' | ||
)} | ||
getKeepLabel={(count) => | ||
i18n.t('Keep {{ count }} source indicators', { | ||
count, | ||
}) | ||
} | ||
getDeleteLabel={(count) => | ||
i18n.t('Delete {{ count }} source indicators', { | ||
count, | ||
}) | ||
} | ||
/> | ||
</FormSection> | ||
<FormSection> | ||
<ConfirmationField /> | ||
</FormSection> | ||
<MergeWarnings /> | ||
</FormSections> | ||
) | ||
} | ||
|
||
const MergeWarnings = () => { | ||
const { values } = useFormState<IndicatorMergeFormValues>({ | ||
subscription: { values: true }, | ||
}) | ||
|
||
if (values.sources?.length === 0 || !values.target) { | ||
return null | ||
} | ||
|
||
const sourcesWithDifferentFactors = | ||
values.sources?.filter((s) => s.factor !== values.target.factor) || [] | ||
if (sourcesWithDifferentFactors.length > 0) { | ||
return ( | ||
<div style={{ maxWidth: 640 }}> | ||
<NoticeBox warning title={i18n.t('Conflicting factors')}> | ||
{i18n.t( | ||
'The following source indicator types have different factors than the target indicator type with factor {{ targetFactor }}:', | ||
{ targetFactor: values.target.factor } | ||
)} | ||
<ul> | ||
{sourcesWithDifferentFactors.map((s) => ( | ||
<li key={s.id}>{s.displayName ?? s.id}</li> | ||
))} | ||
</ul> | ||
{i18n.t( | ||
'It is not recommended to merge indicator types with different factors.' | ||
)} | ||
</NoticeBox> | ||
</div> | ||
) | ||
} | ||
|
||
return null | ||
} |
This file contains 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,29 @@ | ||
import i18n from '@dhis2/d2-i18n' | ||
import { z } from 'zod' | ||
import { mergeFormSchemaBase } from '../../../components/merge' | ||
import { createFormValidate } from '../../../lib' | ||
|
||
const indicatorSchema = z.object({ | ||
id: z.string(), | ||
displayName: z.string(), | ||
name: z.string(), | ||
factor: z.number().optional(), | ||
}) | ||
|
||
export const mergeFormSchema = mergeFormSchemaBase | ||
.extend({ | ||
sources: z | ||
.array(indicatorSchema) | ||
.min(1, i18n.t('At least one source is required')) | ||
.default([]), | ||
target: indicatorSchema, | ||
}) | ||
.transform((data) => ({ | ||
...data, | ||
sources: data.sources.map((source) => source.id), | ||
target: data.target.id, | ||
})) | ||
|
||
export type IndicatorMergeFormValues = z.input<typeof mergeFormSchema> | ||
|
||
export const validate = createFormValidate(mergeFormSchema) |
This file contains 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,2 @@ | ||
export * from './IndicatorMergeFormFields' | ||
export * from './IndicatorMergeSchema' |