fix: record does not open in side panel after returning from fullscreen (#17131)
Closes #17089 ### 1. Can't reopen record after having navigated to its show page After opening a record in the show page from the command menu and going back to the index, clicking the same record again did nothing. The command menu navigation stack was not cleared when opening in the show page, so the "already open" check skipped reopening. We now clear the command menu navigation stack before navigating to the show page (in `RecordShowRightDrawerOpenRecordButton`), so the same record can be reopened from the index. ### 2. Row doesn't highlight when opening command menu after return from show page After returning from the record show page to the index, the first row click opened the command menu but the row did not highlight. The "side panel close" event was emitted not only when the panel actually closed, but also when opening the command menu (cleanup ran with `isCommandMenuClosing` and always emitted the event). Listeners like `RecordTableDeactivateRecordTableRowEffect` then deactivated the row. We now emit the side panel close event only when the close animation actually completes (`CommandMenuSidePanelForDesktop`), and skip emitting it when cleanup is run from the open path (`useNavigateCommandMenu` passes `emitSidePanelCloseEvent: false`). The table still deactivates the row when the user closes the panel, but no longer when they open the command menu by clicking a row.
This commit is contained in:
+8
-2
@@ -2,6 +2,7 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context
|
||||
import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId';
|
||||
import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { contextStoreRecordShowParentViewComponentState } from '@/context-store/states/contextStoreRecordShowParentViewComponentState';
|
||||
@@ -16,9 +17,9 @@ import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/com
|
||||
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
|
||||
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { AppPath } from 'twenty-shared/types';
|
||||
@@ -94,10 +95,15 @@ export const RecordShowRightDrawerOpenRecordButton = ({
|
||||
|
||||
const parentView = store.get(parentViewState);
|
||||
|
||||
if (parentView?.parentViewObjectNameSingular !== objectNameSingular) {
|
||||
if (
|
||||
isDefined(parentView) &&
|
||||
parentView.parentViewObjectNameSingular !== objectNameSingular
|
||||
) {
|
||||
store.set(parentViewState, undefined);
|
||||
}
|
||||
|
||||
store.set(commandMenuNavigationStackState.atom, []);
|
||||
|
||||
navigate(AppPath.RecordShowPage, {
|
||||
objectNameSingular,
|
||||
objectRecordId: recordId,
|
||||
|
||||
+83
-78
@@ -24,10 +24,10 @@ import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getSh
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
import { WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/code-action/constants/WorkflowLogicFunctionTabListComponentId';
|
||||
import { WorkflowLogicFunctionTabId } from '@/workflow/workflow-steps/workflow-actions/code-action/types/WorkflowLogicFunctionTabId';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { CommandMenuPages } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useCommandMenuCloseAnimationCompleteCleanup = () => {
|
||||
const store = useStore();
|
||||
@@ -39,96 +39,101 @@ export const useCommandMenuCloseAnimationCompleteCleanup = () => {
|
||||
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const commandMenuCloseAnimationCompleteCleanup = useCallback(() => {
|
||||
closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID);
|
||||
const commandMenuCloseAnimationCompleteCleanup = useCallback(
|
||||
(options?: { emitSidePanelCloseEvent?: boolean }) => {
|
||||
closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID);
|
||||
|
||||
// Snapshot values before any mutations (Jotai store.get is live and
|
||||
// reflects the latest state, so we capture before mutating).
|
||||
const currentPage = store.get(commandMenuPageState.atom);
|
||||
const targetedRecordsRule = store.get(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
);
|
||||
const morphItemsByPage = store.get(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
);
|
||||
// Snapshot values before any mutations (Jotai store.get is live and
|
||||
// reflects the latest state, so we capture before mutating).
|
||||
const currentPage = store.get(commandMenuPageState.atom);
|
||||
const targetedRecordsRule = store.get(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
);
|
||||
const morphItemsByPage = store.get(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
);
|
||||
|
||||
resetContextStoreStates(COMMAND_MENU_COMPONENT_INSTANCE_ID);
|
||||
resetContextStoreStates(COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID);
|
||||
resetContextStoreStates(COMMAND_MENU_COMPONENT_INSTANCE_ID);
|
||||
resetContextStoreStates(COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID);
|
||||
|
||||
const isPageLayoutEditingPage =
|
||||
currentPage === CommandMenuPages.PageLayoutWidgetTypeSelect ||
|
||||
currentPage === CommandMenuPages.PageLayoutGraphTypeSelect ||
|
||||
currentPage === CommandMenuPages.PageLayoutIframeSettings ||
|
||||
currentPage === CommandMenuPages.PageLayoutTabSettings;
|
||||
const isPageLayoutEditingPage =
|
||||
currentPage === CommandMenuPages.PageLayoutWidgetTypeSelect ||
|
||||
currentPage === CommandMenuPages.PageLayoutGraphTypeSelect ||
|
||||
currentPage === CommandMenuPages.PageLayoutIframeSettings ||
|
||||
currentPage === CommandMenuPages.PageLayoutTabSettings;
|
||||
|
||||
if (isPageLayoutEditingPage) {
|
||||
if (
|
||||
targetedRecordsRule.mode === 'selection' &&
|
||||
targetedRecordsRule.selectedRecordIds.length === 1
|
||||
) {
|
||||
const recordId = targetedRecordsRule.selectedRecordIds[0];
|
||||
const record = store.get(recordStoreFamilyState.atomFamily(recordId));
|
||||
if (isPageLayoutEditingPage) {
|
||||
if (
|
||||
targetedRecordsRule.mode === 'selection' &&
|
||||
targetedRecordsRule.selectedRecordIds.length === 1
|
||||
) {
|
||||
const recordId = targetedRecordsRule.selectedRecordIds[0];
|
||||
const record = store.get(recordStoreFamilyState.atomFamily(recordId));
|
||||
|
||||
if (isDefined(record) && isDefined(record.pageLayoutId)) {
|
||||
store.set(
|
||||
pageLayoutEditingWidgetIdComponentState.atomFamily({
|
||||
instanceId: record.pageLayoutId,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
store.set(
|
||||
pageLayoutTabSettingsOpenTabIdComponentState.atomFamily({
|
||||
instanceId: record.pageLayoutId,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
store.set(
|
||||
pageLayoutDraggedAreaComponentState.atomFamily({
|
||||
instanceId: record.pageLayoutId,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
if (isDefined(record) && isDefined(record.pageLayoutId)) {
|
||||
store.set(
|
||||
pageLayoutEditingWidgetIdComponentState.atomFamily({
|
||||
instanceId: record.pageLayoutId,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
store.set(
|
||||
pageLayoutTabSettingsOpenTabIdComponentState.atomFamily({
|
||||
instanceId: record.pageLayoutId,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
store.set(
|
||||
pageLayoutDraggedAreaComponentState.atomFamily({
|
||||
instanceId: record.pageLayoutId,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store.set(viewableRecordIdState.atom, null);
|
||||
store.set(commandMenuPageState.atom, CommandMenuPages.Root);
|
||||
store.set(commandMenuPageInfoState.atom, {
|
||||
title: undefined,
|
||||
Icon: undefined,
|
||||
instanceId: '',
|
||||
});
|
||||
store.set(isCommandMenuOpenedState.atom, false);
|
||||
store.set(commandMenuSearchState.atom, '');
|
||||
store.set(commandMenuNavigationMorphItemsByPageState.atom, new Map());
|
||||
store.set(commandMenuNavigationStackState.atom, []);
|
||||
resetSelectedItem();
|
||||
store.set(hasUserSelectedCommandState.atom, false);
|
||||
store.set(viewableRecordIdState.atom, null);
|
||||
store.set(commandMenuPageState.atom, CommandMenuPages.Root);
|
||||
store.set(commandMenuPageInfoState.atom, {
|
||||
title: undefined,
|
||||
Icon: undefined,
|
||||
instanceId: '',
|
||||
});
|
||||
store.set(isCommandMenuOpenedState.atom, false);
|
||||
store.set(commandMenuSearchState.atom, '');
|
||||
store.set(commandMenuNavigationMorphItemsByPageState.atom, new Map());
|
||||
store.set(commandMenuNavigationStackState.atom, []);
|
||||
resetSelectedItem();
|
||||
store.set(hasUserSelectedCommandState.atom, false);
|
||||
|
||||
emitSidePanelCloseEvent();
|
||||
store.set(isCommandMenuClosingState.atom, false);
|
||||
store.set(
|
||||
activeTabIdComponentState.atomFamily({
|
||||
instanceId: WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID,
|
||||
}),
|
||||
WorkflowLogicFunctionTabId.CODE,
|
||||
);
|
||||
|
||||
for (const [pageId, morphItems] of morphItemsByPage) {
|
||||
if (options?.emitSidePanelCloseEvent !== false) {
|
||||
emitSidePanelCloseEvent();
|
||||
}
|
||||
store.set(isCommandMenuClosingState.atom, false);
|
||||
store.set(
|
||||
activeTabIdComponentState.atomFamily({
|
||||
instanceId: getShowPageTabListComponentId({
|
||||
pageId,
|
||||
targetObjectId: morphItems[0].recordId,
|
||||
}),
|
||||
instanceId: WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID,
|
||||
}),
|
||||
null,
|
||||
WorkflowLogicFunctionTabId.CODE,
|
||||
);
|
||||
}
|
||||
}, [closeDropdown, resetContextStoreStates, resetSelectedItem, store]);
|
||||
|
||||
for (const [pageId, morphItems] of morphItemsByPage) {
|
||||
store.set(
|
||||
activeTabIdComponentState.atomFamily({
|
||||
instanceId: getShowPageTabListComponentId({
|
||||
pageId,
|
||||
targetObjectId: morphItems[0].recordId,
|
||||
}),
|
||||
}),
|
||||
null,
|
||||
);
|
||||
}
|
||||
},
|
||||
[closeDropdown, resetContextStoreStates, resetSelectedItem, store],
|
||||
);
|
||||
|
||||
return {
|
||||
commandMenuCloseAnimationCompleteCleanup,
|
||||
|
||||
@@ -13,11 +13,11 @@ import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpe
|
||||
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';
|
||||
import { useCallback } from 'react';
|
||||
import { type CommandMenuPages } from 'twenty-shared/types';
|
||||
import { type IconComponent } from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export type CommandMenuNavigationStackItem = {
|
||||
page: CommandMenuPages;
|
||||
@@ -42,7 +42,9 @@ export const useNavigateCommandMenu = () => {
|
||||
const isCommandMenuClosing = store.get(isCommandMenuClosingState.atom);
|
||||
|
||||
if (isCommandMenuClosing) {
|
||||
commandMenuCloseAnimationCompleteCleanup();
|
||||
commandMenuCloseAnimationCompleteCleanup({
|
||||
emitSidePanelCloseEvent: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (isCommandMenuOpened) {
|
||||
|
||||
Reference in New Issue
Block a user