Integrate NavigationMenuItem with feature flag support (#17268)
## Implement Navigation Menu Items Frontend Implements the frontend for navigation menu items, the new system replacing favorites. ### Changes - Added GraphQL fragments and queries for navigation menu items - Added hooks for managing navigation menu items (create, update, delete, sorting, filtering) - Updated components to use navigation menu items instead of favorites - Added test coverage for utility functions ### Migration Note The favorites and navigation menu item modules currently exist in parallel. The favorites code will be removed once all data has been migrated to navigation menu items. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Replaces Favorites with feature-flagged `NavigationMenuItem` across frontend and backend, while keeping Favorites as fallback until migration completes. > > - UI: new `navigation-menu-item` components (folders, orphan items, drag provider/droppable, icons, skeleton), dispatcher components to switch from Favorites, and updated “Add to favorites” action to create `NavigationMenuItem` when `IS_NAVIGATION_MENU_ITEM_ENABLED` > - DnD: shared `validateAndExtractFolderId` and droppable id utils moved to `ui/layout/draggable-list`; favorites DnD updated to use shared utils > - GraphQL (client): add fragments, queries, mutations, hooks (create/update/delete/find), and generated types; added `RecordIdentifier` and `targetRecordIdentifier` on `NavigationMenuItem` > - Prefetch: new prefetch state/effect for navigation menu items; skip favorites prefetch when flag enabled > - Backend: add DTOs (`NavigationMenuItem`, `RecordIdentifier`), resolver `targetRecordIdentifier` field, service logic to fetch record identifiers with permission-aware access and image signing, `getRecordImageIdentifier` util, entity relation to `view`, and migration adding FK on `viewId` > - Feature flags & seeding: add `IS_NAVIGATION_MENU_ITEM_ENABLED` to enums, dev seeder enables it; standard app seeds workspace navigation menu items instead of favorites when flag on > - Tests: add unit tests for sorting/labels/folder id and related utils > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c99746f08b9f84fc8cec4fcc3a7d7afb8ea92db7. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Aman Raj <92664006+araj00@users.noreply.github.com> Co-authored-by: Félix Malfait <felix@twenty.com> Co-authored-by: Paul Rastoin <45004772+prastoin@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions <github-actions@twenty.com>
This commit is contained in:
@@ -1,23 +1,43 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { FavoritesFolderContent } from '@/favorites/components/FavoritesFolderContent';
|
||||
import { useFavoritesByFolder } from '@/favorites/hooks/useFavoritesByFolder';
|
||||
import { NavigationMenuItemFolderContentDispatcherEffect } from '@/navigation-menu-item/components/NavigationMenuItemFolderContentDispatcher';
|
||||
import { useNavigationMenuItemsByFolder } from '@/navigation-menu-item/hooks/useNavigationMenuItemsByFolder';
|
||||
import { MainNavigationDrawerFixedItems } from '@/navigation/components/MainNavigationDrawerFixedItems';
|
||||
import { MainNavigationDrawerScrollableItems } from '@/navigation/components/MainNavigationDrawerScrollableItems';
|
||||
import { NavigationDrawer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
|
||||
import { NavigationDrawerFixedContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerFixedContent';
|
||||
import { NavigationDrawerScrollableContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerScrollableContent';
|
||||
import { currentFavoriteFolderIdState } from '@/ui/navigation/navigation-drawer/states/currentFavoriteFolderIdState';
|
||||
import { currentNavigationMenuItemFolderIdState } from '@/ui/navigation/navigation-drawer/states/currentNavigationMenuItemFolderIdState';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
|
||||
export const MainNavigationDrawer = ({ className }: { className?: string }) => {
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
const currentFavoriteFolderId = useRecoilValue(currentFavoriteFolderIdState);
|
||||
const currentNavigationMenuItemFolderId = useRecoilValue(
|
||||
currentNavigationMenuItemFolderIdState,
|
||||
);
|
||||
const { favoritesByFolder } = useFavoritesByFolder();
|
||||
const openedFolder = favoritesByFolder.find(
|
||||
const { navigationMenuItemsByFolder } = useNavigationMenuItemsByFolder();
|
||||
const isNavigationMenuItemEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_ENABLED,
|
||||
);
|
||||
|
||||
const openedFavoriteFolder = favoritesByFolder.find(
|
||||
(f) => f.folderId === currentFavoriteFolderId,
|
||||
);
|
||||
|
||||
const openedNavigationMenuItemFolder = navigationMenuItemsByFolder.find(
|
||||
(f) => f.folderId === currentNavigationMenuItemFolderId,
|
||||
);
|
||||
|
||||
const openedFolder = isNavigationMenuItemEnabled
|
||||
? openedNavigationMenuItemFolder
|
||||
: openedFavoriteFolder;
|
||||
|
||||
return (
|
||||
<NavigationDrawer
|
||||
className={className}
|
||||
@@ -28,11 +48,14 @@ export const MainNavigationDrawer = ({ className }: { className?: string }) => {
|
||||
</NavigationDrawerFixedContent>
|
||||
|
||||
<NavigationDrawerScrollableContent>
|
||||
{currentFavoriteFolderId && openedFolder ? (
|
||||
<FavoritesFolderContent
|
||||
{openedFolder ? (
|
||||
<NavigationMenuItemFolderContentDispatcherEffect
|
||||
folderName={openedFolder.folderName}
|
||||
folderId={openedFolder.folderId}
|
||||
favorites={openedFolder.favorites}
|
||||
favorites={openedFavoriteFolder?.favorites}
|
||||
navigationMenuItems={
|
||||
openedNavigationMenuItemFolder?.navigationMenuItems
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<MainNavigationDrawerScrollableItems />
|
||||
|
||||
+23
-4
@@ -1,8 +1,23 @@
|
||||
import { CurrentWorkspaceMemberFavoritesFolders } from '@/favorites/components/CurrentWorkspaceMemberFavoritesFolders';
|
||||
import { WorkspaceFavorites } from '@/favorites/components/WorkspaceFavorites';
|
||||
import { NavigationDrawerOpenedSection } from '@/object-metadata/components/NavigationDrawerOpenedSection';
|
||||
import { RemoteNavigationDrawerSection } from '@/object-metadata/components/RemoteNavigationDrawerSection';
|
||||
import styled from '@emotion/styled';
|
||||
import { lazy, Suspense } from 'react';
|
||||
|
||||
const CurrentWorkspaceMemberNavigationMenuItemFoldersDispatcher = lazy(() =>
|
||||
import(
|
||||
'@/navigation-menu-item/components/CurrentWorkspaceMemberNavigationMenuItemFoldersDispatcher'
|
||||
).then((module) => ({
|
||||
default: module.CurrentWorkspaceMemberNavigationMenuItemFoldersDispatcher,
|
||||
})),
|
||||
);
|
||||
|
||||
const WorkspaceNavigationMenuItemsDispatcher = lazy(() =>
|
||||
import(
|
||||
'@/navigation-menu-item/components/WorkspaceNavigationMenuItemsDispatcher'
|
||||
).then((module) => ({
|
||||
default: module.WorkspaceNavigationMenuItemsDispatcher,
|
||||
})),
|
||||
);
|
||||
|
||||
const StyledScrollableItemsContainer = styled.div`
|
||||
display: flex;
|
||||
@@ -14,8 +29,12 @@ export const MainNavigationDrawerScrollableItems = () => {
|
||||
return (
|
||||
<StyledScrollableItemsContainer>
|
||||
<NavigationDrawerOpenedSection />
|
||||
<CurrentWorkspaceMemberFavoritesFolders />
|
||||
<WorkspaceFavorites />
|
||||
<Suspense fallback={null}>
|
||||
<CurrentWorkspaceMemberNavigationMenuItemFoldersDispatcher />
|
||||
</Suspense>
|
||||
<Suspense fallback={null}>
|
||||
<WorkspaceNavigationMenuItemsDispatcher />
|
||||
</Suspense>
|
||||
<RemoteNavigationDrawerSection />
|
||||
</StyledScrollableItemsContainer>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user