Replace hotkey scopes by focus stack (Part 5 - Form field Inputs, Pages, Dialog ...) (#13106)

# Replace hotkey scopes by focus stack (Part 5 - Form field Inputs,
Pages, Dialog ...)

This PR is the 5th part of a refactoring aiming to deprecate the hotkey
scopes api in favor of the new focus stack api which is more robust.
Part 1: https://github.com/twentyhq/twenty/pull/12673
Part 2: https://github.com/twentyhq/twenty/pull/12798
Part 3: https://github.com/twentyhq/twenty/pull/12910
Part 4: https://github.com/twentyhq/twenty/pull/12933

In this part, all the last components using hotkey scopes were
refactored.
In the 6th and final part of this refactoring we will be able to
completely remove the hotkey scopes from the codebase.
This commit is contained in:
Raphaël Bosi
2025-07-08 20:18:32 +02:00
committed by GitHub
parent 66b633e08e
commit 9eaa8ad517
50 changed files with 590 additions and 678 deletions

View File

@ -4,8 +4,8 @@ import { Key } from 'ts-key-enum';
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
import { useRecordBoardCardNavigation } from '@/object-record/record-board/hooks/useRecordBoardCardNavigation';
import { useRecordBoardSelectAllHotkeys } from '@/object-record/record-board/hooks/useRecordBoardSelectAllHotkeys';
import { RECORD_INDEX_FOCUS_ID } from '@/object-record/record-index/constants/RecordIndexFocusId';
import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/RecordIndexHotkeyScope';
import { PageFocusId } from '@/types/PageFocusId';
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
export const RecordBoardHotkeyEffect = () => {
@ -18,7 +18,7 @@ export const RecordBoardHotkeyEffect = () => {
callback: () => {
move('down');
},
focusId: RECORD_INDEX_FOCUS_ID,
focusId: PageFocusId.RecordIndex,
scope: RecordIndexHotkeyScope.RecordIndex,
dependencies: [move],
});

View File

