refactor: remove ProcessedNavigationMenuItem, derive display fields at point of use (#18687)

## Summary

- Removes `ProcessedNavigationMenuItem` type and the
`sortNavigationMenuItems` enrichment pipeline that pre-computed display
fields (label, link, icon, avatarUrl, etc.) for every navigation menu
item upfront
- Replaces with `filterAndSortNavigationMenuItems` (pure filter+sort
returning raw `NavigationMenuItem[]`) and small utility functions
(`getNavigationMenuItemLabel`, `getNavigationMenuItemComputedLink`,
`getNavigationMenuItemObjectNameSingular`) that components call on
demand
- Eliminates the redundant `itemType` field (was identical to the raw
`type` field) across ~30 consumer files
- Each type-specific renderer
(`NavigationDrawerItemForObjectMetadataItem`, `NavigationMenuItemIcon`,
link/folder components) now derives only the 1-2 display fields it
actually needs from the raw item + globally available Jotai atoms

Net result: -1199 / +1177 lines, 7 files deleted, 4 new utility files.
This commit is contained in:
Charles Bochet
2026-03-17 00:33:06 +01:00
committed by GitHub
parent 48285be164
commit 1bb642d7cd
55 changed files with 1188 additions and 1227 deletions
@@ -7,7 +7,7 @@ import { sidePanelPageInfoState } from '@/side-panel/states/sidePanelPageInfoSta
import { sidePanelShouldFocusTitleInputComponentState } from '@/side-panel/states/sidePanelShouldFocusTitleInputComponentState';
import { NavigationMenuItemStyleIcon } from '@/navigation-menu-item/components/NavigationMenuItemStyleIcon';
import { FOLDER_ICON_DEFAULT } from '@/navigation-menu-item/constants/FolderIconDefault';
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
import { NavigationMenuItemType } from 'twenty-shared/types';
import { useUpdateFolderInDraft } from '@/navigation-menu-item/hooks/useUpdateFolderInDraft';
import { useWorkspaceSectionItems } from '@/navigation-menu-item/hooks/useWorkspaceSectionItems';
import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/states/selectedNavigationMenuItemInEditModeState';
@@ -41,7 +41,7 @@ export const SidePanelFolderInfo = () => {
const selectedItem = selectedNavigationMenuItemInEditMode
? items.find(
(item) =>
item.itemType === NavigationMenuItemType.FOLDER &&
item.type === NavigationMenuItemType.FOLDER &&
item.id === selectedNavigationMenuItemInEditMode,
)
: undefined;
@@ -2,7 +2,7 @@ import { useLingui } from '@lingui/react/macro';
import { IconLink, IconWorld } from 'twenty-ui/display';
import { LinkIconWithLinkOverlay } from '@/navigation-menu-item/components/LinkIconWithLinkOverlay';
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
import { NavigationMenuItemType } from 'twenty-shared/types';
import { useUpdateLinkInDraft } from '@/navigation-menu-item/hooks/useUpdateLinkInDraft';
import { useWorkspaceSectionItems } from '@/navigation-menu-item/hooks/useWorkspaceSectionItems';
import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/states/selectedNavigationMenuItemInEditModeState';
@@ -33,7 +33,7 @@ export const SidePanelLinkInfo = () => {
const selectedItem = selectedNavigationMenuItemInEditMode
? items.find(
(item) =>
item.itemType === NavigationMenuItemType.LINK &&
item.type === NavigationMenuItemType.LINK &&
item.id === selectedNavigationMenuItemInEditMode,
)
: undefined;
@@ -3,7 +3,7 @@ import { OverflowingTextWithTooltip } from 'twenty-ui/display';
import { SidePanelPageInfoLayout } from '@/side-panel/components/SidePanelPageInfoLayout';
import { NavigationMenuItemIcon } from '@/navigation-menu-item/components/NavigationMenuItemIcon';
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
import { NavigationMenuItemType } from 'twenty-shared/types';
import { useSelectedNavigationMenuItemEditItem } from '@/navigation-menu-item/hooks/useSelectedNavigationMenuItemEditItem';
import { useSelectedNavigationMenuItemEditItemLabel } from '@/navigation-menu-item/hooks/useSelectedNavigationMenuItemEditItemLabel';
import { useSelectedNavigationMenuItemEditItemObjectMetadata } from '@/navigation-menu-item/hooks/useSelectedNavigationMenuItemEditItemObjectMetadata';
@@ -15,12 +15,12 @@ export const SidePanelObjectViewRecordInfo = () => {
const { selectedItemObjectMetadata } =
useSelectedNavigationMenuItemEditItemObjectMetadata();
const processedItem =
selectedItem && selectedItem.itemType !== NavigationMenuItemType.FOLDER
const navItem =
selectedItem && selectedItem.type !== NavigationMenuItemType.FOLDER
? selectedItem
: undefined;
if (!processedItem || !selectedItemLabel) {
if (!navItem || !selectedItemLabel) {
return null;
}
@@ -28,22 +28,22 @@ export const SidePanelObjectViewRecordInfo = () => {
NavigationMenuItemType.OBJECT,
NavigationMenuItemType.VIEW,
NavigationMenuItemType.RECORD,
].includes(processedItem.itemType);
].includes(navItem.type);
if (!isObjectViewOrRecord) {
return null;
}
const label =
processedItem.itemType === NavigationMenuItemType.RECORD
navItem.type === NavigationMenuItemType.RECORD
? selectedItemObjectMetadata?.labelSingular
: processedItem.itemType === NavigationMenuItemType.OBJECT
: navItem.type === NavigationMenuItemType.OBJECT
? t`Object`
: t`View`;
return (
<SidePanelPageInfoLayout
icon={<NavigationMenuItemIcon navigationMenuItem={processedItem} />}
icon={<NavigationMenuItemIcon navigationMenuItem={navItem} />}
title={<OverflowingTextWithTooltip text={selectedItemLabel} />}
label={label}
/>
@@ -5,7 +5,7 @@ import {
OverflowingTextWithTooltip,
} from 'twenty-ui/display';
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
import { NavigationMenuItemType, SidePanelPages } from 'twenty-shared/types';
import { useWorkspaceSectionItems } from '@/navigation-menu-item/hooks/useWorkspaceSectionItems';
import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/states/selectedNavigationMenuItemInEditModeState';
import { SidePanelAskAIInfo } from '@/side-panel/components/SidePanelAskAIInfo';
@@ -18,7 +18,6 @@ import { SidePanelPageLayoutInfo } from '@/side-panel/components/SidePanelPageLa
import { SidePanelRecordInfo } from '@/side-panel/components/SidePanelRecordInfo';
import { SidePanelWorkflowStepInfo } from '@/side-panel/components/SidePanelWorkflowStepInfo';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { SidePanelPages } from 'twenty-shared/types';
import { type SidePanelContextChipProps } from '@/side-panel/components/SidePanelContextChip';
import { useContext } from 'react';
@@ -51,20 +50,20 @@ export const SidePanelPageInfo = ({ pageChip }: SidePanelPageInfoProps) => {
: undefined;
if (isNavigationMenuItemEditPage && isDefined(selectedNavItem)) {
const itemType = selectedNavItem.itemType;
const navItemType = selectedNavItem.type;
if (itemType === NavigationMenuItemType.FOLDER) {
if (navItemType === NavigationMenuItemType.FOLDER) {
return <SidePanelFolderInfo />;
}
if (itemType === NavigationMenuItemType.LINK) {
if (navItemType === NavigationMenuItemType.LINK) {
return <SidePanelLinkInfo />;
}
if (
itemType === NavigationMenuItemType.OBJECT ||
itemType === NavigationMenuItemType.VIEW ||
itemType === NavigationMenuItemType.RECORD
navItemType === NavigationMenuItemType.OBJECT ||
navItemType === NavigationMenuItemType.VIEW ||
navItemType === NavigationMenuItemType.RECORD
) {
return <SidePanelObjectViewRecordInfo />;
}