diff --git a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx index 65f7104362..e95413eb7f 100644 --- a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx @@ -20,14 +20,8 @@ import { } from '~/testing/mock-data/users'; import { sleep } from '~/utils/sleep'; -import { CommandMenuComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuComponentInstanceContext'; import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState'; -import { SidePanelRouter } from '@/side-panel/components/SidePanelRouter'; -import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; -import { SIDE_PANEL_FOCUS_ID } from '@/side-panel/constants/SidePanelFocusId'; -import { type SidePanelRootPage } from '@/side-panel/pages/root/components/SidePanelRootPage'; -import { sidePanelNavigationStackState } from '@/side-panel/states/sidePanelNavigationStackState'; -import { isSidePanelOpenedState } from '@/side-panel/states/isSidePanelOpenedState'; +import { CommandMenuComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuComponentInstanceContext'; import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; @@ -35,11 +29,19 @@ import { ContextStoreComponentInstanceContext } from '@/context-store/states/con import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper'; +import { SidePanelRouter } from '@/side-panel/components/SidePanelRouter'; +import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; +import { SIDE_PANEL_FOCUS_ID } from '@/side-panel/constants/SidePanelFocusId'; +import { type SidePanelRootPage } from '@/side-panel/pages/root/components/SidePanelRootPage'; +import { isSidePanelOpenedState } from '@/side-panel/states/isSidePanelOpenedState'; +import { sidePanelNavigationStackState } from '@/side-panel/states/sidePanelNavigationStackState'; +import { sidePanelPageInfoState } from '@/side-panel/states/sidePanelPageInfoState'; +import { sidePanelPageState } from '@/side-panel/states/sidePanelPageState'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { HttpResponse, graphql } from 'msw'; import { SidePanelPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; -import { IconDotsVertical } from 'twenty-ui/display'; +import { IconDotsVertical, IconPlus } from 'twenty-ui/display'; import { JestContextStoreSetter } from '~/testing/jest/JestContextStoreSetter'; const openTimeout = 50; @@ -87,6 +89,10 @@ const meta: Meta = { mockedUserData.currentUserWorkspace, ); jotaiStore.set(isSidePanelOpenedState.atom, true); + jotaiStore.set(sidePanelPageInfoState.atom, { + title: 'Command Menu', + instanceId: SIDE_PANEL_COMPONENT_INSTANCE_ID, + }); jotaiStore.set(sidePanelNavigationStackState.atom, [ { page: SidePanelPages.Root, @@ -244,3 +250,43 @@ export const NoResultsSearchFallback: Story = { // expect(await canvas.findByText('Search records')).toBeVisible(); // }, // }; + +export const SubPageNavigation: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + + const objectButton = await canvas.findByText('Object'); + expect(objectButton).toBeVisible(); + + await userEvent.click(objectButton); + + expect(await canvas.findByText('Pick an object')).toBeVisible(); + + const backButton = await canvas.findByRole('button', { name: 'Go back' }); + await userEvent.click(backButton); + + expect(await canvas.findByText('Object')).toBeVisible(); + }, + decorators: [ + (Story) => { + jotaiStore.set( + sidePanelPageState.atom, + SidePanelPages.NavigationMenuAddItem, + ); + jotaiStore.set(sidePanelPageInfoState.atom, { + title: 'Add item', + instanceId: SIDE_PANEL_COMPONENT_INSTANCE_ID, + }); + jotaiStore.set(sidePanelNavigationStackState.atom, [ + { + page: SidePanelPages.NavigationMenuAddItem, + pageTitle: 'Add item', + pageIcon: IconPlus, + pageId: '1', + }, + ]); + + return ; + }, + ], +}; diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHotKeys.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHotKeys.ts index 055a1419d3..8a43ea1931 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHotKeys.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHotKeys.ts @@ -1,20 +1,20 @@ -import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; -import { SIDE_PANEL_FOCUS_ID } from '@/side-panel/constants/SidePanelFocusId'; -import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu'; -import { useSidePanelHistory } from '@/side-panel/hooks/useSidePanelHistory'; -import { useOpenAskAIPageInSidePanel } from '@/side-panel/hooks/useOpenAskAIPageInSidePanel'; -import { useOpenRecordsSearchPageInSidePanel } from '@/side-panel/hooks/useOpenRecordsSearchPageInSidePanel'; import { useSetGlobalCommandMenuContext } from '@/command-menu/hooks/useSetGlobalCommandMenuContext'; -import { sidePanelPageState } from '@/side-panel/states/sidePanelPageState'; -import { sidePanelSearchState } from '@/side-panel/states/sidePanelSearchState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { useKeyboardShortcutMenu } from '@/keyboard-shortcut-menu/hooks/useKeyboardShortcutMenu'; +import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; +import { SIDE_PANEL_FOCUS_ID } from '@/side-panel/constants/SidePanelFocusId'; +import { useOpenAskAIPageInSidePanel } from '@/side-panel/hooks/useOpenAskAIPageInSidePanel'; +import { useOpenRecordsSearchPageInSidePanel } from '@/side-panel/hooks/useOpenRecordsSearchPageInSidePanel'; +import { useSidePanelHistory } from '@/side-panel/hooks/useSidePanelHistory'; +import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu'; +import { sidePanelPageState } from '@/side-panel/states/sidePanelPageState'; +import { sidePanelSearchState } from '@/side-panel/states/sidePanelSearchState'; import { useGlobalHotkeys } from '@/ui/utilities/hotkey/hooks/useGlobalHotkeys'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; +import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { isNonEmptyString } from '@sniptt/guards'; -import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { Key } from 'ts-key-enum'; import { SidePanelPages } from 'twenty-shared/types'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; @@ -26,7 +26,8 @@ export const useCommandMenuHotKeys = () => { const { openAskAIPage } = useOpenAskAIPageInSidePanel(); - const { goBackFromSidePanel } = useSidePanelHistory(); + const { goBackFromSidePanel, goBackOneSubPageOrMainPage } = + useSidePanelHistory(); const { setGlobalCommandMenuContext } = useSetGlobalCommandMenuContext(); @@ -108,7 +109,7 @@ export const useCommandMenuHotKeys = () => { setGlobalCommandMenuContext(); } if (sidePanelPage !== SidePanelPages.Root) { - goBackFromSidePanel(); + goBackOneSubPageOrMainPage(); } }, focusId: SIDE_PANEL_FOCUS_ID, @@ -116,7 +117,7 @@ export const useCommandMenuHotKeys = () => { sidePanelPage, sidePanelSearch, contextStoreTargetedRecordsRule, - goBackFromSidePanel, + goBackOneSubPageOrMainPage, setGlobalCommandMenuContext, ], options: { diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useEditPageLayoutWidget.ts b/packages/twenty-front/src/modules/page-layout/hooks/useEditPageLayoutWidget.ts index 155850ad1c..9bfe4094f7 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useEditPageLayoutWidget.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useEditPageLayoutWidget.ts @@ -5,9 +5,9 @@ import { sidePanelPageState } from '@/side-panel/states/sidePanelPageState'; import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState'; import { SidePanelPages } from 'twenty-shared/types'; -import { useNavigatePageLayoutSidePanel } from '@/side-panel/pages/page-layout/hooks/useNavigatePageLayoutSidePanel'; import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; +import { useNavigatePageLayoutSidePanel } from '@/side-panel/pages/page-layout/hooks/useNavigatePageLayoutSidePanel'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { t } from '@lingui/core/macro'; @@ -36,14 +36,13 @@ export const useEditPageLayoutWidget = (pageLayoutIdFromProps?: string) => { widgetId: string; widgetType: WidgetType; }) => { - setPageLayoutEditingWidgetId(widgetId); - if (widgetType === WidgetType.IFRAME) { navigatePageLayoutSidePanel({ sidePanelPage: SidePanelPages.PageLayoutIframeSettings, pageTitle: t`Edit iFrame`, resetNavigationStack: true, }); + setPageLayoutEditingWidgetId(widgetId); return; } @@ -53,6 +52,7 @@ export const useEditPageLayoutWidget = (pageLayoutIdFromProps?: string) => { pageTitle: t`Edit Graph`, resetNavigationStack: true, }); + setPageLayoutEditingWidgetId(widgetId); return; } @@ -62,6 +62,7 @@ export const useEditPageLayoutWidget = (pageLayoutIdFromProps?: string) => { pageTitle: t`Edit Fields`, resetNavigationStack: true, }); + setPageLayoutEditingWidgetId(widgetId); return; } diff --git a/packages/twenty-front/src/modules/side-panel/components/SidePanelPageInfo.tsx b/packages/twenty-front/src/modules/side-panel/components/SidePanelPageInfo.tsx index 24a6872370..9e0f80b866 100644 --- a/packages/twenty-front/src/modules/side-panel/components/SidePanelPageInfo.tsx +++ b/packages/twenty-front/src/modules/side-panel/components/SidePanelPageInfo.tsx @@ -5,6 +5,9 @@ import { OverflowingTextWithTooltip, } from 'twenty-ui/display'; +import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType'; +import { useWorkspaceSectionItems } from '@/navigation-menu-item/hooks/useWorkspaceSectionItems'; +import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/states/selectedNavigationMenuItemInEditModeState'; import { SidePanelAskAIInfo } from '@/side-panel/components/SidePanelAskAIInfo'; import { SidePanelFolderInfo } from '@/side-panel/components/SidePanelFolderInfo'; import { SidePanelLinkInfo } from '@/side-panel/components/SidePanelLinkInfo'; @@ -14,9 +17,6 @@ import { SidePanelPageInfoLayout } from '@/side-panel/components/SidePanelPageIn import { SidePanelPageLayoutInfo } from '@/side-panel/components/SidePanelPageLayoutInfo'; import { SidePanelRecordInfo } from '@/side-panel/components/SidePanelRecordInfo'; import { SidePanelWorkflowStepInfo } from '@/side-panel/components/SidePanelWorkflowStepInfo'; -import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType'; -import { useWorkspaceSectionItems } from '@/navigation-menu-item/hooks/useWorkspaceSectionItems'; -import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/states/selectedNavigationMenuItemInEditModeState'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { SidePanelPages } from 'twenty-shared/types'; @@ -98,11 +98,9 @@ export const SidePanelPageInfo = ({ pageChip }: SidePanelPageInfoProps) => { ? [ SidePanelPages.PageLayoutWidgetTypeSelect, SidePanelPages.PageLayoutGraphTypeSelect, - SidePanelPages.PageLayoutGraphFilter, SidePanelPages.PageLayoutIframeSettings, SidePanelPages.PageLayoutTabSettings, SidePanelPages.PageLayoutFieldsSettings, - SidePanelPages.PageLayoutFieldsLayout, ].includes(pageChip.page?.page) : false; diff --git a/packages/twenty-front/src/modules/side-panel/components/SidePanelRouter.tsx b/packages/twenty-front/src/modules/side-panel/components/SidePanelRouter.tsx index 3ffbea57a4..f55168ae8d 100644 --- a/packages/twenty-front/src/modules/side-panel/components/SidePanelRouter.tsx +++ b/packages/twenty-front/src/modules/side-panel/components/SidePanelRouter.tsx @@ -1,5 +1,6 @@ import { CommandMenuContextProvider } from '@/command-menu-item/contexts/CommandMenuContextProvider'; import { SidePanelContainer } from '@/side-panel/components/SidePanelContainer'; +import { SidePanelSubPageRouter } from '@/side-panel/components/SidePanelSubPageRouter'; import { SidePanelTopBar } from '@/side-panel/components/SidePanelTopBar'; import { SIDE_PANEL_PAGES_CONFIG } from '@/side-panel/constants/SidePanelPagesConfig'; import { SidePanelPageComponentInstanceContext } from '@/side-panel/states/contexts/SidePanelPageComponentInstanceContext'; @@ -56,7 +57,9 @@ export const SidePanelRouter = () => { displayType="listItem" containerType="command-menu-list" > - {sidePanelPageComponent} + + {sidePanelPageComponent} + diff --git a/packages/twenty-front/src/modules/side-panel/components/SidePanelSubPageRouter.tsx b/packages/twenty-front/src/modules/side-panel/components/SidePanelSubPageRouter.tsx new file mode 100644 index 0000000000..9a87c171b8 --- /dev/null +++ b/packages/twenty-front/src/modules/side-panel/components/SidePanelSubPageRouter.tsx @@ -0,0 +1,54 @@ +import { SIDE_PANEL_SUB_PAGES_CONFIG } from '@/side-panel/constants/SidePanelSubPagesConfig'; +import { useSidePanelSubPageHistory } from '@/side-panel/hooks/useSidePanelSubPageHistory'; +import { SidePanelSubPageNavigationHeader } from '@/side-panel/pages/common/components/SidePanelSubPageNavigationHeader'; +import { styled } from '@linaria/react'; +import React, { type ReactNode } from 'react'; +import { isDefined } from 'twenty-shared/utils'; + +const StyledSubPageContainer = styled.div` + display: flex; + flex-direction: column; + height: 100%; +`; + +type SidePanelSubPageRouterProps = { + children: ReactNode; +}; + +export const SidePanelSubPageRouter = ({ + children, +}: SidePanelSubPageRouterProps) => { + const { currentSidePanelSubPage, goBackFromSidePanelSubPage } = + useSidePanelSubPageHistory(); + + if (!isDefined(currentSidePanelSubPage)) { + return <>{children}; + } + + const subPageComponent = SIDE_PANEL_SUB_PAGES_CONFIG.get( + currentSidePanelSubPage.subPage, + ); + + if (!isDefined(subPageComponent)) { + throw new Error( + `Missing side panel sub-page config for "${currentSidePanelSubPage.subPage}". ` + + 'Please add it to SIDE_PANEL_SUB_PAGES_CONFIG.', + ); + } + + const keyedSubPageComponent = React.isValidElement(subPageComponent) + ? React.cloneElement(subPageComponent, { + key: currentSidePanelSubPage.id, + }) + : subPageComponent; + + return ( + + + {keyedSubPageComponent} + + ); +}; diff --git a/packages/twenty-front/src/modules/side-panel/components/SidePanelSubViewWithSearch.tsx b/packages/twenty-front/src/modules/side-panel/components/SidePanelSubViewWithSearch.tsx index 67ce929c9e..e9ac2e6408 100644 --- a/packages/twenty-front/src/modules/side-panel/components/SidePanelSubViewWithSearch.tsx +++ b/packages/twenty-front/src/modules/side-panel/components/SidePanelSubViewWithSearch.tsx @@ -1,7 +1,6 @@ import { styled } from '@linaria/react'; import { type ReactNode } from 'react'; -import { SidePanelSubPageNavigationHeader } from '@/side-panel/pages/common/components/SidePanelSubPageNavigationHeader'; import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledSubViewContainer = styled.div` @@ -50,8 +49,6 @@ const StyledScrollableListWrapper = styled.div` `; type SidePanelSubViewWithSearchProps = { - backBarTitle: string; - onBack: () => void; searchPlaceholder: string; searchValue: string; onSearchChange: (value: string) => void; @@ -60,8 +57,6 @@ type SidePanelSubViewWithSearchProps = { }; export const SidePanelSubViewWithSearch = ({ - backBarTitle, - onBack, searchPlaceholder, searchValue, onSearchChange, @@ -69,10 +64,6 @@ export const SidePanelSubViewWithSearch = ({ children, }: SidePanelSubViewWithSearchProps) => ( - ( SidePanelPages.PageLayoutGraphTypeSelect, , ], - [SidePanelPages.PageLayoutGraphFilter, ], [ SidePanelPages.PageLayoutIframeSettings, , @@ -65,10 +62,6 @@ export const SIDE_PANEL_PAGES_CONFIG = new Map( SidePanelPages.PageLayoutFieldsSettings, , ], - [ - SidePanelPages.PageLayoutFieldsLayout, - , - ], [SidePanelPages.ViewFrontComponent, ], [ SidePanelPages.NavigationMenuItemEdit, diff --git a/packages/twenty-front/src/modules/side-panel/constants/SidePanelSubPagesConfig.tsx b/packages/twenty-front/src/modules/side-panel/constants/SidePanelSubPagesConfig.tsx new file mode 100644 index 0000000000..54de9d008c --- /dev/null +++ b/packages/twenty-front/src/modules/side-panel/constants/SidePanelSubPagesConfig.tsx @@ -0,0 +1,44 @@ +import { SidePanelEditFolderPickerSubPage } from '@/side-panel/pages/navigation-menu-item/components/SidePanelEditFolderPickerSubPage'; +import { SidePanelNewSidebarItemObjectSubPage } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemObjectSubPage'; +import { SidePanelNewSidebarItemObjectSystemPickerSubPage } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemObjectSystemPickerSubPage'; +import { SidePanelNewSidebarItemRecordSubPage } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemRecordSubPage'; +import { SidePanelNewSidebarItemViewObjectPickerSubPage } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewObjectPickerSubPage'; +import { SidePanelNewSidebarItemViewPickerSubPage } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewPickerSubPage'; +import { SidePanelNewSidebarItemViewSystemPickerSubPage } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewSystemPickerSubPage'; +import { SidePanelChartFilterSubPage } from '@/side-panel/pages/page-layout/components/SidePanelChartFilterSubPage'; +import { SidePanelFieldsLayoutSubPage } from '@/side-panel/pages/page-layout/components/SidePanelFieldsLayoutSubPage'; +import { SidePanelSubPages } from '@/side-panel/types/SidePanelSubPages'; +import React from 'react'; + +export const SIDE_PANEL_SUB_PAGES_CONFIG = new Map< + SidePanelSubPages, + React.ReactNode +>([ + [SidePanelSubPages.PageLayoutGraphFilter, ], + [SidePanelSubPages.PageLayoutFieldsLayout, ], + [ + SidePanelSubPages.NewSidebarItemViewObjectPicker, + , + ], + [ + SidePanelSubPages.NewSidebarItemViewPicker, + , + ], + [ + SidePanelSubPages.NewSidebarItemViewSystemPicker, + , + ], + [ + SidePanelSubPages.NewSidebarItemObjectPicker, + , + ], + [ + SidePanelSubPages.NewSidebarItemObjectSystemPicker, + , + ], + [ + SidePanelSubPages.NewSidebarItemRecord, + , + ], + [SidePanelSubPages.EditFolderPicker, ], +]); diff --git a/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelHistory.ts b/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelHistory.ts index b8b31a77df..7366c45409 100644 --- a/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelHistory.ts +++ b/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelHistory.ts @@ -1,22 +1,65 @@ import { useCallback } from 'react'; import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu'; +import { hasUserSelectedSidePanelListItemState } from '@/side-panel/states/hasUserSelectedSidePanelListItemState'; import { sidePanelNavigationMorphItemsByPageState } from '@/side-panel/states/sidePanelNavigationMorphItemsByPageState'; import { sidePanelNavigationStackState } from '@/side-panel/states/sidePanelNavigationStackState'; import { sidePanelPageInfoState } from '@/side-panel/states/sidePanelPageInfoState'; import { sidePanelPageState } from '@/side-panel/states/sidePanelPageState'; -import { hasUserSelectedSidePanelListItemState } from '@/side-panel/states/hasUserSelectedSidePanelListItemState'; +import { sidePanelSubPageStackComponentState } from '@/side-panel/states/sidePanelSubPageStackComponentState'; import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { isNonEmptyArray } from '@sniptt/guards'; -import { isDefined } from 'twenty-shared/utils'; import { useStore } from 'jotai'; +import { isDefined } from 'twenty-shared/utils'; export const useSidePanelHistory = () => { const store = useStore(); const { closeSidePanelMenu } = useSidePanelMenu(); + const cleanupCurrentPage = useCallback(() => { + const currentNavigationStack = store.get( + sidePanelNavigationStackState.atom, + ); + + const currentMorphItems = store.get( + sidePanelNavigationMorphItemsByPageState.atom, + ); + + if (currentNavigationStack.length > 0) { + const removedItem = currentNavigationStack.at(-1); + + if (isDefined(removedItem)) { + const newMorphItems = new Map(currentMorphItems); + newMorphItems.delete(removedItem.pageId); + store.set(sidePanelNavigationMorphItemsByPageState.atom, newMorphItems); + + store.set( + sidePanelSubPageStackComponentState.atomFamily({ + instanceId: removedItem.pageId, + }), + [], + ); + + const morphItems = currentMorphItems.get(removedItem.pageId); + if (isNonEmptyArray(morphItems)) { + store.set( + activeTabIdComponentState.atomFamily({ + instanceId: getShowPageTabListComponentId({ + pageId: removedItem.pageId, + targetObjectId: morphItems[0].recordId, + }), + }), + null, + ); + } + } + } + }, [store]); + const goBackFromSidePanel = useCallback(() => { + cleanupCurrentPage(); + const currentNavigationStack = store.get( sidePanelNavigationStackState.atom, ); @@ -39,35 +82,30 @@ export const useSidePanelHistory = () => { store.set(sidePanelNavigationStackState.atom, newNavigationStack); - const currentMorphItems = store.get( - sidePanelNavigationMorphItemsByPageState.atom, + store.set(hasUserSelectedSidePanelListItemState.atom, false); + }, [cleanupCurrentPage, closeSidePanelMenu, store]); + + const goBackOneSubPageOrMainPage = useCallback(() => { + const currentPageInfo = store.get(sidePanelPageInfoState.atom); + + const subPageStack = store.get( + sidePanelSubPageStackComponentState.atomFamily({ + instanceId: currentPageInfo.instanceId, + }), ); - if (currentNavigationStack.length > 0) { - const removedItem = currentNavigationStack.at(-1); - - if (isDefined(removedItem)) { - const newMorphItems = new Map(currentMorphItems); - newMorphItems.delete(removedItem.pageId); - store.set(sidePanelNavigationMorphItemsByPageState.atom, newMorphItems); - - const morphItems = currentMorphItems.get(removedItem.pageId); - if (isNonEmptyArray(morphItems)) { - store.set( - activeTabIdComponentState.atomFamily({ - instanceId: getShowPageTabListComponentId({ - pageId: removedItem.pageId, - targetObjectId: morphItems[0].recordId, - }), - }), - null, - ); - } - } + if (isNonEmptyArray(subPageStack)) { + store.set( + sidePanelSubPageStackComponentState.atomFamily({ + instanceId: currentPageInfo.instanceId, + }), + subPageStack.slice(0, -1), + ); + return; } - store.set(hasUserSelectedSidePanelListItemState.atom, false); - }, [closeSidePanelMenu, store]); + goBackFromSidePanel(); + }, [goBackFromSidePanel, store]); const navigateSidePanelHistory = useCallback( (pageIndex: number) => { @@ -99,6 +137,13 @@ export const useSidePanelHistory = () => { for (const [pageId, morphItems] of currentMorphItems.entries()) { if (!newNavigationStack.some((item) => item.pageId === pageId)) { + store.set( + sidePanelSubPageStackComponentState.atomFamily({ + instanceId: pageId, + }), + [], + ); + store.set( activeTabIdComponentState.atomFamily({ instanceId: getShowPageTabListComponentId({ @@ -126,6 +171,7 @@ export const useSidePanelHistory = () => { return { goBackFromSidePanel, + goBackOneSubPageOrMainPage, navigateSidePanelHistory, }; }; diff --git a/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelSubPageHistory.ts b/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelSubPageHistory.ts new file mode 100644 index 0000000000..4307492c73 --- /dev/null +++ b/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelSubPageHistory.ts @@ -0,0 +1,50 @@ +import { useCallback } from 'react'; +import { v4 } from 'uuid'; + +import { sidePanelSubPageStackComponentState } from '@/side-panel/states/sidePanelSubPageStackComponentState'; +import { type SidePanelSubPageEntry } from '@/side-panel/types/SidePanelSubPageEntry'; +import { type SidePanelSubPages } from '@/side-panel/types/SidePanelSubPages'; +import { getSidePanelSubPageTitle } from '@/side-panel/utils/getSidePanelSubPageTitle'; +import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState'; +import { isDefined } from 'twenty-shared/utils'; + +export const useSidePanelSubPageHistory = () => { + const [sidePanelSubPageStack, setSidePanelSubPageStack] = + useAtomComponentState(sidePanelSubPageStackComponentState); + + const currentSidePanelSubPage: SidePanelSubPageEntry | undefined = + sidePanelSubPageStack.at(-1); + + const hasSidePanelSubPages = isDefined(currentSidePanelSubPage); + + const navigateToSidePanelSubPage = useCallback( + (subPage: SidePanelSubPages, titleOverride?: string) => { + const title = isDefined(titleOverride) + ? titleOverride + : getSidePanelSubPageTitle(subPage); + + setSidePanelSubPageStack((currentStack) => [ + ...currentStack, + { id: v4(), subPage, title }, + ]); + }, + [setSidePanelSubPageStack], + ); + + const goBackFromSidePanelSubPage = useCallback(() => { + setSidePanelSubPageStack((currentStack) => currentStack.slice(0, -1)); + }, [setSidePanelSubPageStack]); + + const resetSidePanelSubPages = useCallback(() => { + setSidePanelSubPageStack([]); + }, [setSidePanelSubPageStack]); + + return { + navigateToSidePanelSubPage, + goBackFromSidePanelSubPage, + resetSidePanelSubPages, + currentSidePanelSubPage, + sidePanelSubPageStack, + hasSidePanelSubPages, + }; +}; diff --git a/packages/twenty-front/src/modules/side-panel/pages/common/components/SidePanelSubPageNavigationHeader.tsx b/packages/twenty-front/src/modules/side-panel/pages/common/components/SidePanelSubPageNavigationHeader.tsx index e606c0d1ea..35a675b170 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/common/components/SidePanelSubPageNavigationHeader.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/common/components/SidePanelSubPageNavigationHeader.tsx @@ -34,6 +34,7 @@ export const SidePanelSubPageNavigationHeader = ({ Icon={IconChevronLeft} variant="tertiary" size="small" + ariaLabel="Go back" /> {title} diff --git a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelEditFolderPickerSubPage.tsx b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelEditFolderPickerSubPage.tsx new file mode 100644 index 0000000000..a07574d905 --- /dev/null +++ b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelEditFolderPickerSubPage.tsx @@ -0,0 +1,91 @@ +import { useLingui } from '@lingui/react/macro'; +import { useState } from 'react'; +import { useIcons } from 'twenty-ui/display'; + +import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem'; +import { NavigationMenuItemStyleIcon } from '@/navigation-menu-item/components/NavigationMenuItemStyleIcon'; +import { FOLDER_ICON_DEFAULT } from '@/navigation-menu-item/constants/FolderIconDefault'; +import { DEFAULT_NAVIGATION_MENU_ITEM_COLOR_FOLDER } from '@/navigation-menu-item/constants/NavigationMenuItemDefaultColorFolder'; +import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; +import { SidePanelList } from '@/side-panel/components/SidePanelList'; +import { SidePanelSubViewWithSearch } from '@/side-panel/components/SidePanelSubViewWithSearch'; +import { useFolderPickerSelectionData } from '@/side-panel/pages/navigation-menu-item/hooks/useFolderPickerSelectionData'; +import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; +import { filterBySearchQuery } from '~/utils/filterBySearchQuery'; + +export const SidePanelEditFolderPickerSubPage = () => { + const { t } = useLingui(); + const { getIcon } = useIcons(); + const [searchValue, setSearchValue] = useState(''); + const { foldersToShow, includeNoFolderOption, handleSelectFolder } = + useFolderPickerSelectionData(); + + const filteredFolders = filterBySearchQuery({ + items: foldersToShow, + searchQuery: searchValue, + getSearchableValues: (folder) => [folder.name], + }); + const isEmpty = filteredFolders.length === 0 && !includeNoFolderOption; + const selectableItemIds = [ + ...(includeNoFolderOption ? ['no-folder'] : []), + ...(filteredFolders.length > 0 ? filteredFolders.map((f) => f.id) : []), + ]; + const noResultsText = + searchValue.trim().length > 0 + ? t`No results found` + : t`No folders available`; + + return ( + + + + {includeNoFolderOption && ( + handleSelectFolder(null)} + > + handleSelectFolder(null)} + /> + + )} + {filteredFolders.map((folder) => { + const FolderIcon = getIcon(folder.icon ?? FOLDER_ICON_DEFAULT); + const folderColor = + folder.color ?? DEFAULT_NAVIGATION_MENU_ITEM_COLOR_FOLDER; + return ( + handleSelectFolder(folder.id)} + > + + } + label={folder.name} + id={folder.id} + onClick={() => handleSelectFolder(folder.id)} + /> + + ); + })} + + + + ); +}; diff --git a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelEditFolderPickerSubView.tsx b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelEditFolderPickerSubView.tsx index 060b5f583b..e69de29bb2 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelEditFolderPickerSubView.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelEditFolderPickerSubView.tsx @@ -1,99 +0,0 @@ -import { useLingui } from '@lingui/react/macro'; -import { useState } from 'react'; -import { useIcons } from 'twenty-ui/display'; - -import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; -import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem'; -import { SidePanelList } from '@/side-panel/components/SidePanelList'; -import { SidePanelSubViewWithSearch } from '@/side-panel/components/SidePanelSubViewWithSearch'; -import { useFolderPickerSelectionData } from '@/side-panel/pages/navigation-menu-item/hooks/useFolderPickerSelectionData'; -import { NavigationMenuItemStyleIcon } from '@/navigation-menu-item/components/NavigationMenuItemStyleIcon'; -import { FOLDER_ICON_DEFAULT } from '@/navigation-menu-item/constants/FolderIconDefault'; -import { DEFAULT_NAVIGATION_MENU_ITEM_COLOR_FOLDER } from '@/navigation-menu-item/constants/NavigationMenuItemDefaultColorFolder'; -import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; -import { filterBySearchQuery } from '~/utils/filterBySearchQuery'; - -type SidePanelEditFolderPickerSubViewProps = { - onBack: () => void; -}; - -export const SidePanelEditFolderPickerSubView = ({ - onBack, -}: SidePanelEditFolderPickerSubViewProps) => { - const { t } = useLingui(); - const { getIcon } = useIcons(); - const [searchValue, setSearchValue] = useState(''); - const { foldersToShow, includeNoFolderOption, handleSelectFolder } = - useFolderPickerSelectionData({ onCloseSubView: onBack }); - - const filteredFolders = filterBySearchQuery({ - items: foldersToShow, - searchQuery: searchValue, - getSearchableValues: (folder) => [folder.name], - }); - const isEmpty = filteredFolders.length === 0 && !includeNoFolderOption; - const selectableItemIds = [ - ...(includeNoFolderOption ? ['no-folder'] : []), - ...(filteredFolders.length > 0 ? filteredFolders.map((f) => f.id) : []), - ]; - const noResultsText = - searchValue.trim().length > 0 - ? t`No results found` - : t`No folders available`; - - return ( - - - - {includeNoFolderOption && ( - handleSelectFolder(null)} - > - handleSelectFolder(null)} - /> - - )} - {filteredFolders.map((folder) => { - const FolderIcon = getIcon(folder.icon ?? FOLDER_ICON_DEFAULT); - const folderColor = - folder.color ?? DEFAULT_NAVIGATION_MENU_ITEM_COLOR_FOLDER; - return ( - handleSelectFolder(folder.id)} - > - - } - label={folder.name} - id={folder.id} - onClick={() => handleSelectFolder(folder.id)} - /> - - ); - })} - - - - ); -}; diff --git a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNavigationMenuItemEditPage.tsx b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNavigationMenuItemEditPage.tsx index 58752ab1d0..d177296bf1 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNavigationMenuItemEditPage.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNavigationMenuItemEditPage.tsx @@ -10,20 +10,20 @@ import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-ite import { parseThemeColor } from '@/navigation-menu-item/utils/parseThemeColor'; import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; import { SidePanelList } from '@/side-panel/components/SidePanelList'; +import { useSidePanelSubPageHistory } from '@/side-panel/hooks/useSidePanelSubPageHistory'; import { SidePanelEditColorOption } from '@/side-panel/pages/navigation-menu-item/components/SidePanelEditColorOption'; -import { SidePanelEditFolderPickerSubView } from '@/side-panel/pages/navigation-menu-item/components/SidePanelEditFolderPickerSubView'; import { SidePanelEditLinkItemView } from '@/side-panel/pages/navigation-menu-item/components/SidePanelEditLinkItemView'; import { SidePanelEditObjectViewBase } from '@/side-panel/pages/navigation-menu-item/components/SidePanelEditObjectViewBase'; import { SidePanelEditOrganizeActions } from '@/side-panel/pages/navigation-menu-item/components/SidePanelEditOrganizeActions'; import { SidePanelEditOwnerSection } from '@/side-panel/pages/navigation-menu-item/components/SidePanelEditOwnerSection'; import { useNavigationMenuItemEditOrganizeActions } from '@/side-panel/pages/navigation-menu-item/hooks/useNavigationMenuItemEditOrganizeActions'; import { getOrganizeActionsSelectableItemIds } from '@/side-panel/pages/navigation-menu-item/utils/getOrganizeActionsSelectableItemIds'; +import { SidePanelSubPages } from '@/side-panel/types/SidePanelSubPages'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { ViewKey } from '@/views/types/ViewKey'; import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; -import { useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { IconPlus } from 'twenty-ui/display'; import { themeCssVariables } from 'twenty-ui/theme-constants'; @@ -51,8 +51,9 @@ export const SidePanelNavigationMenuItemEditPage = () => { useSelectedNavigationMenuItemEditItemObjectMetadata(); const selectedItemType = selectedItem?.itemType ?? null; - const [isFolderPickerOpen, setIsFolderPickerOpen] = useState(false); - const openFolderPicker = () => setIsFolderPickerOpen(true); + const { navigateToSidePanelSubPage } = useSidePanelSubPageHistory(); + const openFolderPicker = () => + navigateToSidePanelSubPage(SidePanelSubPages.EditFolderPicker); const { canMoveUp, @@ -95,14 +96,6 @@ export const SidePanelNavigationMenuItemEditPage = () => { ); } - if (isFolderPickerOpen) { - return ( - setIsFolderPickerOpen(false)} - /> - ); - } - switch (selectedItemType) { case NavigationMenuItemType.VIEW: if (!selectedItemObjectMetadata) return null; diff --git a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemObjectFlow.tsx b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemObjectSubPage.tsx similarity index 74% rename from packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemObjectFlow.tsx rename to packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemObjectSubPage.tsx index 6202f2e809..5976d2838f 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemObjectFlow.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemObjectSubPage.tsx @@ -1,4 +1,3 @@ -import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; import { useAddObjectToNavigationMenuDraft } from '@/navigation-menu-item/hooks/useAddObjectToNavigationMenuDraft'; @@ -10,26 +9,19 @@ import { getStandardObjectIconColor } from '@/navigation-menu-item/utils/getStan import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { useSidePanelSubPageHistory } from '@/side-panel/hooks/useSidePanelSubPageHistory'; import { SidePanelObjectPickerSubView } from '@/side-panel/pages/navigation-menu-item/components/SidePanelObjectPickerSubView'; -import { SidePanelSystemObjectPickerSubView } from '@/side-panel/pages/navigation-menu-item/components/SidePanelSystemObjectPickerSubView'; import { getAvailableObjectMetadataForNewSidebarItem } from '@/side-panel/pages/navigation-menu-item/utils/getAvailableObjectMetadataForNewSidebarItem'; +import { SidePanelSubPages } from '@/side-panel/types/SidePanelSubPages'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { ViewKey } from '@/views/types/ViewKey'; import { useIcons } from 'twenty-ui/display'; -type SidePanelNewSidebarItemObjectFlowProps = { - onBack: () => void; -}; - -export const SidePanelNewSidebarItemObjectFlow = ({ - onBack, -}: SidePanelNewSidebarItemObjectFlowProps) => { - const { t } = useLingui(); +export const SidePanelNewSidebarItemObjectSubPage = () => { + const { navigateToSidePanelSubPage } = useSidePanelSubPageHistory(); const { getIcon } = useIcons(); const [objectSearchInput, setObjectSearchInput] = useState(''); - const [systemObjectSearchInput, setSystemObjectSearchInput] = useState(''); - const [isInSystemPicker, setIsInSystemPicker] = useState(false); const { currentDraft } = useDraftNavigationMenuItems(); const { objectMetadataItems } = useObjectMetadataItems(); @@ -56,7 +48,7 @@ export const SidePanelNewSidebarItemObjectFlow = ({ .map((view) => view.objectMetadataId), ); - const { availableObjectMetadataItems, availableSystemObjectMetadataItems } = + const { availableObjectMetadataItems } = getAvailableObjectMetadataForNewSidebarItem({ objectMetadataItems, activeNonSystemObjectMetadataItems, @@ -87,36 +79,18 @@ export const SidePanelNewSidebarItemObjectFlow = ({ }); }; - const handleBackToObjectList = () => { - setIsInSystemPicker(false); - setSystemObjectSearchInput(''); - }; - const disableDrag = addMenuItemInsertionContext?.disableDrag === true; - if (isInSystemPicker) { - return ( - - ); - } - return ( setIsInSystemPicker(true)} + onOpenSystemPicker={() => + navigateToSidePanelSubPage( + SidePanelSubPages.NewSidebarItemObjectSystemPicker, + ) + } isViewItem={false} onChangeObject={handleSelectObject} objectMenuItemVariant="add" diff --git a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemObjectSystemPickerSubPage.tsx b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemObjectSystemPickerSubPage.tsx new file mode 100644 index 0000000000..ee6d0f7942 --- /dev/null +++ b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemObjectSystemPickerSubPage.tsx @@ -0,0 +1,95 @@ +import { useLingui } from '@lingui/react/macro'; + +import { useAddObjectToNavigationMenuDraft } from '@/navigation-menu-item/hooks/useAddObjectToNavigationMenuDraft'; +import { useDraftNavigationMenuItems } from '@/navigation-menu-item/hooks/useDraftNavigationMenuItems'; +import { useNavigationMenuObjectMetadataFromDraft } from '@/navigation-menu-item/hooks/useNavigationMenuObjectMetadataFromDraft'; +import { useOpenNavigationMenuItemInSidePanel } from '@/navigation-menu-item/hooks/useOpenNavigationMenuItemInSidePanel'; +import { addMenuItemInsertionContextState } from '@/navigation-menu-item/states/addMenuItemInsertionContextState'; +import { getStandardObjectIconColor } from '@/navigation-menu-item/utils/getStandardObjectIconColor'; +import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; +import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; +import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { SidePanelSystemObjectPickerSubView } from '@/side-panel/pages/navigation-menu-item/components/SidePanelSystemObjectPickerSubView'; +import { getAvailableObjectMetadataForNewSidebarItem } from '@/side-panel/pages/navigation-menu-item/utils/getAvailableObjectMetadataForNewSidebarItem'; +import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; +import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; +import { ViewKey } from '@/views/types/ViewKey'; +import { useState } from 'react'; +import { useIcons } from 'twenty-ui/display'; + +export const SidePanelNewSidebarItemObjectSystemPickerSubPage = () => { + const { t } = useLingui(); + const { getIcon } = useIcons(); + const [searchValue, setSearchValue] = useState(''); + + const { currentDraft } = useDraftNavigationMenuItems(); + const { objectMetadataItems } = useObjectMetadataItems(); + const { addObjectToDraft } = useAddObjectToNavigationMenuDraft(); + const { openNavigationMenuItemInSidePanel } = + useOpenNavigationMenuItemInSidePanel(); + const { activeNonSystemObjectMetadataItems } = + useFilteredObjectMetadataItems(); + const addMenuItemInsertionContext = useAtomStateValue( + addMenuItemInsertionContextState, + ); + const setAddMenuItemInsertionContext = useSetAtomState( + addMenuItemInsertionContextState, + ); + const { + views, + objectMetadataIdsWithIndexView, + objectMetadataIdsInWorkspace, + } = useNavigationMenuObjectMetadataFromDraft(currentDraft); + + const objectMetadataIdsWithDisplayableViews = new Set( + views + .filter((view) => view.key !== ViewKey.Index) + .map((view) => view.objectMetadataId), + ); + + const { availableSystemObjectMetadataItems } = + getAvailableObjectMetadataForNewSidebarItem({ + objectMetadataItems, + activeNonSystemObjectMetadataItems, + objectMetadataIdsWithIndexView, + objectMetadataIdsWithDisplayableViews, + }); + + const handleSelectObject = ( + objectMetadataItem: ObjectMetadataItem, + defaultViewId: string, + ) => { + if (objectMetadataIdsInWorkspace.has(objectMetadataItem.id)) { + return; + } + const itemId = addObjectToDraft( + objectMetadataItem.id, + defaultViewId, + currentDraft, + addMenuItemInsertionContext?.targetFolderId, + addMenuItemInsertionContext?.targetIndex, + getStandardObjectIconColor(objectMetadataItem.nameSingular), + ); + setAddMenuItemInsertionContext(null); + openNavigationMenuItemInSidePanel({ + itemId, + pageTitle: objectMetadataItem.labelSingular, + pageIcon: getIcon(objectMetadataItem.icon), + }); + }; + + const disableDrag = addMenuItemInsertionContext?.disableDrag === true; + + return ( + + ); +}; diff --git a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemPage.tsx b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemPage.tsx index 157e77aa5a..3088c37424 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemPage.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemPage.tsx @@ -1,45 +1,23 @@ -import { useState } from 'react'; - -import { addMenuItemInsertionContextState } from '@/navigation-menu-item/states/addMenuItemInsertionContextState'; +import { useSidePanelSubPageHistory } from '@/side-panel/hooks/useSidePanelSubPageHistory'; import { SidePanelNewSidebarItemMainMenu } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemMainMenu'; -import { SidePanelNewSidebarItemObjectFlow } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemObjectFlow'; -import { SidePanelNewSidebarItemRecordSubView } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemRecordSubView'; -import { SidePanelNewSidebarItemViewFlow } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewFlow'; -import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { isDefined } from 'twenty-shared/utils'; - -type SelectedOption = 'object' | 'record' | 'view' | null; +import { SidePanelSubPages } from '@/side-panel/types/SidePanelSubPages'; export const SidePanelNewSidebarItemPage = () => { - const [selectedOption, setSelectedOption] = useState(null); - const addMenuItemInsertionContext = useAtomStateValue( - addMenuItemInsertionContextState, + const { navigateToSidePanelSubPage } = useSidePanelSubPageHistory(); + + return ( + + navigateToSidePanelSubPage(SidePanelSubPages.NewSidebarItemRecord) + } + onSelectObject={() => + navigateToSidePanelSubPage(SidePanelSubPages.NewSidebarItemObjectPicker) + } + onSelectView={() => + navigateToSidePanelSubPage( + SidePanelSubPages.NewSidebarItemViewObjectPicker, + ) + } + /> ); - const disableDrag = isDefined(addMenuItemInsertionContext); - - const handleBackToMain = () => { - setSelectedOption(null); - }; - - switch (selectedOption) { - case 'view': - return ; - case 'object': - return ; - case 'record': - return ( - - ); - default: - return ( - setSelectedOption('record')} - onSelectObject={() => setSelectedOption('object')} - onSelectView={() => setSelectedOption('view')} - /> - ); - } }; diff --git a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemRecordSubView.tsx b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemRecordSubPage.tsx similarity index 92% rename from packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemRecordSubView.tsx rename to packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemRecordSubPage.tsx index 9e3d872c8e..8aecc696c6 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemRecordSubView.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemRecordSubPage.tsx @@ -25,21 +25,12 @@ type SearchRecordBase = { imageUrl?: string | null; }; -type SidePanelNewSidebarItemRecordSubViewProps = { - onBack: () => void; - disableDrag?: boolean; -}; - -export const SidePanelNewSidebarItemRecordSubView = ({ - onBack, - disableDrag: disableDragProp, -}: SidePanelNewSidebarItemRecordSubViewProps) => { +export const SidePanelNewSidebarItemRecordSubPage = () => { const { t } = useLingui(); const addMenuItemInsertionContext = useAtomStateValue( addMenuItemInsertionContextState, ); - const disableDrag = - disableDragProp ?? addMenuItemInsertionContext?.disableDrag === true; + const disableDrag = addMenuItemInsertionContext?.disableDrag === true; const { currentDraft } = useDraftNavigationMenuItems(); const { objectMetadataItems } = useObjectMetadataItems(); const [recordSearchInput, setRecordSearchInput] = useState(''); @@ -92,8 +83,6 @@ export const SidePanelNewSidebarItemRecordSubView = ({ return ( void; -}; - -export const SidePanelNewSidebarItemViewFlow = ({ - onBack, -}: SidePanelNewSidebarItemViewFlowProps) => { - const [selectedObjectMetadataIdForView, setSelectedObjectMetadataIdForView] = - useState(null); - const [objectSearchInput, setObjectSearchInput] = useState(''); - const [systemObjectSearchInput, setSystemObjectSearchInput] = useState(''); - const [isInSystemPicker, setIsInSystemPicker] = useState(false); - - const { currentDraft } = useDraftNavigationMenuItems(); - const { objectMetadataItems } = useObjectMetadataItems(); - const { activeNonSystemObjectMetadataItems } = - useFilteredObjectMetadataItems(); - const { views, objectMetadataIdsWithIndexView } = - useNavigationMenuObjectMetadataFromDraft(currentDraft); - - const objectMetadataIdsWithDisplayableViews = new Set( - views - .filter( - (view) => - view.key !== ViewKey.Index && view.type !== ViewType.FieldsWidget, - ) - .map((view) => view.objectMetadataId), - ); - - const { - objectMetadataItemsWithViews, - availableSystemObjectMetadataItemsForView, - } = getAvailableObjectMetadataForNewSidebarItem({ - objectMetadataItems, - activeNonSystemObjectMetadataItems, - objectMetadataIdsWithIndexView, - objectMetadataIdsWithDisplayableViews, - }); - - const handleBackFromViewPicker = () => { - const selectedObjectMetadataItem = isDefined( - selectedObjectMetadataIdForView, - ) - ? objectMetadataItems.find( - (item) => item.id === selectedObjectMetadataIdForView, - ) - : undefined; - const cameFromSystemObjects = selectedObjectMetadataItem?.isSystem ?? false; - - setSelectedObjectMetadataIdForView(null); - setIsInSystemPicker(cameFromSystemObjects); - }; - - const handleBackFromSystemPicker = () => { - setIsInSystemPicker(false); - }; - - const handleSelectObject = (objectId: string) => { - setSelectedObjectMetadataIdForView(objectId); - }; - - const handleSelectObjectFromSystem = (objectId: string) => { - setSelectedObjectMetadataIdForView(objectId); - setIsInSystemPicker(false); - }; - - if (isDefined(selectedObjectMetadataIdForView) && !isInSystemPicker) { - return ( - - ); - } - - if (isInSystemPicker) { - return ( - handleSelectObjectFromSystem(item.id)} - /> - ); - } - - return ( - setIsInSystemPicker(true)} - onSelectObject={(item) => handleSelectObject(item.id)} - showSystemObjectsOption={ - availableSystemObjectMetadataItemsForView.length > 0 - } - /> - ); -}; diff --git a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewObjectPickerSubPage.tsx b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewObjectPickerSubPage.tsx new file mode 100644 index 0000000000..5ad5356db7 --- /dev/null +++ b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewObjectPickerSubPage.tsx @@ -0,0 +1,73 @@ +import { useDraftNavigationMenuItems } from '@/navigation-menu-item/hooks/useDraftNavigationMenuItems'; +import { useNavigationMenuObjectMetadataFromDraft } from '@/navigation-menu-item/hooks/useNavigationMenuObjectMetadataFromDraft'; +import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; +import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; +import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { useSidePanelSubPageHistory } from '@/side-panel/hooks/useSidePanelSubPageHistory'; +import { SidePanelNewSidebarItemViewObjectPickerSubView } from '@/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewObjectPickerSubView'; +import { getAvailableObjectMetadataForNewSidebarItem } from '@/side-panel/pages/navigation-menu-item/utils/getAvailableObjectMetadataForNewSidebarItem'; +import { selectedObjectMetadataIdForViewFlowState } from '@/side-panel/states/selectedObjectMetadataIdForViewFlowState'; +import { SidePanelSubPages } from '@/side-panel/types/SidePanelSubPages'; +import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState'; +import { ViewKey } from '@/views/types/ViewKey'; +import { ViewType } from '@/views/types/ViewType'; +import { useState } from 'react'; + +export const SidePanelNewSidebarItemViewObjectPickerSubPage = () => { + const { navigateToSidePanelSubPage } = useSidePanelSubPageHistory(); + const [searchValue, setSearchValue] = useState(''); + const setSelectedObjectMetadataIdForViewFlow = useSetAtomComponentState( + selectedObjectMetadataIdForViewFlowState, + ); + + const { currentDraft } = useDraftNavigationMenuItems(); + const { objectMetadataItems } = useObjectMetadataItems(); + const { activeNonSystemObjectMetadataItems } = + useFilteredObjectMetadataItems(); + const { views, objectMetadataIdsWithIndexView } = + useNavigationMenuObjectMetadataFromDraft(currentDraft); + + const objectMetadataIdsWithDisplayableViews = new Set( + views + .filter( + (view) => + view.key !== ViewKey.Index && view.type !== ViewType.FieldsWidget, + ) + .map((view) => view.objectMetadataId), + ); + + const { + objectMetadataItemsWithViews, + availableSystemObjectMetadataItemsForView, + } = getAvailableObjectMetadataForNewSidebarItem({ + objectMetadataItems, + activeNonSystemObjectMetadataItems, + objectMetadataIdsWithIndexView, + objectMetadataIdsWithDisplayableViews, + }); + + const handleSelectObject = (objectMetadataItem: ObjectMetadataItem) => { + setSelectedObjectMetadataIdForViewFlow(objectMetadataItem.id); + navigateToSidePanelSubPage( + SidePanelSubPages.NewSidebarItemViewPicker, + objectMetadataItem.labelPlural, + ); + }; + + return ( + + navigateToSidePanelSubPage( + SidePanelSubPages.NewSidebarItemViewSystemPicker, + ) + } + onSelectObject={handleSelectObject} + showSystemObjectsOption={ + availableSystemObjectMetadataItemsForView.length > 0 + } + /> + ); +}; diff --git a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewObjectPickerSubView.tsx b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewObjectPickerSubView.tsx index faf7c71188..a336fd07bb 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewObjectPickerSubView.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewObjectPickerSubView.tsx @@ -1,21 +1,20 @@ import { useLingui } from '@lingui/react/macro'; import { IconSettings, useIcons } from 'twenty-ui/display'; -import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem'; -import { SidePanelList } from '@/side-panel/components/SidePanelList'; -import { SidePanelSubViewWithSearch } from '@/side-panel/components/SidePanelSubViewWithSearch'; -import { useSidePanelFilteredPickerItems } from '@/side-panel/hooks/useSidePanelFilteredPickerItems'; import { NavigationMenuItemStyleIcon } from '@/navigation-menu-item/components/NavigationMenuItemStyleIcon'; import { getStandardObjectIconColor } from '@/navigation-menu-item/utils/getStandardObjectIconColor'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; +import { SidePanelList } from '@/side-panel/components/SidePanelList'; +import { SidePanelSubViewWithSearch } from '@/side-panel/components/SidePanelSubViewWithSearch'; +import { useSidePanelFilteredPickerItems } from '@/side-panel/hooks/useSidePanelFilteredPickerItems'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; type SidePanelNewSidebarItemViewObjectPickerSubViewProps = { objects: ObjectMetadataItem[]; searchValue: string; onSearchChange: (value: string) => void; - onBack: () => void; onOpenSystemPicker: () => void; onSelectObject: (objectMetadataItem: ObjectMetadataItem) => void; showSystemObjectsOption?: boolean; @@ -25,7 +24,6 @@ export const SidePanelNewSidebarItemViewObjectPickerSubView = ({ objects, searchValue, onSearchChange, - onBack, onOpenSystemPicker, onSelectObject, showSystemObjectsOption = true, @@ -45,8 +43,6 @@ export const SidePanelNewSidebarItemViewObjectPickerSubView = ({ return ( { + const selectedObjectMetadataIdForViewFlow = useAtomComponentStateValue( + selectedObjectMetadataIdForViewFlowState, + ); + + if (!isDefined(selectedObjectMetadataIdForViewFlow)) { + return null; + } + + return ( + + ); +}; diff --git a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewPickerSubView.tsx b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewPickerSubView.tsx index 1e96bb8a5e..90055d636a 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewPickerSubView.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewPickerSubView.tsx @@ -27,12 +27,10 @@ import { ViewVisibility } from '~/generated-metadata/graphql'; type SidePanelNewSidebarItemViewPickerSubViewProps = { selectedObjectMetadataIdForView: string; - onBack: () => void; }; export const SidePanelNewSidebarItemViewPickerSubView = ({ selectedObjectMetadataIdForView, - onBack, }: SidePanelNewSidebarItemViewPickerSubViewProps) => { const { t } = useLingui(); const { getIcon } = useIcons(); @@ -63,8 +61,6 @@ export const SidePanelNewSidebarItemViewPickerSubView = ({ const selectedObjectMetadataItem = objectMetadataItems.find( (item) => item.id === selectedObjectMetadataIdForView, ); - const backBarTitle = - selectedObjectMetadataItem?.labelPlural ?? t`Pick a view`; const { filteredItems: filteredViews, @@ -102,8 +98,6 @@ export const SidePanelNewSidebarItemViewPickerSubView = ({ return ( { + const { navigateToSidePanelSubPage } = useSidePanelSubPageHistory(); + const [searchValue, setSearchValue] = useState(''); + const setSelectedObjectMetadataIdForViewFlow = useSetAtomComponentState( + selectedObjectMetadataIdForViewFlowState, + ); + + const { currentDraft } = useDraftNavigationMenuItems(); + const { objectMetadataItems } = useObjectMetadataItems(); + const { activeNonSystemObjectMetadataItems } = + useFilteredObjectMetadataItems(); + const { views, objectMetadataIdsWithIndexView } = + useNavigationMenuObjectMetadataFromDraft(currentDraft); + + const objectMetadataIdsWithDisplayableViews = new Set( + views + .filter( + (view) => + view.key !== ViewKey.Index && view.type !== ViewType.FieldsWidget, + ) + .map((view) => view.objectMetadataId), + ); + + const { availableSystemObjectMetadataItemsForView } = + getAvailableObjectMetadataForNewSidebarItem({ + objectMetadataItems, + activeNonSystemObjectMetadataItems, + objectMetadataIdsWithIndexView, + objectMetadataIdsWithDisplayableViews, + }); + + const handleSelectObject = (objectMetadataItem: ObjectMetadataItem) => { + setSelectedObjectMetadataIdForViewFlow(objectMetadataItem.id); + navigateToSidePanelSubPage( + SidePanelSubPages.NewSidebarItemViewPicker, + objectMetadataItem.labelPlural, + ); + }; + + return ( + + ); +}; diff --git a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewSystemSubView.tsx b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewSystemSubView.tsx index dc211d73ed..3536a4c613 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewSystemSubView.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/navigation-menu-item/components/SidePanelNewSidebarItemViewSystemSubView.tsx @@ -1,21 +1,20 @@ import { useLingui } from '@lingui/react/macro'; import { useIcons } from 'twenty-ui/display'; -import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem'; -import { SidePanelList } from '@/side-panel/components/SidePanelList'; -import { SidePanelSubViewWithSearch } from '@/side-panel/components/SidePanelSubViewWithSearch'; -import { useSidePanelFilteredPickerItems } from '@/side-panel/hooks/useSidePanelFilteredPickerItems'; import { NavigationMenuItemStyleIcon } from '@/navigation-menu-item/components/NavigationMenuItemStyleIcon'; import { getStandardObjectIconColor } from '@/navigation-menu-item/utils/getStandardObjectIconColor'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; +import { SidePanelList } from '@/side-panel/components/SidePanelList'; +import { SidePanelSubViewWithSearch } from '@/side-panel/components/SidePanelSubViewWithSearch'; +import { useSidePanelFilteredPickerItems } from '@/side-panel/hooks/useSidePanelFilteredPickerItems'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; type SidePanelNewSidebarItemViewSystemSubViewProps = { systemObjects: ObjectMetadataItem[]; searchValue: string; onSearchChange: (value: string) => void; - onBack: () => void; onSelectObject: (objectMetadataItem: ObjectMetadataItem) => void; }; @@ -23,7 +22,6 @@ export const SidePanelNewSidebarItemViewSystemSubView = ({ systemObjects, searchValue, onSearchChange, - onBack, onSelectObject, }: SidePanelNewSidebarItemViewSystemSubViewProps) => { const { t } = useLingui(); @@ -44,8 +42,6 @@ export const SidePanelNewSidebarItemViewSystemSubView = ({ return ( void; - onBack: () => void; onOpenSystemPicker: () => void; isViewItem: boolean; onSelectObjectForViewEdit?: (objectMetadataItem: ObjectMetadataItem) => void; @@ -33,7 +32,6 @@ export const SidePanelObjectPickerSubView = ({ objects, searchValue, onSearchChange, - onBack, onOpenSystemPicker, isViewItem, onSelectObjectForViewEdit, @@ -85,8 +83,6 @@ export const SidePanelObjectPickerSubView = ({ return ( void; - onBack: () => void; isViewItem: boolean; onSelectObjectForViewEdit?: (objectMetadataItem: ObjectMetadataItem) => void; onChangeObject: ( @@ -28,7 +27,6 @@ export const SidePanelSystemObjectPickerSubView = ({ systemObjects, searchValue, onSearchChange, - onBack, isViewItem, onSelectObjectForViewEdit, onChangeObject, @@ -69,8 +67,6 @@ export const SidePanelSystemObjectPickerSubView = ({ return ( ( ? folders : folders.filter((folder) => folder.id !== currentFolderId); -type UseFolderPickerSelectionDataParams = { - onCloseSubView: () => void; -}; - -export const useFolderPickerSelectionData = ({ - onCloseSubView, -}: UseFolderPickerSelectionDataParams) => { +export const useFolderPickerSelectionData = () => { const { closeSidePanelMenu } = useSidePanelMenu(); const { moveToFolder } = useNavigationMenuItemMoveRemove(); const selectedNavigationMenuItemInEditMode = useAtomStateValue( @@ -94,7 +88,6 @@ export const useFolderPickerSelectionData = ({ const handleSelectFolder = (folderId: string | null) => { if (isDefined(selectedNavigationMenuItemInEditMode)) { moveToFolder(selectedNavigationMenuItemInEditMode, folderId); - onCloseSubView(); closeSidePanelMenu(); } }; diff --git a/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/ChartFiltersSettings.tsx b/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/ChartFiltersSettings.tsx index 536c270be2..98457eaa9c 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/ChartFiltersSettings.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/ChartFiltersSettings.tsx @@ -1,5 +1,3 @@ -import { useSidePanelHistory } from '@/side-panel/hooks/useSidePanelHistory'; -import { SidePanelSubPageNavigationHeader } from '@/side-panel/pages/common/components/SidePanelSubPageNavigationHeader'; import { ChartFiltersSettingsInitializeStateEffect } from '@/side-panel/pages/page-layout/components/ChartFiltersSettingsInitializeStateEffect'; import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/side-panel/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord'; import { useUpdateCurrentWidgetConfig } from '@/side-panel/pages/page-layout/hooks/useUpdateCurrentWidgetConfig'; @@ -15,9 +13,9 @@ import { RecordFiltersComponentInstanceContext } from '@/object-record/record-fi import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { InputLabel } from '@/ui/input/components/InputLabel'; import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState'; -import { useStore } from 'jotai'; import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; +import { useStore } from 'jotai'; import { themeCssVariables } from 'twenty-ui/theme-constants'; const StyledChartFiltersPageContainer = styled.div` @@ -38,8 +36,6 @@ export const ChartFiltersSettings = ({ objectMetadataItem, widget, }: ChartFiltersSettingsProps) => { - const { goBackFromSidePanel } = useSidePanelHistory(); - const { instanceId } = getChartFiltersSettingsInstanceId({ widgetId: widget.id, objectMetadataItemId: objectMetadataItem.id, @@ -79,32 +75,26 @@ export const ChartFiltersSettings = ({ }; return ( - <> - - -
- {t`Conditions`} - +
+ {t`Conditions`} + + - - - - - -
- - + + + +
+
+
); }; diff --git a/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutGraphFilter.tsx b/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelChartFilterSubPage.tsx similarity index 78% rename from packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutGraphFilter.tsx rename to packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelChartFilterSubPage.tsx index a36b791ec2..c22fb2356b 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutGraphFilter.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelChartFilterSubPage.tsx @@ -1,14 +1,14 @@ -import { ChartFiltersSettings } from '@/side-panel/pages/page-layout/components/ChartFiltersSettings'; -import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/side-panel/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord'; -import { isChartWidget } from '@/side-panel/pages/page-layout/utils/isChartWidget'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; +import { ChartFiltersSettings } from '@/side-panel/pages/page-layout/components/ChartFiltersSettings'; +import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/side-panel/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord'; +import { isChartWidget } from '@/side-panel/pages/page-layout/utils/isChartWidget'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { isDefined } from 'twenty-shared/utils'; -export const SidePanelPageLayoutGraphFilter = () => { +export const SidePanelChartFilterSubPage = () => { const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord(); const pageLayoutDraft = useAtomComponentStateValue( @@ -29,29 +29,26 @@ export const SidePanelPageLayoutGraphFilter = () => { if ( !isDefined(widgetInEditMode) || - !isDefined(widgetInEditMode.objectMetadataId) || - !isChartWidget(widgetInEditMode) + !isChartWidget(widgetInEditMode) || + !isDefined(widgetInEditMode.objectMetadataId) ) { return null; } const objectMetadataItem = objectMetadataItems.find( - (objectMetadataItem) => - objectMetadataItem.id === widgetInEditMode?.objectMetadataId, + (item) => item.id === widgetInEditMode.objectMetadataId, ); if (!isDefined(objectMetadataItem)) { throw new Error( - `Object metadata item not found for id ${widgetInEditMode?.objectMetadataId}`, + `Object metadata item not found for id ${widgetInEditMode.objectMetadataId}`, ); } return ( - <> - - + ); }; diff --git a/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutFieldsLayout.tsx b/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelFieldsLayoutSubPage.tsx similarity index 60% rename from packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutFieldsLayout.tsx rename to packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelFieldsLayoutSubPage.tsx index c10a22b8bc..a61b679ef5 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutFieldsLayout.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelFieldsLayoutSubPage.tsx @@ -1,26 +1,17 @@ -import { useSidePanelHistory } from '@/side-panel/hooks/useSidePanelHistory'; -import { SidePanelSubPageNavigationHeader } from '@/side-panel/pages/common/components/SidePanelSubPageNavigationHeader'; -import { usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord } from '@/side-panel/pages/page-layout/hooks/usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord'; -import { useWidgetInEditMode } from '@/side-panel/pages/page-layout/hooks/useWidgetInEditMode'; import { useTemporaryFieldsConfiguration } from '@/page-layout/hooks/useTemporaryFieldsConfiguration'; import { FieldsConfigurationEditor } from '@/page-layout/widgets/fields/components/FieldsConfigurationEditor'; import { FieldsWidgetGroupsDraftInitializationEffect } from '@/page-layout/widgets/fields/components/FieldsWidgetGroupsDraftInitializationEffect'; +import { usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord } from '@/side-panel/pages/page-layout/hooks/usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord'; +import { useWidgetInEditMode } from '@/side-panel/pages/page-layout/hooks/useWidgetInEditMode'; import { styled } from '@linaria/react'; -import { t } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type FieldsConfiguration, WidgetConfigurationType, } from '~/generated-metadata/graphql'; -import { themeCssVariables } from 'twenty-ui/theme-constants'; -const StyledOuterContainer = styled.div` - display: flex; - flex-direction: column; - height: 100%; -`; - -const StyledContainer = styled.div` +const StyledFieldsLayoutContainer = styled.div` display: flex; flex: 1; flex-direction: column; @@ -29,9 +20,7 @@ const StyledContainer = styled.div` padding: ${themeCssVariables.spacing[2]}; `; -export const SidePanelPageLayoutFieldsLayout = () => { - const { goBackFromSidePanel } = useSidePanelHistory(); - +export const SidePanelFieldsLayoutSubPage = () => { const { pageLayoutId } = usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord(); @@ -44,29 +33,23 @@ export const SidePanelPageLayoutFieldsLayout = () => { const widgetConfiguration = widgetInEditMode.configuration; - const fieldsConfiguration: FieldsConfiguration = + const resolvedFieldsConfiguration: FieldsConfiguration = isDefined(widgetConfiguration) && widgetConfiguration.configurationType === WidgetConfigurationType.FIELDS ? (widgetConfiguration as FieldsConfiguration) : temporaryFieldsConfiguration; return ( - - + - - - - - + + ); }; diff --git a/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutChartSettings.tsx b/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutChartSettings.tsx index 92038948ee..7c13c2865e 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutChartSettings.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutChartSettings.tsx @@ -1,10 +1,10 @@ +import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; +import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; +import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; import { ChartSettings } from '@/side-panel/pages/page-layout/components/ChartSettings'; import { WidgetSettingsFooter } from '@/side-panel/pages/page-layout/components/WidgetSettingsFooter'; import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/side-panel/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord'; import { isChartWidget } from '@/side-panel/pages/page-layout/utils/isChartWidget'; -import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState'; -import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; -import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { styled } from '@linaria/react'; import { isDefined } from 'twenty-shared/utils'; diff --git a/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutFieldsSettings.tsx b/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutFieldsSettings.tsx index b985e4c601..0b91fd838d 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutFieldsSettings.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/SidePanelPageLayoutFieldsSettings.tsx @@ -3,16 +3,16 @@ import { CommandMenuItemToggle } from '@/command-menu/components/CommandMenuItem import { useFieldsWidgetGroups } from '@/page-layout/widgets/fields/hooks/useFieldsWidgetGroups'; import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; import { SidePanelList } from '@/side-panel/components/SidePanelList'; +import { useSidePanelSubPageHistory } from '@/side-panel/hooks/useSidePanelSubPageHistory'; import { NewFieldDefaultVisibilityToggle } from '@/side-panel/pages/page-layout/components/NewFieldDefaultVisibilityToggle'; import { WidgetSettingsFooter } from '@/side-panel/pages/page-layout/components/WidgetSettingsFooter'; -import { useNavigatePageLayoutSidePanel } from '@/side-panel/pages/page-layout/hooks/useNavigatePageLayoutSidePanel'; import { usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord } from '@/side-panel/pages/page-layout/hooks/usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord'; import { useUpdateCurrentWidgetConfig } from '@/side-panel/pages/page-layout/hooks/useUpdateCurrentWidgetConfig'; import { useWidgetInEditMode } from '@/side-panel/pages/page-layout/hooks/useWidgetInEditMode'; +import { SidePanelSubPages } from '@/side-panel/types/SidePanelSubPages'; import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; -import { SidePanelPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { IconChevronDown, IconLayoutSidebarRight } from 'twenty-ui/display'; import { type FieldsConfiguration } from '~/generated-metadata/graphql'; @@ -32,7 +32,7 @@ const StyledSidePanelContainer = styled.div` export const SidePanelPageLayoutFieldsSettings = () => { const { t } = useLingui(); - const { navigatePageLayoutSidePanel } = useNavigatePageLayoutSidePanel(); + const { navigateToSidePanelSubPage } = useSidePanelSubPageHistory(); const { pageLayoutId, objectNameSingular } = usePageLayoutIdForRecordPageLayoutFromContextStoreTargetedRecord(); @@ -60,9 +60,7 @@ export const SidePanelPageLayoutFieldsSettings = () => { ); const handleNavigateToLayout = () => { - navigatePageLayoutSidePanel({ - sidePanelPage: SidePanelPages.PageLayoutFieldsLayout, - }); + navigateToSidePanelSubPage(SidePanelSubPages.PageLayoutFieldsLayout); }; const isShouldAllowUserToSeeHiddenFieldsToggled = diff --git a/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/chart-settings/ChartSettingItem.tsx b/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/chart-settings/ChartSettingItem.tsx index a90572b836..8763a9a9ae 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/chart-settings/ChartSettingItem.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/page-layout/components/chart-settings/ChartSettingItem.tsx @@ -4,8 +4,8 @@ import { CommandMenuItemNumberInput } from '@/command-menu/components/CommandMen import { CommandMenuItemTextInput } from '@/command-menu/components/CommandMenuItemTextInput'; import { CommandMenuItemToggle } from '@/command-menu/components/CommandMenuItemToggle'; import { SIDE_PANEL_SELECTABLE_LIST_ID } from '@/side-panel/constants/SidePanelSelectableListId'; +import { useSidePanelSubPageHistory } from '@/side-panel/hooks/useSidePanelSubPageHistory'; import { useChartSettingsValues } from '@/side-panel/pages/page-layout/hooks/useChartSettingsValues'; -import { useNavigatePageLayoutSidePanel } from '@/side-panel/pages/page-layout/hooks/useNavigatePageLayoutSidePanel'; import { usePageLayoutIdFromContextStoreTargetedRecord } from '@/side-panel/pages/page-layout/hooks/usePageLayoutFromContextStoreTargetedRecord'; import { useUpdateChartSettingInput } from '@/side-panel/pages/page-layout/hooks/useUpdateChartSettingInput'; import { useUpdateChartSettingTextInput } from '@/side-panel/pages/page-layout/hooks/useUpdateChartSettingTextInput'; @@ -14,6 +14,7 @@ import { type ChartConfiguration } from '@/side-panel/pages/page-layout/types/Ch import { CHART_CONFIGURATION_SETTING_IDS } from '@/side-panel/pages/page-layout/types/ChartConfigurationSettingIds'; import { type ChartSettingsItem } from '@/side-panel/pages/page-layout/types/ChartSettingsGroup'; import { isMinMaxRangeValid } from '@/side-panel/pages/page-layout/utils/isMinMaxRangeValid'; +import { SidePanelSubPages } from '@/side-panel/types/SidePanelSubPages'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown'; import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown'; @@ -21,7 +22,6 @@ import { SelectableListItem } from '@/ui/layout/selectable-list/components/Selec import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { t } from '@lingui/core/macro'; import { isString } from '@sniptt/guards'; -import { SidePanelPages } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; type ChartSettingItemProps = { @@ -41,7 +41,7 @@ export const ChartSettingItem = ({ const { setSelectedItemId } = useSelectableList( SIDE_PANEL_SELECTABLE_LIST_ID, ); - const { navigatePageLayoutSidePanel } = useNavigatePageLayoutSidePanel(); + const { navigateToSidePanelSubPage } = useSidePanelSubPageHistory(); const { getChartSettingsValues } = useChartSettingsValues({ objectMetadataId, @@ -80,9 +80,7 @@ export const ChartSettingItem = ({ }; const handleFilterClick = () => { - navigatePageLayoutSidePanel({ - sidePanelPage: SidePanelPages.PageLayoutGraphFilter, - }); + navigateToSidePanelSubPage(SidePanelSubPages.PageLayoutGraphFilter); }; if (item.id === CHART_CONFIGURATION_SETTING_IDS.FILTER) { const filterValue = getChartSettingsValues(item.id); diff --git a/packages/twenty-front/src/modules/side-panel/pages/page-layout/types/PageLayoutSidePanelPage.ts b/packages/twenty-front/src/modules/side-panel/pages/page-layout/types/PageLayoutSidePanelPage.ts index f845295944..c1949d277e 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/page-layout/types/PageLayoutSidePanelPage.ts +++ b/packages/twenty-front/src/modules/side-panel/pages/page-layout/types/PageLayoutSidePanelPage.ts @@ -4,7 +4,5 @@ export type PageLayoutSidePanelPage = | SidePanelPages.PageLayoutWidgetTypeSelect | SidePanelPages.PageLayoutGraphTypeSelect | SidePanelPages.PageLayoutIframeSettings - | SidePanelPages.PageLayoutGraphFilter | SidePanelPages.PageLayoutTabSettings - | SidePanelPages.PageLayoutFieldsSettings - | SidePanelPages.PageLayoutFieldsLayout; + | SidePanelPages.PageLayoutFieldsSettings; diff --git a/packages/twenty-front/src/modules/side-panel/pages/page-layout/utils/getPageLayoutIcon.ts b/packages/twenty-front/src/modules/side-panel/pages/page-layout/utils/getPageLayoutIcon.ts index 681e82cb3c..fa97bf511c 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/page-layout/utils/getPageLayoutIcon.ts +++ b/packages/twenty-front/src/modules/side-panel/pages/page-layout/utils/getPageLayoutIcon.ts @@ -4,9 +4,7 @@ import { assertUnreachable } from 'twenty-shared/utils'; import { IconAppWindow, IconChartPie, - IconFilter, IconFrame, - IconLayoutSidebarRight, IconList, } from 'twenty-ui/display'; @@ -18,14 +16,10 @@ export const getPageLayoutIcon = (page: PageLayoutSidePanelPage) => { return IconChartPie; case SidePanelPages.PageLayoutIframeSettings: return IconFrame; - case SidePanelPages.PageLayoutGraphFilter: - return IconFilter; case SidePanelPages.PageLayoutTabSettings: return IconAppWindow; case SidePanelPages.PageLayoutFieldsSettings: return IconList; - case SidePanelPages.PageLayoutFieldsLayout: - return IconLayoutSidebarRight; default: assertUnreachable(page); } diff --git a/packages/twenty-front/src/modules/side-panel/pages/page-layout/utils/getPageLayoutPageTitle.ts b/packages/twenty-front/src/modules/side-panel/pages/page-layout/utils/getPageLayoutPageTitle.ts index d91afd5ea1..6c94a047f5 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/page-layout/utils/getPageLayoutPageTitle.ts +++ b/packages/twenty-front/src/modules/side-panel/pages/page-layout/utils/getPageLayoutPageTitle.ts @@ -11,14 +11,10 @@ export const getPageLayoutPageTitle = (page: PageLayoutSidePanelPage) => { return t`Select Graph Type`; case SidePanelPages.PageLayoutIframeSettings: return t`iFrame Settings`; - case SidePanelPages.PageLayoutGraphFilter: - return t`Configure filters`; case SidePanelPages.PageLayoutTabSettings: return t`Tab Settings`; case SidePanelPages.PageLayoutFieldsSettings: return t`Fields Settings`; - case SidePanelPages.PageLayoutFieldsLayout: - return t`Layout`; default: assertUnreachable(page); } diff --git a/packages/twenty-front/src/modules/side-panel/states/selectedObjectMetadataIdForViewFlowState.ts b/packages/twenty-front/src/modules/side-panel/states/selectedObjectMetadataIdForViewFlowState.ts new file mode 100644 index 0000000000..2d4719ede5 --- /dev/null +++ b/packages/twenty-front/src/modules/side-panel/states/selectedObjectMetadataIdForViewFlowState.ts @@ -0,0 +1,9 @@ +import { SidePanelPageComponentInstanceContext } from '@/side-panel/states/contexts/SidePanelPageComponentInstanceContext'; +import { createAtomComponentState } from '@/ui/utilities/state/jotai/utils/createAtomComponentState'; + +export const selectedObjectMetadataIdForViewFlowState = + createAtomComponentState({ + key: 'side-panel/selected-object-metadata-id-for-view-flow', + defaultValue: null, + componentInstanceContext: SidePanelPageComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/side-panel/states/sidePanelSubPageStackComponentState.ts b/packages/twenty-front/src/modules/side-panel/states/sidePanelSubPageStackComponentState.ts new file mode 100644 index 0000000000..848fb1e54c --- /dev/null +++ b/packages/twenty-front/src/modules/side-panel/states/sidePanelSubPageStackComponentState.ts @@ -0,0 +1,11 @@ +import { SidePanelPageComponentInstanceContext } from '@/side-panel/states/contexts/SidePanelPageComponentInstanceContext'; +import { type SidePanelSubPageEntry } from '@/side-panel/types/SidePanelSubPageEntry'; +import { createAtomComponentState } from '@/ui/utilities/state/jotai/utils/createAtomComponentState'; + +export const sidePanelSubPageStackComponentState = createAtomComponentState< + SidePanelSubPageEntry[] +>({ + key: 'side-panel/sub-page-stack', + defaultValue: [], + componentInstanceContext: SidePanelPageComponentInstanceContext, +}); diff --git a/packages/twenty-front/src/modules/side-panel/types/SidePanelSubPageEntry.ts b/packages/twenty-front/src/modules/side-panel/types/SidePanelSubPageEntry.ts new file mode 100644 index 0000000000..2d28ef997a --- /dev/null +++ b/packages/twenty-front/src/modules/side-panel/types/SidePanelSubPageEntry.ts @@ -0,0 +1,7 @@ +import { type SidePanelSubPages } from '@/side-panel/types/SidePanelSubPages'; + +export type SidePanelSubPageEntry = { + id: string; + subPage: SidePanelSubPages; + title: string; +}; diff --git a/packages/twenty-front/src/modules/side-panel/types/SidePanelSubPages.ts b/packages/twenty-front/src/modules/side-panel/types/SidePanelSubPages.ts new file mode 100644 index 0000000000..3ca22c657b --- /dev/null +++ b/packages/twenty-front/src/modules/side-panel/types/SidePanelSubPages.ts @@ -0,0 +1,11 @@ +export enum SidePanelSubPages { + PageLayoutGraphFilter = 'page-layout-graph-filter', + PageLayoutFieldsLayout = 'page-layout-fields-layout', + NewSidebarItemViewObjectPicker = 'new-sidebar-item-view-object-picker', + NewSidebarItemViewPicker = 'new-sidebar-item-view-picker', + NewSidebarItemViewSystemPicker = 'new-sidebar-item-view-system-picker', + NewSidebarItemObjectPicker = 'new-sidebar-item-object-picker', + NewSidebarItemObjectSystemPicker = 'new-sidebar-item-object-system-picker', + NewSidebarItemRecord = 'new-sidebar-item-record', + EditFolderPicker = 'edit-folder-picker', +} diff --git a/packages/twenty-front/src/modules/side-panel/utils/getSidePanelSubPageTitle.ts b/packages/twenty-front/src/modules/side-panel/utils/getSidePanelSubPageTitle.ts new file mode 100644 index 0000000000..2133f790f7 --- /dev/null +++ b/packages/twenty-front/src/modules/side-panel/utils/getSidePanelSubPageTitle.ts @@ -0,0 +1,30 @@ +import { SidePanelSubPages } from '@/side-panel/types/SidePanelSubPages'; +import { t } from '@lingui/core/macro'; +import { assertUnreachable } from 'twenty-shared/utils'; + +export const getSidePanelSubPageTitle = ( + subPage: SidePanelSubPages, +): string => { + switch (subPage) { + case SidePanelSubPages.PageLayoutGraphFilter: + return t`Filters`; + case SidePanelSubPages.PageLayoutFieldsLayout: + return t`Layout`; + case SidePanelSubPages.NewSidebarItemViewObjectPicker: + return t`Pick an object`; + case SidePanelSubPages.NewSidebarItemViewPicker: + return t`Pick a view`; + case SidePanelSubPages.NewSidebarItemViewSystemPicker: + return t`System objects`; + case SidePanelSubPages.NewSidebarItemObjectPicker: + return t`Pick an object`; + case SidePanelSubPages.NewSidebarItemObjectSystemPicker: + return t`System objects`; + case SidePanelSubPages.NewSidebarItemRecord: + return t`Add a record`; + case SidePanelSubPages.EditFolderPicker: + return t`Move to a folder`; + default: + assertUnreachable(subPage); + } +}; diff --git a/packages/twenty-shared/src/types/SidePanelPages.ts b/packages/twenty-shared/src/types/SidePanelPages.ts index 51aacc3af4..279341903a 100644 --- a/packages/twenty-shared/src/types/SidePanelPages.ts +++ b/packages/twenty-shared/src/types/SidePanelPages.ts @@ -18,11 +18,9 @@ export enum SidePanelPages { ViewPreviousAIChats = 'view-previous-ai-chats', PageLayoutWidgetTypeSelect = 'page-layout-widget-type-select', PageLayoutGraphTypeSelect = 'page-layout-graph-type-select', - PageLayoutGraphFilter = 'page-layout-graph-filter', PageLayoutIframeSettings = 'page-layout-iframe-settings', PageLayoutTabSettings = 'page-layout-tab-settings', PageLayoutFieldsSettings = 'page-layout-fields-settings', - PageLayoutFieldsLayout = 'page-layout-fields-layout', ViewFrontComponent = 'view-front-component', NavigationMenuItemEdit = 'navigation-menu-item-edit', NavigationMenuAddItem = 'navigation-menu-add-item',