Replace hotkey scopes by focus stack (Part 3 - Record Board, Cards and Inline Cells) (#12910)
# Replace hotkey scopes by focus stack (Part 3 - Record Board, Cards and Inline Cells) This PR is the second 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 The board shortcuts are no longer centralized in the record board, they are now split and the focused element is in charge of applying the desired shortcuts. ## Video QA: https://github.com/user-attachments/assets/20ba4a24-6fc3-4a97-9cd3-68e846699e30
This commit is contained in:
@ -5,17 +5,17 @@ import { RecordBoardContext } from '@/object-record/record-board/contexts/Record
|
|||||||
import { useFocusedRecordBoardCard } from '@/object-record/record-board/hooks/useFocusedRecordBoardCard';
|
import { useFocusedRecordBoardCard } from '@/object-record/record-board/hooks/useFocusedRecordBoardCard';
|
||||||
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection';
|
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection';
|
||||||
import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector';
|
import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector';
|
||||||
import { BoardHotkeyScope } from '@/object-record/record-board/types/BoardHotkeyScope';
|
import { useResetFocusStackToRecordIndex } from '@/object-record/record-index/hooks/useResetFocusStackToRecordIndex';
|
||||||
import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/RecordIndexHotkeyScope';
|
import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/RecordIndexHotkeyScope';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
|
||||||
export const RecordBoardBodyEscapeHotkeyEffect = () => {
|
export const RecordBoardBodyEscapeHotkeyEffect = () => {
|
||||||
const { recordBoardId } = useContext(RecordBoardContext);
|
const { recordBoardId } = useContext(RecordBoardContext);
|
||||||
|
|
||||||
const { resetRecordSelection } = useRecordBoardSelection(recordBoardId);
|
const { resetRecordSelection } = useRecordBoardSelection(recordBoardId);
|
||||||
|
|
||||||
const { unfocusBoardCard } = useFocusedRecordBoardCard(recordBoardId);
|
const { unfocusBoardCard } = useFocusedRecordBoardCard(recordBoardId);
|
||||||
|
const { resetFocusStackToRecordIndex } = useResetFocusStackToRecordIndex();
|
||||||
|
|
||||||
const selectedRecordIds = useRecoilComponentValueV2(
|
const selectedRecordIds = useRecoilComponentValueV2(
|
||||||
recordBoardSelectedRecordIdsComponentSelector,
|
recordBoardSelectedRecordIdsComponentSelector,
|
||||||
@ -24,29 +24,21 @@ export const RecordBoardBodyEscapeHotkeyEffect = () => {
|
|||||||
|
|
||||||
const isAtLeastOneRecordSelected = selectedRecordIds.length > 0;
|
const isAtLeastOneRecordSelected = selectedRecordIds.length > 0;
|
||||||
|
|
||||||
useScopedHotkeys(
|
const handleEscape = () => {
|
||||||
[Key.Escape],
|
unfocusBoardCard();
|
||||||
() => {
|
if (isAtLeastOneRecordSelected) {
|
||||||
unfocusBoardCard();
|
resetRecordSelection();
|
||||||
if (isAtLeastOneRecordSelected) {
|
}
|
||||||
resetRecordSelection();
|
resetFocusStackToRecordIndex();
|
||||||
}
|
};
|
||||||
},
|
|
||||||
RecordIndexHotkeyScope.RecordIndex,
|
|
||||||
[isAtLeastOneRecordSelected, resetRecordSelection, unfocusBoardCard],
|
|
||||||
);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
useHotkeysOnFocusedElement({
|
||||||
[Key.Escape],
|
keys: [Key.Escape],
|
||||||
() => {
|
callback: handleEscape,
|
||||||
unfocusBoardCard();
|
focusId: recordBoardId,
|
||||||
if (isAtLeastOneRecordSelected) {
|
scope: RecordIndexHotkeyScope.RecordIndex,
|
||||||
resetRecordSelection();
|
dependencies: [handleEscape],
|
||||||
}
|
});
|
||||||
},
|
|
||||||
BoardHotkeyScope.BoardFocus,
|
|
||||||
[isAtLeastOneRecordSelected, resetRecordSelection, unfocusBoardCard],
|
|
||||||
);
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,137 +3,30 @@ import { Key } from 'ts-key-enum';
|
|||||||
|
|
||||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||||
import { useRecordBoardCardNavigation } from '@/object-record/record-board/hooks/useRecordBoardCardNavigation';
|
import { useRecordBoardCardNavigation } from '@/object-record/record-board/hooks/useRecordBoardCardNavigation';
|
||||||
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection';
|
import { useRecordBoardSelectAllHotkeys } from '@/object-record/record-board/hooks/useRecordBoardSelectAllHotkeys';
|
||||||
import { BoardHotkeyScope } from '@/object-record/record-board/types/BoardHotkeyScope';
|
import { RECORD_INDEX_FOCUS_ID } from '@/object-record/record-index/constants/RecordIndexFocusId';
|
||||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
|
||||||
import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/RecordIndexHotkeyScope';
|
import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/RecordIndexHotkeyScope';
|
||||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
|
||||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
|
||||||
import { useRecoilCallback } from 'recoil';
|
|
||||||
|
|
||||||
const BOARD_NAVIGATION_CUSTOM_SCOPES = {
|
|
||||||
goto: true,
|
|
||||||
keyboardShortcutMenu: true,
|
|
||||||
searchRecords: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const RecordBoardHotkeyEffect = () => {
|
export const RecordBoardHotkeyEffect = () => {
|
||||||
const { recordBoardId } = useContext(RecordBoardContext);
|
const { recordBoardId } = useContext(RecordBoardContext);
|
||||||
|
|
||||||
const { move } = useRecordBoardCardNavigation(recordBoardId);
|
const { move } = useRecordBoardCardNavigation(recordBoardId);
|
||||||
|
|
||||||
const { setHotkeyScopeAndMemorizePreviousScope } = usePreviousHotkeyScope();
|
useHotkeysOnFocusedElement({
|
||||||
|
keys: [Key.ArrowLeft, Key.ArrowUp, Key.ArrowDown, Key.ArrowRight],
|
||||||
const recordIndexAllRecordIdsState = useRecoilComponentCallbackStateV2(
|
callback: () => {
|
||||||
recordIndexAllRecordIdsComponentSelector,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { setRecordAsSelected } = useRecordBoardSelection(recordBoardId);
|
|
||||||
|
|
||||||
const selectAll = useRecoilCallback(
|
|
||||||
({ snapshot }) =>
|
|
||||||
() => {
|
|
||||||
const allRecordIds = getSnapshotValue(
|
|
||||||
snapshot,
|
|
||||||
recordIndexAllRecordIdsState,
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const recordId of allRecordIds) {
|
|
||||||
setRecordAsSelected(recordId, true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[recordIndexAllRecordIdsState, setRecordAsSelected],
|
|
||||||
);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
|
||||||
'ctrl+a,meta+a',
|
|
||||||
selectAll,
|
|
||||||
RecordIndexHotkeyScope.RecordIndex,
|
|
||||||
);
|
|
||||||
|
|
||||||
useScopedHotkeys('ctrl+a,meta+a', selectAll, BoardHotkeyScope.BoardFocus);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
|
||||||
Key.ArrowLeft,
|
|
||||||
() => {
|
|
||||||
setHotkeyScopeAndMemorizePreviousScope({
|
|
||||||
scope: BoardHotkeyScope.BoardFocus,
|
|
||||||
customScopes: BOARD_NAVIGATION_CUSTOM_SCOPES,
|
|
||||||
});
|
|
||||||
move('left');
|
|
||||||
},
|
|
||||||
RecordIndexHotkeyScope.RecordIndex,
|
|
||||||
);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
|
||||||
Key.ArrowRight,
|
|
||||||
() => {
|
|
||||||
setHotkeyScopeAndMemorizePreviousScope({
|
|
||||||
scope: BoardHotkeyScope.BoardFocus,
|
|
||||||
customScopes: BOARD_NAVIGATION_CUSTOM_SCOPES,
|
|
||||||
});
|
|
||||||
move('right');
|
|
||||||
},
|
|
||||||
RecordIndexHotkeyScope.RecordIndex,
|
|
||||||
);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
|
||||||
Key.ArrowUp,
|
|
||||||
() => {
|
|
||||||
setHotkeyScopeAndMemorizePreviousScope({
|
|
||||||
scope: BoardHotkeyScope.BoardFocus,
|
|
||||||
customScopes: BOARD_NAVIGATION_CUSTOM_SCOPES,
|
|
||||||
});
|
|
||||||
move('up');
|
|
||||||
},
|
|
||||||
RecordIndexHotkeyScope.RecordIndex,
|
|
||||||
);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
|
||||||
Key.ArrowDown,
|
|
||||||
() => {
|
|
||||||
setHotkeyScopeAndMemorizePreviousScope({
|
|
||||||
scope: BoardHotkeyScope.BoardFocus,
|
|
||||||
customScopes: BOARD_NAVIGATION_CUSTOM_SCOPES,
|
|
||||||
});
|
|
||||||
move('down');
|
move('down');
|
||||||
},
|
},
|
||||||
RecordIndexHotkeyScope.RecordIndex,
|
focusId: RECORD_INDEX_FOCUS_ID,
|
||||||
);
|
scope: RecordIndexHotkeyScope.RecordIndex,
|
||||||
|
dependencies: [move],
|
||||||
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useRecordBoardSelectAllHotkeys({
|
||||||
Key.ArrowLeft,
|
recordBoardId,
|
||||||
() => {
|
focusId: recordBoardId,
|
||||||
move('left');
|
});
|
||||||
},
|
|
||||||
BoardHotkeyScope.BoardFocus,
|
|
||||||
);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
|
||||||
Key.ArrowRight,
|
|
||||||
() => {
|
|
||||||
move('right');
|
|
||||||
},
|
|
||||||
BoardHotkeyScope.BoardFocus,
|
|
||||||
);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
|
||||||
Key.ArrowUp,
|
|
||||||
() => {
|
|
||||||
move('up');
|
|
||||||
},
|
|
||||||
BoardHotkeyScope.BoardFocus,
|
|
||||||
);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
|
||||||
Key.ArrowDown,
|
|
||||||
() => {
|
|
||||||
move('down');
|
|
||||||
},
|
|
||||||
BoardHotkeyScope.BoardFocus,
|
|
||||||
);
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
export const RECORD_BOARD_FOCUS_ID = 'record-board';
|
||||||
@ -1,7 +1,12 @@
|
|||||||
|
import { getRecordBoardCardFocusId } from '@/object-record/record-board/record-board-card/utils/getRecordBoardCardFocusId';
|
||||||
import { focusedRecordBoardCardIndexesComponentState } from '@/object-record/record-board/states/focusedRecordBoardCardIndexesComponentState';
|
import { focusedRecordBoardCardIndexesComponentState } from '@/object-record/record-board/states/focusedRecordBoardCardIndexesComponentState';
|
||||||
import { isRecordBoardCardFocusActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCardFocusActiveComponentState';
|
import { isRecordBoardCardFocusActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCardFocusActiveComponentState';
|
||||||
import { isRecordBoardCardFocusedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardFocusedComponentFamilyState';
|
import { isRecordBoardCardFocusedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardFocusedComponentFamilyState';
|
||||||
import { BoardCardIndexes } from '@/object-record/record-board/types/BoardCardIndexes';
|
import { BoardCardIndexes } from '@/object-record/record-board/types/BoardCardIndexes';
|
||||||
|
import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/RecordIndexHotkeyScope';
|
||||||
|
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 { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
@ -22,6 +27,10 @@ export const useFocusedRecordBoardCard = (recordBoardId?: string) => {
|
|||||||
recordBoardId,
|
recordBoardId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||||
|
const { removeFocusItemFromFocusStackById } =
|
||||||
|
useRemoveFocusItemFromFocusStackById();
|
||||||
|
|
||||||
const unfocusBoardCard = useRecoilCallback(
|
const unfocusBoardCard = useRecoilCallback(
|
||||||
({ set, snapshot }) =>
|
({ set, snapshot }) =>
|
||||||
() => {
|
() => {
|
||||||
@ -33,11 +42,26 @@ export const useFocusedRecordBoardCard = (recordBoardId?: string) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const focusId = getRecordBoardCardFocusId({
|
||||||
|
recordBoardId: recordBoardId || '',
|
||||||
|
cardIndexes: focusedBoardCardIndexes,
|
||||||
|
});
|
||||||
|
|
||||||
|
removeFocusItemFromFocusStackById({
|
||||||
|
focusId,
|
||||||
|
});
|
||||||
|
|
||||||
set(focusedBoardCardIndexesState, null);
|
set(focusedBoardCardIndexesState, null);
|
||||||
set(isCardFocusedState(focusedBoardCardIndexes), false);
|
set(isCardFocusedState(focusedBoardCardIndexes), false);
|
||||||
set(isCardFocusActiveState, false);
|
set(isCardFocusActiveState, false);
|
||||||
},
|
},
|
||||||
[focusedBoardCardIndexesState, isCardFocusedState, isCardFocusActiveState],
|
[
|
||||||
|
focusedBoardCardIndexesState,
|
||||||
|
isCardFocusedState,
|
||||||
|
isCardFocusActiveState,
|
||||||
|
recordBoardId,
|
||||||
|
removeFocusItemFromFocusStackById,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const focusBoardCard = useRecoilCallback(
|
const focusBoardCard = useRecoilCallback(
|
||||||
@ -54,13 +78,51 @@ export const useFocusedRecordBoardCard = (recordBoardId?: string) => {
|
|||||||
boardCardIndexes.columnIndex)
|
boardCardIndexes.columnIndex)
|
||||||
) {
|
) {
|
||||||
set(isCardFocusedState(focusedBoardCardIndexes), false);
|
set(isCardFocusedState(focusedBoardCardIndexes), false);
|
||||||
|
|
||||||
|
const currentFocusId = getRecordBoardCardFocusId({
|
||||||
|
recordBoardId: recordBoardId || '',
|
||||||
|
cardIndexes: focusedBoardCardIndexes,
|
||||||
|
});
|
||||||
|
|
||||||
|
removeFocusItemFromFocusStackById({
|
||||||
|
focusId: currentFocusId,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const focusId = getRecordBoardCardFocusId({
|
||||||
|
recordBoardId: recordBoardId || '',
|
||||||
|
cardIndexes: boardCardIndexes,
|
||||||
|
});
|
||||||
|
|
||||||
|
pushFocusItemToFocusStack({
|
||||||
|
focusId,
|
||||||
|
component: {
|
||||||
|
type: FocusComponentType.RECORD_BOARD_CARD,
|
||||||
|
instanceId: focusId,
|
||||||
|
},
|
||||||
|
hotkeyScope: {
|
||||||
|
scope: RecordIndexHotkeyScope.RecordIndex,
|
||||||
|
customScopes: {
|
||||||
|
goto: true,
|
||||||
|
keyboardShortcutMenu: true,
|
||||||
|
searchRecords: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
memoizeKey: focusId,
|
||||||
|
});
|
||||||
|
|
||||||
set(focusedBoardCardIndexesState, boardCardIndexes);
|
set(focusedBoardCardIndexesState, boardCardIndexes);
|
||||||
set(isCardFocusedState(boardCardIndexes), true);
|
set(isCardFocusedState(boardCardIndexes), true);
|
||||||
set(isCardFocusActiveState, true);
|
set(isCardFocusActiveState, true);
|
||||||
},
|
},
|
||||||
[focusedBoardCardIndexesState, isCardFocusedState, isCardFocusActiveState],
|
[
|
||||||
|
focusedBoardCardIndexesState,
|
||||||
|
isCardFocusedState,
|
||||||
|
isCardFocusActiveState,
|
||||||
|
recordBoardId,
|
||||||
|
pushFocusItemToFocusStack,
|
||||||
|
removeFocusItemFromFocusStackById,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
import { useRecordBoardCardNavigation } from '@/object-record/record-board/hooks/useRecordBoardCardNavigation';
|
||||||
|
import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/RecordIndexHotkeyScope';
|
||||||
|
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||||
|
import { Key } from 'ts-key-enum';
|
||||||
|
|
||||||
|
export const useRecordBoardArrowKeysEffect = ({
|
||||||
|
recordBoardId,
|
||||||
|
focusId,
|
||||||
|
}: {
|
||||||
|
recordBoardId: string;
|
||||||
|
focusId: string;
|
||||||
|
}) => {
|
||||||
|
const { move } = useRecordBoardCardNavigation(recordBoardId);
|
||||||
|
|
||||||
|
useHotkeysOnFocusedElement({
|
||||||
|
keys: [Key.ArrowLeft],
|
||||||
|
callback: () => move('left'),
|
||||||
|
focusId,
|
||||||
|
scope: RecordIndexHotkeyScope.RecordIndex,
|
||||||
|
dependencies: [move],
|
||||||
|
});
|
||||||
|
|
||||||
|
useHotkeysOnFocusedElement({
|
||||||
|
keys: [Key.ArrowRight],
|
||||||
|
callback: () => move('right'),
|
||||||
|
focusId,
|
||||||
|
scope: RecordIndexHotkeyScope.RecordIndex,
|
||||||
|
dependencies: [move],
|
||||||
|
});
|
||||||
|
|
||||||
|
useHotkeysOnFocusedElement({
|
||||||
|
keys: [Key.ArrowUp],
|
||||||
|
callback: () => move('up'),
|
||||||
|
focusId,
|
||||||
|
scope: RecordIndexHotkeyScope.RecordIndex,
|
||||||
|
dependencies: [move],
|
||||||
|
});
|
||||||
|
|
||||||
|
useHotkeysOnFocusedElement({
|
||||||
|
keys: [Key.ArrowDown],
|
||||||
|
callback: () => move('down'),
|
||||||
|
focusId,
|
||||||
|
scope: RecordIndexHotkeyScope.RecordIndex,
|
||||||
|
dependencies: [move],
|
||||||
|
});
|
||||||
|
};
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||||
|
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||||
|
import { useActiveRecordBoardCard } from '@/object-record/record-board/hooks/useActiveRecordBoardCard';
|
||||||
|
import { useFocusedRecordBoardCard } from '@/object-record/record-board/hooks/useFocusedRecordBoardCard';
|
||||||
|
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection';
|
||||||
|
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
|
||||||
|
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
|
||||||
|
import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector';
|
||||||
|
import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/RecordIndexHotkeyScope';
|
||||||
|
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||||
|
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { Key } from 'ts-key-enum';
|
||||||
|
|
||||||
|
export const useRecordBoardCardHotkeys = (focusId: string) => {
|
||||||
|
const { objectMetadataItem, recordBoardId } = useContext(RecordBoardContext);
|
||||||
|
const { recordId, rowIndex, columnIndex } = useContext(
|
||||||
|
RecordBoardCardContext,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||||
|
const { activateBoardCard } = useActiveRecordBoardCard();
|
||||||
|
const { setRecordAsSelected, resetRecordSelection } =
|
||||||
|
useRecordBoardSelection();
|
||||||
|
const { unfocusBoardCard } = useFocusedRecordBoardCard(recordBoardId);
|
||||||
|
|
||||||
|
const isRecordBoardCardSelected = useRecoilComponentFamilyValueV2(
|
||||||
|
isRecordBoardCardSelectedComponentFamilyState,
|
||||||
|
recordId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedRecordIds = useRecoilComponentValueV2(
|
||||||
|
recordBoardSelectedRecordIdsComponentSelector,
|
||||||
|
recordBoardId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isAtLeastOneRecordSelected = selectedRecordIds.length > 0;
|
||||||
|
|
||||||
|
const handleSelectCard = () => {
|
||||||
|
setRecordAsSelected(recordId, !isRecordBoardCardSelected);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOpenRecordInCommandMenu = () => {
|
||||||
|
openRecordInCommandMenu({
|
||||||
|
recordId,
|
||||||
|
objectNameSingular: objectMetadataItem.nameSingular,
|
||||||
|
isNewRecord: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
activateBoardCard({
|
||||||
|
rowIndex,
|
||||||
|
columnIndex,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEscape = () => {
|
||||||
|
unfocusBoardCard();
|
||||||
|
if (isAtLeastOneRecordSelected) {
|
||||||
|
resetRecordSelection();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useHotkeysOnFocusedElement({
|
||||||
|
keys: ['x'],
|
||||||
|
callback: handleSelectCard,
|
||||||
|
focusId,
|
||||||
|
scope: RecordIndexHotkeyScope.RecordIndex,
|
||||||
|
dependencies: [handleSelectCard],
|
||||||
|
});
|
||||||
|
|
||||||
|
useHotkeysOnFocusedElement({
|
||||||
|
keys: [
|
||||||
|
Key.Enter,
|
||||||
|
`${Key.Control}+${Key.Enter}`,
|
||||||
|
`${Key.Meta}+${Key.Enter}`,
|
||||||
|
],
|
||||||
|
callback: handleOpenRecordInCommandMenu,
|
||||||
|
focusId,
|
||||||
|
scope: RecordIndexHotkeyScope.RecordIndex,
|
||||||
|
dependencies: [handleOpenRecordInCommandMenu],
|
||||||
|
});
|
||||||
|
|
||||||
|
useHotkeysOnFocusedElement({
|
||||||
|
keys: [Key.Escape],
|
||||||
|
callback: handleEscape,
|
||||||
|
focusId,
|
||||||
|
scope: RecordIndexHotkeyScope.RecordIndex,
|
||||||
|
dependencies: [handleEscape],
|
||||||
|
});
|
||||||
|
};
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection';
|
||||||
|
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||||
|
import { RecordIndexHotkeyScope } from '@/object-record/record-index/types/RecordIndexHotkeyScope';
|
||||||
|
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||||
|
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||||
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
export const useRecordBoardSelectAllHotkeys = ({
|
||||||
|
recordBoardId,
|
||||||
|
focusId,
|
||||||
|
}: {
|
||||||
|
recordBoardId: string;
|
||||||
|
focusId: string;
|
||||||
|
}) => {
|
||||||
|
const recordIndexAllRecordIdsState = useRecoilComponentCallbackStateV2(
|
||||||
|
recordIndexAllRecordIdsComponentSelector,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { setRecordAsSelected } = useRecordBoardSelection(recordBoardId);
|
||||||
|
|
||||||
|
const selectAll = useRecoilCallback(
|
||||||
|
({ snapshot }) =>
|
||||||
|
() => {
|
||||||
|
const allRecordIds = getSnapshotValue(
|
||||||
|
snapshot,
|
||||||
|
recordIndexAllRecordIdsState,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const recordId of allRecordIds) {
|
||||||
|
setRecordAsSelected(recordId, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[recordIndexAllRecordIdsState, setRecordAsSelected],
|
||||||
|
);
|
||||||
|
|
||||||
|
useHotkeysOnFocusedElement({
|
||||||
|
keys: ['ctrl+a', 'meta+a'],
|
||||||
|
callback: selectAll,
|
||||||
|
focusId,
|
||||||
|
scope: RecordIndexHotkeyScope.RecordIndex,
|
||||||
|
dependencies: [selectAll],
|
||||||
|
options: {
|
||||||
|
enableOnFormTags: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
@ -4,7 +4,7 @@ import { useContext } from 'react';
|
|||||||
|
|
||||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||||
import { RecordBoardCard } from '@/object-record/record-board/record-board-card/components/RecordBoardCard';
|
import { RecordBoardCard } from '@/object-record/record-board/record-board-card/components/RecordBoardCard';
|
||||||
import { RecordBoardCardFocusHotkeyEffect } from '@/object-record/record-board/record-board-card/components/RecordBoardCardFocusHotkeyEffect';
|
import { RecordBoardCardHotkeysEffect } from '@/object-record/record-board/record-board-card/components/RecordBoardCardHotkeysEffect';
|
||||||
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
|
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
|
||||||
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||||
import { isRecordBoardCardFocusedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardFocusedComponentFamilyState';
|
import { isRecordBoardCardFocusedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardFocusedComponentFamilyState';
|
||||||
@ -57,9 +57,7 @@ export const RecordBoardCardDraggableContainer = ({
|
|||||||
data-selectable-id={recordId}
|
data-selectable-id={recordId}
|
||||||
data-select-disable
|
data-select-disable
|
||||||
>
|
>
|
||||||
{isRecordBoardCardFocusActive && (
|
{isRecordBoardCardFocusActive && <RecordBoardCardHotkeysEffect />}
|
||||||
<RecordBoardCardFocusHotkeyEffect />
|
|
||||||
)}
|
|
||||||
<RecordBoardCard />
|
<RecordBoardCard />
|
||||||
</StyledDraggableContainer>
|
</StyledDraggableContainer>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,57 +0,0 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import { Key } from 'ts-key-enum';
|
|
||||||
|
|
||||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
|
||||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
|
||||||
import { useActiveRecordBoardCard } from '@/object-record/record-board/hooks/useActiveRecordBoardCard';
|
|
||||||
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection';
|
|
||||||
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
|
|
||||||
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
|
|
||||||
import { BoardHotkeyScope } from '@/object-record/record-board/types/BoardHotkeyScope';
|
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
|
||||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
|
||||||
export const RecordBoardCardFocusHotkeyEffect = () => {
|
|
||||||
const { objectMetadataItem } = useContext(RecordBoardContext);
|
|
||||||
|
|
||||||
const { recordId, rowIndex, columnIndex } = useContext(
|
|
||||||
RecordBoardCardContext,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
|
||||||
|
|
||||||
const { activateBoardCard } = useActiveRecordBoardCard();
|
|
||||||
|
|
||||||
const { setRecordAsSelected } = useRecordBoardSelection();
|
|
||||||
|
|
||||||
const isRecordBoardCardSelected = useRecoilComponentFamilyValueV2(
|
|
||||||
isRecordBoardCardSelectedComponentFamilyState,
|
|
||||||
recordId,
|
|
||||||
);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
|
||||||
'x',
|
|
||||||
() => {
|
|
||||||
setRecordAsSelected(recordId, !isRecordBoardCardSelected);
|
|
||||||
},
|
|
||||||
BoardHotkeyScope.BoardFocus,
|
|
||||||
);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
|
||||||
[Key.Enter, `${Key.Control}+${Key.Enter}`, `${Key.Meta}+${Key.Enter}`],
|
|
||||||
() => {
|
|
||||||
openRecordInCommandMenu({
|
|
||||||
recordId: recordId,
|
|
||||||
objectNameSingular: objectMetadataItem.nameSingular,
|
|
||||||
isNewRecord: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
activateBoardCard({
|
|
||||||
rowIndex,
|
|
||||||
columnIndex,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
BoardHotkeyScope.BoardFocus,
|
|
||||||
);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
|
||||||
|
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||||
|
import { useRecordBoardArrowKeysEffect } from '@/object-record/record-board/hooks/useRecordBoardArrowKeysEffect';
|
||||||
|
import { useRecordBoardCardHotkeys } from '@/object-record/record-board/hooks/useRecordBoardCardHotkeys';
|
||||||
|
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
|
||||||
|
import { getRecordBoardCardFocusId } from '@/object-record/record-board/record-board-card/utils/getRecordBoardCardFocusId';
|
||||||
|
|
||||||
|
export const RecordBoardCardHotkeysEffect = () => {
|
||||||
|
const { recordBoardId } = useContext(RecordBoardContext);
|
||||||
|
const { rowIndex, columnIndex } = useContext(RecordBoardCardContext);
|
||||||
|
|
||||||
|
const focusId = getRecordBoardCardFocusId({
|
||||||
|
recordBoardId,
|
||||||
|
cardIndexes: { rowIndex, columnIndex },
|
||||||
|
});
|
||||||
|
|
||||||
|
useRecordBoardCardHotkeys(focusId);
|
||||||
|
useRecordBoardArrowKeysEffect({ recordBoardId, focusId });
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { BoardCardIndexes } from '@/object-record/record-board/types/BoardCardIndexes';
|
||||||
|
|
||||||
|
export const getRecordBoardCardFocusId = ({
|
||||||
|
recordBoardId,
|
||||||
|
cardIndexes,
|
||||||
|
}: {
|
||||||
|
recordBoardId: string;
|
||||||
|
cardIndexes: BoardCardIndexes;
|
||||||
|
}) => {
|
||||||
|
return `${recordBoardId}-board-card-${cardIndexes.columnIndex}-${cardIndexes.rowIndex}`;
|
||||||
|
};
|
||||||
@ -7,7 +7,6 @@ import { getActivityTargetObjectRecords } from '@/activities/utils/getActivityTa
|
|||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { useOpenRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useOpenRelationFromManyFieldInput';
|
import { useOpenRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useOpenRelationFromManyFieldInput';
|
||||||
import { useOpenRelationToOneFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useOpenRelationToOneFieldInput';
|
import { useOpenRelationToOneFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useOpenRelationToOneFieldInput';
|
||||||
import { getRelationFromManyFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationFromManyFieldInputInstanceId';
|
|
||||||
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||||
import {
|
import {
|
||||||
FieldMetadata,
|
FieldMetadata,
|
||||||
@ -22,6 +21,7 @@ import { recordStoreFamilyState } from '@/object-record/record-store/states/reco
|
|||||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
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 { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
@ -75,7 +75,7 @@ export const useOpenFieldInputEditMode = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
openActivityTargetCellEditMode({
|
openActivityTargetCellEditMode({
|
||||||
recordPickerInstanceId: getRelationFromManyFieldInputInstanceId({
|
recordPickerInstanceId: getFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
}),
|
}),
|
||||||
@ -110,16 +110,16 @@ export const useOpenFieldInputEditMode = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pushFocusItemToFocusStack({
|
pushFocusItemToFocusStack({
|
||||||
focusId: getFieldInputInstanceId(
|
focusId: getFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
),
|
}),
|
||||||
component: {
|
component: {
|
||||||
type: FocusComponentType.OPEN_FIELD_INPUT,
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
instanceId: getFieldInputInstanceId(
|
instanceId: getFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
),
|
}),
|
||||||
},
|
},
|
||||||
hotkeyScope: {
|
hotkeyScope: {
|
||||||
scope: DEFAULT_CELL_SCOPE.scope,
|
scope: DEFAULT_CELL_SCOPE.scope,
|
||||||
@ -136,8 +136,26 @@ export const useOpenFieldInputEditMode = () => {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { removeFocusItemFromFocusStackById } =
|
||||||
|
useRemoveFocusItemFromFocusStackById();
|
||||||
|
|
||||||
|
const closeFieldInput = ({
|
||||||
|
fieldDefinition,
|
||||||
|
recordId,
|
||||||
|
}: {
|
||||||
|
fieldDefinition: FieldDefinition<FieldMetadata>;
|
||||||
|
recordId: string;
|
||||||
|
}) => {
|
||||||
|
removeFocusItemFromFocusStackById({
|
||||||
|
focusId: getFieldInputInstanceId({
|
||||||
|
recordId,
|
||||||
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
openFieldInput: openFieldInput,
|
openFieldInput,
|
||||||
closeFieldInput: () => {},
|
closeFieldInput,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -18,10 +18,10 @@ export const MultiSelectFieldInput = ({
|
|||||||
selectableListComponentInstanceId={
|
selectableListComponentInstanceId={
|
||||||
SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID
|
SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID
|
||||||
}
|
}
|
||||||
focusId={getFieldInputInstanceId(
|
focusId={getFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
)}
|
})}
|
||||||
options={fieldDefinition.metadata.options}
|
options={fieldDefinition.metadata.options}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onOptionSelected={persistField}
|
onOptionSelected={persistField}
|
||||||
|
|||||||
@ -10,11 +10,11 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext
|
|||||||
import { useRelationField } from '@/object-record/record-field/meta-types/hooks/useRelationField';
|
import { useRelationField } from '@/object-record/record-field/meta-types/hooks/useRelationField';
|
||||||
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
||||||
import { useUpdateRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput';
|
import { useUpdateRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput';
|
||||||
import { getRelationFromManyFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationFromManyFieldInputInstanceId';
|
|
||||||
import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionComponentState';
|
import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionComponentState';
|
||||||
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||||
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
|
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
||||||
import { MultipleRecordPicker } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker';
|
import { MultipleRecordPicker } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker';
|
||||||
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
||||||
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
||||||
@ -31,7 +31,7 @@ export const RelationFromManyFieldInput = ({
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
}: RelationFromManyFieldInputProps) => {
|
}: RelationFromManyFieldInputProps) => {
|
||||||
const { fieldDefinition, recordId } = useContext(FieldContext);
|
const { fieldDefinition, recordId } = useContext(FieldContext);
|
||||||
const recordPickerInstanceId = getRelationFromManyFieldInputInstanceId({
|
const recordPickerInstanceId = getFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,10 +3,10 @@ import { useRelationField } from '../../hooks/useRelationField';
|
|||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
||||||
import { getRelationToOneFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationToOneFieldInputInstanceId';
|
|
||||||
import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionComponentState';
|
import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionComponentState';
|
||||||
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
|
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
|
||||||
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
|
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
||||||
import { SingleRecordPicker } from '@/object-record/record-picker/single-record-picker/components/SingleRecordPicker';
|
import { SingleRecordPicker } from '@/object-record/record-picker/single-record-picker/components/SingleRecordPicker';
|
||||||
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
||||||
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
|
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
|
||||||
@ -29,7 +29,7 @@ export const RelationToOneFieldInput = ({
|
|||||||
|
|
||||||
const persistField = usePersistField();
|
const persistField = usePersistField();
|
||||||
|
|
||||||
const recordPickerInstanceId = getRelationToOneFieldInputInstanceId({
|
const recordPickerInstanceId = getFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -67,10 +67,10 @@ export const SelectFieldInput = ({
|
|||||||
SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID
|
SELECT_FIELD_INPUT_SELECTABLE_LIST_COMPONENT_INSTANCE_ID
|
||||||
}
|
}
|
||||||
selectableItemIdArray={optionIds}
|
selectableItemIdArray={optionIds}
|
||||||
focusId={getFieldInputInstanceId(
|
focusId={getFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldDefinition.metadata.fieldName,
|
fieldName: fieldDefinition.metadata.fieldName,
|
||||||
)}
|
})}
|
||||||
onEnter={(itemId) => {
|
onEnter={(itemId) => {
|
||||||
const option = filteredOptions.find(
|
const option = filteredOptions.find(
|
||||||
(option) => option.value === itemId,
|
(option) => option.value === itemId,
|
||||||
|
|||||||
@ -18,8 +18,8 @@ import {
|
|||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useOpenFieldInputEditMode } from '@/object-record/record-field/hooks/useOpenFieldInputEditMode';
|
import { useOpenFieldInputEditMode } from '@/object-record/record-field/hooks/useOpenFieldInputEditMode';
|
||||||
import { getRelationFromManyFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationFromManyFieldInputInstanceId';
|
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
|
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
||||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||||
import { FieldMetadataType } from 'twenty-shared/types';
|
import { FieldMetadataType } from 'twenty-shared/types';
|
||||||
@ -88,7 +88,7 @@ const RelationManyFieldInputWithContext = () => {
|
|||||||
<div>
|
<div>
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
instanceId: getRelationFromManyFieldInputInstanceId({
|
instanceId: getFieldInputInstanceId({
|
||||||
recordId: 'recordId',
|
recordId: 'recordId',
|
||||||
fieldName: 'people',
|
fieldName: 'people',
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -16,9 +16,9 @@ import {
|
|||||||
|
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { getRelationToOneFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationToOneFieldInputInstanceId';
|
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
|
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
|
||||||
|
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
||||||
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
import { DropdownHotkeyScope } from '@/ui/layout/dropdown/constants/DropdownHotkeyScope';
|
||||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||||
@ -68,13 +68,13 @@ const RelationToOneFieldInputWithContext = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
pushFocusItemToFocusStack({
|
pushFocusItemToFocusStack({
|
||||||
focusId: getRelationToOneFieldInputInstanceId({
|
focusId: getFieldInputInstanceId({
|
||||||
recordId: '123',
|
recordId: '123',
|
||||||
fieldName: 'Relation',
|
fieldName: 'Relation',
|
||||||
}),
|
}),
|
||||||
component: {
|
component: {
|
||||||
type: FocusComponentType.DROPDOWN,
|
type: FocusComponentType.DROPDOWN,
|
||||||
instanceId: getRelationToOneFieldInputInstanceId({
|
instanceId: getFieldInputInstanceId({
|
||||||
recordId: '123',
|
recordId: '123',
|
||||||
fieldName: 'Relation',
|
fieldName: 'Relation',
|
||||||
}),
|
}),
|
||||||
@ -82,7 +82,7 @@ const RelationToOneFieldInputWithContext = ({
|
|||||||
hotkeyScope: {
|
hotkeyScope: {
|
||||||
scope: DropdownHotkeyScope.Dropdown,
|
scope: DropdownHotkeyScope.Dropdown,
|
||||||
},
|
},
|
||||||
memoizeKey: getRelationToOneFieldInputInstanceId({
|
memoizeKey: getFieldInputInstanceId({
|
||||||
recordId: '123',
|
recordId: '123',
|
||||||
fieldName: 'Relation',
|
fieldName: 'Relation',
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getRelationFromManyFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationFromManyFieldInputInstanceId';
|
|
||||||
import {
|
import {
|
||||||
FieldRelationFromManyValue,
|
FieldRelationFromManyValue,
|
||||||
FieldRelationValue,
|
FieldRelationValue,
|
||||||
} from '@/object-record/record-field/types/FieldMetadata';
|
} from '@/object-record/record-field/types/FieldMetadata';
|
||||||
|
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
||||||
import { useMultipleRecordPickerOpen } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerOpen';
|
import { useMultipleRecordPickerOpen } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerOpen';
|
||||||
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
||||||
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
||||||
@ -33,7 +33,7 @@ export const useOpenRelationFromManyFieldInput = () => {
|
|||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
recordId: string;
|
recordId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const recordPickerInstanceId = getRelationFromManyFieldInputInstanceId({
|
const recordPickerInstanceId = getFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldName,
|
fieldName,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { getRelationToOneFieldInputInstanceId } from '@/object-record/record-field/meta-types/input/utils/getRelationToOneFieldInputInstanceId';
|
|
||||||
import {
|
import {
|
||||||
FieldRelationToOneValue,
|
FieldRelationToOneValue,
|
||||||
FieldRelationValue,
|
FieldRelationValue,
|
||||||
} from '@/object-record/record-field/types/FieldMetadata';
|
} from '@/object-record/record-field/types/FieldMetadata';
|
||||||
|
import { getFieldInputInstanceId } from '@/object-record/record-field/utils/getFieldInputInstanceId';
|
||||||
import { useSingleRecordPickerOpen } from '@/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerOpen';
|
import { useSingleRecordPickerOpen } from '@/object-record/record-picker/single-record-picker/hooks/useSingleRecordPickerOpen';
|
||||||
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
||||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
@ -19,7 +19,7 @@ export const useOpenRelationToOneFieldInput = () => {
|
|||||||
const openRelationToOneFieldInput = useRecoilCallback(
|
const openRelationToOneFieldInput = useRecoilCallback(
|
||||||
({ set, snapshot }) =>
|
({ set, snapshot }) =>
|
||||||
({ fieldName, recordId }: { fieldName: string; recordId: string }) => {
|
({ fieldName, recordId }: { fieldName: string; recordId: string }) => {
|
||||||
const recordPickerInstanceId = getRelationToOneFieldInputInstanceId({
|
const recordPickerInstanceId = getFieldInputInstanceId({
|
||||||
recordId,
|
recordId,
|
||||||
fieldName,
|
fieldName,
|
||||||
});
|
});
|
||||||
@ -46,7 +46,7 @@ export const useOpenRelationToOneFieldInput = () => {
|
|||||||
pushFocusItemToFocusStack({
|
pushFocusItemToFocusStack({
|
||||||
focusId: recordPickerInstanceId,
|
focusId: recordPickerInstanceId,
|
||||||
component: {
|
component: {
|
||||||
type: FocusComponentType.OPEN_FIELD_INPUT,
|
type: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
instanceId: recordPickerInstanceId,
|
instanceId: recordPickerInstanceId,
|
||||||
},
|
},
|
||||||
// TODO: Remove this once we've fully migrated away from hotkey scopes
|
// TODO: Remove this once we've fully migrated away from hotkey scopes
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
export const getRelationFromManyFieldInputInstanceId = ({
|
|
||||||
recordId,
|
|
||||||
fieldName,
|
|
||||||
}: {
|
|
||||||
recordId: string;
|
|
||||||
fieldName: string;
|
|
||||||
}): string => {
|
|
||||||
return `relation-from-many-field-input-${recordId}-${fieldName}`;
|
|
||||||
};
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
export const getRelationToOneFieldInputInstanceId = ({
|
|
||||||
recordId,
|
|
||||||
fieldName,
|
|
||||||
}: {
|
|
||||||
recordId: string;
|
|
||||||
fieldName: string;
|
|
||||||
}): string => {
|
|
||||||
return `relation-to-one-field-input-${recordId}-${fieldName}`;
|
|
||||||
};
|
|
||||||
@ -1,6 +1,9 @@
|
|||||||
export const getFieldInputInstanceId = (
|
export const getFieldInputInstanceId = ({
|
||||||
recordId: string,
|
recordId,
|
||||||
fieldName: string,
|
fieldName,
|
||||||
) => {
|
}: {
|
||||||
|
recordId: string;
|
||||||
|
fieldName: string;
|
||||||
|
}) => {
|
||||||
return `${recordId}-${fieldName}`;
|
return `${recordId}-${fieldName}`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useContext } from 'react';
|
import { useCallback, useContext } from 'react';
|
||||||
|
|
||||||
import { FieldDisplay } from '@/object-record/record-field/components/FieldDisplay';
|
import { FieldDisplay } from '@/object-record/record-field/components/FieldDisplay';
|
||||||
import { FieldInput } from '@/object-record/record-field/components/FieldInput';
|
import { FieldInput } from '@/object-record/record-field/components/FieldInput';
|
||||||
@ -13,10 +13,13 @@ import {
|
|||||||
import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly';
|
import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFieldInputOnly';
|
||||||
import { useOpenFieldInputEditMode } from '@/object-record/record-field/hooks/useOpenFieldInputEditMode';
|
import { useOpenFieldInputEditMode } from '@/object-record/record-field/hooks/useOpenFieldInputEditMode';
|
||||||
|
|
||||||
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
|
import { isInlineCellInEditModeScopedState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeScopedState';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
|
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
|
||||||
import { currentHotkeyScopeState } from '@/ui/utilities/hotkey/states/internal/currentHotkeyScopeState';
|
import { currentHotkeyScopeState } from '@/ui/utilities/hotkey/states/internal/currentHotkeyScopeState';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||||
import { useIcons } from 'twenty-ui/display';
|
import { useIcons } from 'twenty-ui/display';
|
||||||
import { RecordInlineCellContainer } from './RecordInlineCellContainer';
|
import { RecordInlineCellContainer } from './RecordInlineCellContainer';
|
||||||
import {
|
import {
|
||||||
@ -35,16 +38,47 @@ export const RecordInlineCell = ({ loading }: RecordInlineCellProps) => {
|
|||||||
recordId,
|
recordId,
|
||||||
isCentered,
|
isCentered,
|
||||||
isDisplayModeFixHeight,
|
isDisplayModeFixHeight,
|
||||||
onOpenEditMode,
|
onOpenEditMode: onOpenEditModeFromContext,
|
||||||
onCloseEditMode,
|
onCloseEditMode: onCloseEditModeFromContext,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
} = useContext(FieldContext);
|
} = useContext(FieldContext);
|
||||||
|
|
||||||
|
const { openFieldInput, closeFieldInput } = useOpenFieldInputEditMode();
|
||||||
|
|
||||||
|
const onOpenEditMode = onOpenEditModeFromContext
|
||||||
|
? onOpenEditModeFromContext
|
||||||
|
: () => openFieldInput({ fieldDefinition, recordId });
|
||||||
|
|
||||||
|
const onCloseEditMode = useCallback(() => {
|
||||||
|
onCloseEditModeFromContext
|
||||||
|
? onCloseEditModeFromContext()
|
||||||
|
: closeFieldInput({ fieldDefinition, recordId });
|
||||||
|
}, [onCloseEditModeFromContext, closeFieldInput, fieldDefinition, recordId]);
|
||||||
|
|
||||||
const buttonIcon = useGetButtonIcon();
|
const buttonIcon = useGetButtonIcon();
|
||||||
|
|
||||||
const isFieldInputOnly = useIsFieldInputOnly();
|
const isFieldInputOnly = useIsFieldInputOnly();
|
||||||
|
|
||||||
const { closeInlineCell } = useInlineCell();
|
const { goBackToPreviousDropdownFocusId } =
|
||||||
|
useGoBackToPreviousDropdownFocusId();
|
||||||
|
|
||||||
|
const recordFieldComponentInstanceId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
RecordFieldComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setIsInlineCellInEditMode = useSetRecoilState(
|
||||||
|
isInlineCellInEditModeScopedState(recordFieldComponentInstanceId),
|
||||||
|
);
|
||||||
|
|
||||||
|
const closeInlineCell = useCallback(() => {
|
||||||
|
onCloseEditMode();
|
||||||
|
setIsInlineCellInEditMode(false);
|
||||||
|
goBackToPreviousDropdownFocusId();
|
||||||
|
}, [
|
||||||
|
onCloseEditMode,
|
||||||
|
setIsInlineCellInEditMode,
|
||||||
|
goBackToPreviousDropdownFocusId,
|
||||||
|
]);
|
||||||
|
|
||||||
const handleEnter: FieldInputEvent = (persistField) => {
|
const handleEnter: FieldInputEvent = (persistField) => {
|
||||||
persistField();
|
persistField();
|
||||||
@ -94,7 +128,6 @@ export const RecordInlineCell = ({ loading }: RecordInlineCellProps) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
const { openFieldInput, closeFieldInput } = useOpenFieldInputEditMode();
|
|
||||||
|
|
||||||
const RecordInlineCellContextValue: RecordInlineCellContextProps = {
|
const RecordInlineCellContextValue: RecordInlineCellContextProps = {
|
||||||
readonly: isReadOnly,
|
readonly: isReadOnly,
|
||||||
@ -122,9 +155,8 @@ export const RecordInlineCell = ({ loading }: RecordInlineCellProps) => {
|
|||||||
isDisplayModeFixHeight: isDisplayModeFixHeight,
|
isDisplayModeFixHeight: isDisplayModeFixHeight,
|
||||||
editModeContentOnly: isFieldInputOnly,
|
editModeContentOnly: isFieldInputOnly,
|
||||||
loading: loading,
|
loading: loading,
|
||||||
onOpenEditMode:
|
onOpenEditMode,
|
||||||
onOpenEditMode ?? (() => openFieldInput({ fieldDefinition, recordId })),
|
onCloseEditMode,
|
||||||
onCloseEditMode: onCloseEditMode ?? (() => closeFieldInput()),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
|
||||||
|
import { useListenToSidePanelOpening } from '@/ui/layout/right-drawer/hooks/useListenToSidePanelOpening';
|
||||||
|
|
||||||
|
// TODO: This is a temporary solution to close the inline cell when the command menu is opened.
|
||||||
|
// This is because the useInlineCell hook doesn't work correctly for field inputs when used outside of the field context.
|
||||||
|
// We should refactor field inputs, and remove this listener afterwards.
|
||||||
|
// TODO: create a new hook useCloseAnyOpenedFieldInput which uses the focus stack to close all the field inputs, and call it inside openCommandMenu
|
||||||
|
export const RecordInlineCellCloseOnCommandMenuOpeningEffect = () => {
|
||||||
|
const { closeInlineCell } = useInlineCell();
|
||||||
|
|
||||||
|
useListenToSidePanelOpening(closeInlineCell);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
@ -9,6 +9,7 @@ import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInput
|
|||||||
|
|
||||||
import { assertFieldMetadata } from '@/object-record/record-field/types/guards/assertFieldMetadata';
|
import { assertFieldMetadata } from '@/object-record/record-field/types/guards/assertFieldMetadata';
|
||||||
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
||||||
|
import { RecordInlineCellCloseOnCommandMenuOpeningEffect } from '@/object-record/record-inline-cell/components/RecordInlineCellCloseOnCommandMenuOpeningEffect';
|
||||||
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
|
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
|
||||||
import {
|
import {
|
||||||
AppTooltip,
|
AppTooltip,
|
||||||
@ -160,6 +161,9 @@ export const RecordInlineCellContainer = () => {
|
|||||||
)}
|
)}
|
||||||
</StyledLabelAndIconContainer>
|
</StyledLabelAndIconContainer>
|
||||||
)}
|
)}
|
||||||
|
{isInlineCellInEditMode && (
|
||||||
|
<RecordInlineCellCloseOnCommandMenuOpeningEffect />
|
||||||
|
)}
|
||||||
<StyledValueContainer readonly={readonly ?? false}>
|
<StyledValueContainer readonly={readonly ?? false}>
|
||||||
<RecordInlineCellValue />
|
<RecordInlineCellValue />
|
||||||
</StyledValueContainer>
|
</StyledValueContainer>
|
||||||
|
|||||||
@ -2,12 +2,10 @@ import { useContext } from 'react';
|
|||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
|
||||||
|
|
||||||
import { useInitDraftValueV2 } from '@/object-record/record-field/hooks/useInitDraftValueV2';
|
import { useInitDraftValueV2 } from '@/object-record/record-field/hooks/useInitDraftValueV2';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { useRecordInlineCellContext } from '@/object-record/record-inline-cell/components/RecordInlineCellContext';
|
import { useRecordInlineCellContext } from '@/object-record/record-inline-cell/components/RecordInlineCellContext';
|
||||||
import { INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY } from '@/object-record/record-inline-cell/constants/InlineCellHotkeyScopeMemoizeKey';
|
|
||||||
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
|
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
|
||||||
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
|
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
|
||||||
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
||||||
@ -35,16 +33,12 @@ export const useInlineCell = (
|
|||||||
const { goBackToPreviousDropdownFocusId } =
|
const { goBackToPreviousDropdownFocusId } =
|
||||||
useGoBackToPreviousDropdownFocusId();
|
useGoBackToPreviousDropdownFocusId();
|
||||||
|
|
||||||
const { goBackToPreviousHotkeyScope } = usePreviousHotkeyScope();
|
|
||||||
|
|
||||||
const initFieldInputDraftValue = useInitDraftValueV2();
|
const initFieldInputDraftValue = useInitDraftValueV2();
|
||||||
|
|
||||||
const closeInlineCell = () => {
|
const closeInlineCell = () => {
|
||||||
onCloseEditMode?.();
|
onCloseEditMode?.();
|
||||||
setIsInlineCellInEditMode(false);
|
setIsInlineCellInEditMode(false);
|
||||||
|
|
||||||
goBackToPreviousHotkeyScope(INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY);
|
|
||||||
|
|
||||||
goBackToPreviousDropdownFocusId();
|
goBackToPreviousDropdownFocusId();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ export const useCloseCurrentTableCellInEditMode = (recordTableId?: string) => {
|
|||||||
goBackToPreviousDropdownFocusId();
|
goBackToPreviousDropdownFocusId();
|
||||||
|
|
||||||
removeLastFocusItemFromFocusStackByComponentType({
|
removeLastFocusItemFromFocusStackByComponentType({
|
||||||
componentType: FocusComponentType.OPEN_FIELD_INPUT,
|
componentType: FocusComponentType.OPENED_FIELD_INPUT,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,9 +2,11 @@ export enum FocusComponentType {
|
|||||||
MODAL = 'modal',
|
MODAL = 'modal',
|
||||||
DROPDOWN = 'dropdown',
|
DROPDOWN = 'dropdown',
|
||||||
SIDE_PANEL = 'side-panel',
|
SIDE_PANEL = 'side-panel',
|
||||||
OPEN_FIELD_INPUT = 'open-field-input',
|
OPENED_FIELD_INPUT = 'opened-field-input',
|
||||||
PAGE = 'page',
|
PAGE = 'page',
|
||||||
RECORD_TABLE = 'record-table',
|
RECORD_TABLE = 'record-table',
|
||||||
RECORD_TABLE_ROW = 'record-table-row',
|
RECORD_TABLE_ROW = 'record-table-row',
|
||||||
RECORD_TABLE_CELL = 'record-table-cell',
|
RECORD_TABLE_CELL = 'record-table-cell',
|
||||||
|
RECORD_BOARD = 'record-board',
|
||||||
|
RECORD_BOARD_CARD = 'record-board-card',
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user