feat: deprecate WorkspaceFavorite in favor of NavigationMenuItem (#18624)
## Summary - **Removes the entire `modules/favorites/` directory** (~66 files, ~5000 lines deleted) — components, hooks, states, types, utils, tests, and the favorite-folder-picker sub-module - **Eliminates the dual-write pattern** where creating a favorite also created a NavigationMenuItem — all consumers now use `useCreateNavigationMenuItem` directly - **Removes `IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED` feature flag checks** from ~12 files, always taking the NavigationMenuItem code path - **Cleans up backend dual-writes** in `object-metadata.service.ts` and `twenty-standard-application.service.ts` that were creating Favorite records alongside NavigationMenuItems - **Updates prefetch system** to only load NavigationMenuItems (removes favorites prefetch effects and states) - **Cleans up test infrastructure** — updates Storybook decorators, mock data, and graphql mocks to remove favorites references ### What was intentionally kept - **Backend entity definitions** (`FavoriteWorkspaceEntity`, `FavoriteFolderWorkspaceEntity`) — these define the database schema and need a proper database migration to remove - **Cascade deletion listeners** — still needed to clean up existing Favorite data in workspaces that haven't been fully migrated - **v1.18 migration commands** — needed for workspaces upgrading from older versions --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+19
-39
@@ -11,7 +11,6 @@ import {
|
||||
} from 'twenty-ui/display';
|
||||
import { LightIconButton } from 'twenty-ui/input';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
|
||||
import { FOLDER_ICON_DEFAULT } from '@/navigation-menu-item/constants/FolderIconDefault';
|
||||
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
|
||||
@@ -27,16 +26,13 @@ import { openNavigationMenuItemFolderIdsState } from '@/navigation-menu-item/sta
|
||||
import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/states/selectedNavigationMenuItemInEditModeState';
|
||||
import { filterWorkspaceNavigationMenuItems } from '@/navigation-menu-item/utils/filterWorkspaceNavigationMenuItems';
|
||||
import { preloadWorkspaceDndKit } from '@/navigation/preloadWorkspaceDndKit';
|
||||
import { NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader';
|
||||
import { NavigationDrawerSectionForWorkspaceItems } from '@/object-metadata/components/NavigationDrawerSectionForWorkspaceItems';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
|
||||
import { prefetchNavigationMenuItemsState } from '@/prefetch/states/prefetchNavigationMenuItemsState';
|
||||
import { navigationMenuItemsState } from '@/navigation-menu-item/states/navigationMenuItemsState';
|
||||
import { useNavigateSidePanel } from '@/side-panel/hooks/useNavigateSidePanel';
|
||||
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useStore } from 'jotai';
|
||||
import { SidePanelPages } from 'twenty-shared/types';
|
||||
|
||||
@@ -51,18 +47,13 @@ export const WorkspaceNavigationMenuItems = () => {
|
||||
const { workspaceNavigationMenuItemsSorted } = useSortedNavigationMenuItems();
|
||||
const store = useStore();
|
||||
const enterEditMode = () => {
|
||||
const prefetchNavigationMenuItems = store.get(
|
||||
prefetchNavigationMenuItemsState.atom,
|
||||
);
|
||||
const currentNavigationMenuItems = store.get(navigationMenuItemsState.atom);
|
||||
const workspaceNavigationMenuItems = filterWorkspaceNavigationMenuItems(
|
||||
prefetchNavigationMenuItems,
|
||||
currentNavigationMenuItems,
|
||||
);
|
||||
store.set(navigationMenuItemsDraftState.atom, workspaceNavigationMenuItems);
|
||||
store.set(isNavigationMenuInEditModeState.atom, true);
|
||||
};
|
||||
const isNavigationMenuItemEditingEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED,
|
||||
);
|
||||
const isNavigationMenuInEditMode = useAtomStateValue(
|
||||
isNavigationMenuInEditModeState,
|
||||
);
|
||||
@@ -79,7 +70,6 @@ export const WorkspaceNavigationMenuItems = () => {
|
||||
useOpenNavigationMenuItemInSidePanel();
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
const loading = useIsPrefetchLoading();
|
||||
const { t } = useLingui();
|
||||
|
||||
const handleEditClick = (event: React.MouseEvent) => {
|
||||
@@ -171,46 +161,36 @@ export const WorkspaceNavigationMenuItems = () => {
|
||||
});
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader />;
|
||||
}
|
||||
|
||||
return (
|
||||
<NavigationDrawerSectionForWorkspaceItems
|
||||
sectionTitle={t`Workspace`}
|
||||
items={items}
|
||||
rightIcon={
|
||||
isNavigationMenuItemEditingEnabled ? (
|
||||
<StyledRightIconsContainer>
|
||||
{isNavigationMenuInEditMode ? (
|
||||
<StyledRightIconsContainer>
|
||||
{isNavigationMenuInEditMode ? (
|
||||
<LightIconButton
|
||||
Icon={IconPlus}
|
||||
accent="tertiary"
|
||||
size="small"
|
||||
onClick={handleAddMenuItem}
|
||||
/>
|
||||
) : (
|
||||
<div onMouseEnter={preloadWorkspaceDndKit}>
|
||||
<LightIconButton
|
||||
Icon={IconPlus}
|
||||
Icon={IconTool}
|
||||
accent="tertiary"
|
||||
size="small"
|
||||
onClick={handleAddMenuItem}
|
||||
onClick={handleEditClick}
|
||||
/>
|
||||
) : (
|
||||
<div onMouseEnter={preloadWorkspaceDndKit}>
|
||||
<LightIconButton
|
||||
Icon={IconTool}
|
||||
accent="tertiary"
|
||||
size="small"
|
||||
onClick={handleEditClick}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</StyledRightIconsContainer>
|
||||
) : undefined
|
||||
</div>
|
||||
)}
|
||||
</StyledRightIconsContainer>
|
||||
}
|
||||
selectedNavigationMenuItemId={selectedNavigationMenuItemInEditMode}
|
||||
onNavigationMenuItemClick={
|
||||
isNavigationMenuInEditMode ? handleNavigationMenuItemClick : undefined
|
||||
}
|
||||
onActiveObjectMetadataItemClick={
|
||||
isNavigationMenuItemEditingEnabled
|
||||
? handleActiveObjectMetadataItemClick
|
||||
: undefined
|
||||
}
|
||||
onActiveObjectMetadataItemClick={handleActiveObjectMetadataItemClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user