From 6d6738e7cb3d75de79ed64b515de29ff9ba5e34d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Mon, 16 Jun 2025 10:33:57 +0200 Subject: [PATCH] Fixes on side panel closing and table rows and board cards activation (#12609) Fixes https://github.com/twentyhq/core-team-issues/issues/1096 This PR: - Prevents interaction with elements inside the index page when the side panel is opened, except for switching between records - Prevents stacking multiple records in the side panel navigation stack when navigating from the index - Adds activation and unfocus logic for board cards when clicked - Fixes table row activation after clicking on a record chip Before: https://github.com/user-attachments/assets/dcfec9fb-392b-4760-9b11-b0f077087b82 After: https://github.com/user-attachments/assets/93e0dc6a-c693-4484-b23e-f5ae291eb472 --- .../components/CommandMenuOpenContainer.tsx | 4 ++- .../hooks/useOpenRecordInCommandMenu.ts | 4 ++- .../components/RecordBoardCard.tsx | 6 +++++ .../components/RecordBoardCardHeader.tsx | 25 +++++++++++++------ .../hooks/useOpenRecordFromIndexView.ts | 1 + ...rdTableCellFieldContextLabelIdentifier.tsx | 19 +++++++++++++- 6 files changed, 48 insertions(+), 11 deletions(-) diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuOpenContainer.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuOpenContainer.tsx index 06711cdb2..517e44a3a 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuOpenContainer.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuOpenContainer.tsx @@ -51,12 +51,14 @@ export const CommandMenuOpenContainer = ({ const handleClickOutside = useRecoilCallback( ({ snapshot }) => - () => { + (event: MouseEvent | TouchEvent) => { const hotkeyScope = snapshot .getLoadable(currentHotkeyScopeState) .getValue(); if (hotkeyScope?.scope === CommandMenuHotkeyScope.CommandMenuFocused) { + event.stopImmediatePropagation(); + event.preventDefault(); closeCommandMenu(); } }, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts index bdae671b6..cf5829e36 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts @@ -38,10 +38,12 @@ export const useOpenRecordInCommandMenu = () => { recordId, objectNameSingular, isNewRecord = false, + resetNavigationStack = false, }: { recordId: string; objectNameSingular: string; isNewRecord?: boolean; + resetNavigationStack?: boolean; }) => { const navigationStack = getSnapshotValue( snapshot, @@ -171,7 +173,7 @@ export const useOpenRecordInCommandMenu = () => { pageIcon: Icon, pageIconColor: IconColor, pageId: pageComponentInstanceId, - resetNavigationStack: false, + resetNavigationStack, }); if (objectNameSingular === CoreObjectNameSingular.WorkflowRun) { diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx index f995d3eaa..90c530ce2 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx @@ -10,6 +10,8 @@ import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/re import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector'; import { ActionMenuDropdownHotkeyScope } from '@/action-menu/types/ActionMenuDropdownHotKeyScope'; +import { useActiveRecordBoardCard } from '@/object-record/record-board/hooks/useActiveRecordBoardCard'; +import { useFocusedRecordBoardCard } from '@/object-record/record-board/hooks/useFocusedRecordBoardCard'; import { RecordBoardCardBody } from '@/object-record/record-board/record-board-card/components/RecordBoardCardBody'; import { RecordBoardCardHeader } from '@/object-record/record-board/record-board-card/components/RecordBoardCardHeader'; import { RECORD_BOARD_CARD_CLICK_OUTSIDE_ID } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardClickOutsideId'; @@ -142,6 +144,8 @@ export const RecordBoardCard = () => { const { openDropdown } = useDropdownV2(); const { openRecordFromIndexView } = useOpenRecordFromIndexView(); + const { activateBoardCard } = useActiveRecordBoardCard(recordBoardId); + const { unfocusBoardCard } = useFocusedRecordBoardCard(recordBoardId); const handleActionMenuDropdown = (event: React.MouseEvent) => { event.preventDefault(); @@ -156,6 +160,8 @@ export const RecordBoardCard = () => { }; const handleCardClick = () => { + activateBoardCard({ rowIndex, columnIndex }); + unfocusBoardCard(); openRecordFromIndexView({ recordId }); }; diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardHeader.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardHeader.tsx index 9851bd0d2..6be54ce7f 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCardHeader.tsx @@ -4,15 +4,17 @@ import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useR import { RecordBoardCardHeaderContainer } from '@/object-record/record-board/record-board-card/components/RecordBoardCardHeaderContainer'; import { StopPropagationContainer } from '@/object-record/record-board/record-board-card/components/StopPropagationContainer'; import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext'; -import { RecordBoardScopeInternalContext } from '@/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext'; import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState'; import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState'; +import { useActiveRecordBoardCard } from '@/object-record/record-board/hooks/useActiveRecordBoardCard'; +import { useFocusedRecordBoardCard } from '@/object-record/record-board/hooks/useFocusedRecordBoardCard'; import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView'; +import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; import styled from '@emotion/styled'; import { Dispatch, SetStateAction, useContext } from 'react'; import { useRecoilValue } from 'recoil'; @@ -45,11 +47,10 @@ export const RecordBoardCardHeader = ({ const record = useRecoilValue(recordStoreFamilyState(recordId)); - const { objectMetadataItem } = useContext(RecordBoardContext); - - const recordBoardId = useAvailableScopeIdOrThrow( - RecordBoardScopeInternalContext, - ); + const { objectMetadataItem, recordBoardId } = useContext(RecordBoardContext); + const { rowIndex, columnIndex } = useContext(RecordBoardCardContext); + const { activateBoardCard } = useActiveRecordBoardCard(recordBoardId); + const { unfocusBoardCard } = useFocusedRecordBoardCard(recordBoardId); const showCompactView = useRecoilComponentValueV2( isRecordBoardCompactModeActiveComponentState, @@ -66,6 +67,12 @@ export const RecordBoardCardHeader = ({ const { openRecordFromIndexView } = useOpenRecordFromIndexView(); + const recordIndexOpenRecordIn = useRecoilValue(recordIndexOpenRecordInState); + const triggerEvent = + recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL + ? 'CLICK' + : 'MOUSE_DOWN'; + return ( @@ -76,9 +83,11 @@ export const RecordBoardCardHeader = ({ variant={AvatarChipVariant.Transparent} maxWidth={150} onClick={() => { + activateBoardCard({ rowIndex, columnIndex }); + unfocusBoardCard(); openRecordFromIndexView({ recordId }); }} - triggerEvent="CLICK" + triggerEvent={triggerEvent} /> )} diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useOpenRecordFromIndexView.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useOpenRecordFromIndexView.ts index c4723338d..4ebdc3329 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useOpenRecordFromIndexView.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useOpenRecordFromIndexView.ts @@ -71,6 +71,7 @@ export const useOpenRecordFromIndexView = () => { openRecordInCommandMenu({ recordId, objectNameSingular, + resetNavigationStack: true, }); } else { navigate(AppPath.RecordShowPage, { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier.tsx index 8735a177e..ab4e1fc15 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextLabelIdentifier.tsx @@ -3,13 +3,18 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView'; +import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState'; import { RecordUpdateContext } from '@/object-record/record-table/contexts/EntityUpdateMutationHookContext'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useActiveRecordTableRow } from '@/object-record/record-table/hooks/useActiveRecordTableRow'; +import { useFocusedRecordTableRow } from '@/object-record/record-table/hooks/useFocusedRecordTableRow'; import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; import { ReactNode, useContext } from 'react'; +import { useRecoilValue } from 'recoil'; import { useIsMobile } from 'twenty-ui/utilities'; type RecordTableCellFieldContextLabelIdentifierProps = { @@ -25,7 +30,10 @@ export const RecordTableCellFieldContextLabelIdentifier = ({ useRecordTableRowContextOrThrow(); const { columnDefinition } = useContext(RecordTableCellContext); - const { objectMetadataItem } = useRecordTableContextOrThrow(); + const { objectMetadataItem, recordTableId } = useRecordTableContextOrThrow(); + const { rowIndex } = useRecordTableRowContextOrThrow(); + const { activateRecordTableRow } = useActiveRecordTableRow(recordTableId); + const { unfocusRecordTableRow } = useFocusedRecordTableRow(recordTableId); const isMobile = useIsMobile(); const isRecordTableScrolledLeftComponent = useRecoilComponentValueV2( @@ -51,6 +59,12 @@ export const RecordTableCellFieldContextLabelIdentifier = ({ const { openRecordFromIndexView } = useOpenRecordFromIndexView(); + const recordIndexOpenRecordIn = useRecoilValue(recordIndexOpenRecordInState); + const triggerEvent = + recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL + ? 'CLICK' + : 'MOUSE_DOWN'; + return ( { + activateRecordTableRow(rowIndex); + unfocusRecordTableRow(); openRecordFromIndexView({ recordId }); }, isForbidden: !hasObjectReadPermissions, + triggerEvent, }} > {children}