diff --git a/i18n/en.pot b/i18n/en.pot index b1b577d6..0d0bd2fc 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2023-10-25T11:43:32.223Z\n" -"PO-Revision-Date: 2023-10-25T11:43:32.223Z\n" +"POT-Creation-Date: 2023-11-16T09:17:45.955Z\n" +"PO-Revision-Date: 2023-11-16T09:17:45.955Z\n" msgid "schemas" msgstr "schemas" @@ -78,14 +78,14 @@ msgstr "Aggregation level(s)" msgid "Category combo" msgstr "Category combo" -msgid "Default (none)" -msgstr "Default (none)" +msgid "None" +msgstr "None" msgid "Filter legend sets" msgstr "Filter legend sets" -msgid "None" -msgstr "None" +msgid "" +msgstr "" msgid "Option set" msgstr "Option set" @@ -621,12 +621,64 @@ msgstr "Exit without saving" msgid "Create data element" msgstr "Create data element" +msgid "Loading custom attributes" +msgstr "Loading custom attributes" + +msgid "Something went wrong with retrieving the custom attributes" +msgstr "Something went wrong with retrieving the custom attributes" + msgid "Basic information" msgstr "Basic information" msgid "Set up the information for this data element" msgstr "Set up the information for this data element" +msgid "Disaggregation and Option sets" +msgstr "Disaggregation and Option sets" + +msgid "Set up disaggregation and predefined options." +msgstr "Set up disaggregation and predefined options." + +msgid "LegendSet" +msgstr "LegendSet" + +msgid "" +"Visualize values for this data element in Analytics app. Multiple legendSet " +"can be applied." +msgstr "" +"Visualize values for this data element in Analytics app. Multiple legendSet " +"can be applied." + +msgid "Aggregation levels" +msgstr "Aggregation levels" + +msgid "" +"By default, the aggregation will start at the lowest assigned organisation " +"unit. If you for example select \"Chiefdom\", it means that \"Chiefdom\", " +"\"District\" and \"National\" aggregates use \"Chiefdom\" (the highest " +"aggregation level available) as the data source, and PHU data will not be " +"included. PHU will still be available for the PHU level, but not included " +"in the aggregations to the levels above." +msgstr "" +"By default, the aggregation will start at the lowest assigned organisation " +"unit. If you for example select \"Chiefdom\", it means that \"Chiefdom\", " +"\"District\" and \"National\" aggregates use \"Chiefdom\" (the highest " +"aggregation level available) as the data source, and PHU data will not be " +"included. PHU will still be available for the PHU level, but not included " +"in the aggregations to the levels above." + +msgid "Custom fields for your DHIS2 instance" +msgstr "Custom fields for your DHIS2 instance" + +msgid "Required" +msgstr "Required" + +msgid "Cannot be longer than {{number}} character" +msgstr "Cannot be longer than {{number}} character" + +msgid "The value is to long. You can use up to 255 characters" +msgstr "The value is to long. You can use up to 255 characters" + msgid "{{fieldLabel}} (required)" msgstr "{{fieldLabel}} (required)" @@ -648,6 +700,16 @@ msgstr "Url" msgid "A web link that provides extra information" msgstr "A web link that provides extra information" +msgid "Color and icon" +msgstr "Color and icon" + +msgid "" +"A color and icon are helpful for identifying data elements in " +"information-dense screens." +msgstr "" +"A color and icon are helpful for identifying data elements in " +"information-dense screens." + msgid "Field mask" msgstr "Field mask" @@ -666,38 +728,6 @@ msgstr "An alternative name used in section or automatic data entry forms." msgid "Store zero data values" msgstr "Store zero data values" -msgid "Disaggregation and Option sets" -msgstr "Disaggregation and Option sets" - -msgid "Set up disaggregation and predefined options." -msgstr "Set up disaggregation and predefined options." - -msgid "LegendSet" -msgstr "LegendSet" - -msgid "" -"Visualize values for this data element in Analytics app. Multiple legendSet " -"can be applied." -msgstr "" -"Visualize values for this data element in Analytics app. Multiple legendSet " -"can be applied." - -msgid "Aggregation levels" -msgstr "Aggregation levels" - -msgid "Custom fields for your DHIS2 instance" -msgstr "Custom fields for your DHIS2 instance" - -msgid "Color and icon" -msgstr "Color and icon" - -msgid "" -"A color and icon are helpful for identifying data elements in " -"information-dense screens." -msgstr "" -"A color and icon are helpful for identifying data elements in " -"information-dense screens." - msgid "A data element can either be aggregated or tracked data." msgstr "A data element can either be aggregated or tracked data." @@ -731,6 +761,9 @@ msgstr "Option set comment" msgid "Choose a set of predefined comment for data entry" msgstr "Choose a set of predefined comment for data entry" +msgid "This field requires a unique value, please choose another one" +msgstr "This field requires a unique value, please choose another one" + msgid "Metadata management" msgstr "Metadata management" diff --git a/jest-setup.js b/jest-setup.js index c89d1c98..3cba363c 100644 --- a/jest-setup.js +++ b/jest-setup.js @@ -1,6 +1,13 @@ import { configure } from '@testing-library/react' import '@testing-library/jest-dom' +// Not defined on nodejs +window.IntersectionObserver = jest.fn(() => ({ + observe: jest.fn(), + unobserve: jest.fn(), + disconnect: jest.fn(), +})) + beforeEach(() => { configure({ testIdAttribute: 'data-test' }) }) diff --git a/src/components/SearchableSingleSelect/SearchableSingleSelect.tsx b/src/components/SearchableSingleSelect/SearchableSingleSelect.tsx index 4d1471e6..5cbccdde 100644 --- a/src/components/SearchableSingleSelect/SearchableSingleSelect.tsx +++ b/src/components/SearchableSingleSelect/SearchableSingleSelect.tsx @@ -58,6 +58,7 @@ interface SearchableSingleSelectPropTypes { showEndLoader: boolean loading: boolean selected?: string + invalid?: boolean error?: string showAllOption?: boolean onBlur?: () => void @@ -65,6 +66,7 @@ interface SearchableSingleSelectPropTypes { } export const SearchableSingleSelect = ({ + invalid, error, loading, placeholder, @@ -121,6 +123,7 @@ export const SearchableSingleSelect = ({ // fetched the corresponding label yet. Therefore we don't want to pass in // any value to the "selected" prop, as otherwise an error will be thrown selected={hasSelectedInOptionList ? selected : ''} + error={invalid} onChange={onChange} placeholder={placeholder} onBlur={onBlur} diff --git a/src/components/metadataFormControls/AggregationLevelMultiSelect/AggregationLevelMultiSelect.tsx b/src/components/metadataFormControls/AggregationLevelMultiSelect/AggregationLevelMultiSelect.tsx index 931cb38f..23e3c480 100644 --- a/src/components/metadataFormControls/AggregationLevelMultiSelect/AggregationLevelMultiSelect.tsx +++ b/src/components/metadataFormControls/AggregationLevelMultiSelect/AggregationLevelMultiSelect.tsx @@ -31,6 +31,7 @@ interface AggregationLevelMultiSelectProps { onChange: ({ selected }: { selected: string[] }) => void onRetryClick: () => void inputWidth?: string + invalid?: boolean placeholder?: string selected?: string[] showAllOption?: boolean @@ -43,6 +44,7 @@ export const AggregationLevelMultiSelect = forwardRef( { onChange, inputWidth, + invalid, selected, showAllOption, placeholder = i18n.t('Aggregation level(s)'), @@ -67,7 +69,7 @@ export const AggregationLevelMultiSelect = forwardRef( onChange={({ selected }: { selected: string[] }) => { onChange({ selected }) }} - error={!!optionsQuery.error} + error={!!optionsQuery.error || invalid} selected={loading ? [] : selected} loading={loading} onBlur={onBlur} diff --git a/src/components/metadataFormControls/CategoryComboSelect/CategoryComboSelect.tsx b/src/components/metadataFormControls/CategoryComboSelect/CategoryComboSelect.tsx index 869f7e2a..36ffb628 100644 --- a/src/components/metadataFormControls/CategoryComboSelect/CategoryComboSelect.tsx +++ b/src/components/metadataFormControls/CategoryComboSelect/CategoryComboSelect.tsx @@ -13,6 +13,7 @@ type CategoryComboSelectProps = Omit< export const CategoryComboSelect = forwardRef(function CategoryComboSelect( { onChange, + invalid, placeholder = i18n.t('Category combo'), required, selected, @@ -26,6 +27,7 @@ export const CategoryComboSelect = forwardRef(function CategoryComboSelect( void required?: boolean + invalid?: boolean placeholder?: string selected?: string showAllOption?: boolean @@ -71,6 +72,7 @@ export interface ModelSingleSelectProps { export const ModelSingleSelect = forwardRef(function ModelSingleSelect( { onChange, + invalid, placeholder = '', required, selected, @@ -150,6 +152,7 @@ export const ModelSingleSelect = forwardRef(function ModelSingleSelect( return ( { diff --git a/src/components/metadataFormControls/OptionSetSelect/OptionSetSelect.tsx b/src/components/metadataFormControls/OptionSetSelect/OptionSetSelect.tsx index 4adbd951..2ea77896 100644 --- a/src/components/metadataFormControls/OptionSetSelect/OptionSetSelect.tsx +++ b/src/components/metadataFormControls/OptionSetSelect/OptionSetSelect.tsx @@ -13,6 +13,7 @@ type OptionSetSelectProps = Omit< export const OptionSetSelect = forwardRef(function OptionSetSelect( { onChange, + invalid, placeholder = i18n.t('Option set'), required, selected, @@ -26,6 +27,7 @@ export const OptionSetSelect = forwardRef(function OptionSetSelect( export type ModelSchemas = ModelSchemasBase // same fields as headbar-request to hit the cache -export const userFields = [ +const userFields = [ 'authorities', 'avatar', 'email', @@ -41,6 +41,12 @@ const userFieldsFilter = userFields.concat() type UserPropertyFields = (typeof userFields)[number] type CurrentUserResponse = Pick +/** + * !!! WARNING !!! + * There's already a `CurrentUser` type exported from the generated schema + * types. We need to think about the name of this type, see: + * https://github.com/dhis2/maintenance-app-beta/pull/359#discussion_r1399267866 + */ export interface CurrentUser extends Omit { authorities: Set // use a set for faster lookup } diff --git a/src/pages/dataElements/Edit.tsx b/src/pages/dataElements/Edit.tsx index 85adb34c..1051df0c 100644 --- a/src/pages/dataElements/Edit.tsx +++ b/src/pages/dataElements/Edit.tsx @@ -15,8 +15,12 @@ import { JsonPatchOperation } from '../../types' import { Attribute, DataElement } from '../../types/generated' import { createJsonPatchOperations } from './edit/' import classes from './Edit.module.css' -import { DataElementFormFields, useCustomAttributesQuery } from './form' -import { FormValues } from './form/types' +import { + DataElementFormFields, + useCustomAttributesQuery, + useValidate, +} from './form' +import type { FormValues } from './form' type FinalFormFormApi = FormApi @@ -143,6 +147,7 @@ export const Component = () => { const dataElementQuery = useDataElementQuery(dataElementId) const customAttributesQuery = useCustomAttributesQuery() const patchDirtyFields = usePatchDirtyFields() + const validate = useValidate() async function onSubmit(values: FormValues, form: FinalFormFormApi) { const errors = await patchDirtyFields({ @@ -170,7 +175,12 @@ export const Component = () => { queryResponse={customAttributesQuery} label={i18n.t('Custom attributes')} > -
+ {({ handleSubmit, submitting, submitError }) => ( { const { id } = dataElementsMock.result[0] const firstRow = getByTestId(`section-list-row-${id}`) expect(firstRow).toHaveTextContent( - 'Accute Flaccid Paralysis (Deaths < 5 yrs)AggregateNumber6 years agoPublic can edit' + /Accute Flaccid Paralysis \(Deaths < 5 yrs\)AggregateNumber\d+ years agoPublic can edit/ ) }) it('should display all the columns', async () => { diff --git a/src/pages/dataElements/New.spec.tsx b/src/pages/dataElements/New.spec.tsx index 66c02259..56d01086 100644 --- a/src/pages/dataElements/New.spec.tsx +++ b/src/pages/dataElements/New.spec.tsx @@ -1,10 +1,4 @@ -import { - RenderResult, - act, - fireEvent, - render, - waitFor, -} from '@testing-library/react' +import { RenderResult, fireEvent, render } from '@testing-library/react' import React from 'react' import { RouterProvider, createMemoryRouter } from 'react-router-dom' import dataElementSchemaMock from '../../__mocks__/schema/dataElementsSchema.json' @@ -114,7 +108,7 @@ describe('Data Elements / New', () => { result.container.querySelectorAll( '.error[data-test$="-validation"]' ) - ).toHaveLength(4) + ).toHaveLength(3) const nameRequiredError = await result.findByText('Required', { selector: '[data-test="dataelementsformfields-name-validation"]', @@ -127,24 +121,18 @@ describe('Data Elements / New', () => { }) expect(shortNameRequiredError).toBeTruthy() - const valueTypeRequiredError = await result.findByText('Required', { + const categoryComboRequiredError = await result.findByText('Required', { selector: - '[data-test="dataelementsformfields-valuetype-validation"]', + '[data-test="dataelementsformfields-categorycombo-validation"]', }) - expect(valueTypeRequiredError).toBeTruthy() - - const aggregationTypeRequiredError = await result.findByText( - 'Required', - { - selector: - '[data-test="dataelementsformfields-aggregationtype-validation"]', - } - ) - expect(aggregationTypeRequiredError).toBeTruthy() + expect(categoryComboRequiredError).toBeTruthy() }) it('should submit the data and return to the list view on success', async () => { - const dataElementCustomData = jest.fn(() => Promise.resolve({})) + const dataElementCustomData = () => + Promise.resolve({ + pager: { total: 0 }, + }) const router = createMemoryRouter( [ { path: '/new', element: }, @@ -175,23 +163,27 @@ describe('Data Elements / New', () => { expect(submitButton).toBeTruthy() - fireEvent.change( - result.getByRole('textbox', { - name: 'Name (required) *', - }) as HTMLElement, - { target: { value: 'Data element name' } } - ) - - fireEvent.change( - result.getByRole('textbox', { - name: 'Short name (required) *', - }) as HTMLElement, - { target: { value: 'Data element short name' } } - ) + const nameInput = result.getByRole('textbox', { + name: 'Name (required) *', + }) as HTMLInputElement + fireEvent.change(nameInput, { + target: { value: 'Data element name' }, + }) + fireEvent.blur(nameInput) - await changeSingleSelect(result, 'Value type (required)', 'Text') + const shortNameInput = result.getByRole('textbox', { + name: 'Short name (required) *', + }) as HTMLInputElement + fireEvent.change(shortNameInput, { + target: { value: 'Data element short name' }, + }) + fireEvent.blur(shortNameInput) - await changeSingleSelect(result, 'Aggregation type (required)', 'Sum') + await changeSingleSelect( + result, + 'Category combination (required)', + 'None' + ) fireEvent.click(submitButton) diff --git a/src/pages/dataElements/New.tsx b/src/pages/dataElements/New.tsx index 8f03acba..c0d87c89 100644 --- a/src/pages/dataElements/New.tsx +++ b/src/pages/dataElements/New.tsx @@ -2,7 +2,7 @@ import { useDataEngine } from '@dhis2/app-runtime' import i18n from '@dhis2/d2-i18n' import { NoticeBox } from '@dhis2/ui' import { FORM_ERROR } from 'final-form' -import React, { useEffect, useRef } from 'react' +import React, { useEffect, useMemo, useRef } from 'react' import { Form } from 'react-final-form' import { useNavigate } from 'react-router-dom' import { @@ -10,42 +10,58 @@ import { StandardFormActions, StandardFormSection, } from '../../components' -import { SCHEMA_SECTIONS, getSectionPath } from '../../lib' +import { SCHEMA_SECTIONS, getSectionPath, useSchemas } from '../../lib' import { Attribute } from '../../types/generated' -import { DataElementFormFields, useCustomAttributesQuery } from './form' -import { FormValues } from './form/types' +import { + DataElementFormFields, + useCustomAttributesQuery, + useValidate, +} from './form' +import type { FormValues } from './form' import classes from './New.module.css' const listPath = `/${getSectionPath(SCHEMA_SECTIONS.dataElement)}` -function computeInitialValues(customAttributes: Attribute[]) { - const attributeValues = customAttributes.map((attribute) => ({ - attribute, - value: '', - })) +function useInitialValues(customAttributes: Attribute[]) { + const schemas = useSchemas() - return { - name: '', - shortName: '', - code: '', - description: '', - url: '', - style: { - color: '', - icon: '', - }, - fieldMask: '', - domainType: 'AGGREGATE', - formName: '', - valueType: '', - aggregationType: '', - categoryCombo: { id: '' }, - optionSet: { id: '' }, - commentOptionSet: { id: '' }, - legendSets: [], - aggregationLevels: [], - attributeValues, - } + const attributeValues = useMemo( + () => + customAttributes.map((attribute) => ({ + attribute, + value: '', + })), + [customAttributes] + ) + + return useMemo( + () => ({ + name: '', + shortName: '', + code: '', + description: '', + url: '', + fieldMask: '', + domainType: 'AGGREGATE', + formName: '', + valueType: schemas.dataElement.properties.valueType.constants?.[0], + aggregationType: + schemas.dataElement.properties.aggregationType.constants?.[0], + style: { icon: '', color: '' }, + categoryCombo: { id: '' }, + optionSet: { id: '' }, + commentOptionSet: { id: '' }, + legendSets: [], + aggregationLevels: [], + attributeValues, + zeroIsSignificant: false, + }), + [ + attributeValues, + schemas.dataElement.properties.valueType.constants, + schemas.dataElement.properties.aggregationType.constants, + ] + ) } const ADD_NEW_DATA_ELEMENT_MUTATION = { @@ -85,10 +101,25 @@ function formatFormValues({ values }: { values: FormValues }) { } export const Component = () => { + const validate = useValidate() const dataEngine = useDataEngine() const navigate = useNavigate() const customAttributesQuery = useCustomAttributesQuery() - const initialValues = computeInitialValues(customAttributesQuery.data || []) + + const loading = customAttributesQuery.loading + const error = customAttributesQuery.error + + const initialValues = useInitialValues(customAttributesQuery.data) + + if (error && !loading) { + // @TODO(Edit): Implement error screen + return <>Error: {error.toString()} + } + + if (loading) { + // @TODO(Edit): Implement loading screen + return <>Loading... + } async function onSubmit(values: FormValues) { const payload = formatFormValues({ values }) @@ -112,7 +143,12 @@ export const Component = () => { queryResponse={customAttributesQuery} label={i18n.t('Custom attributes')} > - + {({ handleSubmit, submitting, submitError }) => ( {i18n.t('Loading custom attributes')} + } + + if (error) { + return ( + + {error.toString()} + + ) + } + return ( <> - {customAttributes.map((customAttribute, index) => { + {customAttributes.data?.map((customAttribute, index) => { return ( + <> {i18n.t('Basic information')} + {i18n.t('Set up the information for this data element')} - (!value ? 'Required' : undefined)} - /> - - - - (!value ? 'Required' : undefined)} - inputWidth="400px" - name="shortName" - label={i18n.t('{{fieldLabel}} (required)', { - fieldLabel: i18n.t('Short name'), - })} - helpText={i18n.t( - 'Often used in reports where space is limited' - )} - /> - - - - - - - - - - - - + - + + + + + + + + + - + - + - + + + + + + + + + @@ -167,6 +92,7 @@ export function DataElementFormFields() { {i18n.t('Disaggregation and Option sets')} + {i18n.t('Set up disaggregation and predefined options.')} @@ -188,6 +114,7 @@ export function DataElementFormFields() { {i18n.t('LegendSet')} + {i18n.t( 'Visualize values for this data element in Analytics app. Multiple legendSet can be applied.' @@ -203,6 +130,7 @@ export function DataElementFormFields() { {i18n.t('Aggregation levels')} + {i18n.t( 'By default, the aggregation will start at the lowest assigned organisation unit. If you for example select "Chiefdom", it means that "Chiefdom", "District" and "National" aggregates use "Chiefdom" (the highest aggregation level available) as the data source, and PHU data will not be included. PHU will still be available for the PHU level, but not included in the aggregations to the levels above.' @@ -214,20 +142,17 @@ export function DataElementFormFields() { - {customAttributes.data?.length > 0 && ( - - - {i18n.t('Custom attributes')} - - - {i18n.t('Custom fields for your DHIS2 instance')} - - - - - )} - + + + {i18n.t('Custom attributes')} + + + + {i18n.t('Custom fields for your DHIS2 instance')} + + + + + ) } diff --git a/src/pages/dataElements/form/createDataElementSchema.ts b/src/pages/dataElements/form/createDataElementSchema.ts new file mode 100644 index 00000000..87a35f98 --- /dev/null +++ b/src/pages/dataElements/form/createDataElementSchema.ts @@ -0,0 +1,104 @@ +import i18n from '@dhis2/d2-i18n' +import { z } from 'zod' +import type { ModelSchemas } from '../../../lib' +import { DataElement } from '../../../types/generated' + +const requiredMessage = i18n.t('Required') +const max50Message = i18n.t('Cannot be longer than {{number}} character', { + number: 50, +}) + +export const createDataElementSchema = (schemas: ModelSchemas) => + z.object({ + name: z + .string() + .min(1, { message: requiredMessage }) + .max(schemas.dataElement.properties.name.length as number, { + message: max50Message, + }) + .trim(), + shortName: z + .string() + .min(1, { message: requiredMessage }) + .max(schemas.dataElement.properties.shortName.length as number, { + message: max50Message, + }) + .trim(), + code: z + .string() + .max(schemas.dataElement.properties.code.length as number, { + message: max50Message, + }) + .trim() + .optional(), + description: z + .string() + .max(schemas.dataElement.properties.description.length as number, { + message: i18n.t( + 'The value is to long. You can use up to 255 characters' + ), + }) + .trim() + .optional(), + formName: z + .string() + .max(schemas.dataElement.properties.formName.length as number, { + message: i18n.t( + 'The value is to long. You can use up to 255 characters' + ), + }) + .trim() + .optional(), + url: z + .string() + .max(schemas.dataElement.properties.url.length as number, { + message: i18n.t( + 'The value is to long. You can use up to 255 characters' + ), + }) + .trim() + .optional(), + fieldMask: z + .string() + .max(schemas.dataElement.properties.fieldMask.length as number, { + message: i18n.t( + 'The value is to long. You can use up to 255 characters' + ), + }) + .trim() + .optional(), + style: z.object({ + color: z.string().optional(), + icon: z.string().optional(), + }), + domainType: z.union([z.literal('AGGREGATE'), z.literal('TRACKER')]), + valueType: z + .nativeEnum(DataElement.valueType) + .refine((v) => !!v, { message: requiredMessage }), + aggregationType: z + .nativeEnum(DataElement.aggregationType) + .refine((v) => !!v, { message: requiredMessage }), + categoryCombo: z.object({ + id: z.string().min(1, { message: requiredMessage }), + }), + optionSet: z.object({ + id: z.string().optional(), + }), + commentOptionSet: z.object({ + id: z.string().optional(), + }), + legendSets: z.array( + z.object({ + id: z.string(), + }) + ), + aggregationLevels: z.array(z.number()), + attributeValues: z.array( + z.object({ + value: z.string(), + attribute: z.object({ + id: z.string(), + }), + }) + ), + }) diff --git a/src/pages/dataElements/form/customFields.tsx b/src/pages/dataElements/form/fields.tsx similarity index 63% rename from src/pages/dataElements/form/customFields.tsx rename to src/pages/dataElements/form/fields.tsx index 2bce4ada..a40ccc31 100644 --- a/src/pages/dataElements/form/customFields.tsx +++ b/src/pages/dataElements/form/fields.tsx @@ -2,13 +2,17 @@ import i18n from '@dhis2/d2-i18n' import { ButtonStrip, Button, + CheckboxFieldFF, Field, + InputFieldFF, Radio, SingleSelectFieldFF, + TextAreaFieldFF, } from '@dhis2/ui' import React, { useRef } from 'react' import { Field as FieldRFF, useField } from 'react-final-form' import { useHref } from 'react-router' +import { useParams } from 'react-router-dom' import { AggregationLevelMultiSelect, ColorAndIconPicker, @@ -24,10 +28,122 @@ import { } from '../../../lib' import classes from './customFields.module.css' import { EditableFieldWrapper } from './EditableFieldWrapper' +import { useIsFieldValueUnique } from './useIsFieldValueUnique' + +export function NameField() { + const params = useParams() + const dataElementId = params.id as string + const checkIsValueTaken = useIsFieldValueUnique({ + field: 'name', + id: dataElementId, + }) + const { meta } = useField('name', { + subscription: { validating: true }, + }) + + return ( + checkIsValueTaken(name)} + validateFields={[]} + /> + ) +} + +export function ShortNameField() { + const params = useParams() + const dataElementId = params.id as string + const checkIsValueTaken = useIsFieldValueUnique({ + field: 'shortName', + id: dataElementId, + }) + const { meta } = useField('shortName', { + subscription: { validating: true }, + }) + + return ( + checkIsValueTaken(shortName)} + validateFields={[]} + /> + ) +} + +export function CodeField() { + return ( + + ) +} + +export function DescriptionField() { + return ( + + ) +} + +export function UrlField() { + return ( + + ) +} export function ColorAndIconField() { - const { input: colorInput } = useField('style.color') - const { input: iconInput } = useField('style.icon') + const { input: colorInput } = useField('style.color', { + validateFields: [], + }) + const { input: iconInput } = useField('style.icon', { + validateFields: [], + }) return ( + ) +} + +export function FormNameField() { + return ( + + ) +} + +export function ZeroIsSignificantField() { + return ( + + ) +} + export function DomainField() { const name = 'domainType' - const validate = (value: string) => (!value ? 'Required' : undefined) const aggregateInput = useField(name, { type: 'radio', value: 'AGGREGATE', - validate, + validateFields: [], }) const trackerInput = useField(name, { type: 'radio', value: 'TRACKER', - validate, + validateFields: [], }) + const touched = aggregateInput.meta.touched || trackerInput.meta.touched const error = aggregateInput.meta.error || trackerInput.meta.error return ( @@ -77,8 +239,8 @@ export function DomainField() { helpText={i18n.t( 'A data element can either be aggregated or tracked data.' )} - error={!!error} - validationText={error} + error={touched && !!error} + validationText={touched ? error : undefined} >
legendSets?.map((legendSet) => legendSet.id), parse: (ids: string[]) => ids.map((id) => ({ id })), + validateFields: [], }) const newLegendSetLink = useHref('/legendSets/new') @@ -177,10 +340,9 @@ export function ValueTypeField() { ) return ( (!value ? 'Required' : undefined)} inputWidth="400px" name="valueType" label={i18n.t('{{fieldLabel}} (required)', { @@ -188,6 +350,7 @@ export function ValueTypeField() { })} helpText={i18n.t('The type of data that will be recorded.')} options={options || []} + validateFields={[]} /> ) } @@ -206,7 +369,6 @@ export function AggregationTypeField() { component={SingleSelectFieldFF} dataTest="dataelementsformfields-aggregationtype" required - validate={(value: string) => (!value ? 'Required' : undefined)} inputWidth="400px" name="aggregationType" label={i18n.t('{{fieldLabel}} (required)', { @@ -216,13 +378,16 @@ export function AggregationTypeField() { 'The default way to aggregate this data element in analytics.' )} options={options || []} + validateFields={[]} /> ) } export function CategoryComboField() { const newCategoryComboLink = useHref('/categoryCombos/new') - const { input, meta } = useField('categoryCombo.id') + const { input, meta } = useField('categoryCombo.id', { + validateFields: [], + }) const categoryComboHandle = useRef({ refetch: () => { throw new Error('Not initialized') @@ -238,9 +403,6 @@ export function CategoryComboField() {
- !value ? 'Required' : undefined - } name="categoryCombo.id" label={i18n.t('{{fieldLabel}} (required)', { fieldLabel: i18n.t('Category combination'), @@ -248,14 +410,24 @@ export function CategoryComboField() { helpText={i18n.t( 'Choose how this data element is disaggregated' )} - validationText={meta.error} + error={meta.touched && !!meta.error} + validationText={meta.touched ? meta.error : undefined} + dataTest="dataelementsformfields-categorycombo" > input.onChange(selected)} + onChange={({ selected }) => { + input.onChange(selected) + + // Our selects don't trigger a blur event when + // selecting a value, but the select is not focused + // anymore either + input.onBlur() + }} onBlur={input.onBlur} onFocus={input.onFocus} /> @@ -267,7 +439,9 @@ export function CategoryComboField() { export function OptionSetField() { const newOptionSetLink = useHref('/optionSets/new') - const { input, meta } = useField('optionSet.id') + const { input, meta } = useField('optionSet.id', { + validateFields: [], + }) const optionSetHandle = useRef({ refetch: () => { throw new Error('Not initialized') @@ -287,10 +461,13 @@ export function OptionSetField() { helpText={i18n.t( 'Choose a set of predefined options for data entry' )} - validationText={meta.error} + validationText={meta.touched ? meta.error : undefined} + error={meta.touched && !!meta.error} + dataTest="dataelementsformfields-optionset" > input.onChange(selected)} @@ -305,7 +482,9 @@ export function OptionSetField() { export function OptionSetCommentField() { const newOptionSetLink = useHref('/optionSets/new') - const { input, meta } = useField('commentOptionSet.id') + const { input, meta } = useField('commentOptionSet.id', { + validateFields: [], + }) const optionSetHandle = useRef({ refetch: () => { throw new Error('Not initialized') @@ -325,10 +504,13 @@ export function OptionSetCommentField() { helpText={i18n.t( 'Choose a set of predefined comment for data entry' )} - validationText={meta.error} + validationText={meta.touched ? meta.error : undefined} + error={meta.touched && !!meta.error} + dataTest="dataelementsformfields-commentoptionset" > input.onChange(selected)} @@ -347,6 +529,7 @@ export function AggregationLevelsField() { multiple: true, format: (levels: number[]) => levels.map((level) => level.toString()), parse: (levels: string[]) => levels.map((level) => parseInt(level, 10)), + validateFields: [], }) const aggregationLevelHandle = useRef({ refetch: () => { @@ -367,10 +550,13 @@ export function AggregationLevelsField() { helpText={i18n.t( 'Choose how this data element is disaggregated' )} - validationText={meta.error} + validationText={meta.touched ? meta.error : undefined} + error={meta.touched && !!meta.error} + dataTest="dataelementsformfields-aggregationlevels" > ) => { + const filter = [`${variables.field}:eq:${variables.value}`] + + if (variables.id) { + filter.push(`id:ne:${variables.id}`) + } + + return { pageSize: 1, fields: 'id', filter } + }, + }, +} + +interface QueryResponse { + dataElements: { + pager: Pager + } +} + +export function useIsFieldValueUnique({ + field, + id, +}: { + field: string + id: string +}) { + const engine = useDataEngine() + + const validate = useMemo( + () => + memoize(async (value: string) => { + if (!value) { + return undefined + } + + const data = (await engine.query(HAS_FIELD_VALUE_QUERY, { + variables: { field, value, id }, + })) as unknown as QueryResponse + + if (data.dataElements.pager.total > 0) { + return i18n.t( + 'This field requires a unique value, please choose another one' + ) + } + }), + [field, engine, id] + ) + + return useDebouncedCallback(validate, 200, { leading: true }) +} diff --git a/src/pages/dataElements/form/useValidate.ts b/src/pages/dataElements/form/useValidate.ts new file mode 100644 index 00000000..2d70d326 --- /dev/null +++ b/src/pages/dataElements/form/useValidate.ts @@ -0,0 +1,40 @@ +import { setIn } from 'final-form' +import { useMemo } from 'react' +import { useSchemas } from '../../../lib' +import { createDataElementSchema } from './createDataElementSchema' +import type { FormValues } from './types' + +// @TODO: Figure out if there's a utility for this? I couldn't find one +function segmentsToPath(segments: Array) { + return segments.reduce((path, segment) => { + return typeof segment === 'number' + ? `${path}[${segment}]` + : `${path}.${segment}` + }) as string +} + +export function useValidate() { + const schemas = useSchemas() + const dataElementSchema = useMemo( + () => createDataElementSchema(schemas), + [schemas] + ) + + return (values: FormValues) => { + const zodResult = dataElementSchema.safeParse(values) + + if (zodResult.success !== false) { + return undefined + } + + const allFormErrors = zodResult.error.issues.reduce( + (formErrors, error) => { + const errorPath = segmentsToPath(error.path) + return setIn(formErrors, errorPath, error.message) + }, + {} + ) + + return allFormErrors + } +} diff --git a/src/types/generated/index.ts b/src/types/generated/index.ts index fbd945bd..2084e0d4 100644 --- a/src/types/generated/index.ts +++ b/src/types/generated/index.ts @@ -1,4 +1,4 @@ /* GENERATED BY https://github.com/Birkbjo/dhis2-open-api-ts */ -export type * from './models' +export * from './models' export type * from './utility' diff --git a/yarn.lock b/yarn.lock index 9a9247c9..34a2574d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1407,18 +1407,6 @@ debug "^3.1.0" lodash.once "^4.1.1" -"@dhis2-ui/alert@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/alert/-/alert-8.13.15.tgz#5f9a9665e751bc94d96b1d2993683731ac63c019" - integrity sha512-6KiE4TGaJC3FdChyc5FvghInSlPl4hZNDjukq5lYy0XXgnaKBSz9yUPmod5+NLHFsEr0DCISBKFhVeKAexz/hg== - dependencies: - "@dhis2-ui/portal" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/alert@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/alert/-/alert-8.14.7.tgz#53cdc9bbdceee01dd5b86d0615a1c57314e0e307" @@ -1431,16 +1419,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/box@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/box/-/box-8.13.15.tgz#fb8fce7ee20e27b9e25e7a294c1109a881b123a4" - integrity sha512-SwzPGXbySpU/e0lJyxOfxXipFAc3C9GKKsSQYKVOo2/kxwZDui9zaUcw1hCv4rK4vy2hB1b2GLEvJLnQAE3VIQ== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/box@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/box/-/box-8.14.7.tgz#1f7eabb6da21e67d95a49b5410af151cf61de92b" @@ -1451,20 +1429,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/button@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/button/-/button-8.13.15.tgz#0bcb2365a9dd200c303b4bea003a5b403382c981" - integrity sha512-rzHPLBAbG6Q0k8JZU21eWABa/+GqOvl9WV6ay8ODahJmvauOpKKNOYn2AfUZEjbwrWgVbiuGhPOvnC+bVI+jDw== - dependencies: - "@dhis2-ui/layer" "8.13.15" - "@dhis2-ui/loader" "8.13.15" - "@dhis2-ui/popper" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/button@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/button/-/button-8.14.7.tgz#c241b42d0bbb98c594a8183f1bc432be4a5e23af" @@ -1479,23 +1443,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/calendar@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/calendar/-/calendar-8.13.15.tgz#d37395674df24565258d76aa6f771f76801c8adb" - integrity sha512-/2FVtXI6vGQlFvPul3I/EdWJfpo3QXx5aF/YKZVEEQaM5nhVmdLMVqNoIvNGzh1PJsAyrc6JhqdqqbK5AO2u0w== - dependencies: - "@dhis2-ui/button" "8.13.15" - "@dhis2-ui/card" "8.13.15" - "@dhis2-ui/input" "8.13.15" - "@dhis2-ui/layer" "8.13.15" - "@dhis2-ui/popper" "8.13.15" - "@dhis2/multi-calendar-dates" "1.0.2" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/calendar@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/calendar/-/calendar-8.14.7.tgz#16453c22bfe707f93e695318c6526c14137a4adf" @@ -1513,16 +1460,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/card@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/card/-/card-8.13.15.tgz#87e67ebc2c92512fb729016571d0be40cbf079ca" - integrity sha512-70VZHAuHGBqw4AKBJd1HgcsMyTfQ++yzip5c8ykLU7AZQi7WS8W/fMDvV9DGFE5Lc3JyIZdr15Uh31d/v+EBUA== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/card@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/card/-/card-8.14.7.tgz#ee944a2c86a8f3c397da32b2c0adf3ca956a06b8" @@ -1533,16 +1470,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/center@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/center/-/center-8.13.15.tgz#fd434cd37e6d5eb4a01b4830c2c316fbb814c188" - integrity sha512-+YQFxzNrwYQWsZZYEHM4ywzaGbrjfQWcK4WIPAHifVYau2efPDXAMGQ8cpDrRUivpxCYi3Rpvpp965Dp5+KOYQ== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/center@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/center/-/center-8.14.7.tgz#374d87df7570000549312d4d42d42f1ba8af1dfd" @@ -1553,18 +1480,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/checkbox@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/checkbox/-/checkbox-8.13.15.tgz#ed8beaf55fe32c222f35e2ee2497191dee2ddefe" - integrity sha512-fhi50vBK8v5fXzkNOcZlZR8pxO72GwwVKuTmDkrDeAIKIiNQuNZoxkAkU3vwEGv/rdO3TREbAfzTbtjRui3XHQ== - dependencies: - "@dhis2-ui/field" "8.13.15" - "@dhis2-ui/required" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/checkbox@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/checkbox/-/checkbox-8.14.7.tgz#ae96afc1063fddd642a72b37f7a18c8574e2311e" @@ -1577,16 +1492,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/chip@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/chip/-/chip-8.13.15.tgz#efd576e7556b241c852b7176762e70e22f84b2e0" - integrity sha512-MJSKIX/KIZBKjQPhIUTwMasmvY4M2ftlYQ61d9Px1YAuivuE+VTvGCsFF0q5EAKMx5ETd6SD1X3PrwzdtHru4Q== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/chip@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/chip/-/chip-8.14.7.tgz#b57398e867d4a06847a33faad054ed67f2a195c0" @@ -1597,16 +1502,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/cover@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/cover/-/cover-8.13.15.tgz#28ac0f54a39f217518a0df501665829188d5945d" - integrity sha512-3e4XwsnhaVNSNTF2wNk6V+3CzsKCZuLsqMq049ScdaCCrv83qro1cRfRTNqNUJiXnmTubrgU8yxV0kXrFIKZJg== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/cover@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/cover/-/cover-8.14.7.tgz#c023217b961f2becc479566468a9a0df96cdb0c0" @@ -1617,16 +1512,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/css@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/css/-/css-8.13.15.tgz#8e8073a0c69070f598c27abdef52c36981d77421" - integrity sha512-9aAWUpE36SVS17AQXz3x9KkoRpIkvruat+tk2eabw0vfTB6xVRPzC1oO28mltYhpWNOLLS+k1USwfhDSiiqASw== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/css@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/css/-/css-8.14.7.tgz#8047e2ed197ec4ad03ad69e374a57e5b4eb914fe" @@ -1637,16 +1522,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/divider@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/divider/-/divider-8.13.15.tgz#c4ef063b31aa80735c2288dd9f5cbaa2c79b123e" - integrity sha512-bIQKnaCddH2Pr9e3j3CFFWMvGR51gvw71G4NTHsNGZTWNbVL54tZo4ifhkmkfNvf3cLuF/V6IlpQzrf/X8Iu9g== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/divider@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/divider/-/divider-8.14.7.tgz#ba3ae31e5e62b610ca9f2e7e041ad623116a73fd" @@ -1657,19 +1532,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/field@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/field/-/field-8.13.15.tgz#f91ca25936ea926e82ac17c62b28faa2eae2898b" - integrity sha512-2aBumqc77kBC0gl0A+zGOv+en/pu2YUNYwEEpvq5TE2NOvSktWgUOR6Pk/5NDGtB8ugkxgdjAbgcOk/SRuxQJA== - dependencies: - "@dhis2-ui/box" "8.13.15" - "@dhis2-ui/help" "8.13.15" - "@dhis2-ui/label" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/field@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/field/-/field-8.14.7.tgz#48e27a454b65ddc09b8025a8cfd64505e8448975" @@ -1683,22 +1545,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/file-input@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/file-input/-/file-input-8.13.15.tgz#df974db2ea5cf072b63b4336c84eaa5f989dbcaa" - integrity sha512-il5j+6s+874XX/uS4teXQCrFjnmJgVg5RTViZ5toDUZRUpjx86zLKUcTDANfrxG3eUR+F4dkdsvccXFTkA1dTg== - dependencies: - "@dhis2-ui/button" "8.13.15" - "@dhis2-ui/field" "8.13.15" - "@dhis2-ui/label" "8.13.15" - "@dhis2-ui/loader" "8.13.15" - "@dhis2-ui/status-icon" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/file-input@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/file-input/-/file-input-8.14.7.tgz#c9278b157bd5ef457a99988c627557c280154388" @@ -1715,30 +1561,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/header-bar@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/header-bar/-/header-bar-8.13.15.tgz#40d5c5fb0ba3ff5dce2870125ededa83cd3f1cc6" - integrity sha512-OjGKPU0ia+q53NM0hZMfnNkb8Sh/Ty4q/WcDw9qr0Yzow29G30Z4TH+B8le9SSvUBXBiZ8Q/Rv170JMON0Zygg== - dependencies: - "@dhis2-ui/box" "8.13.15" - "@dhis2-ui/button" "8.13.15" - "@dhis2-ui/card" "8.13.15" - "@dhis2-ui/center" "8.13.15" - "@dhis2-ui/divider" "8.13.15" - "@dhis2-ui/input" "8.13.15" - "@dhis2-ui/layer" "8.13.15" - "@dhis2-ui/loader" "8.13.15" - "@dhis2-ui/logo" "8.13.15" - "@dhis2-ui/menu" "8.13.15" - "@dhis2-ui/modal" "8.13.15" - "@dhis2-ui/user-avatar" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - moment "^2.29.1" - prop-types "^15.7.2" - "@dhis2-ui/header-bar@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/header-bar/-/header-bar-8.14.7.tgz#e7291dee9c6a5d4f95f6665fe47ae8695af102fc" @@ -1763,16 +1585,6 @@ moment "^2.29.1" prop-types "^15.7.2" -"@dhis2-ui/help@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/help/-/help-8.13.15.tgz#a3c1adcc655afcc9f24cf13aa9f0597b24593810" - integrity sha512-7obQDeD0dZOyf+Sm808EZeTeCLIFndd0fdPD1vTmTOnevv+W2grT7dCwsFwZ2AsX+GLbzzd+10ikXE8da6OPPQ== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/help@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/help/-/help-8.14.7.tgz#fad62ccf6c0d93251b189638ce3a483964acb86a" @@ -1783,22 +1595,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/input@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/input/-/input-8.13.15.tgz#cdeb7bf5b63814b4a571b843e580527868f57f32" - integrity sha512-8K4yqeZmYQpvNA+TRWtFwWWC4HbzgotxJ6FoXdUJ34LVHQZJNCaRC0L0B1lHLCnP41WHnY0uYcFovY0kl0G/vA== - dependencies: - "@dhis2-ui/box" "8.13.15" - "@dhis2-ui/field" "8.13.15" - "@dhis2-ui/input" "8.13.15" - "@dhis2-ui/loader" "8.13.15" - "@dhis2-ui/status-icon" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/input@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/input/-/input-8.14.7.tgz#8ab3bb228932bd52a3fd06eb546dba5b7d76eb15" @@ -1815,16 +1611,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/intersection-detector@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/intersection-detector/-/intersection-detector-8.13.15.tgz#460389648c7cd95a45b881db7a4f997ca7fce045" - integrity sha512-M7gaWb50eu3LPoU6vd5CAz9uLDsyFmacr7RCUQO5FlBQ/cGU6Xvfd8+oaH5R7PqP/YSyNsPi4yP9cpXSlzU1Gw== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/intersection-detector@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/intersection-detector/-/intersection-detector-8.14.7.tgz#4b510471b5b1434da8ca31eb7c8df789a29cdc2c" @@ -1835,17 +1621,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/label@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/label/-/label-8.13.15.tgz#6a5a42fce24f2d11507f58c3a4782d50ac2fe764" - integrity sha512-+lC8gJTxB81n0/83Nfs1KrgkR7SitdHb40nZh3/VgfRzWJzxESL/VMpA/dz1Y+7eZ8To/exRYvrfoHGI6qpvog== - dependencies: - "@dhis2-ui/required" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/label@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/label/-/label-8.14.7.tgz#64cce8f2cb3433fdc5feffbeda1d7d58b4d63df4" @@ -1857,17 +1632,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/layer@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/layer/-/layer-8.13.15.tgz#ab0f15ea5dea3666718faf08f0e812830ec536c4" - integrity sha512-OWlwvW1a4/SKdYCy+Dc7OkGT2Cc+6GHIHRDTQwNQdBGUAtosx/AmsmBv+sCPKl2CMaZQTwL7dRbN/80YOWdklA== - dependencies: - "@dhis2-ui/portal" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/layer@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/layer/-/layer-8.14.7.tgz#ab95b3bdfe023e4ceaba93339e5fae165a148c1c" @@ -1879,17 +1643,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/legend@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/legend/-/legend-8.13.15.tgz#0ba933eac4839d31b37083b4291e637c99a9188e" - integrity sha512-KE5+YBs+YUHmUB1EKfWa/yWc5WcICP3+RH1g9zqK+L6FmO+iH+pFHzF+grtaeOM7ZbrqvXGSamK+UbUYlcn5TA== - dependencies: - "@dhis2-ui/required" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/legend@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/legend/-/legend-8.14.7.tgz#56f595da523e8a1dbf1728e8beaf2cff75536612" @@ -1901,16 +1654,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/loader@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/loader/-/loader-8.13.15.tgz#726a3f7c43ec268d1ba4fa115e2ff45f4d983017" - integrity sha512-P/uMn84ME4NVlVNnHcCjbf6Gi042tuRHxAWoYf/R35rYoKnVCJTul4dKf1JCBNRJUpQtEuaT/EGk0G11iZIBog== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/loader@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/loader/-/loader-8.14.7.tgz#77b951c45f72de4488704d59e8da8d86b680f0e8" @@ -1921,16 +1664,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/logo@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/logo/-/logo-8.13.15.tgz#c1c9fe8a6e0ed3055027202790d19e6234b01eee" - integrity sha512-dRW5doMz57kjn+CeHtRXy5eVjkHj2xFzU0CA4A+pfTb6mXlwDrC8C7ixpbwIcYky51AS02zKaygoGmODRZt9Ow== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/logo@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/logo/-/logo-8.14.7.tgz#3b0c28badf9d30c2c22df8688782d1650da28973" @@ -1941,22 +1674,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/menu@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/menu/-/menu-8.13.15.tgz#9193a0fc5cc2610ad5b9a68b97acd0f1f218be70" - integrity sha512-dzkRRRk2eogzHlJuR6JONd7NeVU1Ct1zmhlsHDqTHc8p1vO3/FYIF6SWBJErFTXmWSs9kYA4WnZHk/xiyKWFQA== - dependencies: - "@dhis2-ui/card" "8.13.15" - "@dhis2-ui/divider" "8.13.15" - "@dhis2-ui/layer" "8.13.15" - "@dhis2-ui/popper" "8.13.15" - "@dhis2-ui/portal" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/menu@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/menu/-/menu-8.14.7.tgz#20c448da00c1fb543000c34914b49b3b135a633a" @@ -1973,21 +1690,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/modal@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/modal/-/modal-8.13.15.tgz#d0865e7b60bc4baf2865133007d730f959592713" - integrity sha512-ptCxzIXnHv9AOcwW33XgmMqb072Z8ZishfjLzlZVhNdiFbwBmCvr+yu5zpTj0I0fISotz7fpAF38tWIsp9CPOA== - dependencies: - "@dhis2-ui/card" "8.13.15" - "@dhis2-ui/center" "8.13.15" - "@dhis2-ui/layer" "8.13.15" - "@dhis2-ui/portal" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/modal@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/modal/-/modal-8.14.7.tgz#028dfd3a1f8e740f4d47a0ba6baec50184da05d4" @@ -2003,17 +1705,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/node@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/node/-/node-8.13.15.tgz#c0221389511bf571fc08f9b3c55963b37d65aac3" - integrity sha512-yG39zK1UEBnABqfrVL9dnoZWaqUY4WTnkfHOwxBI8k7DhTDmoFA/Otqlfu1ILgdnz/W1SLpxGhqRqa1pg4m4Gg== - dependencies: - "@dhis2-ui/loader" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/node@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/node/-/node-8.14.7.tgz#90289ffb9ddc649bbc9702bf76d7eaab764a6885" @@ -2025,17 +1716,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/notice-box@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/notice-box/-/notice-box-8.13.15.tgz#e53a8f4db842bae0966b8a562bafc685cf17af83" - integrity sha512-vY7vAwlRQMYZvNvByVRQqGTjTnMHbKPWWcNlAx23otZDIPJG4z+hxBV0dX+e6hKpZFjtW+5zAOMe4JgS8McrmA== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/notice-box@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/notice-box/-/notice-box-8.14.7.tgz#deed5e78870e38774a472891a78b3933cbc72bf4" @@ -2047,19 +1727,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/organisation-unit-tree@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/organisation-unit-tree/-/organisation-unit-tree-8.13.15.tgz#b9750f10d945baca95b8cfb43684d3e1858f7b8a" - integrity sha512-jGPiSBqo9vtvIzKpRVMUeDpmqxmjz6vwEcMqLwyWTh8YxC5nGw20wwj33z6SW/5BoSIgbgQZxxH3B6NBUbO8fA== - dependencies: - "@dhis2-ui/checkbox" "8.13.15" - "@dhis2-ui/loader" "8.13.15" - "@dhis2-ui/node" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/organisation-unit-tree@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/organisation-unit-tree/-/organisation-unit-tree-8.14.7.tgz#49c078222c59b1b9c10129afc0bc5075bb58bbc8" @@ -2073,19 +1740,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/pagination@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/pagination/-/pagination-8.13.15.tgz#ec73473380339ab646db0a5e336e5571e024f9ff" - integrity sha512-Kbixe3HFW168EiLkPu8hNe2CqnI+B6n0maVOeZJv90l0bW5FSXLHs669Fr6y2sTl0YVgwK94IoLOCJSWFldvIA== - dependencies: - "@dhis2-ui/button" "8.13.15" - "@dhis2-ui/select" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/pagination@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/pagination/-/pagination-8.14.7.tgz#8f4a47cd6010e7860f95829155f3587e21d69dcc" @@ -2099,18 +1753,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/popover@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/popover/-/popover-8.13.15.tgz#41bb965b8fddd8b88349c9174ff7c63a392fab25" - integrity sha512-i32u23IAKkCi26Adcom8P8kMEP+EIw/rBcTYNHmPc1wrfVPnMfkVf+fFsVcoY7t1gcNFO88SiyJNffso7S1BPg== - dependencies: - "@dhis2-ui/layer" "8.13.15" - "@dhis2-ui/popper" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/popover@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/popover/-/popover-8.14.7.tgz#373e66dbf780ccfeedf5b5b2e2de269bb98dc940" @@ -2123,19 +1765,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/popper@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/popper/-/popper-8.13.15.tgz#c4c29c16c92221716a8806791bc383b6209acee6" - integrity sha512-gOIDZzvfH8oA0Hf7V0HEi3Y99KRcDdmog/BqnsiqEV/EAV/VRHq5qk239bIqKATM1Ei7Xv7G0lEBXJIZqOeNVA== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@popperjs/core" "^2.10.1" - classnames "^2.3.1" - prop-types "^15.7.2" - react-popper "^2.2.5" - resize-observer-polyfill "^1.5.1" - "@dhis2-ui/popper@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/popper/-/popper-8.14.7.tgz#0101fa266f867f8db3986d07c27b62e000f3e766" @@ -2149,14 +1778,6 @@ react-popper "^2.2.5" resize-observer-polyfill "^1.5.1" -"@dhis2-ui/portal@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/portal/-/portal-8.13.15.tgz#701b0294d069239c7afefd1e1e211b9b80f72dc1" - integrity sha512-oqSbsOyznJwpdpAUiur5v24SOlThcWEbhnvniXSZzZy4thSJpcdF6OLMhgvVcjfO8kyAGgMbQjEx+hZ6cVpCFQ== - dependencies: - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/portal@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/portal/-/portal-8.14.7.tgz#ba050e3b0bd3c4702aa403a405e4b27e750d88c8" @@ -2165,16 +1786,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/radio@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/radio/-/radio-8.13.15.tgz#4475abe33148bef6cd532888ee6077864674ebeb" - integrity sha512-k+ahM17CLIwquuN6XD9LCzkjPR+Zkvpcl8Cb8GzJNpovkhqdDJMvFezmBu7oxyABzVzNYILnuouqGsQwF6G4UQ== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/radio@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/radio/-/radio-8.14.7.tgz#213cc85b1b7a9244f0c216318ae53d24567a9901" @@ -2185,16 +1796,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/required@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/required/-/required-8.13.15.tgz#bba0fda4f693ab9d53f0822b3ad0375ee6c217e7" - integrity sha512-Qlt84rdcsP4i0faaOvOcedP2dFbZp08ASh3ylNwSbLcP2R+aNv9mXQCR6U2mW2WjCMsgAfGzApdMFgYZJfI9QQ== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/required@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/required/-/required-8.14.7.tgz#16edd4b38ddee35680753a908e72484c090e4ee2" @@ -2205,16 +1806,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/segmented-control@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/segmented-control/-/segmented-control-8.13.15.tgz#2ecbd81075ea81b974912bab05d9d23f15c12382" - integrity sha512-+oulCoUVDHkxV5WPjGwzpgN9qmIwVW1/9TbW6JvC87gbiywAWaN59dhIIRoBRqeBOy0Ll9DW2L3siBYfMY43vg== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/segmented-control@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/segmented-control/-/segmented-control-8.14.7.tgz#a80d0fb730a9f7c60b8939960216fd273da5c9c9" @@ -2225,28 +1816,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/select@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/select/-/select-8.13.15.tgz#3125ddb871da60bb1cbdf663ec4109c579fba0fb" - integrity sha512-yVNCws1GUmbXCOBKx2ZdwC5OEVt3wLPOSUOswVrJA3/ZjE0/ji5Or193/u9dhvLgDBzTt/ZIhKVksa4sT/pGCg== - dependencies: - "@dhis2-ui/box" "8.13.15" - "@dhis2-ui/button" "8.13.15" - "@dhis2-ui/card" "8.13.15" - "@dhis2-ui/checkbox" "8.13.15" - "@dhis2-ui/chip" "8.13.15" - "@dhis2-ui/field" "8.13.15" - "@dhis2-ui/input" "8.13.15" - "@dhis2-ui/layer" "8.13.15" - "@dhis2-ui/loader" "8.13.15" - "@dhis2-ui/popper" "8.13.15" - "@dhis2-ui/status-icon" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/select@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/select/-/select-8.14.7.tgz#7a1b3e188715b8d1216e2ba7a9ba623db20b81a9" @@ -2269,21 +1838,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/selector-bar@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/selector-bar/-/selector-bar-8.13.15.tgz#96239ca8025b55999c6823c1a16ccfd95913ca46" - integrity sha512-QSNuy3nx3bh8LRvLnx+1ygovyB9kEcS965Gdfm4l3no2wVcD2GMBsQlhKGtoIgxEWSJKKQ15oGrybEsWWuMAAw== - dependencies: - "@dhis2-ui/button" "8.13.15" - "@dhis2-ui/card" "8.13.15" - "@dhis2-ui/layer" "8.13.15" - "@dhis2-ui/popper" "8.13.15" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - "@testing-library/react" "^12.1.2" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/selector-bar@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/selector-bar/-/selector-bar-8.14.7.tgz#5ff9d34962f594ea9c7db1fea6d52d46aaba0c8e" @@ -2299,32 +1853,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/sharing-dialog@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/sharing-dialog/-/sharing-dialog-8.13.15.tgz#0dd96295d200e22f937e9bfab21b444a7680f3bd" - integrity sha512-IRA5xD3vNwASnEoNV10+j/YXy5s9LqxolDWI/GlCHPGnuYxdlCb4NdbwWSFdyuzBtB3XrrGN4/h3BVMRtCKXBA== - dependencies: - "@dhis2-ui/box" "8.13.15" - "@dhis2-ui/button" "8.13.15" - "@dhis2-ui/card" "8.13.15" - "@dhis2-ui/divider" "8.13.15" - "@dhis2-ui/input" "8.13.15" - "@dhis2-ui/layer" "8.13.15" - "@dhis2-ui/menu" "8.13.15" - "@dhis2-ui/modal" "8.13.15" - "@dhis2-ui/notice-box" "8.13.15" - "@dhis2-ui/popper" "8.13.15" - "@dhis2-ui/select" "8.13.15" - "@dhis2-ui/tab" "8.13.15" - "@dhis2-ui/tooltip" "8.13.15" - "@dhis2-ui/user-avatar" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - "@react-hook/size" "^2.1.2" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/sharing-dialog@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/sharing-dialog/-/sharing-dialog-8.14.7.tgz#f0423418f5bb9221c64e078a226991defbed08b2" @@ -2351,18 +1879,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/status-icon@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/status-icon/-/status-icon-8.13.15.tgz#b97326cb30fab4f6c8913eabc06b9a1f19c7e670" - integrity sha512-+MBRhmaLA9b0bkXEr5eCwN8FFdGq5u3RWXanvAGXlZ0WT7xYUfnqFellJ7qkM/tQQEoBzwuK1nrMLt4YWCrEuw== - dependencies: - "@dhis2-ui/loader" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/status-icon@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/status-icon/-/status-icon-8.14.7.tgz#5ab427ff1d21e7ffdaaa943b4d12aaddcc0ab63a" @@ -2375,18 +1891,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/switch@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/switch/-/switch-8.13.15.tgz#b064e8b1af0666756282da7ae59b40218e454ffb" - integrity sha512-E7o3SsNAN6OAt6zmizIfq1Uh4o0GPnwkK4l65JR32/4aMu6oC8omZFBtigmx26bo2P3AS0iIzar0gXwz4LIdyA== - dependencies: - "@dhis2-ui/field" "8.13.15" - "@dhis2-ui/required" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/switch@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/switch/-/switch-8.14.7.tgz#28b58f266f7c26f42d2348fcbfbc7f6e113ec9f4" @@ -2399,17 +1903,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/tab@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/tab/-/tab-8.13.15.tgz#a076b19761d327d481a25fc33d13be8996889b93" - integrity sha512-ak/OVhhHjnBAGPNuEl8Bekh/i7zroeP6BvkHMljpdDpbUN5Ex6+bgnwMpCEZ4qtwwTlZykbIsYelXDlRIGn7rQ== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/tab@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/tab/-/tab-8.14.7.tgz#6cc169fb97a2f227b0880e7f4c0cb5fe7b7eb20f" @@ -2421,17 +1914,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/table@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/table/-/table-8.13.15.tgz#b71680bef5209a4d30c47edb07edcb4a1e9def15" - integrity sha512-tJVQAA1pwji9AjyFr6oKWRzU01Vp/Lbk/5CQnrCqU9kh+uLIoyAfeyjF0kWGCB2uE37WrR5gC6/zOlSow3QqXw== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/table@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/table/-/table-8.14.7.tgz#769088964d52b2df952688f969f4143c782601df" @@ -2443,16 +1925,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/tag@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/tag/-/tag-8.13.15.tgz#cd6ccdb55bfba2ff102ae0cca0ae4fb1a9aea0b9" - integrity sha512-KzQYvRWEwOt2jkiv98tdyIH4Ibv2iUtoGo2Dik9Y0LAWRrPW5N8+x+/7Lr6G0ggBL10AhVrKOqA0PVxLYbFjMw== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/tag@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/tag/-/tag-8.14.7.tgz#203d7c6d916791e6691ef84b8bdff7f78a22c61d" @@ -2463,21 +1935,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/text-area@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/text-area/-/text-area-8.13.15.tgz#48d21eb7093fae2a2a6667f28c996ddd83251d54" - integrity sha512-djZt2OQH1CBaTPOg4iAgllNLYfbcvMuSQ9AR/hr1mf3/85e9ZLc12enXN0AaVkSQopemHvH/KcgNhA8ogEGWhQ== - dependencies: - "@dhis2-ui/box" "8.13.15" - "@dhis2-ui/field" "8.13.15" - "@dhis2-ui/loader" "8.13.15" - "@dhis2-ui/status-icon" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - "@dhis2/ui-icons" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/text-area@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/text-area/-/text-area-8.14.7.tgz#3814d749713b4b83a1c7b9ba3738244f4b35ae89" @@ -2493,18 +1950,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/tooltip@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/tooltip/-/tooltip-8.13.15.tgz#22acbbf785c51fd9a924621ae9c50f7a58fa88a5" - integrity sha512-6igahGDmonAJJIqmQsm93UCb/mn2Qvivk8NWk6SFDTRVFj6g2I/5ugK5oEn0BQcbIC98bddIj+rBKO2Gzj7oPA== - dependencies: - "@dhis2-ui/popper" "8.13.15" - "@dhis2-ui/portal" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/tooltip@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/tooltip/-/tooltip-8.14.7.tgz#636037a67d0882eb12d089553a39f865fe914be7" @@ -2517,21 +1962,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/transfer@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/transfer/-/transfer-8.13.15.tgz#de7199c68664821c3653a0e123e9bc9cd22ec745" - integrity sha512-blcrk8S3YXwVwlPS7UUkdVq6eg48j4Uqi/nir3t2HbfcnJDl3EjQW22xv/nSHcvDi5rzZ6cflVHWLzp4lJdObg== - dependencies: - "@dhis2-ui/button" "8.13.15" - "@dhis2-ui/field" "8.13.15" - "@dhis2-ui/input" "8.13.15" - "@dhis2-ui/intersection-detector" "8.13.15" - "@dhis2-ui/loader" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/transfer@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/transfer/-/transfer-8.14.7.tgz#a098d178d4e0b880e4b9edddcada55b67168c3f5" @@ -2547,16 +1977,6 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2-ui/user-avatar@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2-ui/user-avatar/-/user-avatar-8.13.15.tgz#619150face6561ecd679385a9fdd099d53a6b86e" - integrity sha512-wo6hYzTYY3rTtwiR1iSGunk02h5rvMfWok5HfCrvV4Dy+aSiegygS1ZQ806Dttmq4s03sVvMuZUX15v7GIfE4w== - dependencies: - "@dhis2/prop-types" "^3.1.2" - "@dhis2/ui-constants" "8.13.15" - classnames "^2.3.1" - prop-types "^15.7.2" - "@dhis2-ui/user-avatar@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2-ui/user-avatar/-/user-avatar-8.14.7.tgz#3cd54d5261ee7f10cee99a347f9f1bce7803dccf" @@ -2767,13 +2187,6 @@ workbox-routing "^6.1.5" workbox-strategies "^6.1.5" -"@dhis2/ui-constants@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2/ui-constants/-/ui-constants-8.13.15.tgz#e1124e79f077aed6b3a9703b8a257701ec68717b" - integrity sha512-XrwKXNM0Xiv7O3E9vAukOJv8sD1QD9ruLOUS66+fs4pBLd0L+W6Gjr7LYG1B19rANXAShmfR+dqgD/pLVLAqsw== - dependencies: - prop-types "^15.7.2" - "@dhis2/ui-constants@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2/ui-constants/-/ui-constants-8.14.7.tgz#bfab11cc3c8dc990f7592089ba9577f7a7c60411" @@ -2781,26 +2194,6 @@ dependencies: prop-types "^15.7.2" -"@dhis2/ui-forms@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2/ui-forms/-/ui-forms-8.13.15.tgz#5098893acada5fb06d263ce271f556fc1bae1acf" - integrity sha512-+skh3quuARmzVlVJUYnN8EM5Dz9OLOsnh/GpCMXyiO4yjhajpbQ0QtMh/dFyQhCB3LzywDVaoge+kwJyrIS82Q== - dependencies: - "@dhis2-ui/button" "8.13.15" - "@dhis2-ui/checkbox" "8.13.15" - "@dhis2-ui/field" "8.13.15" - "@dhis2-ui/file-input" "8.13.15" - "@dhis2-ui/input" "8.13.15" - "@dhis2-ui/radio" "8.13.15" - "@dhis2-ui/select" "8.13.15" - "@dhis2-ui/switch" "8.13.15" - "@dhis2-ui/text-area" "8.13.15" - "@dhis2/prop-types" "^3.1.2" - classnames "^2.3.1" - final-form "^4.20.2" - prop-types "^15.7.2" - react-final-form "^6.5.3" - "@dhis2/ui-forms@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2/ui-forms/-/ui-forms-8.14.7.tgz#fa9c8640cda7cb5417e1e62013d5a745c4098e25" @@ -2821,11 +2214,6 @@ prop-types "^15.7.2" react-final-form "^6.5.3" -"@dhis2/ui-icons@8.13.15": - version "8.13.15" - resolved "https://registry.yarnpkg.com/@dhis2/ui-icons/-/ui-icons-8.13.15.tgz#eb83784975d9686058ce71377928a0d4f726b517" - integrity sha512-d4A7oPgT6HKZgQDGaY8mX04EvQrnDmOv/L9n52JtnmEcPrPTqqhmCqdr/CQ8B/NP91nhFACDFBQ4ez4/YJVYKw== - "@dhis2/ui-icons@8.14.7": version "8.14.7" resolved "https://registry.yarnpkg.com/@dhis2/ui-icons/-/ui-icons-8.14.7.tgz#351d5890544a656c0838bba6979e9068ed051b97" @@ -14794,9 +14182,9 @@ zip-stream@^2.1.2: readable-stream "^3.4.0" zod@^3.22.2: - version "3.22.2" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.2.tgz#3add8c682b7077c05ac6f979fea6998b573e157b" - integrity sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg== + version "3.22.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" + integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg== zustand@^4.4.0: version "4.4.0"