Use side panel sub-pages for add-to-folder flow (#18872)

https://github.com/user-attachments/assets/a31b8523-2d0a-4a02-bcd9-5548c906b7cc

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Abdul Rahman
2026-03-25 03:58:40 +05:30
committed by GitHub
parent 01af7bc7fb
commit 4a099ed097
41 changed files with 289 additions and 284 deletions
@@ -10,7 +10,7 @@ import { FOLDER_ICON_DEFAULT } from '@/navigation-menu-item/common/constants/Fol
import { NavigationMenuItemType } from 'twenty-shared/types';
import { useUpdateFolderInDraft } from '@/navigation-menu-item/edit/folder/hooks/useUpdateFolderInDraft';
import { useNavigationMenuItemSectionItems } from '@/navigation-menu-item/display/hooks/useNavigationMenuItemSectionItems';
import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/common/states/selectedNavigationMenuItemInEditModeState';
import { selectedNavigationMenuItemIdInEditModeState } from '@/navigation-menu-item/common/states/selectedNavigationMenuItemIdInEditModeState';
import { IconPicker } from '@/ui/input/components/IconPicker';
import { TitleInput } from '@/ui/input/components/TitleInput';
import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState';
@@ -29,8 +29,8 @@ export const SidePanelFolderInfo = () => {
sidePanelShouldFocusTitleInputComponentState,
sidePanelPageInfo.instanceId,
);
const selectedNavigationMenuItemInEditMode = useAtomStateValue(
selectedNavigationMenuItemInEditModeState,
const selectedNavigationMenuItemIdInEditMode = useAtomStateValue(
selectedNavigationMenuItemIdInEditModeState,
);
const items = useNavigationMenuItemSectionItems();
const { updateFolderInDraft } = useUpdateFolderInDraft();
@@ -38,11 +38,11 @@ export const SidePanelFolderInfo = () => {
const defaultLabel = t`New folder`;
const placeholder = t`Folder name`;
const selectedItem = selectedNavigationMenuItemInEditMode
const selectedItem = selectedNavigationMenuItemIdInEditMode
? items.find(
(item) =>
item.type === NavigationMenuItemType.FOLDER &&
item.id === selectedNavigationMenuItemInEditMode,
item.id === selectedNavigationMenuItemIdInEditMode,
)
: undefined;
@@ -5,7 +5,7 @@ import { LinkIconWithLinkOverlay } from '@/navigation-menu-item/display/link/com
import { NavigationMenuItemType } from 'twenty-shared/types';
import { useUpdateLinkInDraft } from '@/navigation-menu-item/edit/link/hooks/useUpdateLinkInDraft';
import { useNavigationMenuItemSectionItems } from '@/navigation-menu-item/display/hooks/useNavigationMenuItemSectionItems';
import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/common/states/selectedNavigationMenuItemInEditModeState';
import { selectedNavigationMenuItemIdInEditModeState } from '@/navigation-menu-item/common/states/selectedNavigationMenuItemIdInEditModeState';
import { SidePanelPageInfoLayout } from '@/side-panel/components/SidePanelPageInfoLayout';
import { sidePanelPageInfoState } from '@/side-panel/states/sidePanelPageInfoState';
import { sidePanelShouldFocusTitleInputComponentState } from '@/side-panel/states/sidePanelShouldFocusTitleInputComponentState';
@@ -21,8 +21,8 @@ export const SidePanelLinkInfo = () => {
sidePanelShouldFocusTitleInputComponentState,
sidePanelPageInfo.instanceId,
);
const selectedNavigationMenuItemInEditMode = useAtomStateValue(
selectedNavigationMenuItemInEditModeState,
const selectedNavigationMenuItemIdInEditMode = useAtomStateValue(
selectedNavigationMenuItemIdInEditModeState,
);
const items = useNavigationMenuItemSectionItems();
const { updateLinkInDraft } = useUpdateLinkInDraft();
@@ -30,11 +30,11 @@ export const SidePanelLinkInfo = () => {
const defaultLabel = t`Link label`;
const placeholder = t`Link label`;
const selectedItem = selectedNavigationMenuItemInEditMode
const selectedItem = selectedNavigationMenuItemIdInEditMode
? items.find(
(item) =>
item.type === NavigationMenuItemType.LINK &&
item.id === selectedNavigationMenuItemInEditMode,
item.id === selectedNavigationMenuItemIdInEditMode,
)
: undefined;
@@ -7,7 +7,7 @@ import {
import { NavigationMenuItemType, SidePanelPages } from 'twenty-shared/types';
import { useNavigationMenuItemSectionItems } from '@/navigation-menu-item/display/hooks/useNavigationMenuItemSectionItems';
import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/common/states/selectedNavigationMenuItemInEditModeState';
import { selectedNavigationMenuItemIdInEditModeState } from '@/navigation-menu-item/common/states/selectedNavigationMenuItemIdInEditModeState';
import { SidePanelAskAIInfo } from '@/side-panel/components/SidePanelAskAIInfo';
import { SidePanelFolderInfo } from '@/side-panel/components/SidePanelFolderInfo';
import { SidePanelLinkInfo } from '@/side-panel/components/SidePanelLinkInfo';
@@ -34,8 +34,8 @@ type SidePanelPageInfoProps = {
export const SidePanelPageInfo = ({ pageChip }: SidePanelPageInfoProps) => {
const { theme } = useContext(ThemeContext);
const selectedNavigationMenuItemInEditMode = useAtomStateValue(
selectedNavigationMenuItemInEditModeState,
const selectedNavigationMenuItemIdInEditMode = useAtomStateValue(
selectedNavigationMenuItemIdInEditModeState,
);
const items = useNavigationMenuItemSectionItems();
@@ -46,7 +46,7 @@ export const SidePanelPageInfo = ({ pageChip }: SidePanelPageInfoProps) => {
const isNavigationMenuItemEditPage =
pageChip.page?.page === SidePanelPages.NavigationMenuItemEdit;
const selectedNavItem = isNavigationMenuItemEditPage
? items.find((item) => item.id === selectedNavigationMenuItemInEditMode)
? items.find((item) => item.id === selectedNavigationMenuItemIdInEditMode)
: undefined;
if (isNavigationMenuItemEditPage && isDefined(selectedNavItem)) {
@@ -0,0 +1,11 @@
import { SidePanelSubPages } from '@/side-panel/types/SidePanelSubPages';
export const NEW_SIDEBAR_ITEM_FLOW_SIDE_PANEL_SUB_PAGES: SidePanelSubPages[] = [
SidePanelSubPages.NewSidebarItemMainMenu,
SidePanelSubPages.NewSidebarItemViewObjectPicker,
SidePanelSubPages.NewSidebarItemViewPicker,
SidePanelSubPages.NewSidebarItemViewSystemPicker,
SidePanelSubPages.NewSidebarItemObjectPicker,
SidePanelSubPages.NewSidebarItemObjectSystemPicker,
SidePanelSubPages.NewSidebarItemRecord,
];
@@ -1,4 +1,5 @@
import { SidePanelEditFolderPickerSubPage } from '@/navigation-menu-item/edit/side-panel/components/SidePanelEditFolderPickerSubPage';
import { SidePanelNewSidebarItemPage } from '@/navigation-menu-item/edit/side-panel/components/SidePanelNewSidebarItemPage';
import { SidePanelNewSidebarItemObjectSubPage } from '@/navigation-menu-item/edit/side-panel/components/SidePanelNewSidebarItemObjectSubPage';
import { SidePanelNewSidebarItemObjectSystemPickerSubPage } from '@/navigation-menu-item/edit/side-panel/components/SidePanelNewSidebarItemObjectSystemPickerSubPage';
import { SidePanelNewSidebarItemRecordSubPage } from '@/navigation-menu-item/edit/side-panel/components/SidePanelNewSidebarItemRecordSubPage';
@@ -18,6 +19,7 @@ export const SIDE_PANEL_SUB_PAGES_CONFIG = new Map<
>([
[SidePanelSubPages.PageLayoutGraphFilter, <SidePanelChartFilterSubPage />],
[SidePanelSubPages.PageLayoutFieldsLayout, <SidePanelFieldsLayoutSubPage />],
[SidePanelSubPages.NewSidebarItemMainMenu, <SidePanelNewSidebarItemPage />],
[
SidePanelSubPages.PageLayoutRecordTableFilter,
<SidePanelRecordTableFilterSubPage />,
@@ -1,6 +1,6 @@
import { isLayoutCustomizationModeEnabledState } from '@/layout-customization/states/isLayoutCustomizationModeEnabledState';
import { addToNavPayloadRegistryState } from '@/navigation-menu-item/common/states/addToNavPayloadRegistryState';
import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/common/states/selectedNavigationMenuItemInEditModeState';
import { selectedNavigationMenuItemIdInEditModeState } from '@/navigation-menu-item/common/states/selectedNavigationMenuItemIdInEditModeState';
import { SIDE_PANEL_FOCUS_ID } from '@/side-panel/constants/SidePanelFocusId';
import { useNavigateSidePanel } from '@/side-panel/hooks/useNavigateSidePanel';
import { isSidePanelClosingState } from '@/side-panel/states/isSidePanelClosingState';
@@ -45,7 +45,7 @@ export const useSidePanelMenu = () => {
isLayoutCustomizationModeEnabledState.atom,
);
const selectedNavigationItemId = store.get(
selectedNavigationMenuItemInEditModeState.atom,
selectedNavigationMenuItemIdInEditModeState.atom,
);
if (
isLayoutCustomizationModeEnabled &&
@@ -0,0 +1,22 @@
import { isNonEmptyString } from '@sniptt/guards';
import { sidePanelPageInfoState } from '@/side-panel/states/sidePanelPageInfoState';
import { sidePanelSubPageStackComponentState } from '@/side-panel/states/sidePanelSubPageStackComponentState';
import { type SidePanelSubPageEntry } from '@/side-panel/types/SidePanelSubPageEntry';
import { createAtomSelector } from '@/ui/utilities/state/jotai/utils/createAtomSelector';
export const sidePanelSubPageStackForActiveSidePanelPageSelector =
createAtomSelector<SidePanelSubPageEntry[]>({
key: 'sidePanelSubPageStackForActiveSidePanelPage',
get: ({ get }) => {
const pageInfo = get(sidePanelPageInfoState);
if (!isNonEmptyString(pageInfo.instanceId)) {
return [];
}
return get(sidePanelSubPageStackComponentState, {
instanceId: pageInfo.instanceId,
});
},
});
@@ -3,6 +3,7 @@ export enum SidePanelSubPages {
PageLayoutFieldsLayout = 'page-layout-fields-layout',
PageLayoutRecordTableFilter = 'page-layout-record-table-filter',
PageLayoutRecordTableSort = 'page-layout-record-table-sort',
NewSidebarItemMainMenu = 'new-sidebar-item-main-menu',
NewSidebarItemViewObjectPicker = 'new-sidebar-item-view-object-picker',
NewSidebarItemViewPicker = 'new-sidebar-item-view-picker',
NewSidebarItemViewSystemPicker = 'new-sidebar-item-view-system-picker',
@@ -14,6 +14,8 @@ export const getSidePanelSubPageTitle = (
return t`Filters`;
case SidePanelSubPages.PageLayoutRecordTableSort:
return t`Sorts`;
case SidePanelSubPages.NewSidebarItemMainMenu:
return t`Add menu item`;
case SidePanelSubPages.NewSidebarItemViewObjectPicker:
return t`Pick an object`;
case SidePanelSubPages.NewSidebarItemViewPicker: