From 107686682013094b7875b8923a67cbcd1d421e46 Mon Sep 17 00:00:00 2001 From: Parship Chowdhury Date: Thu, 25 Jun 2026 21:41:35 +0530 Subject: [PATCH] fix(server): preserve anyFieldFilterValue in view manifest sync (#22004) ### Summary - Fixes #19978 - `shouldHideEmptyGroups` was already wired up in the type and converter; this PR only closes the remaining gap for `anyFieldFilterValue`. Review in cubic --------- Signed-off-by: Parship Chowdhury Co-authored-by: Charles Bochet --- ...nifest-to-universal-flat-view.util.spec.ts | 16 ++++++++++++++++ ...ew-manifest-to-universal-flat-view.util.ts | 2 +- ...s-app-owned-view-field.integration-spec.ts | 19 +++++++++++++++++++ .../src/application/viewManifestType.ts | 1 + 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/twenty-server/src/engine/core-modules/application/application-manifest/converters/__tests__/from-view-manifest-to-universal-flat-view.util.spec.ts b/packages/twenty-server/src/engine/core-modules/application/application-manifest/converters/__tests__/from-view-manifest-to-universal-flat-view.util.spec.ts index be2f9c8f19..4971364fb4 100644 --- a/packages/twenty-server/src/engine/core-modules/application/application-manifest/converters/__tests__/from-view-manifest-to-universal-flat-view.util.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/application/application-manifest/converters/__tests__/from-view-manifest-to-universal-flat-view.util.spec.ts @@ -114,6 +114,7 @@ describe('fromViewManifestToUniversalFlatView', () => { ).toBeNull(); expect(result.calendarLayout).toBeNull(); expect(result.calendarFieldMetadataUniversalIdentifier).toBeNull(); + expect(result.anyFieldFilterValue).toBeNull(); }); it('should preserve calendar fields from the manifest', () => { @@ -135,4 +136,19 @@ describe('fromViewManifestToUniversalFlatView', () => { 'field-uuid-date', ); }); + + it('should preserve anyFieldFilterValue from the manifest', () => { + const result = fromViewManifestToUniversalFlatView({ + viewManifest: { + universalIdentifier: 'view-uuid-6', + name: 'Filtered View', + objectUniversalIdentifier: 'object-uuid-1', + anyFieldFilterValue: 'search term', + }, + applicationUniversalIdentifier, + now, + }); + + expect(result.anyFieldFilterValue).toBe('search term'); + }); }); diff --git a/packages/twenty-server/src/engine/core-modules/application/application-manifest/converters/from-view-manifest-to-universal-flat-view.util.ts b/packages/twenty-server/src/engine/core-modules/application/application-manifest/converters/from-view-manifest-to-universal-flat-view.util.ts index 8e98d48445..6588b827b3 100644 --- a/packages/twenty-server/src/engine/core-modules/application/application-manifest/converters/from-view-manifest-to-universal-flat-view.util.ts +++ b/packages/twenty-server/src/engine/core-modules/application/application-manifest/converters/from-view-manifest-to-universal-flat-view.util.ts @@ -40,7 +40,7 @@ export const fromViewManifestToUniversalFlatView = ({ viewManifest.mainGroupByFieldMetadataUniversalIdentifier ?? null, shouldHideEmptyGroups: viewManifest.shouldHideEmptyGroups ?? false, kanbanColumnWidth: viewManifest.kanbanColumnWidth ?? null, - anyFieldFilterValue: null, + anyFieldFilterValue: viewManifest.anyFieldFilterValue ?? null, createdByUserWorkspaceId: null, isActive: true, isSystemSideEffect: false, diff --git a/packages/twenty-server/test/integration/metadata/suites/application/successful-resync-application-with-cross-app-owned-view-field.integration-spec.ts b/packages/twenty-server/test/integration/metadata/suites/application/successful-resync-application-with-cross-app-owned-view-field.integration-spec.ts index 4a2fc3c285..3599d287fe 100644 --- a/packages/twenty-server/test/integration/metadata/suites/application/successful-resync-application-with-cross-app-owned-view-field.integration-spec.ts +++ b/packages/twenty-server/test/integration/metadata/suites/application/successful-resync-application-with-cross-app-owned-view-field.integration-spec.ts @@ -25,6 +25,9 @@ const ARM_VIEW_FIELD_ID = uuidv4(); const HEAD_VIEW_FIELD_ID = uuidv4(); const TAIL_VIEW_FIELD_ID = uuidv4(); +const INITIAL_ANY_FIELD_FILTER_VALUE = 'arm'; +const UPDATED_ANY_FIELD_FILTER_VALUE = 'tail'; + const HUMAN_OBJECT = buildDefaultObjectManifest({ nameSingular: 'human', namePlural: 'humans', @@ -65,6 +68,7 @@ const buildInitialManifest = (): Manifest => universalIdentifier: BODY_VIEW_ID, name: 'Body', objectUniversalIdentifier: HUMAN_OBJECT.universalIdentifier, + anyFieldFilterValue: INITIAL_ANY_FIELD_FILTER_VALUE, fields: [ { universalIdentifier: ARM_VIEW_FIELD_ID, @@ -106,6 +110,7 @@ const buildResyncManifest = (): Manifest => universalIdentifier: BODY_VIEW_ID, name: 'Body', objectUniversalIdentifier: HUMAN_OBJECT.universalIdentifier, + anyFieldFilterValue: UPDATED_ANY_FIELD_FILTER_VALUE, fields: [ { universalIdentifier: ARM_VIEW_FIELD_ID, @@ -179,6 +184,7 @@ describe('Successful re-sync of an application whose app-owned view references a const bodyView = viewsData?.getViews.find((view) => view.name === 'Body'); expect(bodyView).toBeDefined(); + expect(bodyView?.anyFieldFilterValue).toBe(INITIAL_ANY_FIELD_FILTER_VALUE); const { data: createViewFieldData } = await createOneViewField({ input: { @@ -207,6 +213,19 @@ describe('Successful re-sync of an application whose app-owned view references a expect(tailField).toBeDefined(); + const { data: viewsDataAfterResync } = await findViews({ + objectMetadataId: humanObjectAfterResync?.id, + expectToFail: false, + }); + + const bodyViewAfterResync = viewsDataAfterResync?.getViews.find( + (view) => view.name === 'Body', + ); + + expect(bodyViewAfterResync?.anyFieldFilterValue).toBe( + UPDATED_ANY_FIELD_FILTER_VALUE, + ); + const { data: viewFieldsData } = await findViewFields({ viewId: bodyView?.id ?? '', expectToFail: false, diff --git a/packages/twenty-shared/src/application/viewManifestType.ts b/packages/twenty-shared/src/application/viewManifestType.ts index 1179f49188..e788e8d5c7 100644 --- a/packages/twenty-shared/src/application/viewManifestType.ts +++ b/packages/twenty-shared/src/application/viewManifestType.ts @@ -75,6 +75,7 @@ export type ViewManifest = SyncableEntityOptions & { openRecordIn?: ViewOpenRecordIn; mainGroupByFieldMetadataUniversalIdentifier?: string; shouldHideEmptyGroups?: boolean; + anyFieldFilterValue?: string | null; kanbanColumnWidth?: number | null; kanbanAggregateOperation?: AggregateOperations; kanbanAggregateOperationFieldMetadataUniversalIdentifier?: string;