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
This commit is contained in:
Raphaël Bosi
2025-06-16 10:33:57 +02:00
committed by GitHub
parent 46d6e7a8bc
commit 6d6738e7cb
6 changed files with 48 additions and 11 deletions

View File

@ -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();
}
},

View File

@ -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) {

View File

@ -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 });
};

View File

@ -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 (
<RecordBoardCardHeaderContainer showCompactView={showCompactView}>
<StopPropagationContainer>
@ -76,9 +83,11 @@ export const RecordBoardCardHeader = ({
variant={AvatarChipVariant.Transparent}
maxWidth={150}
onClick={() => {
activateBoardCard({ rowIndex, columnIndex });
unfocusBoardCard();
openRecordFromIndexView({ recordId });
}}
triggerEvent="CLICK"
triggerEvent={triggerEvent}
/>
)}
</StopPropagationContainer>

View File

@ -71,6 +71,7 @@ export const useOpenRecordFromIndexView = () => {
openRecordInCommandMenu({
recordId,
objectNameSingular,
resetNavigationStack: true,
});
} else {
navigate(AppPath.RecordShowPage, {

View File

@ -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 (
<FieldContext.Provider
value={{
@ -64,9 +78,12 @@ export const RecordTableCellFieldContextLabelIdentifier = ({
isReadOnly: isFieldReadOnly,
maxWidth: columnDefinition.size,
onRecordChipClick: () => {
activateRecordTableRow(rowIndex);
unfocusRecordTableRow();
openRecordFromIndexView({ recordId });
},
isForbidden: !hasObjectReadPermissions,
triggerEvent,
}}
>
{children}