From fb772c76954c333bf8799d23bab8e7b3c261ebab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Mon, 13 Apr 2026 18:08:15 +0200 Subject: [PATCH] Sync command menu with main context store (#19650) ## PR description - The command menu in the side panel now reads directly from `MAIN_CONTEXT_STORE_INSTANCE_ID` instead of snapshotting the main context store into a separate side-panel instance when opening. This keeps the command menu always in sync with the current page state (selection, filters, view, etc.). - Removed the broadening/reset-to-selection feature (Backspace to clear context, "Reset to" button) since the command menu no longer maintains its own copy of the context. ## Video QA https://github.com/user-attachments/assets/5d5bc664-b6d4-431d-a271-6ce23d8a4ae0 --- packages/twenty-front/jest.config.mjs | 4 +- .../SidePanelCommandMenuItemDisplayPage.tsx | 22 -- .../useSetGlobalCommandMenuContext.test.tsx | 195 ------------- .../hooks/useCommandMenuHotKeys.ts | 28 +- ...useCopyContextStoreAndCommandMenuStates.ts | 144 ---------- .../hooks/useResetContextStoreStates.ts | 71 ----- .../hooks/useSetGlobalCommandMenuContext.ts | 182 ------------ .../hooks/useSetIsPageLayoutInEditMode.ts | 13 - .../components/SidePanelContainer.tsx | 7 +- .../SidePanelContextRecordsChip.tsx | 52 ---- .../SidePanelContextRecordChip.stories.tsx | 269 ------------------ .../SidePanelPreviousComponentInstanceId.ts | 1 - .../SidePanelResetContextToSelection.ts | 2 - ...anelCloseAnimationCompleteCleanup.test.tsx | 18 -- .../side-panel/hooks/useNavigateSidePanel.ts | 10 - ...eSidePanelCloseAnimationCompleteCleanup.ts | 37 +-- ...SidePanelResetContextToSelectionButton.tsx | 63 ---- .../root/components/SidePanelRootPage.tsx | 22 -- .../hooks/useResetPreviousSidePanelContext.ts | 21 -- 19 files changed, 17 insertions(+), 1144 deletions(-) delete mode 100644 packages/twenty-front/src/modules/command-menu/hooks/__tests__/useSetGlobalCommandMenuContext.test.tsx delete mode 100644 packages/twenty-front/src/modules/command-menu/hooks/useCopyContextStoreAndCommandMenuStates.ts delete mode 100644 packages/twenty-front/src/modules/command-menu/hooks/useResetContextStoreStates.ts delete mode 100644 packages/twenty-front/src/modules/command-menu/hooks/useSetGlobalCommandMenuContext.ts delete mode 100644 packages/twenty-front/src/modules/side-panel/components/SidePanelContextRecordsChip.tsx delete mode 100644 packages/twenty-front/src/modules/side-panel/components/__stories__/SidePanelContextRecordChip.stories.tsx delete mode 100644 packages/twenty-front/src/modules/side-panel/constants/SidePanelPreviousComponentInstanceId.ts delete mode 100644 packages/twenty-front/src/modules/side-panel/constants/SidePanelResetContextToSelection.ts delete mode 100644 packages/twenty-front/src/modules/side-panel/pages/root/components/SidePanelResetContextToSelectionButton.tsx delete mode 100644 packages/twenty-front/src/modules/side-panel/pages/root/hooks/useResetPreviousSidePanelContext.ts diff --git a/packages/twenty-front/jest.config.mjs b/packages/twenty-front/jest.config.mjs index ef2af16ffc..7b86e1dd44 100644 --- a/packages/twenty-front/jest.config.mjs +++ b/packages/twenty-front/jest.config.mjs @@ -61,8 +61,8 @@ const jestConfig = { extensionsToTreatAsEsm: ['.ts', '.tsx'], coverageThreshold: { global: { - statements: 48.4, - lines: 47.0, + statements: 48, + lines: 46, functions: 39.5, }, }, diff --git a/packages/twenty-front/src/modules/command-menu-item/display/components/SidePanelCommandMenuItemDisplayPage.tsx b/packages/twenty-front/src/modules/command-menu-item/display/components/SidePanelCommandMenuItemDisplayPage.tsx index eb28c1b03f..fd44b5c30f 100644 --- a/packages/twenty-front/src/modules/command-menu-item/display/components/SidePanelCommandMenuItemDisplayPage.tsx +++ b/packages/twenty-front/src/modules/command-menu-item/display/components/SidePanelCommandMenuItemDisplayPage.tsx @@ -4,20 +4,14 @@ import { PINNED_COMMAND_MENU_ITEMS_GAP } from '@/command-menu-item/display/const import { commandMenuPinnedInlineLayoutState } from '@/command-menu-item/display/states/commandMenuPinnedInlineLayoutState'; import { getVisibleCommandMenuItemCountForContainerWidth } from '@/command-menu-item/display/utils/getVisibleCommandMenuItemCountForContainerWidth'; import { groupCommandMenuItems } from '@/command-menu-item/utils/groupCommandMenuItems'; -import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; import { SidePanelList } from '@/side-panel/components/SidePanelList'; -import { SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelPreviousComponentInstanceId'; -import { SIDE_PANEL_RESET_CONTEXT_TO_SELECTION } from '@/side-panel/constants/SidePanelResetContextToSelection'; -import { SidePanelResetContextToSelectionButton } from '@/side-panel/pages/root/components/SidePanelResetContextToSelectionButton'; import { useFilterCommandMenuItemsWithSidePanelSearch } from '@/side-panel/pages/root/hooks/useFilterCommandMenuItemsWithSidePanelSearch'; import { sidePanelSearchState } from '@/side-panel/states/sidePanelSearchState'; -import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useLingui } from '@lingui/react/macro'; import { isNumber } from '@sniptt/guards'; import { useContext, useMemo } from 'react'; -import { isDefined } from 'twenty-shared/utils'; import { CommandMenuItemAvailabilityType } from '~/generated-metadata/graphql'; export const SidePanelCommandMenuItemDisplayPage = () => { @@ -99,24 +93,8 @@ export const SidePanelCommandMenuItemDisplayPage = () => { ...(noResults ? fallbackCommandMenuItems : []), ].map((item) => item.id); - // oxlint-disable-next-line twenty/matching-state-variable - const previousContextStoreCurrentObjectMetadataItemId = - useAtomComponentStateValue( - contextStoreCurrentObjectMetadataItemIdComponentState, - SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID, - ); - - if (isDefined(previousContextStoreCurrentObjectMetadataItemId)) { - selectableItemIds.unshift(SIDE_PANEL_RESET_CONTEXT_TO_SELECTION); - } - return ( - {isDefined(previousContextStoreCurrentObjectMetadataItemId) && ( - - - - )} {matchingPinnedItems.length > 0 && ( {matchingPinnedItems.map((item) => ( diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useSetGlobalCommandMenuContext.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useSetGlobalCommandMenuContext.test.tsx deleted file mode 100644 index 9ce9e1e8bc..0000000000 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useSetGlobalCommandMenuContext.test.tsx +++ /dev/null @@ -1,195 +0,0 @@ -import { renderHook } from '@testing-library/react'; -import { act } from 'react'; - -import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; -import { SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelPreviousComponentInstanceId'; -import { useSetGlobalCommandMenuContext } from '@/command-menu/hooks/useSetGlobalCommandMenuContext'; -import { sidePanelPageInfoState } from '@/side-panel/states/sidePanelPageInfoState'; -import { hasUserSelectedSidePanelListItemState } from '@/side-panel/states/hasUserSelectedSidePanelListItemState'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; -import { contextStoreAnyFieldFilterValueComponentState } from '@/context-store/states/contextStoreAnyFieldFilterValueComponentState'; -import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; -import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; -import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; -import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; -import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; -import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { getJestMetadataAndApolloMocksAndCommandMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndCommandMenuWrapper'; -import { mockedPersonRecords } from '~/testing/mock-data/generated/data/people/mock-people-data'; -import { getTestEnrichedObjectMetadataItemsMock } from '~/testing/utils/getTestEnrichedObjectMetadataItemsMock'; -import { contextStoreFilterGroupsComponentState } from '@/context-store/states/contextStoreFilterGroupsComponentState'; - -const personMockObjectMetadataItem = - getTestEnrichedObjectMetadataItemsMock().find( - (item) => item.nameSingular === 'person', - )!; - -const peopleMock = [...mockedPersonRecords]; - -jotaiStore.set( - recordStoreFamilyState.atomFamily(peopleMock[0].id), - peopleMock[0], -); -jotaiStore.set( - recordStoreFamilyState.atomFamily(peopleMock[1].id), - peopleMock[1], -); - -const wrapper = getJestMetadataAndApolloMocksAndCommandMenuWrapper({ - apolloMocks: [], - componentInstanceId: SIDE_PANEL_COMPONENT_INSTANCE_ID, - contextStoreCurrentObjectMetadataNameSingular: - personMockObjectMetadataItem.nameSingular, - contextStoreCurrentViewId: 'my-view-id', - contextStoreTargetedRecordsRule: { - mode: 'selection', - selectedRecordIds: [peopleMock[0].id, peopleMock[1].id], - }, - contextStoreNumberOfSelectedRecords: 2, - contextStoreCurrentViewType: ContextStoreViewType.Table, -}); - -describe('useSetGlobalCommandMenuContext', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('should reset all command menu context states', () => { - const { result } = renderHook( - () => { - const { setGlobalCommandMenuContext } = - useSetGlobalCommandMenuContext(); - - const contextStoreTargetedRecordsRule = useAtomComponentStateValue( - contextStoreTargetedRecordsRuleComponentState, - SIDE_PANEL_COMPONENT_INSTANCE_ID, - ); - - const contextStoreNumberOfSelectedRecords = useAtomComponentStateValue( - contextStoreNumberOfSelectedRecordsComponentState, - SIDE_PANEL_COMPONENT_INSTANCE_ID, - ); - - const contextStoreFilters = useAtomComponentStateValue( - contextStoreFiltersComponentState, - SIDE_PANEL_COMPONENT_INSTANCE_ID, - ); - - const contextStoreFilterGroups = useAtomComponentStateValue( - contextStoreFilterGroupsComponentState, - SIDE_PANEL_COMPONENT_INSTANCE_ID, - ); - - const contextStoreAnyFieldFilterValue = useAtomComponentStateValue( - contextStoreAnyFieldFilterValueComponentState, - SIDE_PANEL_COMPONENT_INSTANCE_ID, - ); - - const contextStoreCurrentViewType = useAtomComponentStateValue( - contextStoreCurrentViewTypeComponentState, - SIDE_PANEL_COMPONENT_INSTANCE_ID, - ); - - return { - setGlobalCommandMenuContext, - contextStoreTargetedRecordsRule, - contextStoreNumberOfSelectedRecords, - contextStoreFilters, - contextStoreFilterGroups, - contextStoreCurrentViewType, - contextStoreAnyFieldFilterValue, - }; - }, - { - wrapper, - }, - ); - - expect(result.current.contextStoreTargetedRecordsRule).toEqual({ - mode: 'selection', - selectedRecordIds: [peopleMock[0].id, peopleMock[1].id], - }); - expect(result.current.contextStoreNumberOfSelectedRecords).toBe(2); - expect(result.current.contextStoreFilters).toEqual([]); - expect(result.current.contextStoreAnyFieldFilterValue).toEqual(''); - expect(result.current.contextStoreCurrentViewType).toBe( - ContextStoreViewType.Table, - ); - const sidePanelPageInfo = jotaiStore.get(sidePanelPageInfoState.atom); - expect(sidePanelPageInfo).toEqual({ - title: undefined, - Icon: undefined, - instanceId: '', - }); - const hasUserSelectedSidePanelListItem = jotaiStore.get( - hasUserSelectedSidePanelListItemState.atom, - ); - expect(hasUserSelectedSidePanelListItem).toBe(false); - - act(() => { - result.current.setGlobalCommandMenuContext(); - }); - - expect(result.current.contextStoreTargetedRecordsRule).toEqual({ - mode: 'selection', - selectedRecordIds: [], - }); - expect(result.current.contextStoreNumberOfSelectedRecords).toBe(0); - expect(result.current.contextStoreFilters).toEqual([]); - expect(result.current.contextStoreAnyFieldFilterValue).toEqual(''); - expect(result.current.contextStoreCurrentViewType).toBe( - ContextStoreViewType.Table, - ); - const sidePanelPageInfoAfter = jotaiStore.get(sidePanelPageInfoState.atom); - expect(sidePanelPageInfoAfter).toEqual({ - title: undefined, - Icon: undefined, - instanceId: '', - }); - const hasUserSelectedSidePanelListItemAfter = jotaiStore.get( - hasUserSelectedSidePanelListItemState.atom, - ); - expect(hasUserSelectedSidePanelListItemAfter).toBe(false); - }); - - it('should copy context store states to previous instance before resetting', () => { - const { result } = renderHook( - () => { - const { setGlobalCommandMenuContext } = - useSetGlobalCommandMenuContext(); - - // oxlint-disable-next-line twenty/matching-state-variable - const previousTargetedRecordsRule = useAtomComponentStateValue( - contextStoreTargetedRecordsRuleComponentState, - SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID, - ); - - // oxlint-disable-next-line twenty/matching-state-variable - const previousNumberOfSelectedRecords = useAtomComponentStateValue( - contextStoreNumberOfSelectedRecordsComponentState, - SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID, - ); - - return { - setGlobalCommandMenuContext, - previousTargetedRecordsRule, - previousNumberOfSelectedRecords, - }; - }, - { - wrapper, - }, - ); - - act(() => { - result.current.setGlobalCommandMenuContext(); - }); - - expect(result.current.previousTargetedRecordsRule).toEqual({ - mode: 'selection', - selectedRecordIds: [peopleMock[0].id, peopleMock[1].id], - }); - expect(result.current.previousNumberOfSelectedRecords).toBe(2); - }); -}); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHotKeys.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHotKeys.ts index 73199d2b71..6a4cda074b 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHotKeys.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenuHotKeys.ts @@ -1,7 +1,4 @@ -import { useSetGlobalCommandMenuContext } from '@/command-menu/hooks/useSetGlobalCommandMenuContext'; -import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { useKeyboardShortcutMenu } from '@/keyboard-shortcut-menu/hooks/useKeyboardShortcutMenu'; -import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; import { SIDE_PANEL_FOCUS_ID } from '@/side-panel/constants/SidePanelFocusId'; import { useOpenAskAIPageInSidePanel } from '@/side-panel/hooks/useOpenAskAIPageInSidePanel'; import { useOpenRecordsSearchPageInSidePanel } from '@/side-panel/hooks/useOpenRecordsSearchPageInSidePanel'; @@ -11,7 +8,6 @@ import { sidePanelPageState } from '@/side-panel/states/sidePanelPageState'; import { sidePanelSearchState } from '@/side-panel/states/sidePanelSearchState'; import { useGlobalHotkeys } from '@/ui/utilities/hotkey/hooks/useGlobalHotkeys'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; -import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { isNonEmptyString } from '@sniptt/guards'; @@ -29,8 +25,6 @@ export const useCommandMenuHotKeys = () => { const { goBackFromSidePanel, goBackOneSubPageOrMainPage } = useSidePanelHistory(); - const { setGlobalCommandMenuContext } = useSetGlobalCommandMenuContext(); - const sidePanelSearch = useAtomStateValue(sidePanelSearchState); const { closeKeyboardShortcutMenu } = useKeyboardShortcutMenu(); @@ -39,11 +33,6 @@ export const useCommandMenuHotKeys = () => { const isAiEnabled = useIsFeatureEnabled(FeatureFlagKey.IS_AI_ENABLED); - const contextStoreTargetedRecordsRule = useAtomComponentStateValue( - contextStoreTargetedRecordsRuleComponentState, - SIDE_PANEL_COMPONENT_INSTANCE_ID, - ); - useGlobalHotkeys({ keys: ['ctrl+k', 'meta+k'], callback: () => { @@ -99,27 +88,12 @@ export const useCommandMenuHotKeys = () => { return; } - if ( - sidePanelPage === SidePanelPages.CommandMenuDisplay && - !( - contextStoreTargetedRecordsRule.mode === 'selection' && - contextStoreTargetedRecordsRule.selectedRecordIds.length === 0 - ) - ) { - setGlobalCommandMenuContext(); - } if (sidePanelPage !== SidePanelPages.CommandMenuDisplay) { goBackOneSubPageOrMainPage(); } }, focusId: SIDE_PANEL_FOCUS_ID, - dependencies: [ - sidePanelPage, - sidePanelSearch, - contextStoreTargetedRecordsRule, - goBackOneSubPageOrMainPage, - setGlobalCommandMenuContext, - ], + dependencies: [sidePanelPage, sidePanelSearch, goBackOneSubPageOrMainPage], options: { preventDefault: false, enableOnFormTags: false, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCopyContextStoreAndCommandMenuStates.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCopyContextStoreAndCommandMenuStates.ts deleted file mode 100644 index f98c465a53..0000000000 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCopyContextStoreAndCommandMenuStates.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { contextStoreAnyFieldFilterValueComponentState } from '@/context-store/states/contextStoreAnyFieldFilterValueComponentState'; -import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; -import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; -import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; -import { contextStoreFilterGroupsComponentState } from '@/context-store/states/contextStoreFilterGroupsComponentState'; -import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; -import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState'; -import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; -import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; -import { useCallback } from 'react'; -import { useStore } from 'jotai'; - -export const useCopyContextStoreStates = () => { - const store = useStore(); - const copyContextStoreStates = useCallback( - ({ - instanceIdToCopyFrom, - instanceIdToCopyTo, - }: { - instanceIdToCopyFrom: string; - instanceIdToCopyTo: string; - }) => { - const contextStoreCurrentObjectMetadataItemId = store.get( - contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ); - - store.set( - contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreCurrentObjectMetadataItemId, - ); - - const contextStoreTargetedRecordsRule = store.get( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ); - - store.set( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreTargetedRecordsRule, - ); - - const contextStoreNumberOfSelectedRecords = store.get( - contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ); - - store.set( - contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreNumberOfSelectedRecords, - ); - - const contextStoreFilters = store.get( - contextStoreFiltersComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ); - - store.set( - contextStoreFiltersComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreFilters, - ); - - const contextStoreFilterGroups = store.get( - contextStoreFilterGroupsComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ); - - store.set( - contextStoreFilterGroupsComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreFilterGroups, - ); - - const contextStoreAnyFieldFilterValue = store.get( - contextStoreAnyFieldFilterValueComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ); - - store.set( - contextStoreAnyFieldFilterValueComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreAnyFieldFilterValue, - ); - - const contextStoreCurrentViewId = store.get( - contextStoreCurrentViewIdComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ); - - store.set( - contextStoreCurrentViewIdComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreCurrentViewId, - ); - - const contextStoreCurrentViewType = store.get( - contextStoreCurrentViewTypeComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ); - - store.set( - contextStoreCurrentViewTypeComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreCurrentViewType, - ); - - const contextStoreIsFullTabWidgetInEditMode = store.get( - contextStoreIsPageInEditModeComponentState.atomFamily({ - instanceId: instanceIdToCopyFrom, - }), - ); - - store.set( - contextStoreIsPageInEditModeComponentState.atomFamily({ - instanceId: instanceIdToCopyTo, - }), - contextStoreIsFullTabWidgetInEditMode, - ); - }, - [store], - ); - - return { copyContextStoreStates }; -}; diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useResetContextStoreStates.ts b/packages/twenty-front/src/modules/command-menu/hooks/useResetContextStoreStates.ts deleted file mode 100644 index 87bc3c6650..0000000000 --- a/packages/twenty-front/src/modules/command-menu/hooks/useResetContextStoreStates.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { contextStoreAnyFieldFilterValueComponentState } from '@/context-store/states/contextStoreAnyFieldFilterValueComponentState'; -import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; -import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; -import { contextStoreFilterGroupsComponentState } from '@/context-store/states/contextStoreFilterGroupsComponentState'; -import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; -import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; -import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; -import { useCallback } from 'react'; -import { useStore } from 'jotai'; - -export const useResetContextStoreStates = () => { - const store = useStore(); - const resetContextStoreStates = useCallback( - (instanceId: string) => { - store.set( - contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ - instanceId, - }), - undefined, - ); - - store.set( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId, - }), - { - mode: 'selection', - selectedRecordIds: [], - }, - ); - - store.set( - contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ - instanceId, - }), - 0, - ); - - store.set( - contextStoreFiltersComponentState.atomFamily({ - instanceId, - }), - [], - ); - - store.set( - contextStoreFilterGroupsComponentState.atomFamily({ - instanceId, - }), - [], - ); - - store.set( - contextStoreAnyFieldFilterValueComponentState.atomFamily({ - instanceId, - }), - '', - ); - - store.set( - contextStoreCurrentViewIdComponentState.atomFamily({ - instanceId, - }), - undefined, - ); - }, - [store], - ); - - return { resetContextStoreStates }; -}; diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useSetGlobalCommandMenuContext.ts b/packages/twenty-front/src/modules/command-menu/hooks/useSetGlobalCommandMenuContext.ts deleted file mode 100644 index 48ebd872c0..0000000000 --- a/packages/twenty-front/src/modules/command-menu/hooks/useSetGlobalCommandMenuContext.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; -import { SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelPreviousComponentInstanceId'; -import { sidePanelPageInfoState } from '@/side-panel/states/sidePanelPageInfoState'; -import { hasUserSelectedSidePanelListItemState } from '@/side-panel/states/hasUserSelectedSidePanelListItemState'; -import { contextStoreAnyFieldFilterValueComponentState } from '@/context-store/states/contextStoreAnyFieldFilterValueComponentState'; -import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; -import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; -import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; -import { contextStoreFilterGroupsComponentState } from '@/context-store/states/contextStoreFilterGroupsComponentState'; -import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; -import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState'; -import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; -import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; -import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; -import { atom, useStore } from 'jotai'; -import { useCallback } from 'react'; - -export const useSetGlobalCommandMenuContext = () => { - const store = useStore(); - - const setGlobalCommandMenuContext = useCallback(() => { - store.set( - atom(null, (get, batchSet) => { - const fromId = SIDE_PANEL_COMPONENT_INSTANCE_ID; - const toId = SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID; - - batchSet( - contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ - instanceId: toId, - }), - get( - contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({ - instanceId: fromId, - }), - ), - ); - - batchSet( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: toId, - }), - get( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: fromId, - }), - ), - ); - - batchSet( - contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ - instanceId: toId, - }), - get( - contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ - instanceId: fromId, - }), - ), - ); - - batchSet( - contextStoreFiltersComponentState.atomFamily({ - instanceId: toId, - }), - get( - contextStoreFiltersComponentState.atomFamily({ - instanceId: fromId, - }), - ), - ); - - batchSet( - contextStoreFilterGroupsComponentState.atomFamily({ - instanceId: toId, - }), - get( - contextStoreFilterGroupsComponentState.atomFamily({ - instanceId: fromId, - }), - ), - ); - - batchSet( - contextStoreAnyFieldFilterValueComponentState.atomFamily({ - instanceId: toId, - }), - get( - contextStoreAnyFieldFilterValueComponentState.atomFamily({ - instanceId: fromId, - }), - ), - ); - - batchSet( - contextStoreCurrentViewIdComponentState.atomFamily({ - instanceId: toId, - }), - get( - contextStoreCurrentViewIdComponentState.atomFamily({ - instanceId: fromId, - }), - ), - ); - - batchSet( - contextStoreCurrentViewTypeComponentState.atomFamily({ - instanceId: toId, - }), - get( - contextStoreCurrentViewTypeComponentState.atomFamily({ - instanceId: fromId, - }), - ), - ); - - batchSet( - contextStoreIsPageInEditModeComponentState.atomFamily({ - instanceId: toId, - }), - get( - contextStoreIsPageInEditModeComponentState.atomFamily({ - instanceId: fromId, - }), - ), - ); - - batchSet( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: fromId, - }), - { mode: 'selection', selectedRecordIds: [] }, - ); - - batchSet( - contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ - instanceId: fromId, - }), - 0, - ); - - batchSet( - contextStoreFiltersComponentState.atomFamily({ - instanceId: fromId, - }), - [], - ); - - batchSet( - contextStoreFilterGroupsComponentState.atomFamily({ - instanceId: fromId, - }), - [], - ); - - batchSet( - contextStoreAnyFieldFilterValueComponentState.atomFamily({ - instanceId: fromId, - }), - '', - ); - - batchSet( - contextStoreCurrentViewTypeComponentState.atomFamily({ - instanceId: fromId, - }), - ContextStoreViewType.Table, - ); - - batchSet(sidePanelPageInfoState.atom, { - title: undefined, - Icon: undefined, - instanceId: '', - }); - - batchSet(hasUserSelectedSidePanelListItemState.atom, false); - }), - ); - }, [store]); - - return { - setGlobalCommandMenuContext, - }; -}; diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useSetIsPageLayoutInEditMode.ts b/packages/twenty-front/src/modules/page-layout/hooks/useSetIsPageLayoutInEditMode.ts index ea524697b9..2ee5a61ef6 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useSetIsPageLayoutInEditMode.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useSetIsPageLayoutInEditMode.ts @@ -10,8 +10,6 @@ import { hasInitializedFieldsWidgetGroupsDraftComponentState } from '@/page-layo import { isDashboardInEditModeComponentState } from '@/page-layout/states/isDashboardInEditModeComponentState'; import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState'; -import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; -import { isSidePanelOpenedState } from '@/side-panel/states/isSidePanelOpenedState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState'; import { useStore } from 'jotai'; @@ -98,17 +96,6 @@ export const useSetIsPageLayoutInEditMode = (pageLayoutIdFromProps: string) => { store.set(contextStoreIsFullTabWidgetInEditModeState, value); store.set(currentPageLayoutIdState.atom, value ? pageLayoutId : null); - - const isSidePanelOpened = store.get(isSidePanelOpenedState.atom); - - if (isSidePanelOpened) { - store.set( - contextStoreIsPageInEditModeComponentState.atomFamily({ - instanceId: SIDE_PANEL_COMPONENT_INSTANCE_ID, - }), - value, - ); - } }, [ isDashboardInEditModeState, diff --git a/packages/twenty-front/src/modules/side-panel/components/SidePanelContainer.tsx b/packages/twenty-front/src/modules/side-panel/components/SidePanelContainer.tsx index d6ff95812f..1da5279e10 100644 --- a/packages/twenty-front/src/modules/side-panel/components/SidePanelContainer.tsx +++ b/packages/twenty-front/src/modules/side-panel/components/SidePanelContainer.tsx @@ -1,5 +1,6 @@ import { styled } from '@linaria/react'; import { CommandMenuComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuComponentInstanceContext'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; @@ -30,7 +31,7 @@ type SidePanelContainerProps = { export const SidePanelContainer = ({ children }: SidePanelContainerProps) => { const contextStoreCurrentObjectMetadataItemId = useAtomComponentStateValue( contextStoreCurrentObjectMetadataItemIdComponentState, - SIDE_PANEL_COMPONENT_INSTANCE_ID, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); const isMobile = useIsMobile(); @@ -43,7 +44,7 @@ export const SidePanelContainer = ({ children }: SidePanelContainerProps) => { const contextStoreCurrentViewId = useAtomComponentStateValue( contextStoreCurrentViewIdComponentState, - SIDE_PANEL_COMPONENT_INSTANCE_ID, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); const recordIndexId = getRecordIndexIdFromObjectNamePluralAndViewId( @@ -54,7 +55,7 @@ export const SidePanelContainer = ({ children }: SidePanelContainerProps) => { return ( { - const { objectMetadataItem } = useObjectMetadataItemById({ - objectId: objectMetadataItemId, - }); - const allowRequestsToTwentyIcons = useAtomStateValue( - allowRequestsToTwentyIconsState, - ); - - const { records, loading, totalCount } = - useFindManyRecordsSelectedInContextStore({ - limit: 3, - instanceId, - }); - - if (loading || !totalCount || records.length === 0) { - return null; - } - - const Avatars = records.map((record) => ( - - )); - - return ( - - ); -}; diff --git a/packages/twenty-front/src/modules/side-panel/components/__stories__/SidePanelContextRecordChip.stories.tsx b/packages/twenty-front/src/modules/side-panel/components/__stories__/SidePanelContextRecordChip.stories.tsx deleted file mode 100644 index f73d666055..0000000000 --- a/packages/twenty-front/src/modules/side-panel/components/__stories__/SidePanelContextRecordChip.stories.tsx +++ /dev/null @@ -1,269 +0,0 @@ -import { gql } from '@apollo/client'; -import { - type Decorator, - type Meta, - type StoryObj, -} from '@storybook/react-vite'; - -import { SidePanelContextRecordsChip } from '@/side-panel/components/SidePanelContextRecordsChip'; -import { PreComputedChipGeneratorsContext } from '@/object-metadata/contexts/PreComputedChipGeneratorsContext'; -import { type RecordChipData } from '@/object-record/record-field/ui/types/RecordChipData'; -import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore'; -import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { ComponentDecorator } from 'twenty-ui/testing'; -import { getJestMetadataAndApolloMocksAndCommandMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndCommandMenuWrapper'; -import { mockedCompanyRecords } from '~/testing/mock-data/generated/data/companies/mock-companies-data'; -import { getTestEnrichedObjectMetadataItemsMock } from '~/testing/utils/getTestEnrichedObjectMetadataItemsMock'; - -const FIND_MANY_COMPANIES = gql` - query FindManyCompanies( - $filter: CompanyFilterInput - $orderBy: [CompanyOrderByInput] - $lastCursor: String - $limit: Int - ) { - companies( - filter: $filter - orderBy: $orderBy - first: $limit - after: $lastCursor - ) { - edges { - node { - __typename - accountOwnerId - address { - addressStreet1 - addressStreet2 - addressCity - addressState - addressCountry - addressPostcode - addressLat - addressLng - } - annualRecurringRevenue { - amountMicros - currencyCode - } - createdAt - createdBy { - source - workspaceMemberId - name - context - } - deletedAt - domainName { - primaryLinkUrl - primaryLinkLabel - secondaryLinks - } - employees - id - idealCustomerProfile - introVideo { - primaryLinkUrl - primaryLinkLabel - secondaryLinks - } - linkedinLink { - primaryLinkUrl - primaryLinkLabel - secondaryLinks - } - name - position - tagline - updatedAt - visaSponsorship - workPolicy - xLink { - primaryLinkUrl - primaryLinkLabel - secondaryLinks - } - } - cursor - } - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - totalCount - } - } -`; - -const companyMockObjectMetadataItem = - getTestEnrichedObjectMetadataItemsMock().find( - (item) => item.nameSingular === 'company', - ); - -const companyMock = mockedCompanyRecords[0]; - -const chipGeneratorPerObjectPerField: Record< - string, - Record RecordChipData> -> = { - company: { - name: (record: ObjectRecord): RecordChipData => ({ - recordId: record.id, - name: record.name as string, - avatarUrl: '', - avatarType: 'rounded', - isLabelIdentifier: true, - objectNameSingular: 'company', - }), - }, -}; - -const identifierChipGeneratorPerObject: Record< - string, - (record: ObjectRecord) => RecordChipData -> = { - company: chipGeneratorPerObjectPerField.company.name, -}; - -const ChipGeneratorsDecorator: Decorator = (Story) => ( - - - -); - -const createContextStoreWrapper = ({ - companies, - componentInstanceId, -}: { - companies: typeof mockedCompanyRecords; - componentInstanceId: string; -}) => { - return getJestMetadataAndApolloMocksAndCommandMenuWrapper({ - apolloMocks: [ - { - request: { - query: FIND_MANY_COMPANIES, - variables: { - filter: { - id: { in: companies.map((company) => company.id) }, - deletedAt: { is: 'NOT_NULL' }, - }, - orderBy: [{ position: 'AscNullsFirst' }], - limit: 3, - }, - }, - result: { - data: { - companies: { - edges: companies.slice(0, 3).map((company, index) => ({ - node: company, - cursor: `cursor-${index + 1}`, - })), - pageInfo: { - hasNextPage: companies.length > 3, - hasPreviousPage: false, - startCursor: 'cursor-1', - endCursor: - companies.length > 0 - ? `cursor-${Math.min(companies.length, 3)}` - : null, - }, - totalCount: companies.length, - }, - }, - }, - }, - ], - componentInstanceId, - contextStoreCurrentObjectMetadataNameSingular: - companyMockObjectMetadataItem?.nameSingular, - contextStoreTargetedRecordsRule: { - mode: 'selection', - selectedRecordIds: companies.map((company) => company.id), - }, - contextStoreNumberOfSelectedRecords: companies.length, - onInitializeJotaiStore: () => { - for (const company of companies) { - jotaiStore.set( - recordStoreFamilyState.atomFamily(company.id), - company as ObjectRecord, - ); - } - }, - }); -}; - -const ContextStoreDecorator: Decorator = (Story) => { - const ContextStoreWrapper = createContextStoreWrapper({ - companies: [companyMock], - componentInstanceId: '1', - }); - - return ( - - - - ); -}; - -const meta: Meta = { - title: 'Modules/SidePanel/SidePanelContextRecordChip', - component: SidePanelContextRecordsChip, - decorators: [ - ContextStoreDecorator, - ChipGeneratorsDecorator, - ComponentDecorator, - ], - args: { - objectMetadataItemId: companyMockObjectMetadataItem?.id, - }, -}; - -export default meta; -type Story = StoryObj; - -export const Default: Story = {}; - -export const WithTwoCompanies: Story = { - decorators: [ - (Story) => { - const twoCompaniesMock = mockedCompanyRecords.slice(0, 2); - const TwoCompaniesWrapper = createContextStoreWrapper({ - companies: twoCompaniesMock, - componentInstanceId: '2', - }); - - return ( - - - - ); - }, - ], -}; - -export const WithTenCompanies: Story = { - decorators: [ - (Story) => { - const tenCompaniesMock = mockedCompanyRecords.slice(0, 10); - const TenCompaniesWrapper = createContextStoreWrapper({ - companies: tenCompaniesMock, - componentInstanceId: '3', - }); - - return ( - - - - ); - }, - ], -}; diff --git a/packages/twenty-front/src/modules/side-panel/constants/SidePanelPreviousComponentInstanceId.ts b/packages/twenty-front/src/modules/side-panel/constants/SidePanelPreviousComponentInstanceId.ts deleted file mode 100644 index 3f78a32bde..0000000000 --- a/packages/twenty-front/src/modules/side-panel/constants/SidePanelPreviousComponentInstanceId.ts +++ /dev/null @@ -1 +0,0 @@ -export const SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID = 'side-panel-previous'; diff --git a/packages/twenty-front/src/modules/side-panel/constants/SidePanelResetContextToSelection.ts b/packages/twenty-front/src/modules/side-panel/constants/SidePanelResetContextToSelection.ts deleted file mode 100644 index 1c6047cb27..0000000000 --- a/packages/twenty-front/src/modules/side-panel/constants/SidePanelResetContextToSelection.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const SIDE_PANEL_RESET_CONTEXT_TO_SELECTION = - 'reset-context-to-selection'; diff --git a/packages/twenty-front/src/modules/side-panel/hooks/__tests__/useSidePanelCloseAnimationCompleteCleanup.test.tsx b/packages/twenty-front/src/modules/side-panel/hooks/__tests__/useSidePanelCloseAnimationCompleteCleanup.test.tsx index 6631814f70..cb959f8bc3 100644 --- a/packages/twenty-front/src/modules/side-panel/hooks/__tests__/useSidePanelCloseAnimationCompleteCleanup.test.tsx +++ b/packages/twenty-front/src/modules/side-panel/hooks/__tests__/useSidePanelCloseAnimationCompleteCleanup.test.tsx @@ -2,9 +2,7 @@ import { renderHook } from '@testing-library/react'; import { Provider as JotaiProvider } from 'jotai'; import { act } from 'react'; import { MemoryRouter } from 'react-router-dom'; -import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; import { SIDE_PANEL_CONTEXT_CHIP_GROUPS_DROPDOWN_ID } from '@/side-panel/constants/SidePanelContextChipGroupsDropdownId'; -import { SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelPreviousComponentInstanceId'; import { useSidePanelCloseAnimationCompleteCleanup } from '@/side-panel/hooks/useSidePanelCloseAnimationCompleteCleanup'; import { sidePanelNavigationStackState } from '@/side-panel/states/sidePanelNavigationStackState'; import { sidePanelPageInfoState } from '@/side-panel/states/sidePanelPageInfoState'; @@ -21,7 +19,6 @@ import { SidePanelPages } from 'twenty-shared/types'; import { IconList } from 'twenty-ui/display'; const mockCloseDropdown = jest.fn(); -const mockResetContextStoreStates = jest.fn(); const mockResetSelectedItem = jest.fn(); const mockEmitSidePanelCloseEvent = jest.fn(); @@ -31,12 +28,6 @@ jest.mock('@/ui/layout/dropdown/hooks/useCloseDropdown', () => ({ }), })); -jest.mock('@/command-menu/hooks/useResetContextStoreStates', () => ({ - useResetContextStoreStates: () => ({ - resetContextStoreStates: mockResetContextStoreStates, - }), -})); - jest.mock('@/ui/layout/selectable-list/hooks/useSelectableList', () => ({ useSelectableList: () => ({ resetSelectedItem: mockResetSelectedItem, @@ -162,20 +153,11 @@ describe('useSidePanelCloseAnimationCompleteCleanup', () => { }); expect(mockCloseDropdown).toHaveBeenCalledTimes(1); - expect(mockResetContextStoreStates).toHaveBeenCalledTimes(2); expect(mockResetSelectedItem).toHaveBeenCalledTimes(1); expect(mockEmitSidePanelCloseEvent).toHaveBeenCalledTimes(1); expect(mockCloseDropdown).toHaveBeenCalledWith( SIDE_PANEL_CONTEXT_CHIP_GROUPS_DROPDOWN_ID, ); - expect(mockResetContextStoreStates).toHaveBeenNthCalledWith( - 1, - SIDE_PANEL_COMPONENT_INSTANCE_ID, - ); - expect(mockResetContextStoreStates).toHaveBeenNthCalledWith( - 2, - SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID, - ); }); }); diff --git a/packages/twenty-front/src/modules/side-panel/hooks/useNavigateSidePanel.ts b/packages/twenty-front/src/modules/side-panel/hooks/useNavigateSidePanel.ts index 8ee88b0d69..c8915bb624 100644 --- a/packages/twenty-front/src/modules/side-panel/hooks/useNavigateSidePanel.ts +++ b/packages/twenty-front/src/modules/side-panel/hooks/useNavigateSidePanel.ts @@ -1,7 +1,6 @@ import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; import { SIDE_PANEL_FOCUS_ID } from '@/side-panel/constants/SidePanelFocusId'; import { useSidePanelCloseAnimationCompleteCleanup } from '@/side-panel/hooks/useSidePanelCloseAnimationCompleteCleanup'; -import { useCopyContextStoreStates } from '@/command-menu/hooks/useCopyContextStoreAndCommandMenuStates'; import { sidePanelNavigationMorphItemsByPageState } from '@/side-panel/states/sidePanelNavigationMorphItemsByPageState'; import { sidePanelNavigationStackState } from '@/side-panel/states/sidePanelNavigationStackState'; import { sidePanelPageInfoState } from '@/side-panel/states/sidePanelPageInfoState'; @@ -10,7 +9,6 @@ import { sidePanelShouldFocusTitleInputComponentState } from '@/side-panel/state import { hasUserSelectedSidePanelListItemState } from '@/side-panel/states/hasUserSelectedSidePanelListItemState'; import { isSidePanelClosingState } from '@/side-panel/states/isSidePanelClosingState'; import { isSidePanelOpenedState } from '@/side-panel/states/isSidePanelOpenedState'; -import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack'; import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType'; import { useStore } from 'jotai'; @@ -29,8 +27,6 @@ export type SidePanelNavigationStackItem = { export const useNavigateSidePanel = () => { const store = useStore(); - const { copyContextStoreStates } = useCopyContextStoreStates(); - const { sidePanelCloseAnimationCompleteCleanup } = useSidePanelCloseAnimationCompleteCleanup(); @@ -62,15 +58,9 @@ export const useNavigateSidePanel = () => { }, }); - copyContextStoreStates({ - instanceIdToCopyFrom: MAIN_CONTEXT_STORE_INSTANCE_ID, - instanceIdToCopyTo: SIDE_PANEL_COMPONENT_INSTANCE_ID, - }); - store.set(isSidePanelOpenedState.atom, true); store.set(hasUserSelectedSidePanelListItemState.atom, false); }, [ - copyContextStoreStates, sidePanelCloseAnimationCompleteCleanup, pushFocusItemToFocusStack, store, diff --git a/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelCloseAnimationCompleteCleanup.ts b/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelCloseAnimationCompleteCleanup.ts index e137461030..94ca051a34 100644 --- a/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelCloseAnimationCompleteCleanup.ts +++ b/packages/twenty-front/src/modules/side-panel/hooks/useSidePanelCloseAnimationCompleteCleanup.ts @@ -1,4 +1,4 @@ -import { useResetContextStoreStates } from '@/command-menu/hooks/useResetContextStoreStates'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { addToNavPayloadRegistryState } from '@/navigation-menu-item/common/states/addToNavPayloadRegistryState'; import { pendingInsertionNavigationMenuItemState } from '@/navigation-menu-item/common/states/pendingInsertionNavigationMenuItemState'; @@ -9,9 +9,7 @@ import { pageLayoutDraggedAreaComponentState } from '@/page-layout/states/pageLa import { pageLayoutEditingWidgetIdComponentState } from '@/page-layout/states/pageLayoutEditingWidgetIdComponentState'; import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState'; import { widgetInsertionContextComponentState } from '@/page-layout/states/widgetInsertionContextComponentState'; -import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; import { SIDE_PANEL_CONTEXT_CHIP_GROUPS_DROPDOWN_ID } from '@/side-panel/constants/SidePanelContextChipGroupsDropdownId'; -import { SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelPreviousComponentInstanceId'; import { SIDE_PANEL_SELECTABLE_LIST_ID } from '@/side-panel/constants/SidePanelSelectableListId'; import { isPageLayoutSidePanelPage } from '@/side-panel/pages/page-layout/utils/isPageLayoutSidePanelPage'; import { hasUserSelectedSidePanelListItemState } from '@/side-panel/states/hasUserSelectedSidePanelListItemState'; @@ -42,16 +40,8 @@ export const useSidePanelCloseAnimationCompleteCleanup = () => { SIDE_PANEL_SELECTABLE_LIST_ID, ); - const { resetContextStoreStates } = useResetContextStoreStates(); - const { closeDropdown } = useCloseDropdown(); - const resetNavigationMenuItemState = () => { - store.set(selectedNavigationMenuItemIdInEditModeState.atom, null); - store.set(pendingInsertionNavigationMenuItemState.atom, null); - store.set(addToNavPayloadRegistryState.atom, new Map()); - }; - const sidePanelCloseAnimationCompleteCleanup = useCallback( (options?: { emitSidePanelCloseEvent?: boolean }) => { closeDropdown(SIDE_PANEL_CONTEXT_CHIP_GROUPS_DROPDOWN_ID); @@ -59,19 +49,16 @@ export const useSidePanelCloseAnimationCompleteCleanup = () => { // Snapshot values before any mutations (Jotai store.get is live and // reflects the latest state, so we capture before mutating). const currentPage = store.get(sidePanelPageState.atom); - const targetedRecordsRule = store.get( - contextStoreTargetedRecordsRuleComponentState.atomFamily({ - instanceId: SIDE_PANEL_COMPONENT_INSTANCE_ID, - }), - ); const morphItemsByPage = store.get( sidePanelNavigationMorphItemsByPageState.atom, ); - resetContextStoreStates(SIDE_PANEL_COMPONENT_INSTANCE_ID); - resetContextStoreStates(SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID); - if (isDefined(currentPage) && isPageLayoutSidePanelPage(currentPage)) { + const targetedRecordsRule = store.get( + contextStoreTargetedRecordsRuleComponentState.atomFamily({ + instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, + }), + ); if ( targetedRecordsRule.mode === 'selection' && targetedRecordsRule.selectedRecordIds.length === 1 @@ -121,7 +108,9 @@ export const useSidePanelCloseAnimationCompleteCleanup = () => { store.set(sidePanelShowHiddenObjectsState.atom, false); store.set(sidePanelNavigationMorphItemsByPageState.atom, new Map()); store.set(sidePanelNavigationStackState.atom, []); - resetNavigationMenuItemState(); + store.set(selectedNavigationMenuItemIdInEditModeState.atom, null); + store.set(pendingInsertionNavigationMenuItemState.atom, null); + store.set(addToNavPayloadRegistryState.atom, new Map()); resetSelectedItem(); store.set(hasUserSelectedSidePanelListItemState.atom, false); @@ -148,13 +137,7 @@ export const useSidePanelCloseAnimationCompleteCleanup = () => { ); } }, - [ - closeDropdown, - resetContextStoreStates, - resetNavigationMenuItemState, - resetSelectedItem, - store, - ], + [closeDropdown, resetSelectedItem, store], ); return { diff --git a/packages/twenty-front/src/modules/side-panel/pages/root/components/SidePanelResetContextToSelectionButton.tsx b/packages/twenty-front/src/modules/side-panel/pages/root/components/SidePanelResetContextToSelectionButton.tsx deleted file mode 100644 index ec79e23a7d..0000000000 --- a/packages/twenty-front/src/modules/side-panel/pages/root/components/SidePanelResetContextToSelectionButton.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { SidePanelContextRecordsChip } from '@/side-panel/components/SidePanelContextRecordsChip'; -import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem'; -import { SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelPreviousComponentInstanceId'; -import { SIDE_PANEL_RESET_CONTEXT_TO_SELECTION } from '@/side-panel/constants/SidePanelResetContextToSelection'; -import { useResetPreviousSidePanelContext } from '@/side-panel/pages/root/hooks/useResetPreviousSidePanelContext'; -import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; -import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; -import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector'; -import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem'; -import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; -import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; -import { t } from '@lingui/core/macro'; -import { isDefined } from 'twenty-shared/utils'; -import { IconArrowBackUp } from 'twenty-ui/display'; - -export const SidePanelResetContextToSelectionButton = () => { - const contextStoreTargetedRecordsRule = useAtomComponentStateValue( - contextStoreTargetedRecordsRuleComponentState, - SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID, - ); - - const contextStoreCurrentObjectMetadataItemId = useAtomComponentStateValue( - contextStoreCurrentObjectMetadataItemIdComponentState, - SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID, - ); - - const objectMetadataItems = useAtomStateValue(objectMetadataItemsSelector); - - const objectMetadataItem = objectMetadataItems.find( - (objectMetadataItem) => - objectMetadataItem.id === contextStoreCurrentObjectMetadataItemId, - ); - - const { resetPreviousSidePanelContext } = useResetPreviousSidePanelContext(); - - if ( - !isDefined(objectMetadataItem) || - (contextStoreTargetedRecordsRule.mode === 'selection' && - contextStoreTargetedRecordsRule.selectedRecordIds.length === 0) - ) { - return null; - } - - return ( - - - } - onClick={resetPreviousSidePanelContext} - /> - - ); -}; diff --git a/packages/twenty-front/src/modules/side-panel/pages/root/components/SidePanelRootPage.tsx b/packages/twenty-front/src/modules/side-panel/pages/root/components/SidePanelRootPage.tsx index 7072f43620..8375406197 100644 --- a/packages/twenty-front/src/modules/side-panel/pages/root/components/SidePanelRootPage.tsx +++ b/packages/twenty-front/src/modules/side-panel/pages/root/components/SidePanelRootPage.tsx @@ -2,17 +2,11 @@ import { CommandMenuContext } from '@/command-menu-item/contexts/CommandMenuCont import { CommandMenuItemRenderer } from '@/command-menu-item/display/components/CommandMenuItemRenderer'; import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; import { SidePanelList } from '@/side-panel/components/SidePanelList'; -import { SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelPreviousComponentInstanceId'; -import { SIDE_PANEL_RESET_CONTEXT_TO_SELECTION } from '@/side-panel/constants/SidePanelResetContextToSelection'; import { sidePanelSearchState } from '@/side-panel/states/sidePanelSearchState'; -import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; -import { SidePanelResetContextToSelectionButton } from '@/side-panel/pages/root/components/SidePanelResetContextToSelectionButton'; import { useFilterCommandMenuItemsWithSidePanelSearch } from '@/side-panel/pages/root/hooks/useFilterCommandMenuItemsWithSidePanelSearch'; -import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useLingui } from '@lingui/react/macro'; import { useContext, useMemo } from 'react'; -import { isDefined } from 'twenty-shared/utils'; import { CommandMenuItemAvailabilityType } from '~/generated-metadata/graphql'; export const SidePanelRootPage = () => { @@ -64,30 +58,14 @@ export const SidePanelRootPage = () => { const noResults = !matchingRecordSelectionItems.length && !matchingGlobalItems.length; - // oxlint-disable-next-line twenty/matching-state-variable - const previousContextStoreCurrentObjectMetadataItemId = - useAtomComponentStateValue( - contextStoreCurrentObjectMetadataItemIdComponentState, - SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID, - ); - const selectableItemIds = [ ...matchingRecordSelectionItems, ...matchingGlobalItems, ...(noResults ? fallbackItems : []), ].map((item) => item.id); - if (isDefined(previousContextStoreCurrentObjectMetadataItemId)) { - selectableItemIds.unshift(SIDE_PANEL_RESET_CONTEXT_TO_SELECTION); - } - return ( - {isDefined(previousContextStoreCurrentObjectMetadataItemId) && ( - - - - )} {matchingRecordSelectionItems.length > 0 && ( {matchingRecordSelectionItems.map((item) => ( diff --git a/packages/twenty-front/src/modules/side-panel/pages/root/hooks/useResetPreviousSidePanelContext.ts b/packages/twenty-front/src/modules/side-panel/pages/root/hooks/useResetPreviousSidePanelContext.ts deleted file mode 100644 index d50ee02fb9..0000000000 --- a/packages/twenty-front/src/modules/side-panel/pages/root/hooks/useResetPreviousSidePanelContext.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { SIDE_PANEL_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelComponentInstanceId'; -import { SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/side-panel/constants/SidePanelPreviousComponentInstanceId'; -import { useCopyContextStoreStates } from '@/command-menu/hooks/useCopyContextStoreAndCommandMenuStates'; -import { useResetContextStoreStates } from '@/command-menu/hooks/useResetContextStoreStates'; - -export const useResetPreviousSidePanelContext = () => { - const { copyContextStoreStates } = useCopyContextStoreStates(); - const { resetContextStoreStates } = useResetContextStoreStates(); - - const resetPreviousSidePanelContext = () => { - copyContextStoreStates({ - instanceIdToCopyFrom: SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID, - instanceIdToCopyTo: SIDE_PANEL_COMPONENT_INSTANCE_ID, - }); - resetContextStoreStates(SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID); - }; - - return { - resetPreviousSidePanelContext, - }; -};