From 0e4b18112d8eebd7b2e52663809eb7075c236c33 Mon Sep 17 00:00:00 2001 From: Birk Johansson Date: Thu, 28 Nov 2024 17:55:11 +0100 Subject: [PATCH] fix(list): add additional list filters to dataElementGroup/Set --- i18n/en.pot | 6 ++ .../filterSelectors/BooleanFilters.tsx | 18 +++++ .../filterSelectors/DataElementFilter.tsx | 24 +++++++ .../filterSelectors/DataElementGroup.tsx | 24 +++++++ .../filterSelectors/DataElementGroupSet.tsx | 24 +++++++ .../filterSelectors/DynamicFilters.tsx | 26 +++++--- .../filters/filterSelectors/index.ts | 3 + .../constants/translatedModelProperties.ts | 21 +++--- src/lib/sectionList/filters/filterConfig.tsx | 33 ++++++---- .../filters/parseFiltersToQueryParams.ts | 3 + .../listViews/sectionListViewsConfig.ts | 9 ++- src/pages/dataElements/List.tsx | 65 +------------------ 12 files changed, 164 insertions(+), 92 deletions(-) create mode 100644 src/components/sectionList/filters/filterSelectors/DataElementFilter.tsx create mode 100644 src/components/sectionList/filters/filterSelectors/DataElementGroup.tsx create mode 100644 src/components/sectionList/filters/filterSelectors/DataElementGroupSet.tsx diff --git a/i18n/en.pot b/i18n/en.pot index 1f209e0b..019a902d 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -1279,6 +1279,12 @@ msgstr "Advanced" msgid "Set up the basic information for this Indicator Type." msgstr "Set up the basic information for this Indicator Type." +msgid "Delete source indicator types" +msgstr "Delete source indicator types" + +msgid "Merge" +msgstr "Merge" + msgid "Longitude" msgstr "Longitude" diff --git a/src/components/sectionList/filters/filterSelectors/BooleanFilters.tsx b/src/components/sectionList/filters/filterSelectors/BooleanFilters.tsx index 4cdf3b9c..de73d3ed 100644 --- a/src/components/sectionList/filters/filterSelectors/BooleanFilters.tsx +++ b/src/components/sectionList/filters/filterSelectors/BooleanFilters.tsx @@ -33,3 +33,21 @@ export const IgnoreApprovalFilter = () => { /> ) } + +export const CompulsoryFilter = () => { + return ( + + ) +} + +export const DataDimensionFilter = () => { + return ( + + ) +} diff --git a/src/components/sectionList/filters/filterSelectors/DataElementFilter.tsx b/src/components/sectionList/filters/filterSelectors/DataElementFilter.tsx new file mode 100644 index 00000000..0015f20e --- /dev/null +++ b/src/components/sectionList/filters/filterSelectors/DataElementFilter.tsx @@ -0,0 +1,24 @@ +import i18n from '@dhis2/d2-i18n' +import React from 'react' +import { useSectionListFilter } from '../../../../lib' +import { createFilterDataQuery } from './createFilterDataQuery' +import { ModelFilterSelect } from './ModelFilter' + +const query = createFilterDataQuery('dataElements') + +export const DataElementFilter = () => { + const [filter, setFilter] = useSectionListFilter('dataElement') + + const selected = filter?.[0] + + return ( + + setFilter(selected ? [selected] : undefined) + } + /> + ) +} diff --git a/src/components/sectionList/filters/filterSelectors/DataElementGroup.tsx b/src/components/sectionList/filters/filterSelectors/DataElementGroup.tsx new file mode 100644 index 00000000..13aaed82 --- /dev/null +++ b/src/components/sectionList/filters/filterSelectors/DataElementGroup.tsx @@ -0,0 +1,24 @@ +import i18n from '@dhis2/d2-i18n' +import React from 'react' +import { useSectionListFilter } from '../../../../lib' +import { createFilterDataQuery } from './createFilterDataQuery' +import { ModelFilterSelect } from './ModelFilter' + +const query = createFilterDataQuery('dataElementGroups') + +export const DataElementGroupFilter = () => { + const [filter, setFilter] = useSectionListFilter('dataElementGroup') + + const selected = filter?.[0] + + return ( + + setFilter(selected ? [selected] : undefined) + } + /> + ) +} diff --git a/src/components/sectionList/filters/filterSelectors/DataElementGroupSet.tsx b/src/components/sectionList/filters/filterSelectors/DataElementGroupSet.tsx new file mode 100644 index 00000000..a56f80db --- /dev/null +++ b/src/components/sectionList/filters/filterSelectors/DataElementGroupSet.tsx @@ -0,0 +1,24 @@ +import i18n from '@dhis2/d2-i18n' +import React from 'react' +import { useSectionListFilter } from '../../../../lib' +import { createFilterDataQuery } from './createFilterDataQuery' +import { ModelFilterSelect } from './ModelFilter' + +const query = createFilterDataQuery('dataElementGroupSets') + +export const DataElementGroupSetFilter = () => { + const [filter, setFilter] = useSectionListFilter('dataElementGroupSet') + + const selected = filter?.[0] + + return ( + + setFilter(selected ? [selected] : undefined) + } + /> + ) +} diff --git a/src/components/sectionList/filters/filterSelectors/DynamicFilters.tsx b/src/components/sectionList/filters/filterSelectors/DynamicFilters.tsx index 772da489..c73759c4 100644 --- a/src/components/sectionList/filters/filterSelectors/DynamicFilters.tsx +++ b/src/components/sectionList/filters/filterSelectors/DynamicFilters.tsx @@ -15,24 +15,34 @@ import { ValueTypeSelectionFilter, FormTypeFilter, DataSetFilter, + DataElementGroupFilter, + DataElementGroupSetFilter, + DataElementFilter, + CompulsoryFilter, + DataDimensionFilter, } from '.' type FilterKeyToComponentMap = Partial> const filterKeyToComponentMap: FilterKeyToComponentMap = { + aggregationType: AggregationTypeFilter, category: Categoryfilter, - formType: FormTypeFilter, - indicatorType: IndicatorFilter, - categoryOption: CategoryOptionFilter, categoryCombo: CategoryComboFilter, + categoryOption: CategoryOptionFilter, categoryOptionGroup: CategoryOptionGroupFilter, - domainType: DomainTypeSelectionFilter, - valueType: ValueTypeSelectionFilter, - aggregationType: AggregationTypeFilter, - publicAccess: PublicAccessFilter, + compulsory: CompulsoryFilter, + dataDimension: DataDimensionFilter, dataDimensionType: DataDimensionTypeFilter, - ignoreApproval: IgnoreApprovalFilter, + dataElement: DataElementFilter, + dataElementGroup: DataElementGroupFilter, + dataElementGroupSet: DataElementGroupSetFilter, dataSet: DataSetFilter, + domainType: DomainTypeSelectionFilter, + formType: FormTypeFilter, + ignoreApproval: IgnoreApprovalFilter, + indicatorType: IndicatorFilter, + publicAccess: PublicAccessFilter, + valueType: ValueTypeSelectionFilter, } export const DynamicFilters = () => { diff --git a/src/components/sectionList/filters/filterSelectors/index.ts b/src/components/sectionList/filters/filterSelectors/index.ts index fa056f4d..a782dcc6 100644 --- a/src/components/sectionList/filters/filterSelectors/index.ts +++ b/src/components/sectionList/filters/filterSelectors/index.ts @@ -9,3 +9,6 @@ export * from './BooleanFilters' export * from './CategoryOptionFilter' export * from './IndicatorFilter' export * from './DataSetFilter' +export * from './DataElementGroupSet' +export * from './DataElementGroup' +export * from './DataElementFilter' diff --git a/src/lib/constants/translatedModelProperties.ts b/src/lib/constants/translatedModelProperties.ts index 8916498e..05c22a01 100644 --- a/src/lib/constants/translatedModelProperties.ts +++ b/src/lib/constants/translatedModelProperties.ts @@ -6,27 +6,32 @@ const TRANSLATED_PROPERTY: Record = { categoryCombo: i18n.t('Category combination'), categoryOption: i18n.t('Category option'), code: i18n.t('Code'), + compulsory: i18n.t('Compulsory'), + created: i18n.t('Created'), createdBy: i18n.t('Created by'), + dataElement: i18n.t('Data element'), + dataElementGroup: i18n.t('Data element group'), + dataElementGroupSet: i18n.t('Data element group set'), + dataDimension: i18n.t('Data dimension'), + dataDimensionType: i18n.t('Data dimension type'), + dataSet: i18n.t('Data set'), description: i18n.t('Description'), + domainType: i18n.t('Domain type'), favorite: i18n.t('Favorite'), formName: i18n.t('Form name'), + formType: i18n.t('Form type'), href: i18n.t('API URL'), id: i18n.t('Id'), + ignoreApproval: i18n.t('Ignore data approval'), indicatorType: i18n.t('Indicator type'), - lastUpdatedBy: i18n.t('Last updated by'), - created: i18n.t('Created'), - domainType: i18n.t('Domain type'), - formType: i18n.t('Form type'), - dataSet: i18n.t('Data set'), lastUpdated: i18n.t('Last updated'), + lastUpdatedBy: i18n.t('Last updated by'), name: i18n.t('Name'), sharing: i18n.t('Sharing'), shortName: i18n.t('Short name'), - valueType: i18n.t('Value type'), user: i18n.t('Owner'), // user refers to the owner of the object + valueType: i18n.t('Value type'), zeroIsSignificant: i18n.t('Zero is significant'), - dataDimensionType: i18n.t('Data dimension type'), - ignoreApproval: i18n.t('Ignore data approval'), } const camelCaseToSentenceCase = (camelCase: string) => diff --git a/src/lib/sectionList/filters/filterConfig.tsx b/src/lib/sectionList/filters/filterConfig.tsx index 5593d716..a2347a13 100644 --- a/src/lib/sectionList/filters/filterConfig.tsx +++ b/src/lib/sectionList/filters/filterConfig.tsx @@ -12,21 +12,27 @@ const zodArrayIds = z.array(z.string().refine((val) => isValidUid(val))) export const filterParamsSchema = z .object({ [IDENTIFIABLE_FILTER_KEY]: z.string(), + aggregationType: z.array(z.nativeEnum(DataElement.aggregationType)), - categoryCombo: zodArrayIds, category: zodArrayIds, - formType: z.array(z.nativeEnum(DataSet.formType)), + categoryCombo: zodArrayIds, categoryOption: zodArrayIds, categoryOptionGroup: zodArrayIds, + compulsory: z.boolean(), + dataDimension: z.boolean(), + dataDimensionType: z.nativeEnum(Category.dataDimensionType), + dataElement: zodArrayIds, + dataElementGroup: zodArrayIds, + dataElementGroupSet: zodArrayIds, dataSet: zodArrayIds, domainType: z.array(z.nativeEnum(DataElement.domainType)), + formType: z.array(z.nativeEnum(DataSet.formType)), + ignoreApproval: z.boolean(), + indicatorType: zodArrayIds, publicAccess: z.array( z.string().refine((val) => parseAccessString(val) !== null) ), valueType: z.array(z.nativeEnum(DataElement.valueType)), - dataDimensionType: z.nativeEnum(Category.dataDimensionType), - ignoreApproval: z.boolean(), - indicatorType: zodArrayIds, }) .partial() @@ -35,18 +41,23 @@ Mapping each filter to a config object that handles encoding/decoding */ export const filterQueryParamType = { [IDENTIFIABLE_FILTER_KEY]: StringParam, aggregationType: CustomDelimitedArrayParam, - domainType: CustomDelimitedArrayParam, - valueType: CustomDelimitedArrayParam, - dataSet: CustomDelimitedArrayParam, category: CustomDelimitedArrayParam, - formType: CustomDelimitedArrayParam, - categoryOption: CustomDelimitedArrayParam, categoryCombo: CustomDelimitedArrayParam, + categoryOption: CustomDelimitedArrayParam, categoryOptionGroup: CustomDelimitedArrayParam, - publicAccess: CustomDelimitedArrayParam, + compulsory: BooleanParam, + dataDimension: BooleanParam, dataDimensionType: StringParam, + dataElement: CustomDelimitedArrayParam, + dataElementGroup: CustomDelimitedArrayParam, + dataElementGroupSet: CustomDelimitedArrayParam, + dataSet: CustomDelimitedArrayParam, + domainType: CustomDelimitedArrayParam, + formType: CustomDelimitedArrayParam, ignoreApproval: BooleanParam, indicatorType: CustomDelimitedArrayParam, + publicAccess: CustomDelimitedArrayParam, + valueType: CustomDelimitedArrayParam, } as const satisfies QueryParamsConfigMap export const validFilterKeys = Object.keys(filterQueryParamType) diff --git a/src/lib/sectionList/filters/parseFiltersToQueryParams.ts b/src/lib/sectionList/filters/parseFiltersToQueryParams.ts index 53bb0b47..b5e3419b 100644 --- a/src/lib/sectionList/filters/parseFiltersToQueryParams.ts +++ b/src/lib/sectionList/filters/parseFiltersToQueryParams.ts @@ -44,6 +44,9 @@ const filterToQueryParamMap: FilterToQueryParamsMap = { section.name === SchemaName.dataElement ? inFilter('dataSetElements.dataSet.id', value) : defaultFilter('dataSet', value), + dataElementGroup: (value) => inFilter('dataElementGroups.id', value), + dataElement: (value) => inFilter('dataElements.id', value), + dataElementGroupSet: (value) => inFilter('groupSets.id', value), publicAccess: (value) => inFilter('sharing.public', value), } diff --git a/src/lib/sectionList/listViews/sectionListViewsConfig.ts b/src/lib/sectionList/listViews/sectionListViewsConfig.ts index 6c6403b7..7581fd79 100644 --- a/src/lib/sectionList/listViews/sectionListViewsConfig.ts +++ b/src/lib/sectionList/listViews/sectionListViewsConfig.ts @@ -115,13 +115,18 @@ export const modelListViewsConfig = { columns: { available: [DESCRIPTORS.shortName], }, - filters: {}, + filters: { + default: ['dataElement', 'dataElementGroupSet'], + }, }, dataElementGroupSet: { columns: { available: [DESCRIPTORS.shortName], }, - filters: {}, + filters: { + available: ['compulsory', 'dataDimension'], + default: ['dataElementGroup'], + }, }, dataSet: { columns: { diff --git a/src/pages/dataElements/List.tsx b/src/pages/dataElements/List.tsx index 51c39765..e03292f8 100644 --- a/src/pages/dataElements/List.tsx +++ b/src/pages/dataElements/List.tsx @@ -1,64 +1,3 @@ -import { useDataQuery } from '@dhis2/app-runtime' -import { SharingDialog } from '@dhis2/ui' -import React, { useEffect } from 'react' -import { SectionListWrapper } from '../../components' -import { useModelListView } from '../../components/sectionList/listView' -import { - useSchemaFromHandle, - useParamsForDataQuery, - DEFAULT_FIELD_FILTERS, - DefaultFields, -} from '../../lib/' -import { getFieldFilter } from '../../lib/models/path' -import { Query, WrapQueryResponse } from '../../types' -import { DataElement, ModelCollectionResponse } from '../../types/models' +import { DefaultSectionList } from '../DefaultSectionList' -type FilteredDataElement = Pick & - Partial - -type DataElements = ModelCollectionResponse - -type DataElementsResponse = WrapQueryResponse - -const query: Query = { - result: { - resource: 'dataElements', - params: (params) => params, - }, -} - -export const Component = () => { - const { columns, query: listViewQuery } = useModelListView() - const initialParams = useParamsForDataQuery() - const schema = useSchemaFromHandle() - const { refetch, error, data } = useDataQuery( - query, - // refetched on mount by effect below - { lazy: true } - ) - - useEffect(() => { - // wait to fetch until selected-columns are loaded - // so we dont fetch data multiple times - if (listViewQuery.isLoading) { - return - } - refetch({ - ...initialParams, - fields: columns - .map((column) => getFieldFilter(schema, column.path)) - .concat(DEFAULT_FIELD_FILTERS), - }) - }, [refetch, initialParams, columns, listViewQuery.isLoading, schema]) - - return ( -
- -
- ) -} +export const Component = DefaultSectionList