From a8dad6c8820f67c4725ce56adf16687dcf96cc2d Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Wed, 25 Mar 2026 17:41:15 +0100 Subject: [PATCH] Fix: default to allow-read when object permissions are not yet loaded (#18971) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fixes the merge-queue E2E failures that started after #18912 landed. `filterReadableActiveObjectMetadataItems` (introduced in #18912) treats a **missing** entry in the permissions map as "deny read". The previous helper (`getObjectPermissionsFromMapByObjectMetadataId`) treated it as **"allow read"** via a `?? { canReadObjectRecords: true, … }` fallback. Because the permissions map is empty on initial render (before the API round-trip completes), **every object was temporarily filtered out**. This made `useDefaultHomePagePath` return the settings-profile path, triggering a redirect race that broke Settings navigation in three E2E tests: - `signup_invite_email.spec.ts` — timed out waiting for `getByRole('link', { name: 'Members' })` - `create-kanban-view.spec.ts` — timed out waiting for `getByRole('link', { name: 'Data model' })` - `workflow-creation.spec.ts` — timed out waiting for sidebar Workflows button **Evidence from CI:** - Last passing merge-queue run: base `13ea3ec75c` (before #18912) - First failing merge-queue run: base `5f0d6553f6` (#18912) - All individual PR CI runs continued to pass (they don't rebase on latest main) - Screenshot artifact shows the app stuck on the main page — the Settings drawer never opened ## Fix When an object has no entry in the permissions map, default to allowing read (matching the old behavior). An empty map means permissions haven't loaded yet, not that the user lacks access. ```diff objectMetadataItems.filter((objectMetadataItem) => { + if (!objectMetadataItem.isActive) { + return false; + } + const objectPermissions = objectPermissionsByObjectMetadataId[objectMetadataItem.id]; - - return ( - isDefined(objectPermissions) && - objectPermissions.canReadObjectRecords && - objectMetadataItem.isActive - ); + + if (!isDefined(objectPermissions)) { + return true; + } + + return objectPermissions.canReadObjectRecords; }); ``` --- .../filterReadableActiveObjectMetadataItems.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/twenty-front/src/modules/object-metadata/utils/filterReadableActiveObjectMetadataItems.ts b/packages/twenty-front/src/modules/object-metadata/utils/filterReadableActiveObjectMetadataItems.ts index 23d9b08a9e..09fd254b63 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/filterReadableActiveObjectMetadataItems.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/filterReadableActiveObjectMetadataItems.ts @@ -10,12 +10,16 @@ export const filterReadableActiveObjectMetadataItems = ( >, ): EnrichedObjectMetadataItem[] => objectMetadataItems.filter((objectMetadataItem) => { + if (!objectMetadataItem.isActive) { + return false; + } + const objectPermissions = objectPermissionsByObjectMetadataId[objectMetadataItem.id]; - return ( - isDefined(objectPermissions) && - objectPermissions.canReadObjectRecords && - objectMetadataItem.isActive - ); + if (!isDefined(objectPermissions)) { + return true; + } + + return objectPermissions.canReadObjectRecords; });