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
This commit is contained in:
@@ -61,8 +61,8 @@ const jestConfig = {
|
||||
extensionsToTreatAsEsm: ['.ts', '.tsx'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
statements: 48.4,
|
||||
lines: 47.0,
|
||||
statements: 48,
|
||||
lines: 46,
|
||||
functions: 39.5,
|
||||
},
|
||||
},
|
||||
|
||||
-22
@@ -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 (
|
||||
<SidePanelList selectableItemIds={selectableItemIds} noResults={noResults}>
|
||||
{isDefined(previousContextStoreCurrentObjectMetadataItemId) && (
|
||||
<SidePanelGroup heading={t`Context`}>
|
||||
<SidePanelResetContextToSelectionButton />
|
||||
</SidePanelGroup>
|
||||
)}
|
||||
{matchingPinnedItems.length > 0 && (
|
||||
<SidePanelGroup heading={t`Pinned`}>
|
||||
{matchingPinnedItems.map((item) => (
|
||||
|
||||
-195
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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,
|
||||
|
||||
-144
@@ -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 };
|
||||
};
|
||||
@@ -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 };
|
||||
};
|
||||
-182
@@ -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,
|
||||
};
|
||||
};
|
||||
@@ -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,
|
||||
|
||||
@@ -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 (
|
||||
<RecordComponentInstanceContextsWrapper componentInstanceId={recordIndexId}>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: SIDE_PANEL_COMPONENT_INSTANCE_ID }}
|
||||
value={{ instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID }}
|
||||
>
|
||||
<CommandMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: SIDE_PANEL_COMPONENT_INSTANCE_ID }}
|
||||
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
import { SidePanelContextChip } from '@/side-panel/components/SidePanelContextChip';
|
||||
import { SidePanelContextRecordChipAvatars } from '@/side-panel/components/SidePanelContextRecordChipAvatars';
|
||||
import { getSelectedRecordsContextText } from '@/side-panel/utils/getSelectedRecordsContextText';
|
||||
import { useFindManyRecordsSelectedInContextStore } from '@/context-store/hooks/useFindManyRecordsSelectedInContextStore';
|
||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||
import { allowRequestsToTwentyIconsState } from '@/client-config/states/allowRequestsToTwentyIcons';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
|
||||
export const SidePanelContextRecordsChip = ({
|
||||
objectMetadataItemId,
|
||||
instanceId,
|
||||
}: {
|
||||
objectMetadataItemId: string;
|
||||
instanceId?: string;
|
||||
}) => {
|
||||
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) => (
|
||||
<SidePanelContextRecordChipAvatars
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
key={record.id}
|
||||
record={record}
|
||||
/>
|
||||
));
|
||||
|
||||
return (
|
||||
<SidePanelContextChip
|
||||
text={getSelectedRecordsContextText(
|
||||
objectMetadataItem,
|
||||
records,
|
||||
totalCount,
|
||||
allowRequestsToTwentyIcons,
|
||||
)}
|
||||
Icons={Avatars}
|
||||
/>
|
||||
);
|
||||
};
|
||||
-269
@@ -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<string, (record: ObjectRecord) => 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) => (
|
||||
<PreComputedChipGeneratorsContext.Provider
|
||||
value={{
|
||||
chipGeneratorPerObjectPerField,
|
||||
identifierChipGeneratorPerObject,
|
||||
}}
|
||||
>
|
||||
<Story />
|
||||
</PreComputedChipGeneratorsContext.Provider>
|
||||
);
|
||||
|
||||
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 (
|
||||
<ContextStoreWrapper>
|
||||
<Story />
|
||||
</ContextStoreWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
const meta: Meta<typeof SidePanelContextRecordsChip> = {
|
||||
title: 'Modules/SidePanel/SidePanelContextRecordChip',
|
||||
component: SidePanelContextRecordsChip,
|
||||
decorators: [
|
||||
ContextStoreDecorator,
|
||||
ChipGeneratorsDecorator,
|
||||
ComponentDecorator,
|
||||
],
|
||||
args: {
|
||||
objectMetadataItemId: companyMockObjectMetadataItem?.id,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof SidePanelContextRecordsChip>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
export const WithTwoCompanies: Story = {
|
||||
decorators: [
|
||||
(Story) => {
|
||||
const twoCompaniesMock = mockedCompanyRecords.slice(0, 2);
|
||||
const TwoCompaniesWrapper = createContextStoreWrapper({
|
||||
companies: twoCompaniesMock,
|
||||
componentInstanceId: '2',
|
||||
});
|
||||
|
||||
return (
|
||||
<TwoCompaniesWrapper>
|
||||
<Story />
|
||||
</TwoCompaniesWrapper>
|
||||
);
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const WithTenCompanies: Story = {
|
||||
decorators: [
|
||||
(Story) => {
|
||||
const tenCompaniesMock = mockedCompanyRecords.slice(0, 10);
|
||||
const TenCompaniesWrapper = createContextStoreWrapper({
|
||||
companies: tenCompaniesMock,
|
||||
componentInstanceId: '3',
|
||||
});
|
||||
|
||||
return (
|
||||
<TenCompaniesWrapper>
|
||||
<Story />
|
||||
</TenCompaniesWrapper>
|
||||
);
|
||||
},
|
||||
],
|
||||
};
|
||||
-1
@@ -1 +0,0 @@
|
||||
export const SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID = 'side-panel-previous';
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
export const SIDE_PANEL_RESET_CONTEXT_TO_SELECTION =
|
||||
'reset-context-to-selection';
|
||||
-18
@@ -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,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
+10
-27
@@ -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 {
|
||||
|
||||
-63
@@ -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 (
|
||||
<SelectableListItem
|
||||
itemId={SIDE_PANEL_RESET_CONTEXT_TO_SELECTION}
|
||||
onEnter={resetPreviousSidePanelContext}
|
||||
>
|
||||
<CommandMenuItem
|
||||
id={SIDE_PANEL_RESET_CONTEXT_TO_SELECTION}
|
||||
Icon={IconArrowBackUp}
|
||||
label={t`Reset to`}
|
||||
RightComponent={
|
||||
<SidePanelContextRecordsChip
|
||||
objectMetadataItemId={objectMetadataItem.id}
|
||||
instanceId={SIDE_PANEL_PREVIOUS_COMPONENT_INSTANCE_ID}
|
||||
/>
|
||||
}
|
||||
onClick={resetPreviousSidePanelContext}
|
||||
/>
|
||||
</SelectableListItem>
|
||||
);
|
||||
};
|
||||
-22
@@ -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 (
|
||||
<SidePanelList selectableItemIds={selectableItemIds} noResults={noResults}>
|
||||
{isDefined(previousContextStoreCurrentObjectMetadataItemId) && (
|
||||
<SidePanelGroup heading={t`Context`}>
|
||||
<SidePanelResetContextToSelectionButton />
|
||||
</SidePanelGroup>
|
||||
)}
|
||||
{matchingRecordSelectionItems.length > 0 && (
|
||||
<SidePanelGroup heading={t`Record Selection`}>
|
||||
{matchingRecordSelectionItems.map((item) => (
|
||||
|
||||
-21
@@ -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,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user