271 remove is command menu v2 enabled (#10809)

Closes https://github.com/twentyhq/core-team-issues/issues/271

This PR
- Removes the feature flag IS_COMMAND_MENU_V2_ENABLED
- Removes all old Right drawer components
- Removes the Action menu bar
- Removes unused Copilot page
This commit is contained in:
Raphaël Bosi
2025-03-12 16:26:29 +01:00
committed by GitHub
parent 1b0413bf8b
commit daa501549e
124 changed files with 281 additions and 4222 deletions

View File

@ -1,94 +0,0 @@
import { isRightDrawerAnimationCompletedState } from '@/ui/layout/right-drawer/states/isRightDrawerAnimationCompletedState';
import { isRightDrawerMinimizedState } from '@/ui/layout/right-drawer/states/isRightDrawerMinimizedState';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared';
import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState';
import { rightDrawerPageState } from '../states/rightDrawerPageState';
import { RIGHT_DRAWER_ANIMATION_VARIANTS } from '@/ui/layout/right-drawer/constants/RightDrawerAnimationVariants';
import { RightDrawerAnimationVariant } from '@/ui/layout/right-drawer/types/RightDrawerAnimationVariant';
import { RightDrawerRouter } from './RightDrawerRouter';
const StyledContainer = styled(motion.div)<{ isRightDrawerMinimized: boolean }>`
background: ${({ theme }) => theme.background.primary};
border-left: ${({ theme, isRightDrawerMinimized }) =>
isRightDrawerMinimized
? `1px solid ${theme.border.color.strong}`
: `1px solid ${theme.border.color.medium}`};
border-top: ${({ theme, isRightDrawerMinimized }) =>
isRightDrawerMinimized ? `1px solid ${theme.border.color.strong}` : 'none'};
border-top-left-radius: ${({ theme, isRightDrawerMinimized }) =>
isRightDrawerMinimized ? theme.border.radius.md : '0'};
box-shadow: ${({ theme, isRightDrawerMinimized }) =>
isRightDrawerMinimized ? 'none' : theme.boxShadow.light};
height: 100dvh;
overflow-x: hidden;
position: fixed;
right: 0;
top: 0;
z-index: 30;
.modal-backdrop {
background: ${({ theme }) => theme.background.overlayTertiary};
}
`;
const StyledRightDrawer = styled.div`
display: flex;
flex-direction: row;
width: 100%;
`;
export const RightDrawer = () => {
const theme = useTheme();
const isRightDrawerOpen = useRecoilValue(isRightDrawerOpenState);
const isRightDrawerMinimized = useRecoilValue(isRightDrawerMinimizedState);
const setIsRightDrawerAnimationCompleted = useSetRecoilState(
isRightDrawerAnimationCompletedState,
);
const rightDrawerPage = useRecoilValue(rightDrawerPageState);
const isMobile = useIsMobile();
const targetVariantForAnimation: RightDrawerAnimationVariant =
!isRightDrawerOpen
? 'closed'
: isRightDrawerMinimized
? 'minimized'
: isMobile
? 'fullScreen'
: 'normal';
const handleAnimationComplete = () => {
setIsRightDrawerAnimationCompleted(isRightDrawerOpen);
};
if (!isDefined(rightDrawerPage)) {
return <></>;
}
return (
<StyledContainer
isRightDrawerMinimized={isRightDrawerMinimized}
animate={targetVariantForAnimation}
variants={RIGHT_DRAWER_ANIMATION_VARIANTS}
transition={{ duration: theme.animation.duration.normal }}
onAnimationComplete={handleAnimationComplete}
>
<StyledRightDrawer>
{isRightDrawerOpen && <RightDrawerRouter />}
</StyledRightDrawer>
</StyledContainer>
);
};

View File

@ -1,84 +0,0 @@
import { RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID } from '@/ui/layout/right-drawer/constants/RightDrawerClickOutsideListener';
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
import { isRightDrawerMinimizedState } from '@/ui/layout/right-drawer/states/isRightDrawerMinimizedState';
import { isRightDrawerOpenState } from '@/ui/layout/right-drawer/states/isRightDrawerOpenState';
import { rightDrawerCloseEventState } from '@/ui/layout/right-drawer/states/rightDrawerCloseEventsState';
import { RightDrawerHotkeyScope } from '@/ui/layout/right-drawer/types/RightDrawerHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import {
ClickOutsideMode,
useListenClickOutside,
} from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { workflowReactFlowRefState } from '@/workflow/workflow-diagram/states/workflowReactFlowRefState';
import styled from '@emotion/styled';
import { useRef } from 'react';
import { useRecoilCallback, useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
const StyledRightDrawerPage = styled.div`
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
`;
export const RightDrawerContainer = ({
children,
}: {
children: React.ReactNode;
}) => {
const rightDrawerRef = useRef<HTMLDivElement>(null);
const isRightDrawerOpen = useRecoilValue(isRightDrawerOpenState);
const isRightDrawerMinimized = useRecoilValue(isRightDrawerMinimizedState);
const { closeRightDrawer } = useRightDrawer();
const workflowReactFlowRef = useRecoilValue(workflowReactFlowRefState);
useListenClickOutside({
refs: [
rightDrawerRef,
...(workflowReactFlowRef ? [workflowReactFlowRef] : []),
],
excludeClassNames: ['confirmation-modal'],
listenerId: RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID,
callback: useRecoilCallback(
({ snapshot, set }) =>
(event) => {
const isRightDrawerOpen = snapshot
.getLoadable(isRightDrawerOpenState)
.getValue();
const isRightDrawerMinimized = snapshot
.getLoadable(isRightDrawerMinimizedState)
.getValue();
if (isRightDrawerOpen && !isRightDrawerMinimized) {
set(rightDrawerCloseEventState, event);
closeRightDrawer();
}
},
[closeRightDrawer],
),
mode: ClickOutsideMode.comparePixels,
});
useScopedHotkeys(
[Key.Escape],
() => {
if (isRightDrawerOpen && !isRightDrawerMinimized) {
closeRightDrawer();
}
},
RightDrawerHotkeyScope.RightDrawer,
[isRightDrawerOpen, isRightDrawerMinimized],
);
return (
<StyledRightDrawerPage ref={rightDrawerRef}>
{children}
</StyledRightDrawerPage>
);
};

View File

@ -1,68 +0,0 @@
import styled from '@emotion/styled';
import { useRecoilState, useRecoilValue } from 'recoil';
import { RightDrawerCalendarEvent } from '@/activities/calendar/right-drawer/components/RightDrawerCalendarEvent';
import { RightDrawerAIChat } from '@/activities/copilot/right-drawer/components/RightDrawerAIChat';
import { RightDrawerEmailThread } from '@/activities/emails/right-drawer/components/RightDrawerEmailThread';
import { RightDrawerRecord } from '@/object-record/record-right-drawer/components/RightDrawerRecord';
import { isRightDrawerMinimizedState } from '@/ui/layout/right-drawer/states/isRightDrawerMinimizedState';
import { RightDrawerContainer } from '@/ui/layout/right-drawer/components/RightDrawerContainer';
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
import { RightDrawerWorkflowEditStep } from '@/workflow/workflow-steps/components/RightDrawerWorkflowEditStep';
import { RightDrawerWorkflowRunViewStep } from '@/workflow/workflow-steps/components/RightDrawerWorkflowRunViewStep';
import { RightDrawerWorkflowViewStep } from '@/workflow/workflow-steps/components/RightDrawerWorkflowViewStep';
import { RightDrawerWorkflowSelectAction } from '@/workflow/workflow-steps/workflow-actions/components/RightDrawerWorkflowSelectAction';
import { RightDrawerWorkflowSelectTriggerType } from '@/workflow/workflow-trigger/components/RightDrawerWorkflowSelectTriggerType';
import { isDefined } from 'twenty-shared';
import { rightDrawerPageState } from '../states/rightDrawerPageState';
import { RightDrawerPages } from '../types/RightDrawerPages';
const StyledRightDrawerBody = styled.div`
display: flex;
flex-direction: column;
height: calc(
100vh - ${({ theme }) => theme.spacing(14)} - 1px
); // (-1 for border)
//overflow: auto;
position: relative;
`;
const RIGHT_DRAWER_PAGES_CONFIG = {
[RightDrawerPages.ViewEmailThread]: <RightDrawerEmailThread />,
[RightDrawerPages.ViewCalendarEvent]: <RightDrawerCalendarEvent />,
[RightDrawerPages.ViewRecord]: <RightDrawerRecord />,
[RightDrawerPages.Copilot]: <RightDrawerAIChat />,
[RightDrawerPages.WorkflowStepSelectTriggerType]: (
<RightDrawerWorkflowSelectTriggerType />
),
[RightDrawerPages.WorkflowStepSelectAction]: (
<RightDrawerWorkflowSelectAction />
),
[RightDrawerPages.WorkflowStepEdit]: <RightDrawerWorkflowEditStep />,
[RightDrawerPages.WorkflowStepView]: <RightDrawerWorkflowViewStep />,
[RightDrawerPages.WorkflowRunStepView]: <RightDrawerWorkflowRunViewStep />,
} satisfies Record<RightDrawerPages, JSX.Element>;
export const RightDrawerRouter = () => {
const [rightDrawerPage] = useRecoilState(rightDrawerPageState);
const rightDrawerPageComponent = isDefined(rightDrawerPage) ? (
RIGHT_DRAWER_PAGES_CONFIG[rightDrawerPage]
) : (
<></>
);
const isRightDrawerMinimized = useRecoilValue(isRightDrawerMinimizedState);
return (
<RightDrawerContainer>
<RightDrawerTopBar />
{!isRightDrawerMinimized && (
<StyledRightDrawerBody>
{rightDrawerPageComponent}
</StyledRightDrawerBody>
)}
</RightDrawerContainer>
);
};

View File

@ -1,140 +0,0 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useRecoilState, useRecoilValue } from 'recoil';
import { Chip, ChipAccent, ChipSize, useIcons } from 'twenty-ui';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
import { RightDrawerTopBarCloseButton } from '@/ui/layout/right-drawer/components/RightDrawerTopBarCloseButton';
import { RightDrawerTopBarExpandButton } from '@/ui/layout/right-drawer/components/RightDrawerTopBarExpandButton';
import { RightDrawerTopBarMinimizeButton } from '@/ui/layout/right-drawer/components/RightDrawerTopBarMinimizeButton';
import { StyledRightDrawerTopBar } from '@/ui/layout/right-drawer/components/StyledRightDrawerTopBar';
import { RIGHT_DRAWER_PAGE_ICONS } from '@/ui/layout/right-drawer/constants/RightDrawerPageIcons';
import { RIGHT_DRAWER_PAGE_TITLES } from '@/ui/layout/right-drawer/constants/RightDrawerPageTitles';
import { isRightDrawerMinimizedState } from '@/ui/layout/right-drawer/states/isRightDrawerMinimizedState';
import { rightDrawerPageState } from '@/ui/layout/right-drawer/states/rightDrawerPageState';
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
const StyledTopBarWrapper = styled.div`
align-items: center;
display: flex;
`;
const StyledMinimizeTopBarTitleContainer = styled.div`
align-items: center;
display: flex;
gap: ${({ theme }) => theme.spacing(1)};
height: 24px;
width: 168px;
`;
const StyledMinimizeTopBarTitle = styled.div`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
const StyledMinimizeTopBarIcon = styled.div`
align-items: center;
display: flex;
`;
export const RightDrawerTopBar = () => {
const isMobile = useIsMobile();
const rightDrawerPage = useRecoilValue(rightDrawerPageState);
const [isRightDrawerMinimized, setIsRightDrawerMinimized] = useRecoilState(
isRightDrawerMinimizedState,
);
const theme = useTheme();
const handleOnclick = () => {
if (isRightDrawerMinimized) {
setIsRightDrawerMinimized(false);
}
};
const { getIcon } = useIcons();
const viewableRecordNameSingular = useRecoilValue(
viewableRecordNameSingularState,
);
const isNewViewableRecordLoading = useRecoilValue(
isNewViewableRecordLoadingState,
);
const viewableRecordId = useRecoilValue(viewableRecordIdState);
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular: viewableRecordNameSingular ?? 'company',
});
if (!rightDrawerPage) {
return null;
}
const PageIcon = getIcon(RIGHT_DRAWER_PAGE_ICONS[rightDrawerPage]);
const ObjectIcon = getIcon(objectMetadataItem.icon);
const isViewRecordRightDrawerPage =
rightDrawerPage === RightDrawerPages.ViewRecord;
const label = isViewRecordRightDrawerPage
? objectMetadataItem.labelSingular
: RIGHT_DRAWER_PAGE_TITLES[rightDrawerPage];
const Icon = isViewRecordRightDrawerPage ? ObjectIcon : PageIcon;
return (
<StyledRightDrawerTopBar
onClick={handleOnclick}
isRightDrawerMinimized={isRightDrawerMinimized}
>
{!isRightDrawerMinimized && (
<Chip
disabled={isNewViewableRecordLoading}
label={label}
leftComponent={() => <Icon size={theme.icon.size.md} />}
size={ChipSize.Large}
accent={ChipAccent.TextSecondary}
clickable={false}
/>
)}
{isRightDrawerMinimized && (
<StyledMinimizeTopBarTitleContainer>
<StyledMinimizeTopBarIcon>
<Icon size={theme.icon.size.md} />
</StyledMinimizeTopBarIcon>
<StyledMinimizeTopBarTitle>{label}</StyledMinimizeTopBarTitle>
</StyledMinimizeTopBarTitleContainer>
)}
<StyledTopBarWrapper>
{!isMobile && !isRightDrawerMinimized && (
<RightDrawerTopBarMinimizeButton />
)}
{!isMobile &&
!isRightDrawerMinimized &&
isViewRecordRightDrawerPage && (
<RightDrawerTopBarExpandButton
to={
getBasePathToShowPage({
objectNameSingular: viewableRecordNameSingular ?? '',
}) + viewableRecordId
}
/>
)}
<RightDrawerTopBarCloseButton />
</StyledTopBarWrapper>
</StyledRightDrawerTopBar>
);
};

View File

@ -1,20 +0,0 @@
import { IconX, LightIconButton } from 'twenty-ui';
import { useRightDrawer } from '../hooks/useRightDrawer';
export const RightDrawerTopBarCloseButton = () => {
const { closeRightDrawer } = useRightDrawer();
const handleButtonClick = () => {
closeRightDrawer();
};
return (
<LightIconButton
Icon={IconX}
onClick={handleButtonClick}
size="medium"
accent="tertiary"
/>
);
};

View File

@ -1,17 +0,0 @@
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
import { IconExternalLink, LightIconButton, UndecoratedLink } from 'twenty-ui';
export const RightDrawerTopBarExpandButton = ({ to }: { to: string }) => {
const { closeRightDrawer } = useRightDrawer();
return (
<UndecoratedLink to={to}>
<LightIconButton
size="medium"
accent="tertiary"
Icon={IconExternalLink}
onClick={() => closeRightDrawer()}
/>
</UndecoratedLink>
);
};

View File

@ -1,21 +0,0 @@
import { IconMinus, LightIconButton } from 'twenty-ui';
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
export const RightDrawerTopBarMinimizeButton = () => {
const { isRightDrawerMinimized, minimizeRightDrawer, maximizeRightDrawer } =
useRightDrawer();
const handleButtonClick = () => {
isRightDrawerMinimized ? maximizeRightDrawer() : minimizeRightDrawer();
};
return (
<LightIconButton
Icon={IconMinus}
onClick={handleButtonClick}
size="medium"
accent="tertiary"
/>
);
};

View File

@ -1,22 +0,0 @@
import styled from '@emotion/styled';
export const StyledRightDrawerTopBar = styled.div<{
isRightDrawerMinimized: boolean;
}>`
align-items: center;
background: ${({ theme }) => theme.background.secondary};
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
color: ${({ theme }) => theme.font.color.secondary};
display: flex;
flex-direction: row;
font-size: ${({ theme }) => theme.font.size.md};
gap: ${({ theme }) => theme.spacing(1)};
height: ${({ isRightDrawerMinimized }) =>
isRightDrawerMinimized ? '40px' : '56px'};
justify-content: space-between;
padding-left: ${({ theme }) => theme.spacing(2)};
padding-right: ${({ theme }) => theme.spacing(2)};
cursor: ${({ isRightDrawerMinimized }) =>
isRightDrawerMinimized ? 'pointer' : 'default'};
`;

View File

@ -1,56 +0,0 @@
import { expect } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react';
import { RightDrawerTopBar } from '../RightDrawerTopBar';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { useSetRecoilState } from 'recoil';
import { rightDrawerPageState } from '@/ui/layout/right-drawer/states/rightDrawerPageState';
import { isRightDrawerMinimizedState } from '@/ui/layout/right-drawer/states/isRightDrawerMinimizedState';
import { useEffect } from 'react';
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
import { within } from '@storybook/test';
const RightDrawerTopBarStateSetterEffect = () => {
const setRightDrawerPage = useSetRecoilState(rightDrawerPageState);
const setIsRightDrawerMinimizedState = useSetRecoilState(
isRightDrawerMinimizedState,
);
useEffect(() => {
setRightDrawerPage(RightDrawerPages.ViewRecord);
setIsRightDrawerMinimizedState(false);
}, [setIsRightDrawerMinimizedState, setRightDrawerPage]);
return null;
};
const meta: Meta<typeof RightDrawerTopBar> = {
title: 'Modules/Activities/RightDrawer/RightDrawerTopBar',
component: RightDrawerTopBar,
decorators: [
(Story) => (
<div style={{ width: '500px' }}>
<Story />
<RightDrawerTopBarStateSetterEffect />
</div>
),
IconsProviderDecorator,
ComponentWithRouterDecorator,
ObjectMetadataItemsDecorator,
SnackBarDecorator,
],
};
export default meta;
type Story = StoryObj<typeof RightDrawerTopBar>;
export const Default: Story = {
play: async () => {
const canvas = within(document.body);
expect(await canvas.findByText('Company')).toBeInTheDocument();
},
};

View File

@ -1,32 +0,0 @@
import { THEME_COMMON } from 'twenty-ui';
export const RIGHT_DRAWER_ANIMATION_VARIANTS = {
fullScreen: {
x: '0%',
width: '100%',
height: '100%',
bottom: '0',
top: '0',
},
normal: {
x: '0%',
width: THEME_COMMON.rightDrawerWidth,
height: '100%',
bottom: '0',
top: '0',
},
closed: {
x: '100%',
width: '0',
height: '100%',
bottom: '0',
top: 'auto',
},
minimized: {
x: '0%',
width: 220,
height: 41,
bottom: '0',
top: 'auto',
},
};

View File

@ -1,2 +0,0 @@
export const RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID =
'right-drawer-click-outside-listener';

View File

@ -1,13 +0,0 @@
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
export const RIGHT_DRAWER_PAGE_ICONS = {
[RightDrawerPages.ViewEmailThread]: 'IconMail',
[RightDrawerPages.ViewCalendarEvent]: 'IconCalendarEvent',
[RightDrawerPages.ViewRecord]: 'Icon123',
[RightDrawerPages.Copilot]: 'IconSparkles',
[RightDrawerPages.WorkflowStepSelectTriggerType]: 'IconSparkles',
[RightDrawerPages.WorkflowStepSelectAction]: 'IconSparkles',
[RightDrawerPages.WorkflowStepEdit]: 'IconSparkles',
[RightDrawerPages.WorkflowStepView]: 'IconSparkles',
[RightDrawerPages.WorkflowRunStepView]: 'IconSparkles',
} satisfies Record<RightDrawerPages, string>;

View File

@ -1,13 +0,0 @@
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
export const RIGHT_DRAWER_PAGE_TITLES = {
[RightDrawerPages.ViewEmailThread]: 'Email Thread',
[RightDrawerPages.ViewCalendarEvent]: 'Calendar Event',
[RightDrawerPages.ViewRecord]: 'Record Editor',
[RightDrawerPages.Copilot]: 'Copilot',
[RightDrawerPages.WorkflowStepSelectTriggerType]: 'Workflow',
[RightDrawerPages.WorkflowStepSelectAction]: 'Workflow',
[RightDrawerPages.WorkflowStepEdit]: 'Workflow',
[RightDrawerPages.WorkflowStepView]: 'Workflow',
[RightDrawerPages.WorkflowRunStepView]: 'Workflow',
} satisfies Record<RightDrawerPages, string>;

View File

@ -1,52 +0,0 @@
import { renderHook } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import { RecoilRoot, useRecoilValue } from 'recoil';
import { IconList } from 'twenty-ui';
import { isRightDrawerOpenState } from '../../states/isRightDrawerOpenState';
import { rightDrawerPageState } from '../../states/rightDrawerPageState';
import { RightDrawerPages } from '../../types/RightDrawerPages';
import { useRightDrawer } from '../useRightDrawer';
describe('useRightDrawer', () => {
it('Should test the default behavior of useRightDrawer and change the states as the function calls', async () => {
const useCombinedHooks = () => {
const { openRightDrawer, closeRightDrawer } = useRightDrawer();
const isRightDrawerOpen = useRecoilValue(isRightDrawerOpenState);
const rightDrawerPage = useRecoilValue(rightDrawerPageState);
return {
openRightDrawer,
closeRightDrawer,
isRightDrawerOpen,
rightDrawerPage,
};
};
const { result } = renderHook(() => useCombinedHooks(), {
wrapper: RecoilRoot,
});
expect(result.current.rightDrawerPage).toBeNull();
expect(result.current.isRightDrawerOpen).toBeFalsy();
expect(result.current.openRightDrawer).toBeInstanceOf(Function);
expect(result.current.closeRightDrawer).toBeInstanceOf(Function);
await act(async () => {
result.current.openRightDrawer(RightDrawerPages.ViewRecord, {
title: 'Company',
Icon: IconList,
});
});
expect(result.current.rightDrawerPage).toEqual(RightDrawerPages.ViewRecord);
expect(result.current.isRightDrawerOpen).toBeTruthy();
await act(async () => {
result.current.closeRightDrawer();
});
expect(result.current.isRightDrawerOpen).toBeFalsy();
});
});

View File

@ -1,114 +0,0 @@
import { useRecoilCallback, useRecoilValue } from 'recoil';
import { isRightDrawerMinimizedState } from '@/ui/layout/right-drawer/states/isRightDrawerMinimizedState';
import { rightDrawerCloseEventState } from '@/ui/layout/right-drawer/states/rightDrawerCloseEventsState';
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { emitRightDrawerCloseEvent } from '@/ui/layout/right-drawer/utils/emitRightDrawerCloseEvent';
import { mapRightDrawerPageToCommandMenuPage } from '@/ui/layout/right-drawer/utils/mapRightDrawerPageToCommandMenuPage';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { isDefined } from 'twenty-shared';
import { IconComponent } from 'twenty-ui';
import { FeatureFlagKey } from '~/generated/graphql';
import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState';
import { rightDrawerPageState } from '../states/rightDrawerPageState';
import { RightDrawerPages } from '../types/RightDrawerPages';
export const useRightDrawer = () => {
const isRightDrawerOpen = useRecoilValue(isRightDrawerOpenState);
const isRightDrawerMinimized = useRecoilValue(isRightDrawerMinimizedState);
const rightDrawerPage = useRecoilValue(rightDrawerPageState);
const isCommandMenuV2Enabled = useIsFeatureEnabled(
FeatureFlagKey.IsCommandMenuV2Enabled,
);
const { navigateCommandMenu } = useCommandMenu();
const openRightDrawer = useRecoilCallback(
({ set }) =>
(
rightDrawerPage: RightDrawerPages,
commandMenuPageInfo: {
title: string;
Icon: IconComponent;
},
) => {
if (isCommandMenuV2Enabled) {
const commandMenuPage =
mapRightDrawerPageToCommandMenuPage(rightDrawerPage);
navigateCommandMenu({
page: commandMenuPage,
pageTitle: commandMenuPageInfo.title,
pageIcon: commandMenuPageInfo.Icon,
});
return;
}
set(rightDrawerPageState, rightDrawerPage);
set(isRightDrawerOpenState, true);
set(isRightDrawerMinimizedState, false);
},
[isCommandMenuV2Enabled, navigateCommandMenu],
);
const closeRightDrawer = useRecoilCallback(
({ set }) =>
(args?: { emitCloseEvent?: boolean }) => {
set(isRightDrawerOpenState, false);
set(isRightDrawerMinimizedState, false);
if (isDefined(args?.emitCloseEvent) && args?.emitCloseEvent) {
emitRightDrawerCloseEvent();
}
},
[],
);
const minimizeRightDrawer = useRecoilCallback(
({ set }) =>
() => {
set(isRightDrawerOpenState, true);
set(isRightDrawerMinimizedState, true);
},
[],
);
const maximizeRightDrawer = useRecoilCallback(
({ set }) =>
() => {
set(isRightDrawerMinimizedState, false);
set(isRightDrawerOpenState, true);
},
[],
);
const isSameEventThanRightDrawerClose = useRecoilCallback(
({ snapshot }) =>
(event: MouseEvent | TouchEvent) => {
const rightDrawerCloseEvent = snapshot
.getLoadable(rightDrawerCloseEventState)
.getValue();
const isSameEvent =
rightDrawerCloseEvent?.target === event.target &&
rightDrawerCloseEvent?.timeStamp === event.timeStamp;
return isSameEvent;
},
[],
);
return {
rightDrawerPage,
isRightDrawerOpen,
isRightDrawerMinimized,
openRightDrawer,
closeRightDrawer,
minimizeRightDrawer,
maximizeRightDrawer,
isSameEventThanRightDrawerClose,
};
};

View File

@ -1,6 +0,0 @@
import { createState } from '@ui/utilities/state/utils/createState';
export const isRightDrawerAnimationCompletedState = createState<boolean>({
key: 'isRightDrawerAnimationCompletedState',
defaultValue: false,
});

View File

@ -1,6 +0,0 @@
import { createState } from '@ui/utilities/state/utils/createState';
export const isRightDrawerMinimizedState = createState<boolean>({
key: 'ui/layout/is-right-drawer-minimized',
defaultValue: false,
});

View File

@ -1,6 +0,0 @@
import { createState } from '@ui/utilities/state/utils/createState';
export const isRightDrawerOpenState = createState<boolean>({
key: 'ui/layout/is-right-drawer-open',
defaultValue: false,
});

View File

@ -1,8 +0,0 @@
import { createState } from '@ui/utilities/state/utils/createState';
import { MessageThread } from '@/activities/emails/types/MessageThread';
export const messageThreadState = createState<MessageThread | null>({
key: 'messageThreadState',
defaultValue: null,
});

View File

@ -1,6 +0,0 @@
import { createState } from '@ui/utilities/state/utils/createState';
export const rightDrawerCloseEventState = createState<Event | null>({
key: 'rightDrawerCloseEventState',
defaultValue: null,
});

View File

@ -1,9 +0,0 @@
import { createState } from '@ui/utilities/state/utils/createState';
import { RightDrawerTopBarDropdownButtons } from '@/ui/layout/right-drawer/types/RightDrawerTopBarDropdownButtons';
export const rightDrawerTopBarDropdownButtonState =
createState<RightDrawerTopBarDropdownButtons | null>({
key: 'rightDrawerTopBarDropdownButtonState',
defaultValue: null,
});

View File

@ -1,8 +0,0 @@
import { createState } from '@ui/utilities/state/utils/createState';
import { RightDrawerPages } from '../types/RightDrawerPages';
export const rightDrawerPageState = createState<RightDrawerPages | null>({
key: 'ui/layout/right-drawer-page',
defaultValue: null,
});

View File

@ -1,4 +0,0 @@
import { RIGHT_DRAWER_ANIMATION_VARIANTS } from '@/ui/layout/right-drawer/constants/RightDrawerAnimationVariants';
export type RightDrawerAnimationVariant =
keyof typeof RIGHT_DRAWER_ANIMATION_VARIANTS;

View File

@ -1,3 +0,0 @@
export enum RightDrawerHotkeyScope {
RightDrawer = 'right-drawer',
}

View File

@ -1,11 +0,0 @@
export enum RightDrawerPages {
ViewEmailThread = 'view-email-thread',
ViewCalendarEvent = 'view-calendar-event',
ViewRecord = 'view-record',
Copilot = 'copilot',
WorkflowStepSelectTriggerType = 'workflow-step-select-trigger-type',
WorkflowStepSelectAction = 'workflow-step-select-action',
WorkflowStepView = 'workflow-step-view',
WorkflowStepEdit = 'workflow-step-edit',
WorkflowRunStepView = 'workflow-run-step-view',
}

View File

@ -1,3 +0,0 @@
export enum RightDrawerTopBarDropdownButtons {
EmailThreadSubscribers = 'EmailThreadSubscribers',
}

View File

@ -1,28 +0,0 @@
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
export const mapRightDrawerPageToCommandMenuPage = (
rightDrawerPage: RightDrawerPages,
) => {
const rightDrawerPagesToCommandMenuPages: Record<
RightDrawerPages,
CommandMenuPages
> = {
[RightDrawerPages.ViewRecord]: CommandMenuPages.ViewRecord,
[RightDrawerPages.ViewEmailThread]: CommandMenuPages.ViewEmailThread,
[RightDrawerPages.ViewCalendarEvent]: CommandMenuPages.ViewCalendarEvent,
[RightDrawerPages.Copilot]: CommandMenuPages.Copilot,
[RightDrawerPages.WorkflowStepSelectTriggerType]:
CommandMenuPages.WorkflowStepSelectTriggerType,
[RightDrawerPages.WorkflowStepSelectAction]:
CommandMenuPages.WorkflowStepSelectAction,
[RightDrawerPages.WorkflowStepView]: CommandMenuPages.WorkflowStepView,
[RightDrawerPages.WorkflowRunStepView]:
CommandMenuPages.WorkflowRunStepView,
[RightDrawerPages.WorkflowStepEdit]: CommandMenuPages.WorkflowStepEdit,
};
return (
rightDrawerPagesToCommandMenuPages[rightDrawerPage] ?? CommandMenuPages.Root
);
};