From 394a3cef15aefaae0ddc639f50b28155fa041624 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Wed, 18 Mar 2026 19:06:43 +0100 Subject: [PATCH] fix: restore ViewFilter value stringification lost in converter removal (#18745) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - **Restores `convertViewFilterValueToString()` calls** that were lost when the converter layer was removed in #18667. The GraphQL `ViewFilter.value` is typed as `JSON` (can be a string, array, or object), but the frontend type system expects a `string`. Without stringification, SELECT/MULTI_SELECT filter values (e.g. `['LOST']`) reach `arrayOfStringsOrVariablesSchema` as raw arrays, causing a `ZodError: expected string, received array`. - **Fixes applied at two data boundary points**: `splitViewWithRelated` (primary entry from metadata store) and `mapViewFiltersToFilters` (which also accepts `GqlViewFilter[]` directly). Fixes a production regression introduced by #18667. ## Test plan - [ ] Apply a SELECT filter (e.g. filter Opportunities by Stage = "Lost") — should no longer throw ZodError - [ ] Apply a MULTI_SELECT filter — should work correctly - [ ] Verify filters with multiple selected values work (e.g. Stage is "Lost" or "Won") - [ ] Verify empty filters and "is not" operands still work - [ ] Verify filters loaded from saved views still work after page refresh Made with [Cursor](https://cursor.com) --- .../metadata-store/utils/splitViewWithRelated.ts | 2 ++ .../modules/views/utils/mapViewFiltersToFilters.ts | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/twenty-front/src/modules/metadata-store/utils/splitViewWithRelated.ts b/packages/twenty-front/src/modules/metadata-store/utils/splitViewWithRelated.ts index b062d2615cc..5129e56acc3 100644 --- a/packages/twenty-front/src/modules/metadata-store/utils/splitViewWithRelated.ts +++ b/packages/twenty-front/src/modules/metadata-store/utils/splitViewWithRelated.ts @@ -6,6 +6,7 @@ import { type FlatViewFilterGroup } from '@/metadata-store/types/FlatViewFilterG import { type FlatViewGroup } from '@/metadata-store/types/FlatViewGroup'; import { type FlatViewSort } from '@/metadata-store/types/FlatViewSort'; import { type ViewWithRelations } from '@/views/types/ViewWithRelations'; +import { convertViewFilterValueToString } from 'twenty-shared/utils'; type SplitResult = { flatViews: FlatView[]; @@ -51,6 +52,7 @@ export const splitViewWithRelated = ( for (const viewFilter of viewFilters) { flatViewFilters.push({ ...viewFilter, + value: convertViewFilterValueToString(viewFilter.value), viewId: viewWithRelated.id, }); } diff --git a/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts b/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts index 24c18775f68..8cf6545e560 100644 --- a/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts +++ b/packages/twenty-front/src/modules/views/utils/mapViewFiltersToFilters.ts @@ -4,7 +4,11 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataIte import { isSystemSearchVectorField } from '@/object-record/utils/isSystemSearchVectorField'; import { type CompositeFieldSubFieldName } from '@/settings/data-model/types/CompositeFieldSubFieldName'; -import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils'; +import { + convertViewFilterValueToString, + getFilterTypeFromFieldType, + isDefined, +} from 'twenty-shared/utils'; import { type ViewFilter as GqlViewFilter } from '~/generated-metadata/graphql'; import { type ViewFilter } from '@/views/types/ViewFilter'; @@ -34,14 +38,16 @@ export const mapViewFiltersToFilters = ( const operand = viewFilter.operand; + const stringValue = convertViewFilterValueToString(viewFilter.value); + return { id: viewFilter.id, fieldMetadataId: viewFilter.fieldMetadataId, - value: viewFilter.value, + value: stringValue, displayValue: - 'displayValue' in viewFilter + 'displayValue' in viewFilter && isDefined(viewFilter.displayValue) ? viewFilter.displayValue - : viewFilter.value, + : stringValue, operand, recordFilterGroupId: viewFilter.viewFilterGroupId ?? undefined, positionInRecordFilterGroup: viewFilter.positionInViewFilterGroup,