321 command menu context chips compact version (#10072)

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

- Create component
- Create stories
- Fix bug due to `WorkflowDiagramCanvasEditableEffect`
This commit is contained in:
Raphaël Bosi
2025-02-07 14:48:41 +01:00
committed by GitHub
parent 68183b7c85
commit 1403c55625
22 changed files with 328 additions and 107 deletions

View File

@ -1,5 +1,4 @@
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconLayoutSidebarRightExpand, getOsControlSymbol } from 'twenty-ui';
@ -39,17 +38,11 @@ const StyledSeparator = styled.div<{ size: 'sm' | 'md' }>`
export const RecordIndexActionMenuBarAllActionsButton = () => {
const theme = useTheme();
const { navigateCommandMenu } = useCommandMenu();
const { openRootCommandMenu } = useCommandMenu();
return (
<>
<StyledSeparator size="md" />
<StyledButton
onClick={() =>
navigateCommandMenu({
page: CommandMenuPages.Root,
})
}
>
<StyledButton onClick={openRootCommandMenu}>
<IconLayoutSidebarRightExpand size={theme.icon.size.md} />
<StyledButtonLabel>All Actions</StyledButtonLabel>
<StyledSeparator size="sm" />

View File

@ -9,6 +9,7 @@ import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPage
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { IconList } from 'twenty-ui';
import { FeatureFlagKey } from '~/generated/graphql';
export const useOpenActivityRightDrawer = ({
@ -49,6 +50,9 @@ export const useOpenActivityRightDrawer = ({
setViewableRecordId(activityId);
setViewableRecordNameSingular(objectNameSingular);
openRightDrawer(RightDrawerPages.ViewRecord);
openRightDrawer(RightDrawerPages.ViewRecord, {
title: objectNameSingular,
Icon: IconList,
});
};
};

View File

@ -19,6 +19,7 @@ import { isNewViewableRecordLoadingState } from '@/object-record/record-right-dr
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { IconList } from 'twenty-ui';
import { FeatureFlagKey } from '~/generated/graphql';
import { ActivityTargetableObject } from '../types/ActivityTargetableEntity';
@ -75,7 +76,10 @@ export const useOpenCreateActivityDrawer = ({
customAssignee?: WorkspaceMember;
}) => {
setIsNewViewableRecordLoading(true);
openRightDrawer(RightDrawerPages.ViewRecord);
openRightDrawer(RightDrawerPages.ViewRecord, {
title: activityObjectNameSingular,
Icon: IconList,
});
setViewableRecordId(null);
setViewableRecordNameSingular(activityObjectNameSingular);

View File

@ -33,20 +33,23 @@ const StyledChip = styled.button<{
`;
const StyledIconsContainer = styled.div`
align-items: center;
display: flex;
`;
export type CommandMenuContextChipProps = {
Icons: React.ReactNode[];
text?: string;
onClick?: () => void;
testId?: string;
};
export const CommandMenuContextChip = ({
Icons,
text,
onClick,
testId,
}: {
Icons: React.ReactNode[];
text?: string;
onClick?: () => void;
testId?: string;
}) => {
}: CommandMenuContextChipProps) => {
return (
<StyledChip
withText={isNonEmptyString(text)}

View File

@ -0,0 +1,51 @@
import { isDefined } from 'twenty-shared';
import {
CommandMenuContextChip,
CommandMenuContextChipProps,
} from './CommandMenuContextChip';
export const CommandMenuContextChipGroups = ({
contextChips,
}: {
contextChips: CommandMenuContextChipProps[];
}) => {
if (contextChips.length === 0) {
return null;
}
if (contextChips.length < 3) {
return (
<>
{contextChips.map((chip) => (
<CommandMenuContextChip
key={chip.text}
Icons={chip.Icons}
text={chip.text}
onClick={chip.onClick}
/>
))}
</>
);
}
const firstChips = contextChips.slice(0, -1);
const lastChip = contextChips.at(-1);
return (
<>
{firstChips.length > 0 && (
<CommandMenuContextChip
Icons={firstChips.map((chip) => chip.Icons?.[0])}
/>
)}
{isDefined(lastChip) && (
<CommandMenuContextChip
Icons={lastChip.Icons}
text={lastChip.text}
onClick={lastChip.onClick}
/>
)}
</>
);
};

View File

@ -0,0 +1,53 @@
import { CommandMenuContextChipGroups } from '@/command-menu/components/CommandMenuContextChipGroups';
import { CommandMenuContextRecordChipAvatars } from '@/command-menu/components/CommandMenuContextRecordChipAvatars';
import { getSelectedRecordsContextText } from '@/command-menu/utils/getRecordContextText';
import { useFindManyRecordsSelectedInContextStore } from '@/context-store/hooks/useFindManyRecordsSelectedInContextStore';
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
import { CommandMenuContextChipProps } from './CommandMenuContextChip';
export const CommandMenuContextChipGroupsWithRecordSelection = ({
contextChips,
objectMetadataItemId,
}: {
contextChips: CommandMenuContextChipProps[];
objectMetadataItemId: string;
}) => {
const { objectMetadataItem } = useObjectMetadataItemById({
objectId: objectMetadataItemId,
});
const { records, loading, totalCount } =
useFindManyRecordsSelectedInContextStore({
limit: 3,
});
if (loading || !totalCount) {
return null;
}
const Avatars = records.map((record) => (
<CommandMenuContextRecordChipAvatars
objectMetadataItem={objectMetadataItem}
key={record.id}
record={record}
/>
));
const selectedRecordsContextText = getSelectedRecordsContextText(
objectMetadataItem,
records,
totalCount,
);
return (
<CommandMenuContextChipGroups
contextChips={[
{
text: selectedRecordsContextText,
Icons: Avatars,
},
...contextChips,
]}
/>
);
};

View File

@ -1,10 +1,11 @@
import { CommandMenuContextChip } from '@/command-menu/components/CommandMenuContextChip';
import { CommandMenuContextRecordChip } from '@/command-menu/components/CommandMenuContextRecordChip';
import { CommandMenuContextChipGroups } from '@/command-menu/components/CommandMenuContextChipGroups';
import { CommandMenuContextChipGroupsWithRecordSelection } from '@/command-menu/components/CommandMenuContextChipGroupsWithRecordSelection';
import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/CommandMenuSearchBarHeight';
import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding';
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageTitle';
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
@ -13,6 +14,7 @@ import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useMemo } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared';
import {
@ -98,7 +100,9 @@ export const CommandMenuTopBar = () => {
const commandMenuPage = useRecoilValue(commandMenuPageState);
const { title, Icon } = useRecoilValue(commandMenuPageInfoState);
const commandMenuNavigationStack = useRecoilValue(
commandMenuNavigationStackState,
);
const theme = useTheme();
@ -106,31 +110,40 @@ export const CommandMenuTopBar = () => {
FeatureFlagKey.IsCommandMenuV2Enabled,
);
const contextChips = useMemo(() => {
return commandMenuNavigationStack
.filter((page) => page.page !== CommandMenuPages.Root)
.map((page) => {
return {
Icons: [<page.pageIcon size={theme.icon.size.sm} />],
text: page.pageTitle,
};
});
}, [commandMenuNavigationStack, theme.icon.size.sm]);
return (
<StyledInputContainer>
<StyledContentContainer>
{isCommandMenuV2Enabled && (
<CommandMenuContextChip
Icons={[<IconChevronLeft size={theme.icon.size.sm} />]}
onClick={() => {
goBackFromCommandMenu();
}}
testId="command-menu-go-back-button"
/>
)}
{commandMenuPage !== CommandMenuPages.SearchRecords &&
isDefined(contextStoreCurrentObjectMetadataId) && (
<CommandMenuContextRecordChip
objectMetadataItemId={contextStoreCurrentObjectMetadataId}
<>
<CommandMenuContextChip
Icons={[<IconChevronLeft size={theme.icon.size.sm} />]}
onClick={() => {
goBackFromCommandMenu();
}}
testId="command-menu-go-back-button"
/>
)}
{isDefined(Icon) && (
<CommandMenuContextChip
Icons={[<Icon size={theme.icon.size.sm} />]}
text={title}
/>
{isDefined(contextStoreCurrentObjectMetadataId) &&
commandMenuPage !== CommandMenuPages.SearchRecords ? (
<CommandMenuContextChipGroupsWithRecordSelection
contextChips={contextChips}
objectMetadataItemId={contextStoreCurrentObjectMetadataId}
/>
) : (
<CommandMenuContextChipGroups contextChips={contextChips} />
)}
</>
)}
{(commandMenuPage === CommandMenuPages.Root ||
commandMenuPage === CommandMenuPages.SearchRecords) && (
<StyledInput

View File

@ -22,6 +22,7 @@ import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
import { HttpResponse, graphql } from 'msw';
import { IconDotsVertical } from 'twenty-ui';
import { FeatureFlagKey } from '~/generated/graphql';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { JestContextStoreSetter } from '~/testing/jest/JestContextStoreSetter';
@ -89,6 +90,8 @@ const meta: Meta<typeof CommandMenu> = {
setCommandMenuNavigationStack([
{
page: CommandMenuPages.Root,
pageTitle: 'Command Menu',
pageIcon: IconDotsVertical,
},
]);

View File

@ -0,0 +1,97 @@
import { Meta, StoryObj } from '@storybook/react';
import styled from '@emotion/styled';
import {
ComponentDecorator,
IconBuildingSkyscraper,
IconSearch,
IconSettingsAutomation,
IconUser,
} from 'twenty-ui';
import { CommandMenuContextChipGroups } from '../CommandMenuContextChipGroups';
const StyledContainer = styled.div`
display: flex;
flex-direction: row;
gap: ${({ theme }) => theme.spacing(1)};
`;
const meta: Meta<typeof CommandMenuContextChipGroups> = {
title: 'Modules/CommandMenu/CommandMenuContextChipGroups',
component: CommandMenuContextChipGroups,
decorators: [
(Story) => <StyledContainer>{Story()}</StyledContainer>,
ComponentDecorator,
],
};
export default meta;
type Story = StoryObj<typeof CommandMenuContextChipGroups>;
export const Default: Story = {
args: {
contextChips: [
{
Icons: [<IconBuildingSkyscraper size={16} />],
text: 'Company',
},
{
Icons: [<IconUser size={16} />],
text: 'Person',
},
],
},
};
export const SingleChip: Story = {
args: {
contextChips: [
{
Icons: [<IconUser size={16} />],
text: 'Person',
},
],
},
};
export const ThreeChipsWithIcons: Story = {
args: {
contextChips: [
{
Icons: [<IconBuildingSkyscraper size={16} />],
text: 'Company',
},
{
Icons: [<IconUser size={16} />],
text: 'Person',
},
{
Icons: [<IconSettingsAutomation size={16} />],
text: 'Settings',
},
],
},
};
export const FourChipsWithIcons: Story = {
args: {
contextChips: [
{
Icons: [<IconBuildingSkyscraper size={16} />],
text: 'Company',
},
{
Icons: [<IconUser size={16} />],
text: 'Person',
},
{
Icons: [<IconSettingsAutomation size={16} />],
text: 'Settings',
},
{
Icons: [<IconSearch size={16} />],
text: 'Search',
},
],
},
};

View File

@ -9,7 +9,7 @@ import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageTitle';
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { IconSearch } from 'twenty-ui';
import { IconList, IconSearch } from 'twenty-ui';
const Wrapper = ({ children }: { children: React.ReactNode }) => (
<RecoilRoot>
@ -53,9 +53,7 @@ describe('useCommandMenu', () => {
const { result } = renderHooks();
act(() => {
result.current.commandMenu.navigateCommandMenu({
page: CommandMenuPages.Root,
});
result.current.commandMenu.openRootCommandMenu();
});
expect(result.current.isCommandMenuOpened).toBe(true);
@ -119,7 +117,8 @@ describe('useCommandMenu', () => {
act(() => {
result.current.commandMenu.navigateCommandMenu({
page: CommandMenuPages.ViewRecord,
pageTitle: 'View Record',
pageTitle: 'Company',
pageIcon: IconList,
});
});
@ -131,13 +130,14 @@ describe('useCommandMenu', () => {
},
{
page: CommandMenuPages.ViewRecord,
pageTitle: 'View Record',
pageTitle: 'Company',
pageIcon: IconList,
},
]);
expect(result.current.commandMenuPage).toBe(CommandMenuPages.ViewRecord);
expect(result.current.commandMenuPageInfo).toEqual({
title: 'View Record',
Icon: undefined,
title: 'Company',
Icon: IconList,
});
});
@ -155,7 +155,8 @@ describe('useCommandMenu', () => {
act(() => {
result.current.commandMenu.navigateCommandMenu({
page: CommandMenuPages.ViewRecord,
pageTitle: 'View Record',
pageTitle: 'Company',
pageIcon: IconList,
});
});
@ -167,7 +168,8 @@ describe('useCommandMenu', () => {
},
{
page: CommandMenuPages.ViewRecord,
pageTitle: 'View Record',
pageTitle: 'Company',
pageIcon: IconList,
},
]);

View File

@ -23,8 +23,9 @@ import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
import { emitRightDrawerCloseEvent } from '@/ui/layout/right-drawer/utils/emitRightDrawerCloseEvent';
import { useCallback } from 'react';
import { isDefined } from 'twenty-shared';
import { IconSearch } from 'twenty-ui';
import { IconDotsVertical, IconList, IconSearch } from 'twenty-ui';
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
export const useCommandMenu = () => {
@ -123,6 +124,14 @@ export const useCommandMenu = () => {
[openCommandMenu],
);
const openRootCommandMenu = useCallback(() => {
navigateCommandMenu({
page: CommandMenuPages.Root,
pageTitle: 'Command Menu',
pageIcon: IconDotsVertical,
});
}, [navigateCommandMenu]);
const toggleCommandMenu = useRecoilCallback(
({ snapshot, set }) =>
async () => {
@ -135,12 +144,10 @@ export const useCommandMenu = () => {
if (isCommandMenuOpened) {
closeCommandMenu();
} else {
navigateCommandMenu({
page: CommandMenuPages.Root,
});
openRootCommandMenu();
}
},
[closeCommandMenu, navigateCommandMenu],
[closeCommandMenu, openRootCommandMenu],
);
const goBackFromCommandMenu = useRecoilCallback(
@ -204,6 +211,8 @@ export const useCommandMenu = () => {
set(viewableRecordIdState, recordId);
navigateCommandMenu({
page: CommandMenuPages.ViewRecord,
pageTitle: objectNameSingular,
pageIcon: IconList,
});
};
},
@ -267,6 +276,7 @@ export const useCommandMenu = () => {
);
return {
openRootCommandMenu,
closeCommandMenu,
navigateCommandMenu,
navigateCommandMenuHistory,

View File

@ -3,8 +3,8 @@ import { IconComponent, createState } from 'twenty-ui';
export type CommandMenuNavigationStackItem = {
page: CommandMenuPages;
pageTitle?: string;
pageIcon?: IconComponent;
pageTitle: string;
pageIcon: IconComponent;
};
export const commandMenuNavigationStackState = createState<

View File

@ -12,6 +12,7 @@ import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared';
import { IconList } from 'twenty-ui';
import { v4 } from 'uuid';
export const RecordBoardColumnNewOpportunity = ({
@ -52,7 +53,10 @@ export const RecordBoardColumnNewOpportunity = ({
setViewableRecordId(newRecordId);
setViewableRecordNameSingular(CoreObjectNameSingular.Company);
openRightDrawer(RightDrawerPages.ViewRecord);
openRightDrawer(RightDrawerPages.ViewRecord, {
title: 'Company',
Icon: IconList,
});
if (isDefined(createdCompany)) {
handleEntitySelect(position, createdCompany);

View File

@ -26,6 +26,7 @@ import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropd
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
import { useClickOustideListenerStates } from '@/ui/utilities/pointer-event/hooks/useClickOustideListenerStates';
import { useNavigate } from 'react-router-dom';
import { IconList } from 'twenty-ui';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
@ -123,7 +124,10 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => {
leaveTableFocus();
setViewableRecordId(recordId);
setViewableRecordNameSingular(objectNameSingular);
openRightDrawer(RightDrawerPages.ViewRecord);
openRightDrawer(RightDrawerPages.ViewRecord, {
title: objectNameSingular,
Icon: IconList,
});
return;
}

View File

@ -11,6 +11,7 @@ import { viewableRecordNameSingularState } from '@/object-record/record-right-dr
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
import { isDefined } from 'twenty-shared';
import { IconEye } from 'twenty-ui';
import {
FieldMetadataType,
RelationDefinitionType,
@ -109,7 +110,10 @@ export const useAddNewRecordAndOpenRightDrawer = ({
setViewableRecordId(newRecordId);
setViewableRecordNameSingular(relationObjectMetadataNameSingular);
openRightDrawer(RightDrawerPages.ViewRecord);
openRightDrawer(RightDrawerPages.ViewRecord, {
title: 'View Record',
Icon: IconEye,
});
},
};
};

View File

@ -7,12 +7,11 @@ import {
} from 'twenty-ui';
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { FeatureFlagKey } from '~/generated/graphql';
export const PageHeaderOpenCommandMenuButton = () => {
const { navigateCommandMenu } = useCommandMenu();
const { openRootCommandMenu } = useCommandMenu();
const isCommandMenuV2Enabled = useIsFeatureEnabled(
FeatureFlagKey.IsCommandMenuV2Enabled,
@ -31,11 +30,7 @@ export const PageHeaderOpenCommandMenuButton = () => {
accent="default"
hotkeys={[getOsControlSymbol(), 'K']}
ariaLabel="Open command menu"
onClick={() => {
navigateCommandMenu({
page: CommandMenuPages.Root,
});
}}
onClick={openRootCommandMenu}
/>
) : (
<IconButton
@ -44,11 +39,7 @@ export const PageHeaderOpenCommandMenuButton = () => {
dataTestId="more-showpage-button"
accent="default"
variant="secondary"
onClick={() => {
navigateCommandMenu({
page: CommandMenuPages.Root,
});
}}
onClick={openRootCommandMenu}
/>
)}
</>

View File

@ -2,6 +2,7 @@ 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';
@ -33,7 +34,10 @@ describe('useRightDrawer', () => {
expect(result.current.closeRightDrawer).toBeInstanceOf(Function);
await act(async () => {
result.current.openRightDrawer(RightDrawerPages.ViewRecord);
result.current.openRightDrawer(RightDrawerPages.ViewRecord, {
title: 'Company',
Icon: IconList,
});
});
expect(result.current.rightDrawerPage).toEqual(RightDrawerPages.ViewRecord);

View File

@ -30,9 +30,9 @@ export const useRightDrawer = () => {
({ set }) =>
(
rightDrawerPage: RightDrawerPages,
commandMenuPageInfo?: {
title?: string;
Icon?: IconComponent;
commandMenuPageInfo: {
title: string;
Icon: IconComponent;
},
) => {
if (isCommandMenuV2Enabled) {
@ -41,8 +41,8 @@ export const useRightDrawer = () => {
navigateCommandMenu({
page: commandMenuPage,
pageTitle: commandMenuPageInfo?.title,
pageIcon: commandMenuPageInfo?.Icon,
pageTitle: commandMenuPageInfo.title,
pageIcon: commandMenuPageInfo.Icon,
});
return;

View File

@ -1,4 +1,5 @@
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
import { RightDrawerHotkeyScope } from '@/ui/layout/right-drawer/types/RightDrawerHotkeyScope';
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
@ -32,11 +33,17 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
const setCommandMenuNavigationStack = useSetRecoilState(
commandMenuNavigationStackState,
);
const handleSelectionChange = useCallback(
({ nodes }: OnSelectionChangeParams) => {
const selectedNode = nodes[0] as WorkflowDiagramNode;
const isClosingStep = isDefined(selectedNode) === false;
setCommandMenuNavigationStack([]);
if (isClosingStep) {
closeRightDrawer();
closeCommandMenu();
@ -69,14 +76,15 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
});
},
[
setCommandMenuNavigationStack,
setWorkflowSelectedNode,
setHotkeyScope,
openRightDrawer,
getIcon,
closeRightDrawer,
closeCommandMenu,
startNodeCreation,
getIcon,
t,
startNodeCreation,
],
);

View File

@ -28,7 +28,7 @@ export const useStartNodeCreation = () => {
Icon: IconSettingsAutomation,
});
},
[openRightDrawer, setWorkflowCreateStepFromParentStepId, setHotkeyScope],
[setWorkflowCreateStepFromParentStepId, setHotkeyScope, openRightDrawer],
);
return {

View File

@ -2,7 +2,6 @@ import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow';
import { renderHook } from '@testing-library/react';
import { useCreateStep } from '../useCreateStep';
const mockOpenRightDrawer = jest.fn();
const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457');
const mockCreateWorkflowVersionStep = jest.fn().mockResolvedValue({
data: { createWorkflowVersionStep: { id: '1', type: 'CODE' } },
@ -14,12 +13,6 @@ jest.mock('recoil', () => ({
atom: (params: any) => params,
}));
jest.mock('@/ui/layout/right-drawer/hooks/useRightDrawer', () => ({
useRightDrawer: () => ({
openRightDrawer: mockOpenRightDrawer,
}),
}));
jest.mock(
'@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep',
() => ({
@ -56,6 +49,5 @@ describe('useCreateStep', () => {
await result.current.createStep('CODE');
expect(mockCreateWorkflowVersionStep).toHaveBeenCalled();
expect(mockOpenRightDrawer).toHaveBeenCalled();
});
});

View File

@ -1,5 +1,3 @@
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion';
import { workflowLastCreatedStepIdState } from '@/workflow/states/workflowLastCreatedStepIdState';
import {
@ -7,19 +5,16 @@ import {
WorkflowWithCurrentVersion,
} from '@/workflow/types/Workflow';
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
import { useCreateWorkflowVersionStep } from '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep';
import { workflowCreateStepFromParentStepIdState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared';
import { useIcons } from 'twenty-ui';
export const useCreateStep = ({
workflow,
}: {
workflow: WorkflowWithCurrentVersion;
}) => {
const { getIcon } = useIcons();
const { createWorkflowVersionStep } = useCreateWorkflowVersionStep();
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
const setWorkflowLastCreatedStepId = useSetRecoilState(
@ -32,8 +27,6 @@ export const useCreateStep = ({
const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion();
const { openRightDrawer } = useRightDrawer();
const createStep = async (newStepType: WorkflowStepType) => {
if (!isDefined(workflowCreateStepFromParentStepId)) {
throw new Error('Select a step to create a new step from first.');
@ -54,18 +47,6 @@ export const useCreateStep = ({
setWorkflowSelectedNode(createdStep.id);
setWorkflowLastCreatedStepId(createdStep.id);
const stepIcon = getWorkflowNodeIconKey({
nodeType: 'action',
actionType: createdStep.type as WorkflowStepType,
name: createdStep.name,
isLeafNode: false,
});
openRightDrawer(RightDrawerPages.WorkflowStepEdit, {
title: createdStep.name,
Icon: getIcon(stepIcon),
});
};
return {