Files
twenty/packages/twenty-front/src/modules/command-menu-item/server-items/edit/components/CommandMenuItemEditButton.tsx
T
Raphaël Bosi 77315b7f6e Sync record selection with the edit mode (#19276)
## PR description

The previous approach used a detached flag to represent selection mode,
which could was not synced sync with actual UI selection state. This
change ties the edit mode's selection/fallback behavior directly to
whether records are truly selected in the record index.

- Removes `commandMenuItemEditSelectionModeState` (a standalone 'none' |
'selection' atom) and replaces it with
`mainContextStoreHasSelectedRecordsSelector`, which derives selection
state from the real record selection in the context store.
- Adds `useSelectFirstRecordForEditMode` to programmatically select the
first record (table row or kanban card) when toggling to selection mode,
and useResetRecordIndexSelection to clear selection when toggling off or
exiting edit mode.
- Ensures record selection is properly cleaned up when exiting layout
customization mode or closing the side panel.

## Video QA

### Table


https://github.com/user-attachments/assets/1d845809-8369-4872-b3a9-a0281b8e464b

### Board


https://github.com/user-attachments/assets/325c2d58-4ca0-408a-ab4a-66b97d9d70de
2026-04-02 16:35:14 +00:00

62 lines
2.0 KiB
TypeScript

import { AnimatedIconCrossfade } from 'twenty-ui/utilities';
import { isLayoutCustomizationModeEnabledState } from '@/layout-customization/states/isLayoutCustomizationModeEnabledState';
import { useNavigateSidePanel } from '@/side-panel/hooks/useNavigateSidePanel';
import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu';
import { isSidePanelOpenedState } from '@/side-panel/states/isSidePanelOpenedState';
import { sidePanelPageState } from '@/side-panel/states/sidePanelPageState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useLingui } from '@lingui/react/macro';
import { SidePanelPages } from 'twenty-shared/types';
import { IconPencil, IconX } from 'twenty-ui/display';
import { AnimatedButton } from 'twenty-ui/input';
export const CommandMenuItemEditButton = () => {
const { t } = useLingui();
const { navigateSidePanel } = useNavigateSidePanel();
const { closeSidePanelMenu } = useSidePanelMenu();
const isLayoutCustomizationModeEnabled = useAtomStateValue(
isLayoutCustomizationModeEnabledState,
);
const isSidePanelOpened = useAtomStateValue(isSidePanelOpenedState);
const sidePanelPage = useAtomStateValue(sidePanelPageState);
const isCommandMenuEditPageActive =
isSidePanelOpened && sidePanelPage === SidePanelPages.CommandMenuEdit;
if (!isLayoutCustomizationModeEnabled) {
return null;
}
const handleClick = () => {
if (isCommandMenuEditPageActive) {
closeSidePanelMenu();
return;
}
navigateSidePanel({
page: SidePanelPages.CommandMenuEdit,
pageTitle: t`Edit actions`,
pageIcon: IconPencil,
resetNavigationStack: true,
});
};
return (
<AnimatedButton
animatedSvg={
<AnimatedIconCrossfade
isActive={isCommandMenuEditPageActive}
ActiveIcon={IconX}
InactiveIcon={IconPencil}
/>
}
title={t`Edit actions`}
variant="secondary"
size="small"
onClick={handleClick}
/>
);
};