From 544c89119ca535d90dfc95b19c454f1b6b4c37ad Mon Sep 17 00:00:00 2001
From: Abdul Rahman <81605929+abdulrahmancodes@users.noreply.github.com>
Date: Sun, 21 Jun 2026 20:54:55 +0530
Subject: [PATCH] fix: hide restricted objects and views nested in navigation
folders (#21914)
Closes #20141
---
.../utils/isNavigationMenuItemReadable.ts | 56 ++++++++++++++++
.../components/WorkspaceSectionContainer.tsx | 66 +++++++++----------
2 files changed, 88 insertions(+), 34 deletions(-)
create mode 100644 packages/twenty-front/src/modules/navigation-menu-item/common/utils/isNavigationMenuItemReadable.ts
diff --git a/packages/twenty-front/src/modules/navigation-menu-item/common/utils/isNavigationMenuItemReadable.ts b/packages/twenty-front/src/modules/navigation-menu-item/common/utils/isNavigationMenuItemReadable.ts
new file mode 100644
index 0000000000..16fad50bcc
--- /dev/null
+++ b/packages/twenty-front/src/modules/navigation-menu-item/common/utils/isNavigationMenuItemReadable.ts
@@ -0,0 +1,56 @@
+import { NavigationMenuItemType } from 'twenty-shared/types';
+import { isDefined } from 'twenty-shared/utils';
+import { type NavigationMenuItem } from '~/generated-metadata/graphql';
+
+import { getObjectMetadataForNavigationMenuItem } from '@/navigation-menu-item/display/object/utils/getObjectMetadataForNavigationMenuItem';
+import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
+import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
+import { type ViewWithRelations } from '@/views/types/ViewWithRelations';
+
+type IsNavigationMenuItemReadableArgs = {
+ item: NavigationMenuItem;
+ objectMetadataItems: EnrichedObjectMetadataItem[];
+ views: ViewWithRelations[];
+ objectPermissionsByObjectMetadataId: Parameters<
+ typeof getObjectPermissionsForObject
+ >[0];
+};
+
+export const isNavigationMenuItemReadable = ({
+ item,
+ objectMetadataItems,
+ views,
+ objectPermissionsByObjectMetadataId,
+}: IsNavigationMenuItemReadableArgs): boolean => {
+ const itemType = item.type;
+
+ if (
+ itemType === NavigationMenuItemType.FOLDER ||
+ itemType === NavigationMenuItemType.LINK ||
+ itemType === NavigationMenuItemType.PAGE_LAYOUT
+ ) {
+ return true;
+ }
+
+ if (
+ itemType === NavigationMenuItemType.OBJECT ||
+ itemType === NavigationMenuItemType.VIEW ||
+ itemType === NavigationMenuItemType.RECORD
+ ) {
+ const objectMetadataItem = getObjectMetadataForNavigationMenuItem(
+ item,
+ objectMetadataItems,
+ views,
+ );
+
+ return (
+ isDefined(objectMetadataItem) &&
+ getObjectPermissionsForObject(
+ objectPermissionsByObjectMetadataId,
+ objectMetadataItem.id,
+ ).canReadObjectRecords
+ );
+ }
+
+ return false;
+};
diff --git a/packages/twenty-front/src/modules/navigation-menu-item/display/sections/workspace/components/WorkspaceSectionContainer.tsx b/packages/twenty-front/src/modules/navigation-menu-item/display/sections/workspace/components/WorkspaceSectionContainer.tsx
index 9e1326e425..e727e91253 100644
--- a/packages/twenty-front/src/modules/navigation-menu-item/display/sections/workspace/components/WorkspaceSectionContainer.tsx
+++ b/packages/twenty-front/src/modules/navigation-menu-item/display/sections/workspace/components/WorkspaceSectionContainer.tsx
@@ -1,6 +1,5 @@
import { styled } from '@linaria/react';
import React, { lazy, Suspense, useContext } from 'react';
-import { NavigationMenuItemType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { type NavigationMenuItem } from '~/generated-metadata/graphql';
@@ -8,15 +7,16 @@ import { type NavigationMenuItem } from '~/generated-metadata/graphql';
import { isLayoutCustomizationModeEnabledState } from '@/layout-customization/states/isLayoutCustomizationModeEnabledState';
import { NavigationMenuItemDroppableIds } from '@/navigation-menu-item/common/constants/NavigationMenuItemDroppableIds';
import { NavigationDropTargetContext } from '@/navigation-menu-item/common/contexts/NavigationDropTargetContext';
+import { isNavigationMenuItemFolder } from '@/navigation-menu-item/common/utils/isNavigationMenuItemFolder';
+import { isNavigationMenuItemReadable } from '@/navigation-menu-item/common/utils/isNavigationMenuItemReadable';
import { type NavigationMenuItemClickParams } from '@/navigation-menu-item/display/hooks/useNavigationMenuItemSectionItems';
import { getObjectMetadataForNavigationMenuItem } from '@/navigation-menu-item/display/object/utils/getObjectMetadataForNavigationMenuItem';
-import { WorkspaceSectionListReadOnly } from '@/navigation-menu-item/display/sections/workspace/components/WorkspaceSectionListReadOnly';
import { NavigationMenuItemSection } from '@/navigation-menu-item/display/sections/components/NavigationMenuItemSection';
+import { WorkspaceSectionListReadOnly } from '@/navigation-menu-item/display/sections/workspace/components/WorkspaceSectionListReadOnly';
import type { EditModeProps } from '@/object-metadata/components/EditModeProps';
import { WorkspaceSectionListEditModeFallback } from '@/object-metadata/components/WorkspaceSectionListEditModeFallback';
import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector';
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
-import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
@@ -69,47 +69,45 @@ export const WorkspaceSectionContainer = ({
const isAddToNavigationDropTargetVisible =
addToNavigationFallbackDestination?.droppableId ===
NavigationMenuItemDroppableIds.WORKSPACE_ORPHAN_NAVIGATION_MENU_ITEMS;
- const folderChildrenById = items.reduce