From 746e7f011ca1aaa9dcf7bd4eeb38e68d10f73cdb Mon Sep 17 00:00:00 2001 From: Radoslaw Szwajkowski Date: Wed, 8 Nov 2023 20:14:47 +0100 Subject: [PATCH] Create the filter dynamically based on available data Before, filter definition was static and could only use data known at compile time i.e. constant enums. With this change the framework is extended to create filters dynamically based on current data. The main use case is to filter items based on data unknown at the compile time i.e. host names. Signed-off-by: Radoslaw Szwajkowski --- .../FilterGroup/AttributeValueFilter.stories.tsx | 4 ++-- .../FilterGroup/FilterGroup.stories.tsx | 4 ++-- .../src/components/Filter/GroupedEnumFilter.tsx | 2 +- .../common/src/components/FilterGroup/helpers.ts | 12 +++++++----- packages/common/src/utils/types.ts | 1 + .../src/components/page/StandardPage.tsx | 8 +++++--- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/common/src/components-stories/FilterGroup/AttributeValueFilter.stories.tsx b/packages/common/src/components-stories/FilterGroup/AttributeValueFilter.stories.tsx index c265c1c13..4eb468eb4 100644 --- a/packages/common/src/components-stories/FilterGroup/AttributeValueFilter.stories.tsx +++ b/packages/common/src/components-stories/FilterGroup/AttributeValueFilter.stories.tsx @@ -91,7 +91,7 @@ export const AttributeValueWithMultipleSelectionTypes: Story = { type: ['india', 'japan', 'france'], archived: ['true'], }, - fieldFilters: fieldsMetadata.filter((field) => field.filter?.primary).map(toFieldFilter), + fieldFilters: fieldsMetadata.filter((field) => field.filter?.primary).map(toFieldFilter()), supportedFilterTypes: defaultSupportedFilters, }, }; @@ -107,7 +107,7 @@ export const AttributeValueWithMultipleSelectionTypes: Story = { export const AttributeValueWithNoSelectedValues: Story = { args: { selectedFilters: {}, - fieldFilters: fieldsMetadata.filter((field) => field.filter?.primary).map(toFieldFilter), + fieldFilters: fieldsMetadata.filter((field) => field.filter?.primary).map(toFieldFilter()), supportedFilterTypes: defaultSupportedFilters, }, }; diff --git a/packages/common/src/components-stories/FilterGroup/FilterGroup.stories.tsx b/packages/common/src/components-stories/FilterGroup/FilterGroup.stories.tsx index 496f58eae..cc3483948 100644 --- a/packages/common/src/components-stories/FilterGroup/FilterGroup.stories.tsx +++ b/packages/common/src/components-stories/FilterGroup/FilterGroup.stories.tsx @@ -90,7 +90,7 @@ export const FilterGroupWithMultipleSelectionTypes: Story = { type: ['india', 'japan', 'france'], archived: ['true'], }, - fieldFilters: fieldsMetadata.filter((field) => field.filter?.primary).map(toFieldFilter), + fieldFilters: fieldsMetadata.filter((field) => field.filter?.primary).map(toFieldFilter()), supportedFilterTypes: defaultSupportedFilters, }, }; @@ -106,7 +106,7 @@ export const FilterGroupWithMultipleSelectionTypes: Story = { export const FilterGroupWithNoSelectedValues: Story = { args: { selectedFilters: {}, - fieldFilters: fieldsMetadata.filter((field) => field.filter?.primary).map(toFieldFilter), + fieldFilters: fieldsMetadata.filter((field) => field.filter?.primary).map(toFieldFilter()), supportedFilterTypes: defaultSupportedFilters, }, }; diff --git a/packages/common/src/components/Filter/GroupedEnumFilter.tsx b/packages/common/src/components/Filter/GroupedEnumFilter.tsx index 95258c1bf..733a3e236 100644 --- a/packages/common/src/components/Filter/GroupedEnumFilter.tsx +++ b/packages/common/src/components/Filter/GroupedEnumFilter.tsx @@ -37,7 +37,7 @@ export const GroupedEnumFilter = ({ selectedFilters: selectedEnumIds = [], onFilterUpdate: onSelectedEnumIdsChange, supportedValues: supportedEnumValues = [], - supportedGroups, + supportedGroups = [], placeholderLabel, showFilter = true, }: FilterTypeProps) => { diff --git a/packages/common/src/components/FilterGroup/helpers.ts b/packages/common/src/components/FilterGroup/helpers.ts index d17952f48..27bf31d80 100644 --- a/packages/common/src/components/FilterGroup/helpers.ts +++ b/packages/common/src/components/FilterGroup/helpers.ts @@ -2,11 +2,13 @@ import { ResourceField } from '../../utils'; import { FieldFilter } from './types'; -export const toFieldFilter = ({ - resourceFieldId, - label, - filter: filterDef, -}: ResourceField): FieldFilter => ({ resourceFieldId, label, filterDef }); +export const toFieldFilter = + (data?: unknown[]): ((field: ResourceField) => FieldFilter) => + ({ resourceFieldId, label, filter }: ResourceField): FieldFilter => ({ + resourceFieldId, + label, + filterDef: { ...filter, ...filter?.dynamicFilter?.(data ?? []) }, + }); export const EnumToTuple = (i18nEnum: { [k: string]: string }) => Object.entries(i18nEnum).map(([type, label]) => ({ id: type, label })); diff --git a/packages/common/src/utils/types.ts b/packages/common/src/utils/types.ts index 7f30aaebe..aa515c795 100644 --- a/packages/common/src/utils/types.ts +++ b/packages/common/src/utils/types.ts @@ -22,6 +22,7 @@ export interface FilterDef { // by default missing/empty filters result in positive match (vacuous truth) defaultValues?: string[]; helperText?: string | React.ReactNode; + dynamicFilter?: (items: unknown[]) => Partial; } type OpenApiJsonPath = string | ((resourceData: unknown) => unknown); diff --git a/packages/forklift-console-plugin/src/components/page/StandardPage.tsx b/packages/forklift-console-plugin/src/components/page/StandardPage.tsx index 23c7c4be6..878290852 100644 --- a/packages/forklift-console-plugin/src/components/page/StandardPage.tsx +++ b/packages/forklift-console-plugin/src/components/page/StandardPage.tsx @@ -217,7 +217,9 @@ export function StandardPage({ const noResults = loaded && !error && flatData.length == 0; const noMatchingResults = loaded && !error && filteredData.length === 0 && flatData.length > 0; - const primaryFilters = fields.filter((field) => field.filter?.primary).map(toFieldFilter); + const primaryFilters = fields + .filter((field) => field.filter?.primary) + .map(toFieldFilter(flatData)); return ( <> @@ -246,7 +248,7 @@ export function StandardPage({ filter && !filter.primary && !filter.standalone) - .map(toFieldFilter)} + .map(toFieldFilter(flatData))} onFilterUpdate={setSelectedFilters} selectedFilters={selectedFilters} supportedFilterTypes={supportedFilters} @@ -256,7 +258,7 @@ export function StandardPage({ field.filter?.standalone) - .map(toFieldFilter)} + .map(toFieldFilter(flatData))} onFilterUpdate={setSelectedFilters} selectedFilters={selectedFilters} supportedFilterTypes={supportedFilters}