mirror of
https://github.com/twentyhq/twenty.git
synced 2024-10-27 03:33:21 +03:00
Board improvements (#3694)
* New board improvements * Improve board * Fix
This commit is contained in:
parent
511627ccb8
commit
f68de1a299
@ -126,7 +126,7 @@
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-helmet-async": "^1.3.0",
|
||||
"react-hook-form": "^7.45.1",
|
||||
"react-hotkeys-hook": "^4.4.3",
|
||||
"react-hotkeys-hook": "^4.4.4",
|
||||
"react-icons": "^4.12.0",
|
||||
"react-intersection-observer": "^9.5.2",
|
||||
"react-loading-skeleton": "^3.3.1",
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { useMemo, useRef, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer';
|
||||
import { Activity } from '@/activities/types/Activity';
|
||||
@ -124,7 +125,7 @@ export const CommandMenu = () => {
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
'esc',
|
||||
[Key.Escape],
|
||||
() => {
|
||||
closeCommandMenu();
|
||||
},
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
@ -22,6 +23,7 @@ export const KeyboardShortcutMenu = () => {
|
||||
isKeyboardShortcutMenuOpenedState,
|
||||
);
|
||||
const { closeCommandMenu } = useCommandMenu();
|
||||
|
||||
useScopedHotkeys(
|
||||
'shift+?,meta+?',
|
||||
() => {
|
||||
@ -33,12 +35,12 @@ export const KeyboardShortcutMenu = () => {
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
'esc',
|
||||
[Key.Escape],
|
||||
() => {
|
||||
closeKeyboardShortcutMenu();
|
||||
},
|
||||
AppHotkeyScope.KeyboardShortcutMenu,
|
||||
[toggleKeyboardShortcutMenu],
|
||||
AppHotkeyScope.KeyboardShortcutMenuOpen,
|
||||
[closeKeyboardShortcutMenu],
|
||||
);
|
||||
|
||||
return (
|
||||
@ -46,8 +48,8 @@ export const KeyboardShortcutMenu = () => {
|
||||
{isKeyboardShortcutMenuOpened && (
|
||||
<KeyboardMenuDialog onClose={toggleKeyboardShortcutMenu}>
|
||||
<KeyboardMenuGroup heading="Table">
|
||||
{keyboardShortcutsTable.map((TableShortcut) => (
|
||||
<KeyboardMenuItem shortcut={TableShortcut} />
|
||||
{keyboardShortcutsTable.map((TableShortcut, index) => (
|
||||
<KeyboardMenuItem shortcut={TableShortcut} key={index} />
|
||||
))}
|
||||
</KeyboardMenuGroup>
|
||||
<KeyboardMenuGroup heading="General">
|
||||
|
@ -12,9 +12,7 @@ import { useRecordBoardDeprecatedScopedStates } from '@/object-record/record-boa
|
||||
import { useSetRecordBoardDeprecatedCardSelectedInternal } from '@/object-record/record-board-deprecated/hooks/internal/useSetRecordBoardDeprecatedCardSelectedInternal';
|
||||
import { RecordBoardDeprecatedScope } from '@/object-record/record-board-deprecated/scopes/RecordBoardDeprecatedScope';
|
||||
import { Opportunity } from '@/pipeline/types/Opportunity';
|
||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useListenClickOutsideByClassName } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import { logError } from '~/utils/logError';
|
||||
@ -129,12 +127,6 @@ export const RecordBoardDeprecated = ({
|
||||
|
||||
const boardRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useScopedHotkeys(
|
||||
'escape',
|
||||
unselectAllActiveCards,
|
||||
PageHotkeyScope.OpportunitiesPage,
|
||||
);
|
||||
|
||||
return (
|
||||
<RecordBoardDeprecatedScope recordBoardScopeId={recordBoardId}>
|
||||
<RecordBoardDeprecatedContextMenu />
|
||||
|
@ -69,7 +69,9 @@ export const RecordBoardDeprecatedColumnDropdownMenu = ({
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Escape, Key.Enter],
|
||||
closeMenu,
|
||||
() => {
|
||||
closeMenu();
|
||||
},
|
||||
BoardColumnHotkeyScope.BoardColumn,
|
||||
[],
|
||||
);
|
||||
|
@ -123,7 +123,7 @@ export const RecordBoardDeprecatedOptionsDropdownContent = ({
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
[Key.Escape],
|
||||
() => {
|
||||
setViewEditMode('none');
|
||||
closeDropdown();
|
||||
|
@ -2,15 +2,19 @@ import { useContext, useRef } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { DragDropContext, OnDragEndResponder } from '@hello-pangea/dnd'; // Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350
|
||||
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection';
|
||||
import { RecordBoardColumn } from '@/object-record/record-board/record-board-column/components/RecordBoardColumn';
|
||||
import { RecordBoardScope } from '@/object-record/record-board/scopes/RecordBoardScope';
|
||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useListenClickOutsideByClassName } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
export type RecordBoardProps = {
|
||||
recordBoardId: string;
|
||||
@ -40,17 +44,25 @@ const StyledBoardHeader = styled.div`
|
||||
`;
|
||||
|
||||
export const RecordBoard = ({ recordBoardId }: RecordBoardProps) => {
|
||||
const { updateOneRecord, objectMetadataItem } =
|
||||
const { updateOneRecord, selectFieldMetadataItem } =
|
||||
useContext(RecordBoardContext);
|
||||
const boardRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { getColumnIdsState, columnsFamilySelector } =
|
||||
useRecordBoardStates(recordBoardId);
|
||||
|
||||
const columnIds = useRecoilValue(getColumnIdsState());
|
||||
|
||||
const selectFieldMetadataItem = objectMetadataItem.fields.find(
|
||||
(field) => field.type === FieldMetadataType.Select,
|
||||
);
|
||||
const { resetRecordSelection, setRecordAsSelected } =
|
||||
useRecordBoardSelection(recordBoardId);
|
||||
|
||||
useListenClickOutsideByClassName({
|
||||
classNames: ['record-board-card'],
|
||||
excludeClassNames: ['action-bar', 'context-menu'],
|
||||
callback: resetRecordSelection,
|
||||
});
|
||||
|
||||
useScopedHotkeys([Key.Escape], resetRecordSelection, TableHotkeyScope.Table);
|
||||
|
||||
const onDragEnd: OnDragEndResponder = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
@ -106,7 +118,8 @@ export const RecordBoard = ({ recordBoardId }: RecordBoardProps) => {
|
||||
</ScrollWrapper>
|
||||
<DragSelect
|
||||
dragSelectable={boardRef}
|
||||
onDragSelectionChange={() => {}}
|
||||
onDragSelectionStart={resetRecordSelection}
|
||||
onDragSelectionChange={setRecordAsSelected}
|
||||
/>
|
||||
</StyledWrapper>
|
||||
</RecordBoardScope>
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
type RecordBoardContextProps = {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
selectFieldMetadataItem: FieldMetadataItem;
|
||||
createOneRecord: (recordInput: Partial<ObjectRecord>) => void;
|
||||
updateOneRecord: ({
|
||||
idToUpdate,
|
||||
|
@ -2,7 +2,7 @@ import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
|
||||
export const useResetBoardRecordSelection = (recordBoardId?: string) => {
|
||||
export const useRecordBoardSelection = (recordBoardId?: string) => {
|
||||
const { getSelectedRecordIdsSelector, isRecordBoardCardSelectedFamilyState } =
|
||||
useRecordBoardStates(recordBoardId);
|
||||
|
||||
@ -20,5 +20,21 @@ export const useResetBoardRecordSelection = (recordBoardId?: string) => {
|
||||
[getSelectedRecordIdsSelector, isRecordBoardCardSelectedFamilyState],
|
||||
);
|
||||
|
||||
return { resetRecordSelection };
|
||||
const setRecordAsSelected = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
(recordId: string, isSelected: boolean) => {
|
||||
const isRecordCurrentlySelected = snapshot
|
||||
.getLoadable(isRecordBoardCardSelectedFamilyState(recordId))
|
||||
.getValue();
|
||||
|
||||
if (isRecordCurrentlySelected === isSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
set(isRecordBoardCardSelectedFamilyState(recordId), isSelected);
|
||||
},
|
||||
[isRecordBoardCardSelectedFamilyState],
|
||||
);
|
||||
|
||||
return { resetRecordSelection, setRecordAsSelected };
|
||||
};
|
@ -18,7 +18,7 @@ export const RecordBoardCardDraggableContainer = ({
|
||||
{...draggableProvided?.dragHandleProps}
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...draggableProvided?.draggableProps}
|
||||
className="entity-board-card"
|
||||
className="record-board-card"
|
||||
data-selectable-id={recordId}
|
||||
data-select-disable
|
||||
>
|
||||
|
@ -14,6 +14,7 @@ const StyledColumn = styled.div<{ isFirstColumn: boolean }>`
|
||||
isFirstColumn ? 'none' : theme.border.color.light};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: fit-content;
|
||||
max-width: 200px;
|
||||
min-width: 200px;
|
||||
|
||||
@ -60,6 +61,7 @@ export const RecordBoardColumn = ({
|
||||
columnDefinition: columnDefinition,
|
||||
isFirstColumn: isFirstColumn,
|
||||
isLastColumn: isLastColumn,
|
||||
recordCount: recordIds.length,
|
||||
}}
|
||||
>
|
||||
<Droppable droppableId={recordBoardColumnId}>
|
||||
|
@ -1,8 +1,10 @@
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { DroppableProvided } from '@hello-pangea/dnd';
|
||||
import { Draggable, DroppableProvided } from '@hello-pangea/dnd';
|
||||
|
||||
import { RecordBoardColumnCardsMemo } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardsMemo';
|
||||
import { RecordBoardColumnNewButton } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnNewButton';
|
||||
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||
|
||||
const StyledPlaceholder = styled.div`
|
||||
min-height: 1px;
|
||||
@ -14,6 +16,10 @@ const StyledColumnCardsContainer = styled.div`
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const StyledNewButtonContainer = styled.div`
|
||||
padding-bottom: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
type RecordBoardColumnCardsContainerProps = {
|
||||
recordIds: string[];
|
||||
droppableProvided: DroppableProvided;
|
||||
@ -23,6 +29,8 @@ export const RecordBoardColumnCardsContainer = ({
|
||||
recordIds,
|
||||
droppableProvided,
|
||||
}: RecordBoardColumnCardsContainerProps) => {
|
||||
const { columnDefinition } = useContext(RecordBoardColumnContext);
|
||||
|
||||
return (
|
||||
<StyledColumnCardsContainer
|
||||
ref={droppableProvided?.innerRef}
|
||||
@ -31,6 +39,23 @@ export const RecordBoardColumnCardsContainer = ({
|
||||
>
|
||||
<RecordBoardColumnCardsMemo recordIds={recordIds} />
|
||||
<StyledPlaceholder>{droppableProvided?.placeholder}</StyledPlaceholder>
|
||||
<Draggable
|
||||
draggableId={`new-${columnDefinition.id}`}
|
||||
index={recordIds.length}
|
||||
isDragDisabled={true}
|
||||
>
|
||||
{(draggableProvided) => (
|
||||
<div
|
||||
ref={draggableProvided?.innerRef}
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...draggableProvided?.draggableProps}
|
||||
>
|
||||
<StyledNewButtonContainer>
|
||||
<RecordBoardColumnNewButton />
|
||||
</StyledNewButtonContainer>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
</StyledColumnCardsContainer>
|
||||
);
|
||||
};
|
||||
|
@ -46,7 +46,9 @@ export const RecordBoardColumnHeader = () => {
|
||||
const [isBoardColumnMenuOpen, setIsBoardColumnMenuOpen] = useState(false);
|
||||
const [isHeaderHovered, setIsHeaderHovered] = useState(false);
|
||||
|
||||
const { columnDefinition } = useContext(RecordBoardColumnContext);
|
||||
const { columnDefinition, recordCount } = useContext(
|
||||
RecordBoardColumnContext,
|
||||
);
|
||||
|
||||
const {
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
@ -66,7 +68,6 @@ export const RecordBoardColumnHeader = () => {
|
||||
};
|
||||
|
||||
const boardColumnTotal = 0;
|
||||
const cardIds = [];
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -81,7 +82,7 @@ export const RecordBoardColumnHeader = () => {
|
||||
/>
|
||||
{!!boardColumnTotal && <StyledAmount>${boardColumnTotal}</StyledAmount>}
|
||||
{!isHeaderHovered && (
|
||||
<StyledNumChildren>{cardIds.length}</StyledNumChildren>
|
||||
<StyledNumChildren>{recordCount}</StyledNumChildren>
|
||||
)}
|
||||
{isHeaderHovered && (
|
||||
<StyledHeaderActions>
|
||||
|
@ -0,0 +1,44 @@
|
||||
import { useContext } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||
import { IconPlus } from '@/ui/display/icon/index';
|
||||
|
||||
const StyledButton = styled.button`
|
||||
align-items: center;
|
||||
align-self: baseline;
|
||||
background-color: ${({ theme }) => theme.background.primary};
|
||||
border: none;
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
|
||||
&:hover {
|
||||
background-color: ${({ theme }) => theme.background.tertiary};
|
||||
}
|
||||
`;
|
||||
|
||||
export const RecordBoardColumnNewButton = () => {
|
||||
const theme = useTheme();
|
||||
const { columnDefinition } = useContext(RecordBoardColumnContext);
|
||||
const { createOneRecord, selectFieldMetadataItem } =
|
||||
useContext(RecordBoardContext);
|
||||
|
||||
const onNewClick = () => {
|
||||
createOneRecord({
|
||||
[selectFieldMetadataItem.name]: columnDefinition.value,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledButton onClick={onNewClick}>
|
||||
<IconPlus size={theme.icon.size.md} />
|
||||
New
|
||||
</StyledButton>
|
||||
);
|
||||
};
|
@ -6,6 +6,7 @@ type RecordBoardColumnContextProps = {
|
||||
columnDefinition: RecordBoardColumnDefinition;
|
||||
isFirstColumn: boolean;
|
||||
isLastColumn: boolean;
|
||||
recordCount: number;
|
||||
};
|
||||
|
||||
export const RecordBoardColumnContext =
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
@ -41,7 +43,7 @@ export const useRegisterInputEvents = <T>({
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
'esc',
|
||||
[Key.Escape],
|
||||
() => {
|
||||
onEscape?.(inputValue);
|
||||
},
|
||||
|
@ -6,6 +6,7 @@ import { RecordBoardActionBar } from '@/object-record/record-board/action-bar/co
|
||||
import { RecordBoard } from '@/object-record/record-board/components/RecordBoard';
|
||||
import { RecordBoardContextMenu } from '@/object-record/record-board/context-menu/components/RecordBoardContextMenu';
|
||||
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
type RecordIndexBoardContainerProps = {
|
||||
recordBoardId: string;
|
||||
@ -20,14 +21,23 @@ export const RecordIndexBoardContainer = ({
|
||||
}: RecordIndexBoardContainerProps) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular });
|
||||
|
||||
const selectFieldMetadataItem = objectMetadataItem.fields.find(
|
||||
(field) => field.type === FieldMetadataType.Select,
|
||||
);
|
||||
|
||||
const { deleteOneRecord } = useDeleteOneRecord({ objectNameSingular });
|
||||
const { updateOneRecord } = useUpdateOneRecord({ objectNameSingular });
|
||||
const { createOneRecord } = useCreateOneRecord({ objectNameSingular });
|
||||
|
||||
if (!selectFieldMetadataItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecordBoardContext.Provider
|
||||
value={{
|
||||
objectMetadataItem,
|
||||
selectFieldMetadataItem,
|
||||
createOneRecord,
|
||||
updateOneRecord,
|
||||
deleteOneRecord,
|
||||
|
@ -5,8 +5,9 @@ import { useRecoilValue } from 'recoil';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useRecordActionBar } from '@/object-record/record-action-bar/hooks/useRecordActionBar';
|
||||
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
||||
import { useResetBoardRecordSelection } from '@/object-record/record-board/hooks/useResetBoardRecordSelection';
|
||||
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection';
|
||||
import { useLoadRecordIndexBoard } from '@/object-record/record-index/hooks/useLoadRecordIndexBoard';
|
||||
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
||||
import { computeRecordBoardColumnDefinitionsFromObjectMetadata } from '@/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata';
|
||||
|
||||
type RecordIndexBoardContainerEffectProps = {
|
||||
@ -18,12 +19,13 @@ type RecordIndexBoardContainerEffectProps = {
|
||||
export const RecordIndexBoardContainerEffect = ({
|
||||
objectNameSingular,
|
||||
recordBoardId,
|
||||
viewBarId,
|
||||
}: RecordIndexBoardContainerEffectProps) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
useLoadRecordIndexBoard(objectNameSingular, recordBoardId);
|
||||
useLoadRecordIndexBoard({ objectNameSingular, recordBoardId, viewBarId });
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
@ -31,9 +33,13 @@ export const RecordIndexBoardContainerEffect = ({
|
||||
navigate(`/settings/objects/${objectMetadataItem.namePlural}`);
|
||||
}, [navigate, objectMetadataItem.namePlural]);
|
||||
|
||||
const { setColumns, setObjectSingularName, getSelectedRecordIdsSelector } =
|
||||
useRecordBoard(recordBoardId);
|
||||
const { resetRecordSelection } = useResetBoardRecordSelection(recordBoardId);
|
||||
const {
|
||||
setColumns,
|
||||
setObjectSingularName,
|
||||
getSelectedRecordIdsSelector,
|
||||
setFieldDefinitions,
|
||||
} = useRecordBoard(recordBoardId);
|
||||
const { resetRecordSelection } = useRecordBoardSelection(recordBoardId);
|
||||
|
||||
useEffect(() => {
|
||||
setObjectSingularName(objectNameSingular);
|
||||
@ -53,6 +59,14 @@ export const RecordIndexBoardContainerEffect = ({
|
||||
setColumns,
|
||||
]);
|
||||
|
||||
const recordIndexFieldDefinitions = useRecoilValue(
|
||||
recordIndexFieldDefinitionsState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setFieldDefinitions(recordIndexFieldDefinitions);
|
||||
}, [objectMetadataItem, setFieldDefinitions, recordIndexFieldDefinitions]);
|
||||
|
||||
const selectedRecordIds = useRecoilValue(getSelectedRecordIdsSelector());
|
||||
|
||||
const { setActionBarEntries, setContextMenuEntries } = useRecordActionBar({
|
||||
|
@ -10,11 +10,19 @@ import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/s
|
||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
||||
import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore';
|
||||
import { useViewBar } from '@/views/hooks/useViewBar';
|
||||
|
||||
export const useLoadRecordIndexBoard = (
|
||||
objectNameSingular: string,
|
||||
recordBoardId: string,
|
||||
) => {
|
||||
type UseLoadRecordIndexBoardProps = {
|
||||
objectNameSingular: string;
|
||||
viewBarId: string;
|
||||
recordBoardId: string;
|
||||
};
|
||||
|
||||
export const useLoadRecordIndexBoard = ({
|
||||
objectNameSingular,
|
||||
viewBarId,
|
||||
recordBoardId,
|
||||
}: UseLoadRecordIndexBoardProps) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
@ -47,6 +55,10 @@ export const useLoadRecordIndexBoard = (
|
||||
orderBy,
|
||||
});
|
||||
|
||||
const { setEntityCountInCurrentView } = useViewBar({
|
||||
viewBarId,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setRecordIdsInBoard(records);
|
||||
}, [records, setRecordIdsInBoard]);
|
||||
@ -55,6 +67,10 @@ export const useLoadRecordIndexBoard = (
|
||||
setRecordsInStore(records);
|
||||
}, [records, setRecordsInStore]);
|
||||
|
||||
useEffect(() => {
|
||||
setEntityCountInCurrentView(records.length);
|
||||
}, [records.length, setEntityCountInCurrentView]);
|
||||
|
||||
return {
|
||||
records,
|
||||
loading,
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
@ -28,7 +30,7 @@ export const RecordTableInternalEffect = ({
|
||||
});
|
||||
|
||||
useScopedHotkeys(
|
||||
'escape',
|
||||
[Key.Escape],
|
||||
() => {
|
||||
resetTableRowSelection();
|
||||
},
|
||||
|
@ -80,7 +80,7 @@ export const TableOptionsDropdownContent = ({
|
||||
const resetMenu = () => setCurrentMenu(undefined);
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
[Key.Escape],
|
||||
() => {
|
||||
closeDropdown();
|
||||
},
|
||||
|
@ -59,7 +59,7 @@ export const SingleEntitySelectMenuItems = ({
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
[Key.Escape],
|
||||
() => {
|
||||
onCancel?.();
|
||||
},
|
||||
|
@ -94,7 +94,7 @@ export const DoubleTextInput = ({
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
[Key.Escape],
|
||||
() => {
|
||||
onEscape({
|
||||
firstValue: firstInternalValue,
|
||||
|
@ -2,6 +2,7 @@ import { useState } from 'react';
|
||||
import { HotkeysEvent } from 'react-hotkeys-hook/dist/types';
|
||||
import TextareaAutosize from 'react-textarea-autosize';
|
||||
import styled from '@emotion/styled';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { IconArrowRight } from '@/ui/display/icon/index';
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
@ -151,7 +152,7 @@ export const AutosizeTextInput = ({
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
'esc',
|
||||
Key.Escape,
|
||||
(event: KeyboardEvent) => {
|
||||
if (!isFocused) {
|
||||
return;
|
||||
|
@ -94,7 +94,7 @@ export const Dropdown = ({
|
||||
});
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
[Key.Escape],
|
||||
() => {
|
||||
closeDropdown();
|
||||
},
|
||||
|
@ -66,7 +66,10 @@ export const RightDrawer = () => {
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Escape],
|
||||
() => closeRightDrawer(),
|
||||
|
||||
() => {
|
||||
closeRightDrawer();
|
||||
},
|
||||
RightDrawerHotkeyScope.RightDrawer,
|
||||
[setIsRightDrawerOpen],
|
||||
);
|
||||
|
@ -4,4 +4,5 @@ export enum AppHotkeyScope {
|
||||
CommandMenu = 'command-menu',
|
||||
CommandMenuOpen = 'command-menu-open',
|
||||
KeyboardShortcutMenu = 'keyboard-shortcut-menu',
|
||||
KeyboardShortcutMenuOpen = 'keyboard-shortcut-menu-open',
|
||||
}
|
||||
|
@ -127,8 +127,9 @@ export const useViewBar = (props?: UseViewProps) => {
|
||||
if (!isDeeplyEqual(savedViewFields, queriedViewFields)) {
|
||||
set(currentViewFieldsState, queriedViewFields);
|
||||
set(savedViewFieldsState, queriedViewFields);
|
||||
onViewFieldsChange?.(queriedViewFields);
|
||||
}
|
||||
|
||||
onViewFieldsChange?.(queriedViewFields);
|
||||
},
|
||||
[scopeId],
|
||||
);
|
||||
|
10
yarn.lock
10
yarn.lock
@ -38381,13 +38381,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-hotkeys-hook@npm:^4.4.3":
|
||||
version: 4.4.3
|
||||
resolution: "react-hotkeys-hook@npm:4.4.3"
|
||||
"react-hotkeys-hook@npm:^4.4.4":
|
||||
version: 4.4.4
|
||||
resolution: "react-hotkeys-hook@npm:4.4.4"
|
||||
peerDependencies:
|
||||
react: ">=16.8.1"
|
||||
react-dom: ">=16.8.1"
|
||||
checksum: ef79e279129f6e55d81c8762b1da214d9c6ee4617b9597dbc3f93057cba8d166831508967b8e3f763a0c4ce0af3b59e6888c6fc94d152deac9335020b2ba80df
|
||||
checksum: afe7418c8bd0ecd3a3f315648b84d9978d06a02e55f93df23aaa00e56613fca839f9ff4d10387e8336454702b4aa03cef97f3e67bfe3e121e42f16d84685f55a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -43453,7 +43453,7 @@ __metadata:
|
||||
react-error-boundary: "npm:^4.0.11"
|
||||
react-helmet-async: "npm:^1.3.0"
|
||||
react-hook-form: "npm:^7.45.1"
|
||||
react-hotkeys-hook: "npm:^4.4.3"
|
||||
react-hotkeys-hook: "npm:^4.4.4"
|
||||
react-icons: "npm:^4.12.0"
|
||||
react-intersection-observer: "npm:^9.5.2"
|
||||
react-loading-skeleton: "npm:^3.3.1"
|
||||
|
Loading…
Reference in New Issue
Block a user