@ -1,65 +1,28 @@
import styled from '@emotion/styled';
import { useCallback, useRef } from 'react';
import { useRecordGroupActions } from '@/object-record/record-group/hooks/useRecordGroupActions';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { ViewType } from '@/views/types/ViewType';
import { MenuItem } from 'twenty-ui/navigation';
const StyledMenuContainer = styled.div`
position: absolute;
top: ${({ theme }) => theme.spacing(10)};
width: 200px;
z-index: 1;
`;
type RecordBoardColumnDropdownMenuProps = {
onClose: () => void;
onDelete?: (id: string) => void;
stageId: string;
};
export const RecordBoardColumnDropdownMenu = ({
onClose,
}: RecordBoardColumnDropdownMenuProps) => {
const boardColumnMenuRef = useRef<HTMLDivElement>(null);
export const RecordBoardColumnDropdownMenu = () => {
const recordGroupActions = useRecordGroupActions({
viewType: ViewType.Kanban,
});
const closeMenu = useCallback(() => {
onClose();
}, [onClose]);
useListenClickOutside({
refs: [boardColumnMenuRef],
callback: closeMenu,
listenerId: 'record-board-column-dropdown-menu',
});
return (
<StyledMenuContainer ref={boardColumnMenuRef}>
<OverlayContainer>
<DropdownContent selectDisabled>
<DropdownMenuItemsContainer>
{recordGroupActions.map((action) => (
<MenuItem
key={action.id}
onClick={() => {
action.callback();
closeMenu();
}}
LeftIcon={action.icon}
text={action.label}
/>
))}
</DropdownMenuItemsContainer>
</DropdownContent>
</OverlayContainer>
</StyledMenuContainer>
<DropdownContent selectDisabled>
<DropdownMenuItemsContainer>
{recordGroupActions.map((action) => (
<MenuItem
key={action.id}
onClick={() => {
action.callback();
}}
LeftIcon={action.icon}
text={action.label}
/>
))}
</DropdownMenuItemsContainer>
</DropdownContent>
);
};

View File

@ -7,10 +7,10 @@ import { RecordBoardColumnDropdownMenu } from '@/object-record/record-board/reco
import { RecordBoardColumnHeaderAggregateDropdown } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdown';
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
import { useAggregateRecordsForRecordBoardColumn } from '@/object-record/record-board/record-board-column/hooks/useAggregateRecordsForRecordBoardColumn';
import { RecordBoardColumnHotkeyScope } from '@/object-record/record-board/types/BoardColumnHotkeyScope';
import { RecordGroupDefinitionType } from '@/object-record/record-group/types/RecordGroupDefinition';
import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useToggleDropdown } from '@/ui/layout/dropdown/hooks/useToggleDropdown';
import { Tag } from 'twenty-ui/components';
import { IconDotsVertical, IconPlus } from 'twenty-ui/display';
import { LightIconButton } from 'twenty-ui/input';
@ -66,32 +66,11 @@ const StyledTag = styled(Tag)`
export const RecordBoardColumnHeader = () => {
const { columnDefinition } = useContext(RecordBoardColumnContext);
const [isBoardColumnMenuOpen, setIsBoardColumnMenuOpen] = useState(false);
const [isHeaderHovered, setIsHeaderHovered] = useState(false);
const { objectMetadataItem, selectFieldMetadataItem } =
useContext(RecordBoardContext);
const {
setHotkeyScopeAndMemorizePreviousScope,
goBackToPreviousHotkeyScope,
} = usePreviousHotkeyScope();
const handleBoardColumnMenuOpen = () => {
setIsBoardColumnMenuOpen(true);
setHotkeyScopeAndMemorizePreviousScope({
scope: RecordBoardColumnHotkeyScope.BoardColumn,
customScopes: {
goto: false,
},
});
};
const handleBoardColumnMenuClose = () => {
goBackToPreviousHotkeyScope();
setIsBoardColumnMenuOpen(false);
};
const { aggregateValue, aggregateLabel } =
useAggregateRecordsForRecordBoardColumn();
@ -105,6 +84,10 @@ export const RecordBoardColumnHeader = () => {
objectMetadataItem: objectMetadataItem,
});
const { toggleDropdown } = useToggleDropdown();
const dropdownId = `record-board-column-dropdown-${columnDefinition.id}`;
return (
<StyledColumn>
<StyledHeader
@ -113,25 +96,36 @@ export const RecordBoardColumnHeader = () => {
>
<StyledHeaderContainer>
<StyledLeftContainer>
<StyledTag
onClick={handleBoardColumnMenuOpen}
variant={
columnDefinition.type === RecordGroupDefinitionType.Value
? 'solid'
: 'outline'
}
color={
columnDefinition.type === RecordGroupDefinitionType.Value
? columnDefinition.color
: 'transparent'
}
text={columnDefinition.title}
weight={
columnDefinition.type === RecordGroupDefinitionType.Value
? 'regular'
: 'medium'
<Dropdown
dropdownId={dropdownId}
dropdownPlacement="bottom-start"
dropdownOffset={{
x: 0,
y: 10,
}}
clickableComponent={
<StyledTag
variant={
columnDefinition.type === RecordGroupDefinitionType.Value
? 'solid'
: 'outline'
}
color={
columnDefinition.type === RecordGroupDefinitionType.Value
? columnDefinition.color
: 'transparent'
}
text={columnDefinition.title}
weight={
columnDefinition.type === RecordGroupDefinitionType.Value
? 'regular'
: 'medium'
}
/>
}
dropdownComponents={<RecordBoardColumnDropdownMenu />}
/>
<RecordBoardColumnHeaderAggregateDropdown
aggregateValue={aggregateValue}
dropdownId={`record-board-column-aggregate-dropdown-${columnDefinition.id}`}
@ -145,7 +139,11 @@ export const RecordBoardColumnHeader = () => {
<LightIconButton
accent="tertiary"
Icon={IconDotsVertical}
onClick={handleBoardColumnMenuOpen}
onClick={() => {
toggleDropdown({
dropdownComponentInstanceIdFromProps: dropdownId,
});
}}
/>
{hasObjectUpdatePermissions && (
<LightIconButton
@ -164,12 +162,6 @@ export const RecordBoardColumnHeader = () => {
</StyledRightContainer>
</StyledHeaderContainer>
</StyledHeader>
{isBoardColumnMenuOpen && (
<RecordBoardColumnDropdownMenu
onClose={handleBoardColumnMenuClose}
stageId={columnDefinition.id}
/>
)}
</StyledColumn>
);
};

View File

@ -1,36 +1,24 @@
import { Key } from 'ts-key-enum';
import { useDropdownContextStateManagement } from '@/dropdown-context-state-management/hooks/useDropdownContextStateManagement';
import {
RecordBoardColumnHeaderAggregateDropdownContext,
RecordBoardColumnHeaderAggregateDropdownContextValue,
} from '@/object-record/record-board/record-board-column/components/RecordBoardColumnHeaderAggregateDropdownContext';
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useLingui } from '@lingui/react/macro';
import { MenuItem } from 'twenty-ui/navigation';
export const RecordBoardColumnHeaderAggregateDropdownMenuContent = () => {
const { t } = useLingui();
const { onContentChange, closeDropdown } =
const { onContentChange } =
useDropdownContextStateManagement<RecordBoardColumnHeaderAggregateDropdownContextValue>(
{
context: RecordBoardColumnHeaderAggregateDropdownContext,
},
);
useScopedHotkeys(
[Key.Escape],
() => {
closeDropdown();
},
TableOptionsHotkeyScope.Dropdown,
);
return (
<DropdownContent>
<DropdownMenuItemsContainer>

View File

@ -10,18 +10,15 @@ import { getAggregateOperationLabel } from '@/object-record/record-board/record-
import { recordIndexKanbanAggregateOperationState } from '@/object-record/record-index/states/recordIndexKanbanAggregateOperationState';
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
import { ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
import { AvailableFieldsForAggregateOperation } from '@/object-record/types/AvailableFieldsForAggregateOperation';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { useUpdateViewAggregate } from '@/views/hooks/useUpdateViewAggregate';
import isEmpty from 'lodash.isempty';
import { useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import { IconCheck, IconChevronLeft } from 'twenty-ui/display';
export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({
@ -38,14 +35,6 @@ export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({
},
);
useScopedHotkeys(
[Key.Escape],
() => {
closeDropdown();
},
TableOptionsHotkeyScope.Dropdown,
);
const setAggregateOperation = useSetRecoilComponentStateV2(
aggregateOperationComponentState,
);

View File

@ -85,6 +85,7 @@ export const FormBooleanFieldInput = ({
<FormFieldInputRowContainer>
<FormFieldInputInnerContainer
formFieldInputInstanceId={instanceId}
hasRightElement={isDefined(VariablePicker) && !readonly}
>
{draftValue.type === 'static' ? (

View File

@ -296,6 +296,7 @@ export const FormDateTimeFieldInput = ({
<FormFieldInputRowContainer>
<StyledInputContainer
formFieldInputInstanceId={instanceId}
ref={datePickerWrapperRef}
hasRightElement={isDefined(VariablePicker) && !readonly}
>

View File

@ -1,5 +1,7 @@
import { FormFieldInputHotKeyScope } from '@/object-record/record-field/form-types/constants/FormFieldInputHotKeyScope';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import { forwardRef, HTMLAttributes, Ref } from 'react';
@ -9,9 +11,12 @@ type FormFieldInputInnerContainerProps = {
multiline?: boolean;
readonly?: boolean;
preventSetHotkeyScope?: boolean;
formFieldInputInstanceId: string;
};
const StyledFormFieldInputInnerContainer = styled.div<FormFieldInputInnerContainerProps>`
const StyledFormFieldInputInnerContainer = styled.div<
Omit<FormFieldInputInnerContainerProps, 'formFieldInputInstanceId'>
>`
background-color: ${({ theme }) => theme.background.transparent.lighter};
border: 1px solid ${({ theme }) => theme.border.color.medium};
border-top-left-radius: ${({ theme }) => theme.border.radius.sm};
@ -48,20 +53,25 @@ export const FormFieldInputInnerContainer = forwardRef(
readonly,
preventSetHotkeyScope = false,
onClick,
formFieldInputInstanceId,
}: HTMLAttributes<HTMLDivElement> & FormFieldInputInnerContainerProps,
ref: Ref<HTMLDivElement>,
) => {
const {
goBackToPreviousHotkeyScope,
setHotkeyScopeAndMemorizePreviousScope,
} = usePreviousHotkeyScope();
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
const { removeFocusItemFromFocusStackById } =
useRemoveFocusItemFromFocusStackById();
const handleFocus = (e: React.FocusEvent<HTMLDivElement>) => {
onFocus?.(e);
if (!preventSetHotkeyScope) {
setHotkeyScopeAndMemorizePreviousScope({
scope: FormFieldInputHotKeyScope.FormFieldInput,
pushFocusItemToFocusStack({
focusId: formFieldInputInstanceId,
component: {
type: FocusComponentType.FORM_FIELD_INPUT,
instanceId: formFieldInputInstanceId,
},
hotkeyScope: { scope: FormFieldInputHotKeyScope.FormFieldInput },
});
}
};
@ -70,7 +80,9 @@ export const FormFieldInputInnerContainer = forwardRef(
onBlur?.(e);
if (!preventSetHotkeyScope) {
goBackToPreviousHotkeyScope();
removeFocusItemFromFocusStackById({
focusId: formFieldInputInstanceId,
});
}
};

View File

@ -14,7 +14,9 @@ import { MultiSelectInput } from '@/ui/field/input/components/MultiSelectInput';
import { InputLabel } from '@/ui/input/components/InputLabel';
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
import { OverlayContainer } from '@/ui/layout/overlay/components/OverlayContainer';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
import { useTheme } from '@emotion/react';
import { isArray } from '@sniptt/guards';
@ -88,10 +90,9 @@ export const FormMultiSelectFieldInput = ({
const hotkeyScope =
FormMultiSelectFieldInputHotKeyScope.FormMultiSelectFieldInput;
const {
setHotkeyScopeAndMemorizePreviousScope,
goBackToPreviousHotkeyScope,
} = usePreviousHotkeyScope();
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
const { removeFocusItemFromFocusStackById } =
useRemoveFocusItemFromFocusStackById();
const [draftValue, setDraftValue] = useState<
| {
@ -128,8 +129,13 @@ export const FormMultiSelectFieldInput = ({
editingMode: 'edit',
});
setHotkeyScopeAndMemorizePreviousScope({
scope: hotkeyScope,
pushFocusItemToFocusStack({
focusId: instanceId,
component: {
type: FocusComponentType.FORM_FIELD_INPUT,
instanceId,
},
hotkeyScope: { scope: hotkeyScope },
});
};
@ -157,7 +163,7 @@ export const FormMultiSelectFieldInput = ({
editingMode: 'view',
});
goBackToPreviousHotkeyScope();
removeFocusItemFromFocusStackById({ focusId: instanceId });
};
const handleVariableTagInsert = (variableName: string) => {
@ -201,6 +207,7 @@ export const FormMultiSelectFieldInput = ({
<FormFieldInputRowContainer>
<FormFieldInputInnerContainer
formFieldInputInstanceId={instanceId}
hasRightElement={isDefined(VariablePicker) && !readonly}
>
{draftValue.type === 'static' ? (

View File

@ -121,6 +121,7 @@ export const FormNumberFieldInput = ({
<FormFieldInputRowContainer>
<FormFieldInputInnerContainer
formFieldInputInstanceId={instanceId}
hasRightElement={isDefined(VariablePicker) && !readonly}
onBlur={onBlur}
>

View File

@ -71,6 +71,7 @@ export const FormRawJsonFieldInput = ({
<FormFieldInputRowContainer multiline>
<FormFieldInputInnerContainer
formFieldInputInstanceId={instanceId}
hasRightElement={isDefined(VariablePicker) && !readonly}
multiline
onBlur={onBlur}

View File

@ -7,8 +7,8 @@ import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/
import { InputLabel } from '@/ui/input/components/InputLabel';
import { Select } from '@/ui/input/components/Select';
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
import { useTheme } from '@emotion/react';
import { useId, useState } from 'react';
@ -40,7 +40,8 @@ export const FormSelectFieldInput = ({
const hotkeyScope = InlineCellHotkeyScope.InlineCell;
const { goBackToPreviousHotkeyScope } = usePreviousHotkeyScope();
const { removeFocusItemFromFocusStackById } =
useRemoveFocusItemFromFocusStackById();
const [draftValue, setDraftValue] = useState<
| {
@ -72,7 +73,7 @@ export const FormSelectFieldInput = ({
editingMode: 'view',
});
goBackToPreviousHotkeyScope();
removeFocusItemFromFocusStackById({ focusId: instanceId });
onChange(option);
};
@ -87,7 +88,7 @@ export const FormSelectFieldInput = ({
editingMode: 'view',
});
goBackToPreviousHotkeyScope();
removeFocusItemFromFocusStackById({ focusId: instanceId });
};
const selectedOption = options.find(
@ -119,14 +120,13 @@ export const FormSelectFieldInput = ({
onChange(variableName);
};
useScopedHotkeys(
Key.Escape,
() => {
onCancel();
},
hotkeyScope,
[onCancel],
);
useHotkeysOnFocusedElement({
keys: Key.Escape,
callback: onCancel,
focusId: instanceId,
scope: hotkeyScope,
dependencies: [onCancel],
});
return (
<FormFieldInputContainer>
@ -149,6 +149,7 @@ export const FormSelectFieldInput = ({
/>
) : (
<FormFieldInputInnerContainer
formFieldInputInstanceId={instanceId}
hasRightElement={isDefined(VariablePicker) && !readonly}
>
<VariableChipStandalone

View File

@ -150,7 +150,11 @@ export const FormSingleRecordPicker = ({
{label ? <InputLabel>{label}</InputLabel> : null}
<FormFieldInputRowContainer>
{disabled ? (
<StyledFormSelectContainer hasRightElement={false} readonly>
<StyledFormSelectContainer
formFieldInputInstanceId={componentId}
hasRightElement={false}
readonly
>
<FormSingleRecordFieldChip
draftValue={draftValue}
selectedRecord={selectedRecord}
@ -169,6 +173,7 @@ export const FormSingleRecordPicker = ({
dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }}
clickableComponent={
<StyledFormSelectContainer
formFieldInputInstanceId={componentId}
hasRightElement={isDefined(VariablePicker) && !disabled}
preventSetHotkeyScope={true}
>

View File

@ -71,6 +71,7 @@ export const FormTextFieldInput = ({
<FormFieldInputRowContainer multiline={multiline}>
<FormFieldInputInnerContainer
formFieldInputInstanceId={instanceId}
hasRightElement={isDefined(VariablePicker) && !readonly}
multiline={multiline}
onBlur={onBlur}

View File

@ -95,6 +95,7 @@ export const FormUuidFieldInput = ({
<FormFieldInputRowContainer>
<FormFieldInputInnerContainer
formFieldInputInstanceId={instanceId}
hasRightElement={isDefined(VariablePicker) && !readonly}
>
{draftValue.type === 'static' ? (

View File

@ -1 +0,0 @@
export const RECORD_INDEX_FOCUS_ID = 'record-index';

View File

@ -1,5 +1,5 @@
import { RECORD_INDEX_FOCUS_ID } from '@/object-record/record-index/constants/RecordIndexFocusId';
import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/RecordIndexHotkeyScope';
import { PageFocusId } from '@/types/PageFocusId';
import { useResetFocusStackToFocusItem } from '@/ui/utilities/focus/hooks/useResetFocusStackToFocusItem';
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
@ -9,10 +9,10 @@ export const useResetFocusStackToRecordIndex = () => {
const resetFocusStackToRecordIndex = () => {
resetFocusStackToFocusItem({
focusStackItem: {
focusId: RECORD_INDEX_FOCUS_ID,
focusId: PageFocusId.RecordIndex,
componentInstance: {
componentType: FocusComponentType.PAGE,
componentInstanceId: RECORD_INDEX_FOCUS_ID,
componentInstanceId: PageFocusId.RecordIndex,
},
globalHotkeysConfig: {
enableGlobalHotkeysWithModifiers: true,

View File

@ -14,7 +14,6 @@ import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/Recor
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { RecordUpdateContext } from '../contexts/EntityUpdateMutationHookContext';
import { useRecordTable } from '../hooks/useRecordTable';
@ -48,16 +47,6 @@ export const RecordTableWithWrappers = ({
selectAllRows();
};
useScopedHotkeys(
'ctrl+a,meta+a',
handleSelectAllRows,
RecordIndexHotkeyScope.RecordIndex,
[],
{
enableOnFormTags: false,
},
);
useHotkeysOnFocusedElement({
keys: ['ctrl+a,meta+a'],
callback: handleSelectAllRows,

View File

@ -1,10 +1,10 @@
import { Key } from 'ts-key-enum';
import { RECORD_INDEX_FOCUS_ID } from '@/object-record/record-index/constants/RecordIndexFocusId';
import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/RecordIndexHotkeyScope';
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { isAtLeastOneTableRowSelectedSelector } from '@/object-record/record-table/record-table-row/states/isAtLeastOneTableRowSelectedSelector';
import { PageFocusId } from '@/types/PageFocusId';
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
@ -28,7 +28,7 @@ export const RecordTableBodyEscapeHotkeyEffect = () => {
useHotkeysOnFocusedElement({
keys: [Key.Escape],
callback: handleEscape,
focusId: RECORD_INDEX_FOCUS_ID,
focusId: PageFocusId.RecordIndex,
scope: RecordIndexHotkeyScope.RecordIndex,
dependencies: [handleEscape],
options: {

View File

@ -1,10 +1,10 @@
import { RECORD_INDEX_FOCUS_ID } from '@/object-record/record-index/constants/RecordIndexFocusId';
import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/RecordIndexHotkeyScope';
import { useRecordTableRowFocusHotkeys } from '@/object-record/record-table/hooks/useRecordTableRowFocusHotkeys';
import { PageFocusId } from '@/types/PageFocusId';
export const RecordTableBodyFocusKeyboardEffect = () => {
useRecordTableRowFocusHotkeys({
focusId: RECORD_INDEX_FOCUS_ID,
focusId: PageFocusId.RecordIndex,
hotkeyScope: RecordIndexHotkeyScope.RecordIndex,
});

View File

@ -1,15 +1,11 @@
import { RecordTableColumnAggregateFooterAggregateOperationMenuItems } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterAggregateOperationMenuItems';
import { RecordTableColumnAggregateFooterDropdownContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContext';
import { ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useContext } from 'react';
import { Key } from 'ts-key-enum';
import { IconChevronLeft } from 'twenty-ui/display';
export const RecordTableColumnAggregateFooterDropdownSubmenuContent = ({
@ -19,19 +15,10 @@ export const RecordTableColumnAggregateFooterDropdownSubmenuContent = ({
aggregateOperations: ExtendedAggregateOperations[];
title: string;
}) => {
const { dropdownId, resetContent } = useContext(
const { resetContent } = useContext(
RecordTableColumnAggregateFooterDropdownContext,
);
const { closeDropdown } = useCloseDropdown();
useScopedHotkeys(
[Key.Escape],
() => {
resetContent();
closeDropdown(dropdownId);
},
TableOptionsHotkeyScope.Dropdown,
);
return (
<DropdownContent>
<DropdownMenuHeader

View File

@ -4,14 +4,11 @@ import { RecordTableColumnAggregateFooterDropdownContext } from '@/object-record
import { NON_STANDARD_AGGREGATE_OPERATION_OPTIONS } from '@/object-record/record-table/record-table-footer/constants/nonStandardAggregateOperationsOptions';
import { useViewFieldAggregateOperation } from '@/object-record/record-table/record-table-footer/hooks/useViewFieldAggregateOperation';
import { getAvailableAggregateOperationsForFieldMetadataType } from '@/object-record/record-table/record-table-footer/utils/getAvailableAggregateOperationsForFieldMetadataType';
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { t } from '@lingui/core/macro';
import { useContext, useMemo } from 'react';
import { Key } from 'ts-key-enum';
import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils';
import { IconCheck } from 'twenty-ui/display';
import { MenuItem } from 'twenty-ui/navigation';
@ -28,14 +25,6 @@ export const RecordTableColumnAggregateFooterMenuContent = () => {
const { closeDropdown } = useCloseDropdown();
const { objectMetadataItem } = useRecordTableContextOrThrow();
useScopedHotkeys(
[Key.Escape],
() => {
closeDropdown(dropdownId);
},
TableOptionsHotkeyScope.Dropdown,
);
const availableAggregateOperation = useMemo(
() =>
getAvailableAggregateOperationsForFieldMetadataType({