Navbar drag drop using dnd kit (#18288)

This commit is contained in:
Abdul Rahman
2026-03-09 01:55:50 +05:30
committed by GitHub
parent 66d93c4d28
commit 5b28e59ca7
119 changed files with 3563 additions and 1297 deletions
@@ -0,0 +1,4 @@
export type EditModeProps = {
isSelectedInEditMode: boolean;
onEditModeClick?: () => void;
};
@@ -3,6 +3,7 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/
import { ObjectIconWithViewOverlay } from '@/navigation-menu-item/components/ObjectIconWithViewOverlay';
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
import { useObjectNavItemColor } from '@/navigation-menu-item/hooks/useObjectNavItemColor';
import { isNavigationMenuInEditModeState } from '@/navigation-menu-item/states/isNavigationMenuInEditModeState';
import { getStandardObjectIconColor } from '@/navigation-menu-item/utils/getStandardObjectIconColor';
import { type ProcessedNavigationMenuItem } from '@/navigation-menu-item/utils/sortNavigationMenuItems';
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
@@ -28,7 +29,6 @@ import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
export type NavigationDrawerItemForObjectMetadataItemProps = {
objectMetadataItem: ObjectMetadataItem;
navigationMenuItem?: ProcessedNavigationMenuItem;
isEditMode?: boolean;
isSelectedInEditMode?: boolean;
onEditModeClick?: () => void;
onActiveItemClickWhenNotInEditMode?: () => void;
@@ -38,12 +38,14 @@ export type NavigationDrawerItemForObjectMetadataItemProps = {
export const NavigationDrawerItemForObjectMetadataItem = ({
objectMetadataItem,
navigationMenuItem,
isEditMode = false,
isSelectedInEditMode = false,
onEditModeClick,
onActiveItemClickWhenNotInEditMode,
onActiveItemClickWhenNotInEditMode: _onActiveItemClickWhenNotInEditMode,
isDragging = false,
}: NavigationDrawerItemForObjectMetadataItemProps) => {
const isNavigationMenuInEditMode = useAtomStateValue(
isNavigationMenuInEditModeState,
);
const isNavigationMenuItemEditingEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED,
);
@@ -99,18 +101,9 @@ export const NavigationDrawerItemForObjectMetadataItem = ({
}) + '/',
);
const shouldUseClickHandler = isEditMode
? Boolean(onEditModeClick)
: isActive && Boolean(onActiveItemClickWhenNotInEditMode);
const handleClick = isNavigationMenuInEditMode ? onEditModeClick : undefined;
const handleClick = shouldUseClickHandler
? isEditMode
? onEditModeClick
: onActiveItemClickWhenNotInEditMode
: undefined;
const shouldNavigate =
!isEditMode && !(isActive && onActiveItemClickWhenNotInEditMode);
const shouldNavigate = !isNavigationMenuInEditMode;
const isViewWithCustomName =
isView &&
@@ -218,7 +211,7 @@ export const NavigationDrawerItemForObjectMetadataItem = ({
label={label}
secondaryLabel={secondaryLabel}
to={
isEditMode || isDragging
isNavigationMenuInEditMode || isDragging
? undefined
: shouldNavigate
? navigationPath
@@ -230,7 +223,7 @@ export const NavigationDrawerItemForObjectMetadataItem = ({
active={isActive}
isSelectedInEditMode={isSelectedInEditMode}
isDragging={isDragging}
triggerEvent={isEditMode ? 'CLICK' : undefined}
triggerEvent={isNavigationMenuInEditMode ? 'CLICK' : undefined}
/>
);
};
@@ -3,10 +3,12 @@ import { useParams } from 'react-router-dom';
import { useWorkspaceFavorites } from '@/favorites/hooks/useWorkspaceFavorites';
import { useWorkspaceNavigationMenuItems } from '@/navigation-menu-item/hooks/useWorkspaceNavigationMenuItems';
import { NavigationDrawerSectionForObjectMetadataItems } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems';
import { NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader';
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
import { CoreObjectNameSingular } from 'twenty-shared/types';
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
import { prefetchIsLoadedFamilyState } from '@/prefetch/states/prefetchIsLoadedFamilyState';
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useLingui } from '@lingui/react/macro';
import { FeatureFlagKey } from '~/generated-metadata/graphql';
@@ -24,14 +26,22 @@ export const NavigationDrawerOpenedSection = () => {
const filteredActiveNonSystemObjectMetadataItems =
activeObjectMetadataItems.filter((item) => !item.isRemote);
const loading = useIsPrefetchLoading();
const isPrefetchLoading = useIsPrefetchLoading();
const isNavigationMenuItemEditingEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED,
);
const prefetchIsLoaded = useAtomFamilyStateValue(
prefetchIsLoadedFamilyState,
PrefetchKey.AllNavigationMenuItems,
);
const loading =
isPrefetchLoading ||
(isNavigationMenuItemEditingEnabled && !prefetchIsLoaded);
const { workspaceFavoritesObjectMetadataItems } = useWorkspaceFavorites();
const { workspaceNavigationMenuItemsObjectMetadataItems } =
useWorkspaceNavigationMenuItems();
const isNavigationMenuItemEditingEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED,
);
const {
objectNamePlural: currentObjectNamePlural,
@@ -67,7 +77,7 @@ export const NavigationDrawerOpenedSection = () => {
.includes(objectMetadataItem.id);
if (loading) {
return <NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader />;
return null;
}
return (
@@ -28,7 +28,6 @@ type NavigationDrawerSectionForObjectMetadataItemsProps = {
isRemote: boolean;
objectMetadataItems: ObjectMetadataItem[];
rightIcon?: React.ReactNode;
isEditMode?: boolean;
selectedObjectMetadataItemId?: string | null;
onObjectMetadataItemClick?: (objectMetadataItem: ObjectMetadataItem) => void;
onActiveObjectMetadataItemClick?: (
@@ -41,7 +40,6 @@ export const NavigationDrawerSectionForObjectMetadataItems = ({
isRemote,
objectMetadataItems,
rightIcon,
isEditMode = false,
selectedObjectMetadataItemId = null,
onObjectMetadataItemClick,
onActiveObjectMetadataItemClick,
@@ -119,6 +117,7 @@ export const NavigationDrawerSectionForObjectMetadataItems = ({
label={sectionTitle}
onClick={() => toggleNavigationSection()}
rightIcon={rightIcon}
isOpen={isNavigationSectionOpen}
/>
</NavigationDrawerAnimatedCollapseWrapper>
{isNavigationSectionOpen &&
@@ -127,7 +126,6 @@ export const NavigationDrawerSectionForObjectMetadataItems = ({
<NavigationDrawerItemForObjectMetadataItem
key={`navigation-drawer-item-${objectMetadataItem.id}`}
objectMetadataItem={objectMetadataItem}
isEditMode={isEditMode}
isSelectedInEditMode={
selectedObjectMetadataItemId === objectMetadataItem.id
}
@@ -0,0 +1,64 @@
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
import { NavigationDrawerSectionForWorkspaceItemFolderContent } from '@/object-metadata/components/NavigationDrawerSectionForWorkspaceItemFolderContent';
import { NavigationDrawerSectionForWorkspaceItemLinkContent } from '@/object-metadata/components/NavigationDrawerSectionForWorkspaceItemLinkContent';
import { NavigationDrawerSectionForWorkspaceItemObjectContent } from '@/object-metadata/components/NavigationDrawerSectionForWorkspaceItemObjectContent';
import type { WorkspaceSectionItemContentProps } from '@/object-metadata/components/WorkspaceSectionItemContentProps';
type NavigationDrawerSectionForWorkspaceItemContentProps =
WorkspaceSectionItemContentProps;
export const NavigationDrawerSectionForWorkspaceItemContent = ({
item,
editModeProps,
isDragging,
folderChildrenById,
folderCount,
selectedNavigationMenuItemId,
onNavigationMenuItemClick,
onActiveObjectMetadataItemClick,
readOnly,
}: NavigationDrawerSectionForWorkspaceItemContentProps) => {
switch (item.itemType) {
case NavigationMenuItemType.FOLDER:
return (
<NavigationDrawerSectionForWorkspaceItemFolderContent
item={item}
editModeProps={editModeProps}
isDragging={isDragging}
folderChildrenById={folderChildrenById}
folderCount={folderCount}
selectedNavigationMenuItemId={selectedNavigationMenuItemId}
onNavigationMenuItemClick={onNavigationMenuItemClick}
readOnly={readOnly}
/>
);
case NavigationMenuItemType.LINK:
return (
<NavigationDrawerSectionForWorkspaceItemLinkContent
item={item}
editModeProps={editModeProps}
isDragging={isDragging}
folderChildrenById={folderChildrenById}
folderCount={folderCount}
selectedNavigationMenuItemId={selectedNavigationMenuItemId}
onNavigationMenuItemClick={onNavigationMenuItemClick}
onActiveObjectMetadataItemClick={onActiveObjectMetadataItemClick}
readOnly={readOnly}
/>
);
default:
return (
<NavigationDrawerSectionForWorkspaceItemObjectContent
item={item}
editModeProps={editModeProps}
isDragging={isDragging}
folderChildrenById={folderChildrenById}
folderCount={folderCount}
selectedNavigationMenuItemId={selectedNavigationMenuItemId}
onNavigationMenuItemClick={onNavigationMenuItemClick}
onActiveObjectMetadataItemClick={onActiveObjectMetadataItemClick}
readOnly={readOnly}
/>
);
}
};
@@ -0,0 +1,72 @@
import { lazy, Suspense } from 'react';
import { WorkspaceFolderReadOnly } from '@/object-metadata/components/WorkspaceFolderReadOnly';
import type { WorkspaceSectionItemContentProps } from '@/object-metadata/components/WorkspaceSectionItemContentProps';
const LazyWorkspaceNavigationMenuItemsFolder = lazy(() =>
import(
'@/navigation-menu-item/components/WorkspaceNavigationMenuItemsFolder'
).then((m) => ({ default: m.WorkspaceNavigationMenuItemsFolder })),
);
type NavigationDrawerSectionForWorkspaceItemFolderContentProps =
WorkspaceSectionItemContentProps;
export const NavigationDrawerSectionForWorkspaceItemFolderContent = ({
item,
editModeProps,
isDragging,
folderChildrenById,
folderCount,
selectedNavigationMenuItemId,
onNavigationMenuItemClick,
readOnly = false,
}: NavigationDrawerSectionForWorkspaceItemFolderContentProps) => {
const folderId = item.id;
const folderName = item.name ?? 'Folder';
const folderIconKey = item.Icon;
const folderColor = 'color' in item ? item.color : undefined;
const navigationMenuItems = folderChildrenById.get(item.id) ?? [];
const isGroup = folderCount > 1;
if (readOnly) {
return (
<WorkspaceFolderReadOnly
folderId={folderId}
folderName={folderName}
folderIconKey={folderIconKey}
folderColor={folderColor}
navigationMenuItems={navigationMenuItems}
isGroup={isGroup}
/>
);
}
return (
<Suspense
fallback={
<WorkspaceFolderReadOnly
folderId={folderId}
folderName={folderName}
folderIconKey={folderIconKey}
folderColor={folderColor}
navigationMenuItems={navigationMenuItems}
isGroup={isGroup}
/>
}
>
<LazyWorkspaceNavigationMenuItemsFolder
folderId={folderId}
folderName={folderName}
folderIconKey={folderIconKey}
folderColor={folderColor}
navigationMenuItems={navigationMenuItems}
isGroup={isGroup}
isSelectedInEditMode={editModeProps.isSelectedInEditMode}
onEditModeClick={editModeProps.onEditModeClick}
onNavigationMenuItemClick={onNavigationMenuItemClick}
selectedNavigationMenuItemId={selectedNavigationMenuItemId}
isDragging={isDragging}
/>
</Suspense>
);
};
@@ -0,0 +1,45 @@
import { NavigationMenuItemIcon } from '@/navigation-menu-item/components/NavigationMenuItemIcon';
import { isNavigationMenuInEditModeState } from '@/navigation-menu-item/states/isNavigationMenuInEditModeState';
import type { ProcessedNavigationMenuItem } from '@/navigation-menu-item/utils/sortNavigationMenuItems';
import type { WorkspaceSectionItemContentProps } from '@/object-metadata/components/WorkspaceSectionItemContentProps';
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { IconArrowUpRight } from 'twenty-ui/display';
import { themeCssVariables } from 'twenty-ui/theme-constants';
type NavigationDrawerSectionForWorkspaceItemLinkContentProps =
WorkspaceSectionItemContentProps;
export const NavigationDrawerSectionForWorkspaceItemLinkContent = ({
item,
editModeProps,
isDragging,
}: NavigationDrawerSectionForWorkspaceItemLinkContentProps) => {
const isNavigationMenuInEditMode = useAtomStateValue(
isNavigationMenuInEditModeState,
);
const linkItem = item as ProcessedNavigationMenuItem;
return (
<NavigationDrawerItem
label={linkItem.labelIdentifier}
to={isNavigationMenuInEditMode || isDragging ? undefined : linkItem.link}
onClick={
isNavigationMenuInEditMode ? editModeProps.onEditModeClick : undefined
}
Icon={() => <NavigationMenuItemIcon navigationMenuItem={linkItem} />}
active={false}
isSelectedInEditMode={editModeProps.isSelectedInEditMode}
isDragging={isDragging}
triggerEvent="CLICK"
rightOptions={
!isNavigationMenuInEditMode && (
<IconArrowUpRight
size={themeCssVariables.icon.size.sm}
stroke={themeCssVariables.icon.stroke.md}
color={themeCssVariables.font.color.light}
/>
)
}
/>
);
};
@@ -0,0 +1,44 @@
import { getObjectMetadataForNavigationMenuItem } from '@/navigation-menu-item/utils/getObjectMetadataForNavigationMenuItem';
import type { ProcessedNavigationMenuItem } from '@/navigation-menu-item/utils/sortNavigationMenuItems';
import { NavigationDrawerItemForObjectMetadataItem } from '@/object-metadata/components/NavigationDrawerItemForObjectMetadataItem';
import type { WorkspaceSectionItemContentProps } from '@/object-metadata/components/WorkspaceSectionItemContentProps';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { coreViewsState } from '@/views/states/coreViewState';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
type NavigationDrawerSectionForWorkspaceItemObjectContentProps =
WorkspaceSectionItemContentProps;
export const NavigationDrawerSectionForWorkspaceItemObjectContent = ({
item,
editModeProps,
isDragging,
onActiveObjectMetadataItemClick,
}: NavigationDrawerSectionForWorkspaceItemObjectContentProps) => {
const objectMetadataItems = useAtomStateValue(objectMetadataItemsState);
const coreViews = useAtomStateValue(coreViewsState);
const views = coreViews.map(convertCoreViewToView);
const objectMetadataItem = getObjectMetadataForNavigationMenuItem(
item as ProcessedNavigationMenuItem,
objectMetadataItems,
views,
);
if (!objectMetadataItem) {
return null;
}
return (
<NavigationDrawerItemForObjectMetadataItem
objectMetadataItem={objectMetadataItem}
navigationMenuItem={item as ProcessedNavigationMenuItem}
isSelectedInEditMode={editModeProps.isSelectedInEditMode}
onEditModeClick={editModeProps.onEditModeClick}
isDragging={isDragging}
onActiveItemClickWhenNotInEditMode={
onActiveObjectMetadataItemClick
? () => onActiveObjectMetadataItemClick(objectMetadataItem, item.id)
: undefined
}
/>
);
};
@@ -1,33 +1,25 @@
import { NavigationDropTargetContext } from '@/navigation-menu-item/contexts/NavigationDropTargetContext';
import { styled } from '@linaria/react';
import { Droppable } from '@hello-pangea/dnd';
import { useLingui } from '@lingui/react/macro';
import { useContext } from 'react';
import React, { lazy, Suspense, useContext } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { IconLink, IconPlus } from 'twenty-ui/display';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { AnimatedExpandableContainer } from 'twenty-ui/layout';
import { NavigationItemDropTarget } from '@/navigation-menu-item/components/NavigationItemDropTarget';
import { WorkspaceNavigationMenuItemsFolder } from '@/navigation-menu-item/components/WorkspaceNavigationMenuItemsFolder';
import { NavigationMenuItemDroppableIds } from '@/navigation-menu-item/constants/NavigationMenuItemDroppableIds';
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
import { NavigationSections } from '@/navigation-menu-item/constants/NavigationSections.constants';
import { NavigationMenuItemDragContext } from '@/navigation-menu-item/contexts/NavigationMenuItemDragContext';
import { useIsDropDisabledForSection } from '@/navigation-menu-item/hooks/useIsDropDisabledForSection';
import {
type FlatWorkspaceItem,
type NavigationMenuItemClickParams,
} from '@/navigation-menu-item/hooks/useWorkspaceSectionItems';
import { isNavigationMenuInEditModeState } from '@/navigation-menu-item/states/isNavigationMenuInEditModeState';
import { getObjectMetadataForNavigationMenuItem } from '@/navigation-menu-item/utils/getObjectMetadataForNavigationMenuItem';
import { type ProcessedNavigationMenuItem } from '@/navigation-menu-item/utils/sortNavigationMenuItems';
import { NavigationDrawerItemForObjectMetadataItem } from '@/object-metadata/components/NavigationDrawerItemForObjectMetadataItem';
import type { EditModeProps } from '@/object-metadata/components/EditModeProps';
import { NavigationDrawerSectionForWorkspaceItemsListReadOnly } from '@/object-metadata/components/NavigationDrawerSectionForWorkspaceItemsListReadOnly';
import { WorkspaceSectionListEditModeFallback } from '@/object-metadata/components/WorkspaceSectionListEditModeFallback';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';
import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper';
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle';
import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection';
@@ -35,18 +27,16 @@ import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomState
import { coreViewsState } from '@/views/states/coreViewState';
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
const StyledWorkspaceDroppableList = styled.div`
display: flex;
flex-direction: column;
gap: ${themeCssVariables.betweenSiblingsGap};
`;
const LazyWorkspaceSectionListDndKit = lazy(() =>
import(
'@/object-metadata/components/NavigationDrawerSectionForWorkspaceItemsListDndKit'
).then((m) => ({ default: m.WorkspaceSectionListDndKit })),
);
type NavigationDrawerSectionForWorkspaceItemsProps = {
sectionTitle: string;
items: FlatWorkspaceItem[];
rightIcon?: React.ReactNode;
onAddMenuItem?: () => void;
isEditMode?: boolean;
selectedNavigationMenuItemId?: string | null;
onNavigationMenuItemClick?: (params: NavigationMenuItemClickParams) => void;
onActiveObjectMetadataItemClick?: (
@@ -59,14 +49,13 @@ export const NavigationDrawerSectionForWorkspaceItems = ({
sectionTitle,
items,
rightIcon,
onAddMenuItem,
isEditMode = false,
selectedNavigationMenuItemId = null,
onNavigationMenuItemClick,
onActiveObjectMetadataItemClick,
}: NavigationDrawerSectionForWorkspaceItemsProps) => {
const { t } = useLingui();
const workspaceDropDisabled = useIsDropDisabledForSection(true);
const isNavigationMenuInEditMode = useAtomStateValue(
isNavigationMenuInEditModeState,
);
const { toggleNavigationSection, isNavigationSectionOpen } =
useNavigationSection('Workspace');
const coreViews = useAtomStateValue(coreViewsState);
@@ -74,7 +63,6 @@ export const NavigationDrawerSectionForWorkspaceItems = ({
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const objectMetadataItems = useAtomStateValue(objectMetadataItemsState);
const { isDragging } = useContext(NavigationMenuItemDragContext);
const { addToNavigationFallbackDestination } = useContext(
NavigationDropTargetContext,
);
@@ -95,10 +83,6 @@ export const NavigationDrawerSectionForWorkspaceItems = ({
return acc;
}, new Map());
const folderCount = flatItems.filter(
(item) => item.itemType === NavigationMenuItemType.FOLDER,
).length;
const filteredItems = flatItems.filter((item) => {
const type = item.itemType;
if (
@@ -127,7 +111,7 @@ export const NavigationDrawerSectionForWorkspaceItems = ({
return false;
});
const getEditModeProps = (item: FlatWorkspaceItem) => {
const getEditModeProps = (item: FlatWorkspaceItem): EditModeProps => {
const itemId = item.id;
return {
isSelectedInEditMode: selectedNavigationMenuItemId === itemId,
@@ -151,9 +135,6 @@ export const NavigationDrawerSectionForWorkspaceItems = ({
};
};
const isAddMenuItemButtonVisible =
isEditMode && isDefined(onAddMenuItem) && !isDragging;
if (flatItems.length === 0 && !isAddToNavigationDropTargetVisible) {
return null;
}
@@ -165,193 +146,48 @@ export const NavigationDrawerSectionForWorkspaceItems = ({
label={sectionTitle}
onClick={() => toggleNavigationSection()}
rightIcon={rightIcon}
alwaysShowRightIcon={isEditMode}
alwaysShowRightIcon={isNavigationMenuInEditMode}
isOpen={isNavigationSectionOpen}
/>
</NavigationDrawerAnimatedCollapseWrapper>
{(isNavigationSectionOpen || isAddToNavigationDropTargetVisible) && (
<Droppable
droppableId={
NavigationMenuItemDroppableIds.WORKSPACE_ORPHAN_NAVIGATION_MENU_ITEMS
}
isDropDisabled={workspaceDropDisabled}
>
{(provided) => (
<StyledWorkspaceDroppableList
ref={provided.innerRef}
// oxlint-disable-next-line react/jsx-props-no-spreading
{...provided.droppableProps}
>
{filteredItems.map((item, index) => {
const type = item.itemType;
const editModeProps = getEditModeProps(item);
if (type === 'folder') {
return (
<NavigationItemDropTarget
key={item.id}
folderId={null}
index={index}
sectionId={NavigationSections.WORKSPACE}
>
<DraggableItem
draggableId={item.id}
index={index}
isInsideScrollableContainer
isDragDisabled={!isEditMode}
disableInteractiveElementBlocking={isEditMode}
itemComponent={
<WorkspaceNavigationMenuItemsFolder
folderId={item.id}
folderName={item.name ?? 'Folder'}
folderIconKey={item.Icon}
folderColor={
'color' in item ? item.color : undefined
}
navigationMenuItems={
folderChildrenById.get(item.id) ?? []
}
isGroup={folderCount > 1}
isEditMode={isEditMode}
isSelectedInEditMode={
editModeProps.isSelectedInEditMode
}
onEditModeClick={editModeProps.onEditModeClick}
onNavigationMenuItemClick={
onNavigationMenuItemClick
}
selectedNavigationMenuItemId={
selectedNavigationMenuItemId
}
isDragging={isDragging}
/>
}
/>
</NavigationItemDropTarget>
);
<AnimatedExpandableContainer
isExpanded={
isNavigationSectionOpen || isAddToNavigationDropTargetVisible
}
dimension="height"
mode="fit-content"
containAnimation
initial={false}
>
{isNavigationMenuInEditMode ? (
<Suspense
fallback={
<WorkspaceSectionListEditModeFallback
filteredItems={filteredItems}
folderChildrenById={folderChildrenById}
onActiveObjectMetadataItemClick={
onActiveObjectMetadataItemClick
}
if (type === 'link') {
const linkItem = item as ProcessedNavigationMenuItem;
return (
<NavigationItemDropTarget
key={item.id}
folderId={null}
index={index}
sectionId={NavigationSections.WORKSPACE}
>
<DraggableItem
draggableId={item.id}
index={index}
isInsideScrollableContainer
isDragDisabled={!isEditMode}
disableInteractiveElementBlocking={isEditMode}
itemComponent={
<NavigationDrawerItem
label={linkItem.labelIdentifier}
to={
isEditMode || isDragging
? undefined
: linkItem.link
}
onClick={
isEditMode
? editModeProps.onEditModeClick
: undefined
}
Icon={IconLink}
iconColor={linkItem.color}
active={false}
isSelectedInEditMode={
editModeProps.isSelectedInEditMode
}
isDragging={isDragging}
triggerEvent="CLICK"
/>
}
/>
</NavigationItemDropTarget>
);
}
const objectMetadataItem =
getObjectMetadataForNavigationMenuItem(
item as ProcessedNavigationMenuItem,
objectMetadataItems,
views,
);
if (!objectMetadataItem) return null;
return (
<NavigationItemDropTarget
key={item.id}
folderId={null}
index={index}
sectionId={NavigationSections.WORKSPACE}
>
<DraggableItem
draggableId={item.id}
index={index}
isInsideScrollableContainer
isDragDisabled={!isEditMode}
disableInteractiveElementBlocking={isEditMode}
itemComponent={
<NavigationDrawerItemForObjectMetadataItem
objectMetadataItem={objectMetadataItem}
navigationMenuItem={
item as ProcessedNavigationMenuItem
}
isEditMode={isEditMode}
isSelectedInEditMode={
editModeProps.isSelectedInEditMode
}
onEditModeClick={editModeProps.onEditModeClick}
isDragging={isDragging}
onActiveItemClickWhenNotInEditMode={
onActiveObjectMetadataItemClick
? () =>
onActiveObjectMetadataItemClick(
objectMetadataItem,
item.id,
)
: undefined
}
/>
}
/>
</NavigationItemDropTarget>
);
})}
<NavigationItemDropTarget
folderId={null}
index={filteredItems.length}
sectionId={NavigationSections.WORKSPACE}
compact={!isAddMenuItemButtonVisible}
>
{isAddMenuItemButtonVisible && (
<NavigationDrawerItem
Icon={IconPlus}
label={t`Add menu item`}
onClick={onAddMenuItem}
triggerEvent="CLICK"
/>
)}
</NavigationItemDropTarget>
{addToNavigationFallbackDestination?.droppableId ===
NavigationMenuItemDroppableIds.WORKSPACE_ORPHAN_NAVIGATION_MENU_ITEMS &&
addToNavigationFallbackDestination.index >
filteredItems.length && (
<NavigationItemDropTarget
folderId={null}
index={addToNavigationFallbackDestination.index}
sectionId={NavigationSections.WORKSPACE}
compact
/>
)}
{provided.placeholder}
</StyledWorkspaceDroppableList>
)}
</Droppable>
)}
/>
}
>
<LazyWorkspaceSectionListDndKit
filteredItems={filteredItems}
getEditModeProps={getEditModeProps}
folderChildrenById={folderChildrenById}
selectedNavigationMenuItemId={selectedNavigationMenuItemId}
onNavigationMenuItemClick={onNavigationMenuItemClick}
onActiveObjectMetadataItemClick={onActiveObjectMetadataItemClick}
/>
</Suspense>
) : (
<NavigationDrawerSectionForWorkspaceItemsListReadOnly
filteredItems={filteredItems}
folderChildrenById={folderChildrenById}
onActiveObjectMetadataItemClick={onActiveObjectMetadataItemClick}
/>
)}
</AnimatedExpandableContainer>
</NavigationDrawerSection>
);
};
@@ -0,0 +1,109 @@
import { WorkspaceDndKitDroppableSlot } from '@/navigation-menu-item/components/WorkspaceDndKitDroppableSlot';
import { WorkspaceDndKitSortableItem } from '@/navigation-menu-item/components/WorkspaceDndKitSortableItem';
import { NavigationMenuItemDroppableIds } from '@/navigation-menu-item/constants/NavigationMenuItemDroppableIds';
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
import { NavigationDropTargetContext } from '@/navigation-menu-item/contexts/NavigationDropTargetContext';
import { NavigationMenuItemDragContext } from '@/navigation-menu-item/contexts/NavigationMenuItemDragContext';
import { useIsDropDisabledForSection } from '@/navigation-menu-item/hooks/useIsDropDisabledForSection';
import { isNavigationMenuInEditModeState } from '@/navigation-menu-item/states/isNavigationMenuInEditModeState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { styled } from '@linaria/react';
import { useContext } from 'react';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { NavigationDrawerSectionForWorkspaceItemContent } from '@/object-metadata/components/NavigationDrawerSectionForWorkspaceItemContent';
import { WorkspaceOrphanDropTarget } from '@/object-metadata/components/WorkspaceOrphanDropTarget';
import { WorkspaceSectionAddMenuItemButton } from '@/object-metadata/components/WorkspaceSectionAddMenuItemButton';
import type { WorkspaceSectionListDndKitProps } from '@/object-metadata/components/WorkspaceSectionListDndKitProps';
const StyledList = styled.div`
display: flex;
flex-direction: column;
gap: ${themeCssVariables.betweenSiblingsGap};
`;
const StyledListItemRow = styled.div`
display: flex;
flex-direction: column;
gap: 0;
`;
export const WorkspaceSectionListDndKit = ({
filteredItems,
getEditModeProps,
folderChildrenById,
selectedNavigationMenuItemId,
onNavigationMenuItemClick,
onActiveObjectMetadataItemClick,
}: WorkspaceSectionListDndKitProps) => {
const isNavigationMenuInEditMode = useAtomStateValue(
isNavigationMenuInEditModeState,
);
const workspaceDropDisabled = useIsDropDisabledForSection(true);
const { isDragging } = useContext(NavigationMenuItemDragContext);
const { addToNavigationFallbackDestination } = useContext(
NavigationDropTargetContext,
);
const folderCount = filteredItems.filter(
(item) => item.itemType === NavigationMenuItemType.FOLDER,
).length;
const isAddMenuItemButtonVisible = isNavigationMenuInEditMode;
return (
<StyledList>
{filteredItems.map((item, index) => (
<StyledListItemRow key={item.id}>
<WorkspaceOrphanDropTarget index={index} compact />
<WorkspaceDndKitSortableItem
id={item.id}
index={index}
group={
NavigationMenuItemDroppableIds.WORKSPACE_ORPHAN_NAVIGATION_MENU_ITEMS
}
disabled={!isNavigationMenuInEditMode || workspaceDropDisabled}
>
<NavigationDrawerSectionForWorkspaceItemContent
item={item}
editModeProps={getEditModeProps(item)}
isDragging={isDragging}
folderChildrenById={folderChildrenById}
folderCount={folderCount}
selectedNavigationMenuItemId={selectedNavigationMenuItemId}
onNavigationMenuItemClick={onNavigationMenuItemClick}
onActiveObjectMetadataItemClick={onActiveObjectMetadataItemClick}
/>
</WorkspaceDndKitSortableItem>
</StyledListItemRow>
))}
<WorkspaceDndKitDroppableSlot
droppableId={
NavigationMenuItemDroppableIds.WORKSPACE_ORPHAN_NAVIGATION_MENU_ITEMS
}
index={filteredItems.length}
disabled={workspaceDropDisabled}
>
<WorkspaceOrphanDropTarget
index={filteredItems.length}
compact={!isAddMenuItemButtonVisible}
>
{isAddMenuItemButtonVisible && <WorkspaceSectionAddMenuItemButton />}
</WorkspaceOrphanDropTarget>
</WorkspaceDndKitDroppableSlot>
{addToNavigationFallbackDestination?.droppableId ===
NavigationMenuItemDroppableIds.WORKSPACE_ORPHAN_NAVIGATION_MENU_ITEMS &&
addToNavigationFallbackDestination.index > filteredItems.length && (
<WorkspaceDndKitDroppableSlot
droppableId={
NavigationMenuItemDroppableIds.WORKSPACE_ORPHAN_NAVIGATION_MENU_ITEMS
}
index={addToNavigationFallbackDestination.index}
disabled={workspaceDropDisabled}
>
<WorkspaceOrphanDropTarget
index={addToNavigationFallbackDestination.index}
compact
/>
</WorkspaceDndKitDroppableSlot>
)}
</StyledList>
);
};
@@ -0,0 +1,51 @@
import { styled } from '@linaria/react';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
import type { FlatWorkspaceItem } from '@/navigation-menu-item/hooks/useWorkspaceSectionItems';
import type { WorkspaceSectionListDndKitProps } from '@/object-metadata/components/WorkspaceSectionListDndKitProps';
import { NavigationDrawerSectionForWorkspaceItemContent } from '@/object-metadata/components/NavigationDrawerSectionForWorkspaceItemContent';
const StyledList = styled.div`
display: flex;
flex-direction: column;
gap: ${themeCssVariables.betweenSiblingsGap};
`;
type NavigationDrawerSectionForWorkspaceItemsListReadOnlyProps = Pick<
WorkspaceSectionListDndKitProps,
'filteredItems' | 'folderChildrenById' | 'onActiveObjectMetadataItemClick'
>;
const READ_ONLY_EDIT_MODE_PROPS = {
isSelectedInEditMode: false,
onEditModeClick: undefined,
} as const;
export const NavigationDrawerSectionForWorkspaceItemsListReadOnly = ({
filteredItems,
folderChildrenById,
onActiveObjectMetadataItemClick,
}: NavigationDrawerSectionForWorkspaceItemsListReadOnlyProps) => {
const folderCount = filteredItems.filter(
(item) => item.itemType === NavigationMenuItemType.FOLDER,
).length;
return (
<StyledList>
{filteredItems.map((item: FlatWorkspaceItem) => (
<NavigationDrawerSectionForWorkspaceItemContent
key={item.id}
item={item}
editModeProps={READ_ONLY_EDIT_MODE_PROPS}
isDragging={false}
folderChildrenById={folderChildrenById}
folderCount={folderCount}
selectedNavigationMenuItemId={null}
onActiveObjectMetadataItemClick={onActiveObjectMetadataItemClick}
readOnly
/>
))}
</StyledList>
);
};
@@ -0,0 +1,53 @@
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
import { styled } from '@linaria/react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledTitleSkeleton = styled.div`
align-items: center;
display: flex;
height: ${themeCssVariables.spacing[5]};
padding-left: ${themeCssVariables.spacing[1]};
padding-right: ${themeCssVariables.spacing['0.5']};
`;
const StyledRowsContainer = styled.div`
display: flex;
flex-direction: column;
gap: ${themeCssVariables.spacing[1]};
padding-left: ${themeCssVariables.spacing[1]};
`;
export const NavigationDrawerWorkspaceSectionSkeletonLoader = () => {
return (
<NavigationDrawerSection>
<SkeletonTheme
baseColor={themeCssVariables.background.tertiary}
highlightColor={themeCssVariables.background.transparent.light}
borderRadius={4}
>
<StyledTitleSkeleton>
<Skeleton
width={72}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.xs}
/>
</StyledTitleSkeleton>
<StyledRowsContainer>
<Skeleton
width={196}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
/>
<Skeleton
width={196}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
/>
<Skeleton
width={196}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
/>
</StyledRowsContainer>
</SkeletonTheme>
</NavigationDrawerSection>
);
};
@@ -0,0 +1,120 @@
import { styled } from '@linaria/react';
import { IconChevronDown, IconChevronRight, useIcons } from 'twenty-ui/display';
import { AnimatedExpandableContainer } from 'twenty-ui/layout';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { useIsMobile } from 'twenty-ui/utilities';
import { useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { WorkspaceNavigationMenuItemFolderSubItem } from '@/navigation-menu-item/components/WorkspaceNavigationMenuItemFolderSubItem';
import { FOLDER_ICON_DEFAULT } from '@/navigation-menu-item/constants/FolderIconDefault';
import { DEFAULT_NAVIGATION_MENU_ITEM_COLOR_FOLDER } from '@/navigation-menu-item/constants/NavigationMenuItemDefaultColorFolder';
import { useWorkspaceFolderOpenState } from '@/navigation-menu-item/hooks/useWorkspaceFolderOpenState';
import type { ProcessedNavigationMenuItem } from '@/navigation-menu-item/utils/sortNavigationMenuItems';
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
import { NavigationDrawerItemsCollapsableContainer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsableContainer';
const StyledFolderContainer = styled.div`
border: 1px solid transparent;
border-radius: ${themeCssVariables.border.radius.sm};
`;
const StyledFolderContent = styled.div`
display: flex;
flex-direction: column;
`;
const StyledFolderExpandableWrapper = styled.div`
& > div {
overflow: visible !important;
}
`;
type WorkspaceFolderReadOnlyProps = {
folderId: string;
folderName: string;
folderIconKey?: string | null;
folderColor?: string | null;
navigationMenuItems: ProcessedNavigationMenuItem[];
isGroup: boolean;
};
export const WorkspaceFolderReadOnly = ({
folderId,
folderName,
folderIconKey,
folderColor,
navigationMenuItems,
isGroup,
}: WorkspaceFolderReadOnlyProps) => {
const { getIcon } = useIcons();
const FolderIcon = getIcon(folderIconKey ?? FOLDER_ICON_DEFAULT);
const isMobile = useIsMobile();
const { isOpen, handleToggle, selectedNavigationMenuItemIndex } =
useWorkspaceFolderOpenState({ folderId, navigationMenuItems });
const [skipInitialExpandAnimation] = useState(() => isOpen);
return (
<StyledFolderContainer>
<NavigationDrawerItemsCollapsableContainer isGroup={isGroup}>
<NavigationDrawerItem
label={folderName}
Icon={FolderIcon}
iconColor={
isDefined(folderColor)
? folderColor
: DEFAULT_NAVIGATION_MENU_ITEM_COLOR_FOLDER
}
active={!isOpen && selectedNavigationMenuItemIndex >= 0}
onClick={handleToggle}
className="navigation-drawer-item"
triggerEvent="CLICK"
preventCollapseOnMobile={isMobile}
alwaysShowRightOptions
rightOptions={
isOpen ? (
<IconChevronDown
size={themeCssVariables.icon.size.sm}
stroke={themeCssVariables.icon.stroke.sm}
color={themeCssVariables.font.color.tertiary}
/>
) : (
<IconChevronRight
size={themeCssVariables.icon.size.sm}
stroke={themeCssVariables.icon.stroke.sm}
color={themeCssVariables.font.color.tertiary}
/>
)
}
/>
<StyledFolderExpandableWrapper>
<AnimatedExpandableContainer
isExpanded={isOpen}
dimension="height"
mode="fit-content"
containAnimation
initial={!skipInitialExpandAnimation}
>
<StyledFolderContent>
{navigationMenuItems.map((navigationMenuItem, index) => (
<WorkspaceNavigationMenuItemFolderSubItem
key={navigationMenuItem.id}
navigationMenuItem={navigationMenuItem}
index={index}
arrayLength={navigationMenuItems.length}
selectedNavigationMenuItemIndex={
selectedNavigationMenuItemIndex
}
onNavigationMenuItemClick={undefined}
selectedNavigationMenuItemId={null}
isContextDragging={false}
/>
))}
</StyledFolderContent>
</AnimatedExpandableContainer>
</StyledFolderExpandableWrapper>
</NavigationDrawerItemsCollapsableContainer>
</StyledFolderContainer>
);
};
@@ -0,0 +1,31 @@
import type { ReactNode } from 'react';
import { NavigationItemDropTarget } from '@/navigation-menu-item/components/NavigationItemDropTarget';
import { NavigationSections } from '@/navigation-menu-item/constants/NavigationSections.constants';
import { NavigationMenuItemDroppableIds } from '@/navigation-menu-item/constants/NavigationMenuItemDroppableIds';
import { getDndKitDropTargetId } from '@/navigation-menu-item/utils/getDndKitDropTargetId';
type WorkspaceOrphanDropTargetProps = {
index: number;
compact?: boolean;
children?: ReactNode;
};
export const WorkspaceOrphanDropTarget = ({
index,
compact = false,
children,
}: WorkspaceOrphanDropTargetProps) => (
<NavigationItemDropTarget
folderId={null}
index={index}
sectionId={NavigationSections.WORKSPACE}
compact={compact}
dropTargetIdOverride={getDndKitDropTargetId(
NavigationMenuItemDroppableIds.WORKSPACE_ORPHAN_NAVIGATION_MENU_ITEMS,
index,
)}
>
{children}
</NavigationItemDropTarget>
);
@@ -0,0 +1,55 @@
import { useLingui } from '@lingui/react/macro';
import React from 'react';
import { SidePanelPages } from 'twenty-shared/types';
import { IconColumnInsertRight, IconPlus } from 'twenty-ui/display';
import { addMenuItemInsertionContextState } from '@/navigation-menu-item/states/addMenuItemInsertionContextState';
import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/states/selectedNavigationMenuItemInEditModeState';
import { useNavigateSidePanel } from '@/side-panel/hooks/useNavigateSidePanel';
import { sidePanelPageState } from '@/side-panel/states/sidePanelPageState';
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
export const WorkspaceSectionAddMenuItemButton = () => {
const { t } = useLingui();
const { navigateSidePanel } = useNavigateSidePanel();
const sidePanelPage = useAtomStateValue(sidePanelPageState);
const addMenuItemInsertionContext = useAtomStateValue(
addMenuItemInsertionContextState,
);
const setAddMenuItemInsertionContext = useSetAtomState(
addMenuItemInsertionContextState,
);
const setSelectedNavigationMenuItemInEditMode = useSetAtomState(
selectedNavigationMenuItemInEditModeState,
);
const handleClick = (event?: React.MouseEvent) => {
event?.stopPropagation();
setAddMenuItemInsertionContext(null);
setSelectedNavigationMenuItemInEditMode(null);
navigateSidePanel({
page: SidePanelPages.NavigationMenuAddItem,
pageTitle: t`New sidebar item`,
pageIcon: IconColumnInsertRight,
resetNavigationStack: true,
});
};
const isSelected =
sidePanelPage === SidePanelPages.NavigationMenuAddItem &&
addMenuItemInsertionContext === null;
return (
<NavigationDrawerItem
Icon={IconPlus}
label={t`Add menu item`}
onClick={handleClick}
triggerEvent="CLICK"
variant="tertiary"
isSelectedInEditMode={isSelected}
/>
);
};
@@ -0,0 +1,23 @@
import type {
FlatWorkspaceItem,
NavigationMenuItemClickParams,
} from '@/navigation-menu-item/hooks/useWorkspaceSectionItems';
import type { ProcessedNavigationMenuItem } from '@/navigation-menu-item/utils/sortNavigationMenuItems';
import type { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import type { EditModeProps } from '@/object-metadata/components/EditModeProps';
export type WorkspaceSectionItemContentProps = {
item: FlatWorkspaceItem;
editModeProps: EditModeProps;
isDragging: boolean;
folderChildrenById: Map<string, ProcessedNavigationMenuItem[]>;
folderCount: number;
selectedNavigationMenuItemId: string | null;
onNavigationMenuItemClick?: (params: NavigationMenuItemClickParams) => void;
onActiveObjectMetadataItemClick?: (
objectMetadataItem: ObjectMetadataItem,
navigationMenuItemId: string,
) => void;
readOnly?: boolean;
};
@@ -0,0 +1,20 @@
import type {
FlatWorkspaceItem,
NavigationMenuItemClickParams,
} from '@/navigation-menu-item/hooks/useWorkspaceSectionItems';
import type { ProcessedNavigationMenuItem } from '@/navigation-menu-item/utils/sortNavigationMenuItems';
import type { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import type { EditModeProps } from '@/object-metadata/components/EditModeProps';
export type WorkspaceSectionListDndKitProps = {
filteredItems: FlatWorkspaceItem[];
getEditModeProps: (item: FlatWorkspaceItem) => EditModeProps;
folderChildrenById: Map<string, ProcessedNavigationMenuItem[]>;
selectedNavigationMenuItemId: string | null;
onNavigationMenuItemClick?: (params: NavigationMenuItemClickParams) => void;
onActiveObjectMetadataItemClick?: (
objectMetadataItem: ObjectMetadataItem,
navigationMenuItemId: string,
) => void;
};
@@ -0,0 +1,32 @@
import { styled } from '@linaria/react';
import { NavigationDrawerSectionForWorkspaceItemsListReadOnly } from '@/object-metadata/components/NavigationDrawerSectionForWorkspaceItemsListReadOnly';
import { WorkspaceSectionAddMenuItemButton } from '@/object-metadata/components/WorkspaceSectionAddMenuItemButton';
import type { WorkspaceSectionListDndKitProps } from '@/object-metadata/components/WorkspaceSectionListDndKitProps';
import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledFallback = styled.div`
display: flex;
flex-direction: column;
gap: ${themeCssVariables.spacing[1]};
`;
type WorkspaceSectionListEditModeFallbackProps = Pick<
WorkspaceSectionListDndKitProps,
'filteredItems' | 'folderChildrenById' | 'onActiveObjectMetadataItemClick'
>;
export const WorkspaceSectionListEditModeFallback = ({
filteredItems,
folderChildrenById,
onActiveObjectMetadataItemClick,
}: WorkspaceSectionListEditModeFallbackProps) => (
<StyledFallback>
<NavigationDrawerSectionForWorkspaceItemsListReadOnly
filteredItems={filteredItems}
folderChildrenById={folderChildrenById}
onActiveObjectMetadataItemClick={onActiveObjectMetadataItemClick}
/>
<WorkspaceSectionAddMenuItemButton />
</StyledFallback>
);