Make filters and sorts work on record page pagination (#12460)
Fixes #7929 This PR implements a system to capture and preserve the filters and sorts when navigating from an index view to a record show page. This information is stored in a context store component state. This allows users to navigate between records inside the record page while maintaining context from the index view.
This commit is contained in:
@ -2,6 +2,8 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context
|
|||||||
import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId';
|
import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId';
|
||||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||||
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
|
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
|
||||||
|
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||||
|
import { contextStoreRecordShowParentViewComponentState } from '@/context-store/states/contextStoreRecordShowParentViewComponentState';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
@ -13,10 +15,10 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
|||||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
||||||
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { useCallback } from 'react';
|
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { IconBrowserMaximize } from 'twenty-ui/display';
|
import { IconBrowserMaximize } from 'twenty-ui/display';
|
||||||
import { Button } from 'twenty-ui/input';
|
import { Button } from 'twenty-ui/input';
|
||||||
@ -60,6 +62,11 @@ export const RecordShowRightDrawerOpenRecordButton = ({
|
|||||||
tabListComponentIdInRecordPage,
|
tabListComponentIdInRecordPage,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const parentViewState = useRecoilComponentCallbackStateV2(
|
||||||
|
contextStoreRecordShowParentViewComponentState,
|
||||||
|
MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||||
|
);
|
||||||
|
|
||||||
const navigate = useNavigateApp();
|
const navigate = useNavigateApp();
|
||||||
|
|
||||||
const actionMenuId = useAvailableComponentInstanceIdOrThrow(
|
const actionMenuId = useAvailableComponentInstanceIdOrThrow(
|
||||||
@ -68,43 +75,54 @@ export const RecordShowRightDrawerOpenRecordButton = ({
|
|||||||
|
|
||||||
const { closeDropdown } = useDropdownV2();
|
const { closeDropdown } = useDropdownV2();
|
||||||
|
|
||||||
const handleOpenRecord = useCallback(() => {
|
const handleOpenRecord = useRecoilCallback(
|
||||||
const tabIdToOpen =
|
({ snapshot, reset }) =>
|
||||||
activeTabIdInRightDrawer === 'home'
|
() => {
|
||||||
? objectNameSingular === CoreObjectNameSingular.Note ||
|
const tabIdToOpen =
|
||||||
objectNameSingular === CoreObjectNameSingular.Task
|
activeTabIdInRightDrawer === 'home'
|
||||||
? 'richText'
|
? objectNameSingular === CoreObjectNameSingular.Note ||
|
||||||
: 'timeline'
|
objectNameSingular === CoreObjectNameSingular.Task
|
||||||
: activeTabIdInRightDrawer;
|
? 'richText'
|
||||||
|
: 'timeline'
|
||||||
|
: activeTabIdInRightDrawer;
|
||||||
|
|
||||||
setActiveTabIdInRecordPage(tabIdToOpen);
|
setActiveTabIdInRecordPage(tabIdToOpen);
|
||||||
|
|
||||||
navigate(AppPath.RecordShowPage, {
|
const parentView = snapshot.getLoadable(parentViewState).getValue();
|
||||||
|
|
||||||
|
if (parentView?.parentViewObjectNameSingular !== objectNameSingular) {
|
||||||
|
reset(parentViewState);
|
||||||
|
}
|
||||||
|
|
||||||
|
navigate(AppPath.RecordShowPage, {
|
||||||
|
objectNameSingular,
|
||||||
|
objectRecordId: recordId,
|
||||||
|
});
|
||||||
|
|
||||||
|
closeDropdown(
|
||||||
|
getRightDrawerActionMenuDropdownIdFromActionMenuId(actionMenuId),
|
||||||
|
);
|
||||||
|
|
||||||
|
closeCommandMenu();
|
||||||
|
},
|
||||||
|
[
|
||||||
|
actionMenuId,
|
||||||
|
activeTabIdInRightDrawer,
|
||||||
|
closeCommandMenu,
|
||||||
|
closeDropdown,
|
||||||
|
navigate,
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
objectRecordId: recordId,
|
parentViewState,
|
||||||
});
|
recordId,
|
||||||
|
setActiveTabIdInRecordPage,
|
||||||
closeDropdown(
|
],
|
||||||
getRightDrawerActionMenuDropdownIdFromActionMenuId(actionMenuId),
|
);
|
||||||
);
|
|
||||||
|
|
||||||
closeCommandMenu();
|
|
||||||
}, [
|
|
||||||
actionMenuId,
|
|
||||||
activeTabIdInRightDrawer,
|
|
||||||
closeCommandMenu,
|
|
||||||
closeDropdown,
|
|
||||||
navigate,
|
|
||||||
objectNameSingular,
|
|
||||||
recordId,
|
|
||||||
setActiveTabIdInRecordPage,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
['ctrl+Enter,meta+Enter'],
|
['ctrl+Enter,meta+Enter'],
|
||||||
handleOpenRecord,
|
handleOpenRecord,
|
||||||
AppHotkeyScope.CommandMenuOpen,
|
AppHotkeyScope.CommandMenuOpen,
|
||||||
[closeCommandMenu, navigate, objectNameSingular, recordId],
|
[handleOpenRecord],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isDefined(record)) {
|
if (!isDefined(record)) {
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||||
|
import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||||
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
|
|
||||||
|
type RecordShowParentViewComponentState = {
|
||||||
|
parentViewComponentId: string;
|
||||||
|
parentViewObjectNameSingular: string;
|
||||||
|
parentViewFilterGroups: RecordFilterGroup[];
|
||||||
|
parentViewFilters: RecordFilter[];
|
||||||
|
parentViewSorts: RecordSort[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const contextStoreRecordShowParentViewComponentState =
|
||||||
|
createComponentStateV2<RecordShowParentViewComponentState | undefined | null>(
|
||||||
|
{
|
||||||
|
key: 'contextStoreRecordShowParentViewComponentState',
|
||||||
|
defaultValue: undefined,
|
||||||
|
componentInstanceContext: ContextStoreComponentInstanceContext,
|
||||||
|
},
|
||||||
|
);
|
||||||
@ -7,6 +7,7 @@ import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
|||||||
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
||||||
import { MouseEvent } from 'react';
|
import { MouseEvent } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import {
|
import {
|
||||||
AvatarChip,
|
AvatarChip,
|
||||||
AvatarChipVariant,
|
AvatarChipVariant,
|
||||||
@ -27,6 +28,7 @@ export type RecordChipProps = {
|
|||||||
size?: ChipSize;
|
size?: ChipSize;
|
||||||
isLabelHidden?: boolean;
|
isLabelHidden?: boolean;
|
||||||
triggerEvent?: TriggerEventType;
|
triggerEvent?: TriggerEventType;
|
||||||
|
onClick?: (event: MouseEvent) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RecordChip = ({
|
export const RecordChip = ({
|
||||||
@ -40,6 +42,7 @@ export const RecordChip = ({
|
|||||||
forceDisableClick = false,
|
forceDisableClick = false,
|
||||||
isLabelHidden = false,
|
isLabelHidden = false,
|
||||||
triggerEvent = 'MOUSE_DOWN',
|
triggerEvent = 'MOUSE_DOWN',
|
||||||
|
onClick,
|
||||||
}: RecordChipProps) => {
|
}: RecordChipProps) => {
|
||||||
const { recordChipData } = useRecordChipData({
|
const { recordChipData } = useRecordChipData({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
@ -53,14 +56,16 @@ export const RecordChip = ({
|
|||||||
const isSidePanelViewOpenRecordInType =
|
const isSidePanelViewOpenRecordInType =
|
||||||
recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL;
|
recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL;
|
||||||
|
|
||||||
const handleCustomClick = isSidePanelViewOpenRecordInType
|
const handleCustomClick = isDefined(onClick)
|
||||||
? (_event: MouseEvent<HTMLElement>) => {
|
? onClick
|
||||||
openRecordInCommandMenu({
|
: isSidePanelViewOpenRecordInType
|
||||||
recordId: record.id,
|
? (_event: MouseEvent<HTMLElement>) => {
|
||||||
objectNameSingular,
|
openRecordInCommandMenu({
|
||||||
});
|
recordId: record.id,
|
||||||
}
|
objectNameSingular,
|
||||||
: undefined;
|
});
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
|
|
||||||
// TODO temporary until we create a record show page for Workspaces members
|
// TODO temporary until we create a record show page for Workspaces members
|
||||||
|
|
||||||
|
|||||||
@ -10,13 +10,10 @@ import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/re
|
|||||||
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
|
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
|
||||||
|
|
||||||
import { ActionMenuDropdownHotkeyScope } from '@/action-menu/types/ActionMenuDropdownHotKeyScope';
|
import { ActionMenuDropdownHotkeyScope } from '@/action-menu/types/ActionMenuDropdownHotKeyScope';
|
||||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
|
||||||
import { RecordBoardCardBody } from '@/object-record/record-board/record-board-card/components/RecordBoardCardBody';
|
import { RecordBoardCardBody } from '@/object-record/record-board/record-board-card/components/RecordBoardCardBody';
|
||||||
import { RecordBoardCardHeader } from '@/object-record/record-board/record-board-card/components/RecordBoardCardHeader';
|
import { RecordBoardCardHeader } from '@/object-record/record-board/record-board-card/components/RecordBoardCardHeader';
|
||||||
import { RECORD_BOARD_CARD_CLICK_OUTSIDE_ID } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardClickOutsideId';
|
import { RECORD_BOARD_CARD_CLICK_OUTSIDE_ID } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardClickOutsideId';
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView';
|
||||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
|
||||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||||
import { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement';
|
import { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement';
|
||||||
@ -24,14 +21,12 @@ import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-
|
|||||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||||
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useContext, useState } from 'react';
|
import { useContext, useState } from 'react';
|
||||||
import { InView, useInView } from 'react-intersection-observer';
|
import { InView, useInView } from 'react-intersection-observer';
|
||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { AnimatedEaseInOut } from 'twenty-ui/utilities';
|
import { AnimatedEaseInOut } from 'twenty-ui/utilities';
|
||||||
import { useDebouncedCallback } from 'use-debounce';
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
|
||||||
|
|
||||||
const StyledBoardCard = styled.div<{
|
const StyledBoardCard = styled.div<{
|
||||||
isDragging?: boolean;
|
isDragging?: boolean;
|
||||||
@ -92,9 +87,6 @@ const StyledBoardCardWrapper = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const RecordBoardCard = () => {
|
export const RecordBoardCard = () => {
|
||||||
const navigate = useNavigateApp();
|
|
||||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
|
||||||
|
|
||||||
const { recordId, rowIndex, columnIndex } = useContext(
|
const { recordId, rowIndex, columnIndex } = useContext(
|
||||||
RecordBoardCardContext,
|
RecordBoardCardContext,
|
||||||
);
|
);
|
||||||
@ -131,8 +123,6 @@ export const RecordBoardCard = () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const { objectNameSingular } = useRecordIndexContextOrThrow();
|
|
||||||
|
|
||||||
const recordBoardId = useAvailableScopeIdOrThrow(
|
const recordBoardId = useAvailableScopeIdOrThrow(
|
||||||
RecordBoardScopeInternalContext,
|
RecordBoardScopeInternalContext,
|
||||||
);
|
);
|
||||||
@ -151,7 +141,7 @@ export const RecordBoardCard = () => {
|
|||||||
|
|
||||||
const { openDropdown } = useDropdownV2();
|
const { openDropdown } = useDropdownV2();
|
||||||
|
|
||||||
const recordIndexOpenRecordIn = useRecoilValue(recordIndexOpenRecordInState);
|
const { openRecordFromIndexView } = useOpenRecordFromIndexView();
|
||||||
|
|
||||||
const handleActionMenuDropdown = (event: React.MouseEvent) => {
|
const handleActionMenuDropdown = (event: React.MouseEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -166,17 +156,7 @@ export const RecordBoardCard = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCardClick = () => {
|
const handleCardClick = () => {
|
||||||
if (recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL) {
|
openRecordFromIndexView({ recordId });
|
||||||
openRecordInCommandMenu({
|
|
||||||
recordId,
|
|
||||||
objectNameSingular,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
navigate(AppPath.RecordShowPage, {
|
|
||||||
objectNameSingular,
|
|
||||||
objectRecordId: recordId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseLeaveBoard = useDebouncedCallback(() => {
|
const onMouseLeaveBoard = useDebouncedCallback(() => {
|
||||||
|
|||||||
@ -8,13 +8,11 @@ import { RecordBoardScopeInternalContext } from '@/object-record/record-board/sc
|
|||||||
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
|
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
|
||||||
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
||||||
|
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView';
|
||||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||||
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
|
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { Dispatch, SetStateAction, useContext } from 'react';
|
import { Dispatch, SetStateAction, useContext } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
@ -45,8 +43,6 @@ export const RecordBoardCardHeader = ({
|
|||||||
}: RecordBoardCardHeaderProps) => {
|
}: RecordBoardCardHeaderProps) => {
|
||||||
const { recordId } = useContext(RecordBoardCardContext);
|
const { recordId } = useContext(RecordBoardCardContext);
|
||||||
|
|
||||||
const { indexIdentifierUrl } = useRecordIndexContextOrThrow();
|
|
||||||
|
|
||||||
const record = useRecoilValue(recordStoreFamilyState(recordId));
|
const record = useRecoilValue(recordStoreFamilyState(recordId));
|
||||||
|
|
||||||
const { objectMetadataItem } = useContext(RecordBoardContext);
|
const { objectMetadataItem } = useContext(RecordBoardContext);
|
||||||
@ -68,7 +64,7 @@ export const RecordBoardCardHeader = ({
|
|||||||
recordId,
|
recordId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const recordIndexOpenRecordIn = useRecoilValue(recordIndexOpenRecordInState);
|
const { openRecordFromIndexView } = useOpenRecordFromIndexView();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordBoardCardHeaderContainer showCompactView={showCompactView}>
|
<RecordBoardCardHeaderContainer showCompactView={showCompactView}>
|
||||||
@ -79,11 +75,9 @@ export const RecordBoardCardHeader = ({
|
|||||||
record={record}
|
record={record}
|
||||||
variant={AvatarChipVariant.Transparent}
|
variant={AvatarChipVariant.Transparent}
|
||||||
maxWidth={150}
|
maxWidth={150}
|
||||||
to={
|
onClick={() => {
|
||||||
recordIndexOpenRecordIn === ViewOpenRecordInType.RECORD_PAGE
|
openRecordFromIndexView({ recordId });
|
||||||
? indexIdentifierUrl(recordId)
|
}}
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
triggerEvent="CLICK"
|
triggerEvent="CLICK"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { createContext } from 'react';
|
import { createContext, MouseEvent } from 'react';
|
||||||
|
|
||||||
import { TriggerEventType } from 'twenty-ui/utilities';
|
import { TriggerEventType } from 'twenty-ui/utilities';
|
||||||
import { FieldDefinition } from '../types/FieldDefinition';
|
import { FieldDefinition } from '../types/FieldDefinition';
|
||||||
@ -35,6 +35,7 @@ export type GenericFieldContextType = {
|
|||||||
isDisplayModeFixHeight?: boolean;
|
isDisplayModeFixHeight?: boolean;
|
||||||
isReadOnly: boolean;
|
isReadOnly: boolean;
|
||||||
disableChipClick?: boolean;
|
disableChipClick?: boolean;
|
||||||
|
onRecordChipClick?: (event: MouseEvent) => void;
|
||||||
onOpenEditMode?: () => void;
|
onOpenEditMode?: () => void;
|
||||||
onCloseEditMode?: () => void;
|
onCloseEditMode?: () => void;
|
||||||
triggerEvent?: TriggerEventType;
|
triggerEvent?: TriggerEventType;
|
||||||
|
|||||||
@ -12,6 +12,7 @@ export const ChipFieldDisplay = () => {
|
|||||||
disableChipClick,
|
disableChipClick,
|
||||||
maxWidth,
|
maxWidth,
|
||||||
triggerEvent,
|
triggerEvent,
|
||||||
|
onRecordChipClick,
|
||||||
} = useChipFieldDisplay();
|
} = useChipFieldDisplay();
|
||||||
|
|
||||||
if (!isDefined(recordValue)) {
|
if (!isDefined(recordValue)) {
|
||||||
@ -28,6 +29,7 @@ export const ChipFieldDisplay = () => {
|
|||||||
isLabelHidden={isLabelIdentifierCompact}
|
isLabelHidden={isLabelIdentifierCompact}
|
||||||
forceDisableClick={disableChipClick}
|
forceDisableClick={disableChipClick}
|
||||||
triggerEvent={triggerEvent}
|
triggerEvent={triggerEvent}
|
||||||
|
onClick={onRecordChipClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -21,6 +21,7 @@ export const useChipFieldDisplay = () => {
|
|||||||
disableChipClick,
|
disableChipClick,
|
||||||
maxWidth,
|
maxWidth,
|
||||||
triggerEvent,
|
triggerEvent,
|
||||||
|
onRecordChipClick,
|
||||||
} = useContext(FieldContext);
|
} = useContext(FieldContext);
|
||||||
|
|
||||||
const { chipGeneratorPerObjectPerField } = useContext(
|
const { chipGeneratorPerObjectPerField } = useContext(
|
||||||
@ -54,5 +55,6 @@ export const useChipFieldDisplay = () => {
|
|||||||
disableChipClick,
|
disableChipClick,
|
||||||
maxWidth,
|
maxWidth,
|
||||||
triggerEvent,
|
triggerEvent,
|
||||||
|
onRecordChipClick,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,94 @@
|
|||||||
|
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||||
|
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||||
|
import { contextStoreRecordShowParentViewComponentState } from '@/context-store/states/contextStoreRecordShowParentViewComponentState';
|
||||||
|
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||||
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
|
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
||||||
|
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||||
|
import { AppPath } from '@/types/AppPath';
|
||||||
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
|
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
||||||
|
|
||||||
|
export const useOpenRecordFromIndexView = () => {
|
||||||
|
const { recordIndexId } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
|
const { objectNameSingular } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
|
const navigate = useNavigateApp();
|
||||||
|
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||||
|
|
||||||
|
const currentRecordFilters = useRecoilComponentCallbackStateV2(
|
||||||
|
currentRecordFiltersComponentState,
|
||||||
|
recordIndexId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const currentRecordSorts = useRecoilComponentCallbackStateV2(
|
||||||
|
currentRecordSortsComponentState,
|
||||||
|
recordIndexId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const currentRecordFilterGroups = useRecoilComponentCallbackStateV2(
|
||||||
|
currentRecordFilterGroupsComponentState,
|
||||||
|
recordIndexId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const openRecordFromIndexView = useRecoilCallback(
|
||||||
|
({ snapshot, set }) =>
|
||||||
|
({ recordId }: { recordId: string }) => {
|
||||||
|
const recordIndexOpenRecordIn = snapshot
|
||||||
|
.getLoadable(recordIndexOpenRecordInState)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const parentViewFilters = snapshot
|
||||||
|
.getLoadable(currentRecordFilters)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const parentViewSorts = snapshot
|
||||||
|
.getLoadable(currentRecordSorts)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const parentViewFilterGroups = snapshot
|
||||||
|
.getLoadable(currentRecordFilterGroups)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
set(
|
||||||
|
contextStoreRecordShowParentViewComponentState.atomFamily({
|
||||||
|
instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
parentViewComponentId: recordIndexId,
|
||||||
|
parentViewObjectNameSingular: objectNameSingular,
|
||||||
|
parentViewFilterGroups,
|
||||||
|
parentViewFilters,
|
||||||
|
parentViewSorts,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (recordIndexOpenRecordIn === ViewOpenRecordInType.SIDE_PANEL) {
|
||||||
|
openRecordInCommandMenu({
|
||||||
|
recordId,
|
||||||
|
objectNameSingular,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
navigate(AppPath.RecordShowPage, {
|
||||||
|
objectNameSingular,
|
||||||
|
objectRecordId: recordId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
currentRecordFilters,
|
||||||
|
currentRecordSorts,
|
||||||
|
currentRecordFilterGroups,
|
||||||
|
recordIndexId,
|
||||||
|
objectNameSingular,
|
||||||
|
navigate,
|
||||||
|
openRecordInCommandMenu,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { openRecordFromIndexView };
|
||||||
|
};
|
||||||
@ -8,7 +8,7 @@ import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
|||||||
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
|
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
|
||||||
import { useRecordIdsFromFindManyCacheRootQuery } from '@/object-record/record-show/hooks/useRecordIdsFromFindManyCacheRootQuery';
|
import { useRecordIdsFromFindManyCacheRootQuery } from '@/object-record/record-show/hooks/useRecordIdsFromFindManyCacheRootQuery';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { useQueryVariablesFromActiveFieldsOfViewOrDefaultView } from '@/views/hooks/useQueryVariablesFromActiveFieldsOfViewOrDefaultView';
|
import { useQueryVariablesFromParentView } from '@/views/hooks/useQueryVariablesFromParentView';
|
||||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||||
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
||||||
|
|
||||||
@ -36,10 +36,9 @@ export const useRecordShowPagePagination = (
|
|||||||
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular });
|
const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular });
|
||||||
|
|
||||||
const { filter, orderBy } =
|
const { filter, orderBy } = useQueryVariablesFromParentView({
|
||||||
useQueryVariablesFromActiveFieldsOfViewOrDefaultView({
|
objectMetadataItem,
|
||||||
objectMetadataItem,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
const { loading: loadingCursor, pageInfo: currentRecordsPageInfo } =
|
const { loading: loadingCursor, pageInfo: currentRecordsPageInfo } =
|
||||||
useFindManyRecords({
|
useFindManyRecords({
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
export const computeRecordShowComponentInstanceId = (
|
||||||
|
objectRecordId: string,
|
||||||
|
) => {
|
||||||
|
return `record-show-${objectRecordId}`;
|
||||||
|
};
|
||||||
@ -2,6 +2,7 @@ import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObject
|
|||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly';
|
import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly';
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
|
import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView';
|
||||||
import { RecordUpdateContext } from '@/object-record/record-table/contexts/EntityUpdateMutationHookContext';
|
import { RecordUpdateContext } from '@/object-record/record-table/contexts/EntityUpdateMutationHookContext';
|
||||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
@ -48,6 +49,8 @@ export const RecordTableCellFieldContextLabelIdentifier = ({
|
|||||||
const isLabelIdentifierCompact =
|
const isLabelIdentifierCompact =
|
||||||
isMobile && !isRecordTableScrolledLeftComponent;
|
isMobile && !isRecordTableScrolledLeftComponent;
|
||||||
|
|
||||||
|
const { openRecordFromIndexView } = useOpenRecordFromIndexView();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
value={{
|
value={{
|
||||||
@ -60,6 +63,9 @@ export const RecordTableCellFieldContextLabelIdentifier = ({
|
|||||||
displayedMaxRows: 1,
|
displayedMaxRows: 1,
|
||||||
isReadOnly: isFieldReadOnly,
|
isReadOnly: isFieldReadOnly,
|
||||||
maxWidth: columnDefinition.size,
|
maxWidth: columnDefinition.size,
|
||||||
|
onRecordChipClick: () => {
|
||||||
|
openRecordFromIndexView({ recordId });
|
||||||
|
},
|
||||||
isForbidden: !hasObjectReadPermissions,
|
isForbidden: !hasObjectReadPermissions,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -14,9 +14,7 @@ import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
|||||||
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||||
|
|
||||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
|
||||||
import { useOpenFieldInputEditMode } from '@/object-record/record-field/hooks/useOpenFieldInputEditMode';
|
import { useOpenFieldInputEditMode } from '@/object-record/record-field/hooks/useOpenFieldInputEditMode';
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
|
||||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
||||||
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
|
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
|
||||||
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
|
import { RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-table/constants/RecordTableClickOutsideListenerId';
|
||||||
@ -25,6 +23,7 @@ import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropd
|
|||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
||||||
|
|
||||||
|
import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView';
|
||||||
import { useSetRecordTableFocusPosition } from '@/object-record/record-table/hooks/internal/useSetRecordTableFocusPosition';
|
import { useSetRecordTableFocusPosition } from '@/object-record/record-table/hooks/internal/useSetRecordTableFocusPosition';
|
||||||
import { useActiveRecordTableRow } from '@/object-record/record-table/hooks/useActiveRecordTableRow';
|
import { useActiveRecordTableRow } from '@/object-record/record-table/hooks/useActiveRecordTableRow';
|
||||||
import { useFocusedRecordTableRow } from '@/object-record/record-table/hooks/useFocusedRecordTableRow';
|
import { useFocusedRecordTableRow } from '@/object-record/record-table/hooks/useFocusedRecordTableRow';
|
||||||
@ -33,8 +32,8 @@ import { clickOutsideListenerIsActivatedComponentState } from '@/ui/utilities/po
|
|||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||||
|
|
||||||
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
|
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
|
||||||
scope: TableHotkeyScope.CellEditMode,
|
scope: TableHotkeyScope.CellEditMode,
|
||||||
};
|
};
|
||||||
@ -51,21 +50,20 @@ export type OpenTableCellArgs = {
|
|||||||
isNavigating: boolean;
|
isNavigating: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useOpenRecordTableCellV2 = (tableScopeId: string) => {
|
export const useOpenRecordTableCellV2 = (recordTableId: string) => {
|
||||||
const clickOutsideListenerIsActivatedState =
|
const clickOutsideListenerIsActivatedState =
|
||||||
useRecoilComponentCallbackStateV2(
|
useRecoilComponentCallbackStateV2(
|
||||||
clickOutsideListenerIsActivatedComponentState,
|
clickOutsideListenerIsActivatedComponentState,
|
||||||
RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID,
|
RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID,
|
||||||
);
|
);
|
||||||
const { indexIdentifierUrl } = useRecordIndexContextOrThrow();
|
|
||||||
const setCurrentTableCellInEditModePosition = useSetRecoilComponentStateV2(
|
const setCurrentTableCellInEditModePosition = useSetRecoilComponentStateV2(
|
||||||
recordTableCellEditModePositionComponentState,
|
recordTableCellEditModePositionComponentState,
|
||||||
tableScopeId,
|
recordTableId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { setDragSelectionStartEnabled } = useDragSelect();
|
const { setDragSelectionStartEnabled } = useDragSelect();
|
||||||
|
|
||||||
const leaveTableFocus = useLeaveTableFocus(tableScopeId);
|
const leaveTableFocus = useLeaveTableFocus(recordTableId);
|
||||||
const { toggleClickOutside } = useClickOutsideListener(
|
const { toggleClickOutside } = useClickOutsideListener(
|
||||||
FOCUS_CLICK_OUTSIDE_LISTENER_ID,
|
FOCUS_CLICK_OUTSIDE_LISTENER_ID,
|
||||||
);
|
);
|
||||||
@ -77,27 +75,25 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => {
|
|||||||
viewableRecordNameSingularState,
|
viewableRecordNameSingularState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const { setActiveDropdownFocusIdAndMemorizePrevious } =
|
const { setActiveDropdownFocusIdAndMemorizePrevious } =
|
||||||
useSetActiveDropdownFocusIdAndMemorizePrevious();
|
useSetActiveDropdownFocusIdAndMemorizePrevious();
|
||||||
|
|
||||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
|
||||||
|
|
||||||
const { openFieldInput } = useOpenFieldInputEditMode();
|
const { openFieldInput } = useOpenFieldInputEditMode();
|
||||||
|
|
||||||
const { activateRecordTableRow, deactivateRecordTableRow } =
|
const { activateRecordTableRow, deactivateRecordTableRow } =
|
||||||
useActiveRecordTableRow(tableScopeId);
|
useActiveRecordTableRow(recordTableId);
|
||||||
|
|
||||||
const { unfocusRecordTableRow } = useFocusedRecordTableRow(tableScopeId);
|
const { unfocusRecordTableRow } = useFocusedRecordTableRow(recordTableId);
|
||||||
|
|
||||||
const setIsRowFocusActive = useSetRecoilComponentStateV2(
|
const setIsRowFocusActive = useSetRecoilComponentStateV2(
|
||||||
isRecordTableRowFocusActiveComponentState,
|
isRecordTableRowFocusActiveComponentState,
|
||||||
tableScopeId,
|
recordTableId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const setFocusPosition = useSetRecordTableFocusPosition();
|
const setFocusPosition = useSetRecordTableFocusPosition();
|
||||||
|
|
||||||
|
const { openRecordFromIndexView } = useOpenRecordFromIndexView();
|
||||||
|
|
||||||
const openTableCell = useRecoilCallback(
|
const openTableCell = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
({
|
({
|
||||||
@ -141,20 +137,13 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => {
|
|||||||
.getLoadable(recordIndexOpenRecordInState)
|
.getLoadable(recordIndexOpenRecordInState)
|
||||||
.getValue();
|
.getValue();
|
||||||
|
|
||||||
if (openRecordIn === ViewOpenRecordInType.RECORD_PAGE) {
|
|
||||||
navigate(indexIdentifierUrl(recordId));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (openRecordIn === ViewOpenRecordInType.SIDE_PANEL) {
|
if (openRecordIn === ViewOpenRecordInType.SIDE_PANEL) {
|
||||||
openRecordInCommandMenu({
|
|
||||||
recordId,
|
|
||||||
objectNameSingular,
|
|
||||||
});
|
|
||||||
|
|
||||||
activateRecordTableRow(cellPosition.row);
|
activateRecordTableRow(cellPosition.row);
|
||||||
unfocusRecordTableRow();
|
unfocusRecordTableRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openRecordFromIndexView({ recordId });
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,13 +203,11 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => {
|
|||||||
toggleClickOutside,
|
toggleClickOutside,
|
||||||
setActiveDropdownFocusIdAndMemorizePrevious,
|
setActiveDropdownFocusIdAndMemorizePrevious,
|
||||||
leaveTableFocus,
|
leaveTableFocus,
|
||||||
navigate,
|
|
||||||
indexIdentifierUrl,
|
|
||||||
openRecordInCommandMenu,
|
|
||||||
activateRecordTableRow,
|
activateRecordTableRow,
|
||||||
unfocusRecordTableRow,
|
unfocusRecordTableRow,
|
||||||
setViewableRecordId,
|
setViewableRecordId,
|
||||||
setViewableRecordNameSingular,
|
setViewableRecordNameSingular,
|
||||||
|
openRecordFromIndexView,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
|
||||||
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
|
||||||
import { useViewOrDefaultViewFromPrefetchedViews } from '@/views/hooks/useViewOrDefaultViewFromPrefetchedViews';
|
|
||||||
import { useQueryVariablesFromView } from './useQueryVariablesFromView';
|
|
||||||
|
|
||||||
export const useQueryVariablesFromActiveFieldsOfViewOrDefaultView = ({
|
|
||||||
objectMetadataItem,
|
|
||||||
}: {
|
|
||||||
objectMetadataItem: ObjectMetadataItem;
|
|
||||||
}) => {
|
|
||||||
const { view } = useViewOrDefaultViewFromPrefetchedViews({
|
|
||||||
objectMetadataItemId: objectMetadataItem.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { filterValueDependencies } = useFilterValueDependencies();
|
|
||||||
|
|
||||||
const { filter, orderBy } = useQueryVariablesFromView({
|
|
||||||
objectMetadataItem,
|
|
||||||
view,
|
|
||||||
filterValueDependencies,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
filter,
|
|
||||||
orderBy,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||||
|
import { contextStoreRecordShowParentViewComponentState } from '@/context-store/states/contextStoreRecordShowParentViewComponentState';
|
||||||
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { getQueryVariablesFromFiltersAndSorts } from '../utils/getQueryVariablesFromFiltersAndSorts';
|
||||||
|
|
||||||
|
export const useQueryVariablesFromParentView = ({
|
||||||
|
objectMetadataItem,
|
||||||
|
}: {
|
||||||
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
|
}) => {
|
||||||
|
const recordShowParentView = useRecoilComponentValueV2(
|
||||||
|
contextStoreRecordShowParentViewComponentState,
|
||||||
|
MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
|
const { filter, orderBy } = getQueryVariablesFromFiltersAndSorts({
|
||||||
|
recordFilterGroups: recordShowParentView?.parentViewFilterGroups ?? [],
|
||||||
|
recordFilters: recordShowParentView?.parentViewFilters ?? [],
|
||||||
|
recordSorts: recordShowParentView?.parentViewSorts ?? [],
|
||||||
|
objectMetadataItem,
|
||||||
|
filterValueDependencies,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
filter,
|
||||||
|
orderBy,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,58 +0,0 @@
|
|||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
|
||||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
|
||||||
import { RecordFilterValueDependencies } from '@/object-record/record-filter/types/RecordFilterValueDependencies';
|
|
||||||
import { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeRecordGqlOperationFilter';
|
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { getFilterableFieldsWithVectorSearch } from '@/views/utils/getFilterableFieldsWithVectorSearch';
|
|
||||||
import { mapViewFilterGroupsToRecordFilterGroups } from '@/views/utils/mapViewFilterGroupsToRecordFilterGroups';
|
|
||||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
|
||||||
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
|
||||||
|
|
||||||
export const useQueryVariablesFromView = ({
|
|
||||||
view,
|
|
||||||
objectMetadataItem,
|
|
||||||
filterValueDependencies,
|
|
||||||
}: {
|
|
||||||
view: View | null | undefined;
|
|
||||||
objectMetadataItem: ObjectMetadataItem;
|
|
||||||
filterValueDependencies: RecordFilterValueDependencies;
|
|
||||||
}) => {
|
|
||||||
if (!isDefined(view)) {
|
|
||||||
return {
|
|
||||||
filter: undefined,
|
|
||||||
orderBy: undefined,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const { viewFilterGroups, viewFilters, viewSorts } = view;
|
|
||||||
|
|
||||||
const recordFilterGroups = mapViewFilterGroupsToRecordFilterGroups(
|
|
||||||
viewFilterGroups ?? [],
|
|
||||||
);
|
|
||||||
|
|
||||||
const filterableFieldMetadataItems =
|
|
||||||
getFilterableFieldsWithVectorSearch(objectMetadataItem);
|
|
||||||
|
|
||||||
const recordFilters = mapViewFiltersToFilters(
|
|
||||||
viewFilters,
|
|
||||||
filterableFieldMetadataItems,
|
|
||||||
);
|
|
||||||
|
|
||||||
const filter = computeRecordGqlOperationFilter({
|
|
||||||
fields: objectMetadataItem?.fields ?? [],
|
|
||||||
filterValueDependencies,
|
|
||||||
recordFilterGroups,
|
|
||||||
recordFilters,
|
|
||||||
});
|
|
||||||
|
|
||||||
const orderBy = turnSortsIntoOrderBy(
|
|
||||||
objectMetadataItem,
|
|
||||||
mapViewSortsToSorts(viewSorts),
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
filter,
|
|
||||||
orderBy,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||||
|
import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||||
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
|
import { RecordFilterValueDependencies } from '@/object-record/record-filter/types/RecordFilterValueDependencies';
|
||||||
|
import { computeRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeRecordGqlOperationFilter';
|
||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
|
|
||||||
|
export const getQueryVariablesFromFiltersAndSorts = ({
|
||||||
|
recordFilterGroups,
|
||||||
|
recordFilters,
|
||||||
|
recordSorts,
|
||||||
|
objectMetadataItem,
|
||||||
|
filterValueDependencies,
|
||||||
|
}: {
|
||||||
|
recordFilterGroups: RecordFilterGroup[];
|
||||||
|
recordFilters: RecordFilter[];
|
||||||
|
recordSorts: RecordSort[];
|
||||||
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
|
filterValueDependencies: RecordFilterValueDependencies;
|
||||||
|
}) => {
|
||||||
|
const filter = computeRecordGqlOperationFilter({
|
||||||
|
fields: objectMetadataItem?.fields ?? [],
|
||||||
|
filterValueDependencies,
|
||||||
|
recordFilterGroups,
|
||||||
|
recordFilters,
|
||||||
|
});
|
||||||
|
|
||||||
|
const orderBy = turnSortsIntoOrderBy(objectMetadataItem, recordSorts);
|
||||||
|
|
||||||
|
return {
|
||||||
|
filter,
|
||||||
|
orderBy,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -10,6 +10,7 @@ import { RecordFiltersComponentInstanceContext } from '@/object-record/record-fi
|
|||||||
import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer';
|
import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer';
|
||||||
import { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect';
|
import { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect';
|
||||||
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
||||||
|
import { computeRecordShowComponentInstanceId } from '@/object-record/record-show/utils/computeRecordShowComponentInstanceId';
|
||||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||||
import { PageHeaderToggleCommandMenuButton } from '@/ui/layout/page-header/components/PageHeaderToggleCommandMenuButton';
|
import { PageHeaderToggleCommandMenuButton } from '@/ui/layout/page-header/components/PageHeaderToggleCommandMenuButton';
|
||||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||||
@ -28,21 +29,24 @@ export const RecordShowPage = () => {
|
|||||||
parameters.objectRecordId ?? '',
|
parameters.objectRecordId ?? '',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const recordShowComponentInstanceId =
|
||||||
|
computeRecordShowComponentInstanceId(objectRecordId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
value={{ instanceId: recordShowComponentInstanceId }}
|
||||||
>
|
>
|
||||||
<RecordFiltersComponentInstanceContext.Provider
|
<RecordFiltersComponentInstanceContext.Provider
|
||||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
value={{ instanceId: recordShowComponentInstanceId }}
|
||||||
>
|
>
|
||||||
<RecordSortsComponentInstanceContext.Provider
|
<RecordSortsComponentInstanceContext.Provider
|
||||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
value={{ instanceId: recordShowComponentInstanceId }}
|
||||||
>
|
>
|
||||||
<ContextStoreComponentInstanceContext.Provider
|
<ContextStoreComponentInstanceContext.Provider
|
||||||
value={{ instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID }}
|
value={{ instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID }}
|
||||||
>
|
>
|
||||||
<ActionMenuComponentInstanceContext.Provider
|
<ActionMenuComponentInstanceContext.Provider
|
||||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
value={{ instanceId: recordShowComponentInstanceId }}
|
||||||
>
|
>
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<RecordShowPageTitle
|
<RecordShowPageTitle
|
||||||
|
|||||||
Reference in New Issue
Block a user