From efe1700cc8283d8b288d48bbf1b7d76f08212997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Tue, 17 Jun 2025 13:37:27 +0200 Subject: [PATCH] Set hotkey scope when navigating in side panel's history (#12634) This PR fixes a bug where the side panel couldn't be closed after the execution of a workflow with a form. After the execution of the workflow, `goBackFromCommandMenu` is called to show the workflow run. The hotkey scope wasn't reset properly, and the click outside listener from the side panel is only triggered when the scope is `CommandMenuFocused`. This PR sets the hotkey scope to `CommandMenuFocused` when going back or when navigating inside the command menu history. Note: (we don't use `setHotkeyScopeAndMemorizePreviousScope` here because we don't need to memorize the active hotkey scope of the page we are leaving) Before: https://github.com/user-attachments/assets/09edf97b-7520-46ce-ade3-6bb6b15ef435 After: https://github.com/user-attachments/assets/16c288cb-1d42-4099-8925-74a673f7a479 --- .../hooks/useCommandMenuHistory.ts | 107 ++++++++++-------- 1 file changed, 62 insertions(+), 45 deletions(-) diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHistory.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHistory.ts index c9002abd7..7f5332c99 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHistory.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHistory.ts @@ -6,12 +6,15 @@ import { commandMenuNavigationStackState } from '@/command-menu/states/commandMe import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState'; import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState'; import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState'; +import { CommandMenuHotkeyScope } from '@/command-menu/types/CommandMenuHotkeyScope'; import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; +import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { isDefined } from 'twenty-shared/utils'; export const useCommandMenuHistory = () => { const { closeCommandMenu } = useCommandMenu(); + const setHotkeyScope = useSetHotkeyScope(); const goBackFromCommandMenu = useRecoilCallback( ({ snapshot, set }) => { @@ -66,64 +69,78 @@ export const useCommandMenuHistory = () => { } set(hasUserSelectedCommandState, false); + + setHotkeyScope(CommandMenuHotkeyScope.CommandMenuFocused, { + commandMenuOpen: true, + }); }; }, - [closeCommandMenu], + [closeCommandMenu, setHotkeyScope], ); - const navigateCommandMenuHistory = useRecoilCallback(({ snapshot, set }) => { - return (pageIndex: number) => { - const currentNavigationStack = snapshot - .getLoadable(commandMenuNavigationStackState) - .getValue(); + const navigateCommandMenuHistory = useRecoilCallback( + ({ snapshot, set }) => { + return (pageIndex: number) => { + const currentNavigationStack = snapshot + .getLoadable(commandMenuNavigationStackState) + .getValue(); - const newNavigationStack = currentNavigationStack.slice(0, pageIndex + 1); - - set(commandMenuNavigationStackState, newNavigationStack); - - const newNavigationStackItem = newNavigationStack.at(-1); - - if (!isDefined(newNavigationStackItem)) { - throw new Error( - `No command menu navigation stack item found for index ${pageIndex}`, + const newNavigationStack = currentNavigationStack.slice( + 0, + pageIndex + 1, ); - } - set(commandMenuPageState, newNavigationStackItem.page); - set(commandMenuPageInfoState, { - title: newNavigationStackItem.pageTitle, - Icon: newNavigationStackItem.pageIcon, - instanceId: newNavigationStackItem.pageId, - }); - const currentMorphItems = snapshot - .getLoadable(commandMenuNavigationMorphItemByPageState) - .getValue(); + set(commandMenuNavigationStackState, newNavigationStack); - for (const [pageId, morphItem] of currentMorphItems.entries()) { - if (!newNavigationStack.some((item) => item.pageId === pageId)) { - set( - activeTabIdComponentState.atomFamily({ - instanceId: getShowPageTabListComponentId({ - pageId, - targetObjectId: morphItem.recordId, - }), - }), - null, + const newNavigationStackItem = newNavigationStack.at(-1); + + if (!isDefined(newNavigationStackItem)) { + throw new Error( + `No command menu navigation stack item found for index ${pageIndex}`, ); } - } - const newMorphItems = new Map( - Array.from(currentMorphItems.entries()).filter(([pageId]) => - newNavigationStack.some((item) => item.pageId === pageId), - ), - ); + set(commandMenuPageState, newNavigationStackItem.page); + set(commandMenuPageInfoState, { + title: newNavigationStackItem.pageTitle, + Icon: newNavigationStackItem.pageIcon, + instanceId: newNavigationStackItem.pageId, + }); + const currentMorphItems = snapshot + .getLoadable(commandMenuNavigationMorphItemByPageState) + .getValue(); - set(commandMenuNavigationMorphItemByPageState, newMorphItems); + for (const [pageId, morphItem] of currentMorphItems.entries()) { + if (!newNavigationStack.some((item) => item.pageId === pageId)) { + set( + activeTabIdComponentState.atomFamily({ + instanceId: getShowPageTabListComponentId({ + pageId, + targetObjectId: morphItem.recordId, + }), + }), + null, + ); + } + } - set(hasUserSelectedCommandState, false); - }; - }, []); + const newMorphItems = new Map( + Array.from(currentMorphItems.entries()).filter(([pageId]) => + newNavigationStack.some((item) => item.pageId === pageId), + ), + ); + + set(commandMenuNavigationMorphItemByPageState, newMorphItems); + + set(hasUserSelectedCommandState, false); + + setHotkeyScope(CommandMenuHotkeyScope.CommandMenuFocused, { + commandMenuOpen: true, + }); + }; + }, + [setHotkeyScope], + ); return { goBackFromCommandMenu,