fix: restore ViewFilter value stringification lost in converter removal (#18745)

## 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)
This commit is contained in:
Charles Bochet 2026-03-18 19:06:43 +01:00 committed by GitHub
parent 189c564840
commit 394a3cef15
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 12 additions and 4 deletions

View file

@ -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,
});
}

View file

@ -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,