From 1403c55625b7f6c31cc884e87293d6d6906f097b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Fri, 7 Feb 2025 14:48:41 +0100 Subject: [PATCH] 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` --- ...cordIndexActionMenuBarAllActionsButton.tsx | 11 +-- .../hooks/useOpenActivityRightDrawer.ts | 6 +- .../hooks/useOpenCreateActivityDrawer.ts | 6 +- .../components/CommandMenuContextChip.tsx | 15 +-- .../CommandMenuContextChipGroups.tsx | 51 ++++++++++ ...nuContextChipGroupsWithRecordSelection.tsx | 53 ++++++++++ .../components/CommandMenuTopBar.tsx | 57 ++++++----- .../__stories__/CommandMenu.stories.tsx | 3 + .../CommandMenuContextChipGroups.stories.tsx | 97 +++++++++++++++++++ .../hooks/__tests__/useCommandMenu.test.tsx | 22 +++-- .../command-menu/hooks/useCommandMenu.ts | 20 +++- .../states/commandMenuNavigationStackState.ts | 4 +- .../RecordBoardColumnNewOpportunity.tsx | 6 +- .../hooks/useOpenRecordTableCellV2.ts | 6 +- .../useAddNewRecordAndOpenRightDrawer.ts | 6 +- .../PageHeaderOpenCommandMenuButton.tsx | 15 +-- .../hooks/__tests__/useRightDrawer.test.tsx | 6 +- .../right-drawer/hooks/useRightDrawer.ts | 10 +- .../WorkflowDiagramCanvasEditableEffect.tsx | 12 ++- .../hooks/useStartNodeCreation.ts | 2 +- .../hooks/__tests__/useCreateStep.test.ts | 8 -- .../workflow-steps/hooks/useCreateStep.ts | 19 ---- 22 files changed, 328 insertions(+), 107 deletions(-) create mode 100644 packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChipGroups.tsx create mode 100644 packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChipGroupsWithRecordSelection.tsx create mode 100644 packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenuContextChipGroups.stories.tsx diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarAllActionsButton.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarAllActionsButton.tsx index 6a0d8067c..572df3a1d 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarAllActionsButton.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarAllActionsButton.tsx @@ -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 ( <> - - navigateCommandMenu({ - page: CommandMenuPages.Root, - }) - } - > + All Actions diff --git a/packages/twenty-front/src/modules/activities/hooks/useOpenActivityRightDrawer.ts b/packages/twenty-front/src/modules/activities/hooks/useOpenActivityRightDrawer.ts index 5d0aec52a..d5185b34a 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useOpenActivityRightDrawer.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useOpenActivityRightDrawer.ts @@ -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, + }); }; }; diff --git a/packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawer.ts b/packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawer.ts index 98dc4a0a4..ee809c12f 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawer.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawer.ts @@ -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); diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChip.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChip.tsx index 02fe9fa61..bf203113c 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChip.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChip.tsx @@ -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 ( { + if (contextChips.length === 0) { + return null; + } + + if (contextChips.length < 3) { + return ( + <> + {contextChips.map((chip) => ( + + ))} + + ); + } + + const firstChips = contextChips.slice(0, -1); + const lastChip = contextChips.at(-1); + + return ( + <> + {firstChips.length > 0 && ( + chip.Icons?.[0])} + /> + )} + + {isDefined(lastChip) && ( + + )} + + ); +}; diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChipGroupsWithRecordSelection.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChipGroupsWithRecordSelection.tsx new file mode 100644 index 000000000..f013603ac --- /dev/null +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChipGroupsWithRecordSelection.tsx @@ -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) => ( + + )); + + const selectedRecordsContextText = getSelectedRecordsContextText( + objectMetadataItem, + records, + totalCount, + ); + + return ( + + ); +}; diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx index 77832b49a..0eb0598a5 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx @@ -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: [], + text: page.pageTitle, + }; + }); + }, [commandMenuNavigationStack, theme.icon.size.sm]); + return ( {isCommandMenuV2Enabled && ( - ]} - onClick={() => { - goBackFromCommandMenu(); - }} - testId="command-menu-go-back-button" - /> - )} - {commandMenuPage !== CommandMenuPages.SearchRecords && - isDefined(contextStoreCurrentObjectMetadataId) && ( - + ]} + onClick={() => { + goBackFromCommandMenu(); + }} + testId="command-menu-go-back-button" /> - )} - {isDefined(Icon) && ( - ]} - text={title} - /> + {isDefined(contextStoreCurrentObjectMetadataId) && + commandMenuPage !== CommandMenuPages.SearchRecords ? ( + + ) : ( + + )} + )} - {(commandMenuPage === CommandMenuPages.Root || commandMenuPage === CommandMenuPages.SearchRecords) && ( = { setCommandMenuNavigationStack([ { page: CommandMenuPages.Root, + pageTitle: 'Command Menu', + pageIcon: IconDotsVertical, }, ]); diff --git a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenuContextChipGroups.stories.tsx b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenuContextChipGroups.stories.tsx new file mode 100644 index 000000000..bba2906f4 --- /dev/null +++ b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenuContextChipGroups.stories.tsx @@ -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 = { + title: 'Modules/CommandMenu/CommandMenuContextChipGroups', + component: CommandMenuContextChipGroups, + decorators: [ + (Story) => {Story()}, + ComponentDecorator, + ], +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + contextChips: [ + { + Icons: [], + text: 'Company', + }, + { + Icons: [], + text: 'Person', + }, + ], + }, +}; + +export const SingleChip: Story = { + args: { + contextChips: [ + { + Icons: [], + text: 'Person', + }, + ], + }, +}; + +export const ThreeChipsWithIcons: Story = { + args: { + contextChips: [ + { + Icons: [], + text: 'Company', + }, + { + Icons: [], + text: 'Person', + }, + { + Icons: [], + text: 'Settings', + }, + ], + }, +}; + +export const FourChipsWithIcons: Story = { + args: { + contextChips: [ + { + Icons: [], + text: 'Company', + }, + { + Icons: [], + text: 'Person', + }, + { + Icons: [], + text: 'Settings', + }, + { + Icons: [], + text: 'Search', + }, + ], + }, +}; diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx index 66b56a3b0..8cbf1af2a 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx @@ -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 }) => ( @@ -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, }, ]); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts index 8d4fe6d1f..ee37b894d 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts @@ -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, diff --git a/packages/twenty-front/src/modules/command-menu/states/commandMenuNavigationStackState.ts b/packages/twenty-front/src/modules/command-menu/states/commandMenuNavigationStackState.ts index fa7650f42..9445952e4 100644 --- a/packages/twenty-front/src/modules/command-menu/states/commandMenuNavigationStackState.ts +++ b/packages/twenty-front/src/modules/command-menu/states/commandMenuNavigationStackState.ts @@ -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< diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewOpportunity.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewOpportunity.tsx index 32d9fe4ff..64dc0a747 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewOpportunity.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewOpportunity.tsx @@ -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); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2.ts index bf1efc24c..18cc48e65 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2.ts @@ -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; } diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useAddNewRecordAndOpenRightDrawer.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useAddNewRecordAndOpenRightDrawer.ts index ea3dd0aa2..296ee39bb 100644 --- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useAddNewRecordAndOpenRightDrawer.ts +++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useAddNewRecordAndOpenRightDrawer.ts @@ -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, + }); }, }; }; diff --git a/packages/twenty-front/src/modules/ui/layout/page-header/components/PageHeaderOpenCommandMenuButton.tsx b/packages/twenty-front/src/modules/ui/layout/page-header/components/PageHeaderOpenCommandMenuButton.tsx index b52eba66d..d444f4738 100644 --- a/packages/twenty-front/src/modules/ui/layout/page-header/components/PageHeaderOpenCommandMenuButton.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page-header/components/PageHeaderOpenCommandMenuButton.tsx @@ -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} /> ) : ( { dataTestId="more-showpage-button" accent="default" variant="secondary" - onClick={() => { - navigateCommandMenu({ - page: CommandMenuPages.Root, - }); - }} + onClick={openRootCommandMenu} /> )} diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/hooks/__tests__/useRightDrawer.test.tsx b/packages/twenty-front/src/modules/ui/layout/right-drawer/hooks/__tests__/useRightDrawer.test.tsx index 4556ac627..a7b678c6a 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/hooks/__tests__/useRightDrawer.test.tsx +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/hooks/__tests__/useRightDrawer.test.tsx @@ -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); diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/hooks/useRightDrawer.ts b/packages/twenty-front/src/modules/ui/layout/right-drawer/hooks/useRightDrawer.ts index e659eb936..36b915b7d 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/hooks/useRightDrawer.ts +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/hooks/useRightDrawer.ts @@ -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; diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditableEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditableEffect.tsx index 0221a2728..3111319b5 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditableEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowDiagramCanvasEditableEffect.tsx @@ -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, ], ); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts index f33c2b13f..91099e0a9 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/hooks/useStartNodeCreation.ts @@ -28,7 +28,7 @@ export const useStartNodeCreation = () => { Icon: IconSettingsAutomation, }); }, - [openRightDrawer, setWorkflowCreateStepFromParentStepId, setHotkeyScope], + [setWorkflowCreateStepFromParentStepId, setHotkeyScope, openRightDrawer], ); return { diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.ts index 751f65799..3d9694c2c 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/__tests__/useCreateStep.test.ts @@ -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(); }); }); diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts index dfa93c42b..3427b6eb5 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts @@ -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 {