Fix relation from many notes (#11120)
Fixes https://github.com/twentyhq/twenty/issues/3415
This commit is contained in:
@ -3,6 +3,7 @@ import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
|||||||
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
|
import { CommandMenuPageComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuPageComponentInstanceContext';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { getLinkToShowPage } from '@/object-metadata/utils/getLinkToShowPage';
|
import { getLinkToShowPage } from '@/object-metadata/utils/getLinkToShowPage';
|
||||||
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId';
|
import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId';
|
||||||
@ -15,6 +16,8 @@ import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-sta
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { Button, IconBrowserMaximize, getOsControlSymbol } from 'twenty-ui';
|
import { Button, IconBrowserMaximize, getOsControlSymbol } from 'twenty-ui';
|
||||||
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
||||||
const StyledLink = styled(Link)`
|
const StyledLink = styled(Link)`
|
||||||
@ -23,13 +26,16 @@ const StyledLink = styled(Link)`
|
|||||||
|
|
||||||
type RecordShowRightDrawerOpenRecordButtonProps = {
|
type RecordShowRightDrawerOpenRecordButtonProps = {
|
||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
record: ObjectRecord;
|
recordId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RecordShowRightDrawerOpenRecordButton = ({
|
export const RecordShowRightDrawerOpenRecordButton = ({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
record,
|
recordId,
|
||||||
}: RecordShowRightDrawerOpenRecordButtonProps) => {
|
}: RecordShowRightDrawerOpenRecordButtonProps) => {
|
||||||
|
const record = useRecoilValue<ObjectRecord | null>(
|
||||||
|
recordStoreFamilyState(recordId),
|
||||||
|
);
|
||||||
const { closeCommandMenu } = useCommandMenu();
|
const { closeCommandMenu } = useCommandMenu();
|
||||||
|
|
||||||
const commandMenuPageComponentInstance = useComponentInstanceStateContext(
|
const commandMenuPageComponentInstance = useComponentInstanceStateContext(
|
||||||
@ -38,7 +44,7 @@ export const RecordShowRightDrawerOpenRecordButton = ({
|
|||||||
|
|
||||||
const tabListComponentId = getShowPageTabListComponentId({
|
const tabListComponentId = getShowPageTabListComponentId({
|
||||||
pageId: commandMenuPageComponentInstance?.instanceId,
|
pageId: commandMenuPageComponentInstance?.instanceId,
|
||||||
targetObjectId: record.id,
|
targetObjectId: recordId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const activeTabIdInRightDrawer = useRecoilComponentValueV2(
|
const activeTabIdInRightDrawer = useRecoilComponentValueV2(
|
||||||
@ -47,7 +53,7 @@ export const RecordShowRightDrawerOpenRecordButton = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const tabListComponentIdInRecordPage = getShowPageTabListComponentId({
|
const tabListComponentIdInRecordPage = getShowPageTabListComponentId({
|
||||||
targetObjectId: record.id,
|
targetObjectId: recordId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const setActiveTabIdInRecordPage = useSetRecoilComponentStateV2(
|
const setActiveTabIdInRecordPage = useSetRecoilComponentStateV2(
|
||||||
@ -55,8 +61,6 @@ export const RecordShowRightDrawerOpenRecordButton = ({
|
|||||||
tabListComponentIdInRecordPage,
|
tabListComponentIdInRecordPage,
|
||||||
);
|
);
|
||||||
|
|
||||||
const to = getLinkToShowPage(objectNameSingular, record);
|
|
||||||
|
|
||||||
const navigate = useNavigateApp();
|
const navigate = useNavigateApp();
|
||||||
|
|
||||||
const handleOpenRecord = useCallback(() => {
|
const handleOpenRecord = useCallback(() => {
|
||||||
@ -72,7 +76,7 @@ export const RecordShowRightDrawerOpenRecordButton = ({
|
|||||||
|
|
||||||
navigate(AppPath.RecordShowPage, {
|
navigate(AppPath.RecordShowPage, {
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
objectRecordId: record.id,
|
objectRecordId: recordId,
|
||||||
});
|
});
|
||||||
|
|
||||||
closeCommandMenu();
|
closeCommandMenu();
|
||||||
@ -81,7 +85,7 @@ export const RecordShowRightDrawerOpenRecordButton = ({
|
|||||||
closeCommandMenu,
|
closeCommandMenu,
|
||||||
navigate,
|
navigate,
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
record.id,
|
recordId,
|
||||||
setActiveTabIdInRecordPage,
|
setActiveTabIdInRecordPage,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -89,16 +93,22 @@ export const RecordShowRightDrawerOpenRecordButton = ({
|
|||||||
['ctrl+Enter,meta+Enter'],
|
['ctrl+Enter,meta+Enter'],
|
||||||
handleOpenRecord,
|
handleOpenRecord,
|
||||||
AppHotkeyScope.CommandMenuOpen,
|
AppHotkeyScope.CommandMenuOpen,
|
||||||
[closeCommandMenu, navigate, objectNameSingular, record.id],
|
[closeCommandMenu, navigate, objectNameSingular, recordId],
|
||||||
);
|
);
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
['ctrl+Enter,meta+Enter'],
|
['ctrl+Enter,meta+Enter'],
|
||||||
handleOpenRecord,
|
handleOpenRecord,
|
||||||
CommandMenuActionMenuDropdownHotkeyScope.CommandMenuActionMenuDropdown,
|
CommandMenuActionMenuDropdownHotkeyScope.CommandMenuActionMenuDropdown,
|
||||||
[closeCommandMenu, navigate, objectNameSingular, record.id],
|
[closeCommandMenu, navigate, objectNameSingular, recordId],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!isDefined(record)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const to = getLinkToShowPage(objectNameSingular, record);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledLink to={to} onClick={closeCommandMenu}>
|
<StyledLink to={to} onClick={closeCommandMenu}>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTa
|
|||||||
import { useOpenActivityTargetInlineCellEditMode } from '@/activities/inline-cell/hooks/useOpenActivityTargetInlineCellEditMode';
|
import { useOpenActivityTargetInlineCellEditMode } from '@/activities/inline-cell/hooks/useOpenActivityTargetInlineCellEditMode';
|
||||||
import { useUpdateActivityTargetFromInlineCell } from '@/activities/inline-cell/hooks/useUpdateActivityTargetFromInlineCell';
|
import { useUpdateActivityTargetFromInlineCell } from '@/activities/inline-cell/hooks/useUpdateActivityTargetFromInlineCell';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useFieldContext } from '@/object-record/hooks/useFieldContext';
|
import { FieldContextProvider } from '@/object-record/record-field/components/FieldContextProvider';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { FieldFocusContextProvider } from '@/object-record/record-field/contexts/FieldFocusContextProvider';
|
import { FieldFocusContextProvider } from '@/object-record/record-field/contexts/FieldFocusContextProvider';
|
||||||
import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly';
|
import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly';
|
||||||
@ -43,15 +43,6 @@ export const ActivityTargetsInlineCell = ({
|
|||||||
|
|
||||||
const isFieldReadOnly = useIsFieldValueReadOnly();
|
const isFieldReadOnly = useIsFieldValueReadOnly();
|
||||||
|
|
||||||
const { FieldContextProvider: ActivityTargetsContextProvider } =
|
|
||||||
useFieldContext({
|
|
||||||
objectNameSingular: activityObjectNameSingular,
|
|
||||||
objectRecordId: activityRecordId,
|
|
||||||
fieldMetadataName: fieldDefinition.metadata.fieldName,
|
|
||||||
fieldPosition: 3,
|
|
||||||
overridenIsFieldEmpty: activityTargetObjectRecords.length === 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { openActivityTargetInlineCellEditMode } =
|
const { openActivityTargetInlineCellEditMode } =
|
||||||
useOpenActivityTargetInlineCellEditMode();
|
useOpenActivityTargetInlineCellEditMode();
|
||||||
|
|
||||||
@ -68,55 +59,59 @@ export const ActivityTargetsInlineCell = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldFocusContextProvider>
|
<FieldFocusContextProvider>
|
||||||
{ActivityTargetsContextProvider && (
|
<FieldContextProvider
|
||||||
<ActivityTargetsContextProvider>
|
objectNameSingular={activityObjectNameSingular}
|
||||||
<RecordInlineCellContext.Provider
|
objectRecordId={activityRecordId}
|
||||||
value={{
|
fieldMetadataName={fieldDefinition.metadata.fieldName}
|
||||||
buttonIcon: IconPencil,
|
fieldPosition={3}
|
||||||
customEditHotkeyScope:
|
overridenIsFieldEmpty={activityTargetObjectRecords.length === 0}
|
||||||
MultipleRecordPickerHotkeyScope.MultipleRecordPicker,
|
>
|
||||||
IconLabel: showLabel ? IconArrowUpRight : undefined,
|
<RecordInlineCellContext.Provider
|
||||||
showLabel: showLabel,
|
value={{
|
||||||
readonly: isFieldReadOnly,
|
buttonIcon: IconPencil,
|
||||||
labelWidth: fieldDefinition?.labelWidth,
|
customEditHotkeyScope:
|
||||||
editModeContent: (
|
MultipleRecordPickerHotkeyScope.MultipleRecordPicker,
|
||||||
<MultipleRecordPicker
|
IconLabel: showLabel ? IconArrowUpRight : undefined,
|
||||||
componentInstanceId={componentInstanceId}
|
showLabel: showLabel,
|
||||||
onClickOutside={() => {
|
readonly: isFieldReadOnly,
|
||||||
closeInlineCell();
|
labelWidth: fieldDefinition?.labelWidth,
|
||||||
}}
|
editModeContent: (
|
||||||
onChange={(morphItem) => {
|
<MultipleRecordPicker
|
||||||
updateActivityTargetFromInlineCell({
|
componentInstanceId={componentInstanceId}
|
||||||
recordPickerInstanceId: componentInstanceId,
|
onClickOutside={() => {
|
||||||
morphItem,
|
closeInlineCell();
|
||||||
activityTargetWithTargetRecords:
|
}}
|
||||||
activityTargetObjectRecords,
|
onChange={(morphItem) => {
|
||||||
});
|
updateActivityTargetFromInlineCell({
|
||||||
}}
|
recordPickerInstanceId: componentInstanceId,
|
||||||
onSubmit={() => {
|
morphItem,
|
||||||
closeInlineCell();
|
activityTargetWithTargetRecords:
|
||||||
}}
|
activityTargetObjectRecords,
|
||||||
/>
|
});
|
||||||
),
|
}}
|
||||||
label: 'Relations',
|
onSubmit={() => {
|
||||||
displayModeContent: (
|
closeInlineCell();
|
||||||
<ActivityTargetChips
|
}}
|
||||||
activityTargetObjectRecords={activityTargetObjectRecords}
|
/>
|
||||||
maxWidth={maxWidth}
|
),
|
||||||
/>
|
label: 'Relations',
|
||||||
),
|
displayModeContent: (
|
||||||
onOpenEditMode: () => {
|
<ActivityTargetChips
|
||||||
openActivityTargetInlineCellEditMode({
|
activityTargetObjectRecords={activityTargetObjectRecords}
|
||||||
recordPickerInstanceId: componentInstanceId,
|
maxWidth={maxWidth}
|
||||||
activityTargetObjectRecords,
|
/>
|
||||||
});
|
),
|
||||||
},
|
onOpenEditMode: () => {
|
||||||
}}
|
openActivityTargetInlineCellEditMode({
|
||||||
>
|
recordPickerInstanceId: componentInstanceId,
|
||||||
<RecordInlineCellContainer />
|
activityTargetObjectRecords,
|
||||||
</RecordInlineCellContext.Provider>
|
});
|
||||||
</ActivityTargetsContextProvider>
|
},
|
||||||
)}
|
}}
|
||||||
|
>
|
||||||
|
<RecordInlineCellContainer />
|
||||||
|
</RecordInlineCellContext.Provider>
|
||||||
|
</FieldContextProvider>
|
||||||
</FieldFocusContextProvider>
|
</FieldFocusContextProvider>
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { Note } from '@/activities/types/Note';
|
|||||||
import { getActivityPreview } from '@/activities/utils/getActivityPreview';
|
import { getActivityPreview } from '@/activities/utils/getActivityPreview';
|
||||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useFieldContext } from '@/object-record/hooks/useFieldContext';
|
import { FieldContextProvider } from '@/object-record/record-field/components/FieldContextProvider';
|
||||||
|
|
||||||
const StyledCard = styled.div<{ isSingleNote: boolean }>`
|
const StyledCard = styled.div<{ isSingleNote: boolean }>`
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@ -72,13 +72,6 @@ export const NoteCard = ({
|
|||||||
|
|
||||||
const body = getActivityPreview(note?.bodyV2?.blocknote ?? null);
|
const body = getActivityPreview(note?.bodyV2?.blocknote ?? null);
|
||||||
|
|
||||||
const { FieldContextProvider: NoteTargetsContextProvider } = useFieldContext({
|
|
||||||
objectNameSingular: CoreObjectNameSingular.Note,
|
|
||||||
objectRecordId: note.id,
|
|
||||||
fieldMetadataName: 'noteTargets',
|
|
||||||
fieldPosition: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledCard isSingleNote={isSingleNote}>
|
<StyledCard isSingleNote={isSingleNote}>
|
||||||
<StyledCardDetailsContainer
|
<StyledCardDetailsContainer
|
||||||
@ -93,15 +86,18 @@ export const NoteCard = ({
|
|||||||
<StyledCardContent>{body}</StyledCardContent>
|
<StyledCardContent>{body}</StyledCardContent>
|
||||||
</StyledCardDetailsContainer>
|
</StyledCardDetailsContainer>
|
||||||
<StyledFooter>
|
<StyledFooter>
|
||||||
{NoteTargetsContextProvider && (
|
<FieldContextProvider
|
||||||
<NoteTargetsContextProvider>
|
objectNameSingular={CoreObjectNameSingular.Note}
|
||||||
<ActivityTargetsInlineCell
|
objectRecordId={note.id}
|
||||||
componentInstanceId={`note-card-${note.id}-targets`}
|
fieldMetadataName={'noteTargets'}
|
||||||
activityRecordId={note.id}
|
fieldPosition={0}
|
||||||
activityObjectNameSingular={CoreObjectNameSingular.Note}
|
>
|
||||||
/>
|
<ActivityTargetsInlineCell
|
||||||
</NoteTargetsContextProvider>
|
componentInstanceId={`note-card-${note.id}-targets`}
|
||||||
)}
|
activityRecordId={note.id}
|
||||||
|
activityObjectNameSingular={CoreObjectNameSingular.Note}
|
||||||
|
/>
|
||||||
|
</FieldContextProvider>
|
||||||
</StyledFooter>
|
</StyledFooter>
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import { ActivityRow } from '@/activities/components/ActivityRow';
|
|||||||
import { Task } from '@/activities/types/Task';
|
import { Task } from '@/activities/types/Task';
|
||||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useFieldContext } from '@/object-record/hooks/useFieldContext';
|
import { FieldContextProvider } from '@/object-record/record-field/components/FieldContextProvider';
|
||||||
import { useCompleteTask } from '../hooks/useCompleteTask';
|
import { useCompleteTask } from '../hooks/useCompleteTask';
|
||||||
|
|
||||||
const StyledTaskBody = styled.div`
|
const StyledTaskBody = styled.div`
|
||||||
@ -84,13 +84,6 @@ export const TaskRow = ({ task }: { task: Task }) => {
|
|||||||
|
|
||||||
const { completeTask } = useCompleteTask(task);
|
const { completeTask } = useCompleteTask(task);
|
||||||
|
|
||||||
const { FieldContextProvider: TaskTargetsContextProvider } = useFieldContext({
|
|
||||||
objectNameSingular: CoreObjectNameSingular.Task,
|
|
||||||
objectRecordId: task.id,
|
|
||||||
fieldMetadataName: 'taskTargets',
|
|
||||||
fieldPosition: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ActivityRow
|
<ActivityRow
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -128,8 +121,13 @@ export const TaskRow = ({ task }: { task: Task }) => {
|
|||||||
{beautifyExactDate(task.dueAt)}
|
{beautifyExactDate(task.dueAt)}
|
||||||
</StyledDueDate>
|
</StyledDueDate>
|
||||||
)}
|
)}
|
||||||
{TaskTargetsContextProvider && (
|
{
|
||||||
<TaskTargetsContextProvider>
|
<FieldContextProvider
|
||||||
|
objectNameSingular={CoreObjectNameSingular.Task}
|
||||||
|
objectRecordId={task.id}
|
||||||
|
fieldMetadataName={'taskTargets'}
|
||||||
|
fieldPosition={0}
|
||||||
|
>
|
||||||
<ActivityTargetsInlineCell
|
<ActivityTargetsInlineCell
|
||||||
activityObjectNameSingular={CoreObjectNameSingular.Task}
|
activityObjectNameSingular={CoreObjectNameSingular.Task}
|
||||||
activityRecordId={task.id}
|
activityRecordId={task.id}
|
||||||
@ -137,8 +135,8 @@ export const TaskRow = ({ task }: { task: Task }) => {
|
|||||||
maxWidth={200}
|
maxWidth={200}
|
||||||
componentInstanceId={`task-row-targets-${task.id}`}
|
componentInstanceId={`task-row-targets-${task.id}`}
|
||||||
/>
|
/>
|
||||||
</TaskTargetsContextProvider>
|
</FieldContextProvider>
|
||||||
)}
|
}
|
||||||
</StyledRightSideContainer>
|
</StyledRightSideContainer>
|
||||||
</ActivityRow>
|
</ActivityRow>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import { ReactNode } from 'react';
|
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
@ -9,8 +7,9 @@ import {
|
|||||||
RecordUpdateHookParams,
|
RecordUpdateHookParams,
|
||||||
} from '@/object-record/record-field/contexts/FieldContext';
|
} from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope';
|
import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
export const useFieldContext = ({
|
export const FieldContextProvider = ({
|
||||||
clearable,
|
clearable,
|
||||||
fieldMetadataName,
|
fieldMetadataName,
|
||||||
fieldPosition,
|
fieldPosition,
|
||||||
@ -19,6 +18,7 @@ export const useFieldContext = ({
|
|||||||
objectRecordId,
|
objectRecordId,
|
||||||
customUseUpdateOneObjectHook,
|
customUseUpdateOneObjectHook,
|
||||||
overridenIsFieldEmpty,
|
overridenIsFieldEmpty,
|
||||||
|
children,
|
||||||
}: {
|
}: {
|
||||||
clearable?: boolean;
|
clearable?: boolean;
|
||||||
fieldMetadataName: string;
|
fieldMetadataName: string;
|
||||||
@ -28,6 +28,7 @@ export const useFieldContext = ({
|
|||||||
objectRecordId: string;
|
objectRecordId: string;
|
||||||
customUseUpdateOneObjectHook?: RecordUpdateHook;
|
customUseUpdateOneObjectHook?: RecordUpdateHook;
|
||||||
overridenIsFieldEmpty?: boolean;
|
overridenIsFieldEmpty?: boolean;
|
||||||
|
children: ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
const { objectMetadataItem } = useObjectMetadataItem({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
@ -52,34 +53,31 @@ export const useFieldContext = ({
|
|||||||
return [updateEntity, { loading: false }];
|
return [updateEntity, { loading: false }];
|
||||||
};
|
};
|
||||||
|
|
||||||
const FieldContextProvider =
|
if (!fieldMetadataItem) {
|
||||||
fieldMetadataItem && objectMetadataItem
|
return null;
|
||||||
? ({ children }: { children: ReactNode }) => (
|
}
|
||||||
<FieldContext.Provider
|
|
||||||
key={objectRecordId + fieldMetadataItem.id}
|
|
||||||
value={{
|
|
||||||
recordId: objectRecordId,
|
|
||||||
isLabelIdentifier,
|
|
||||||
fieldDefinition: formatFieldMetadataItemAsColumnDefinition({
|
|
||||||
field: fieldMetadataItem,
|
|
||||||
showLabel: true,
|
|
||||||
position: fieldPosition,
|
|
||||||
objectMetadataItem,
|
|
||||||
labelWidth: 90,
|
|
||||||
}),
|
|
||||||
useUpdateRecord:
|
|
||||||
customUseUpdateOneObjectHook ?? useUpdateOneObjectMutation,
|
|
||||||
hotkeyScope: InlineCellHotkeyScope.InlineCell,
|
|
||||||
clearable,
|
|
||||||
overridenIsFieldEmpty,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</FieldContext.Provider>
|
|
||||||
)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
return {
|
return (
|
||||||
FieldContextProvider,
|
<FieldContext.Provider
|
||||||
};
|
key={objectRecordId + fieldMetadataItem.id}
|
||||||
|
value={{
|
||||||
|
recordId: objectRecordId,
|
||||||
|
isLabelIdentifier,
|
||||||
|
fieldDefinition: formatFieldMetadataItemAsColumnDefinition({
|
||||||
|
field: fieldMetadataItem,
|
||||||
|
showLabel: true,
|
||||||
|
position: fieldPosition,
|
||||||
|
objectMetadataItem,
|
||||||
|
labelWidth: 90,
|
||||||
|
}),
|
||||||
|
useUpdateRecord:
|
||||||
|
customUseUpdateOneObjectHook ?? useUpdateOneObjectMutation,
|
||||||
|
hotkeyScope: InlineCellHotkeyScope.InlineCell,
|
||||||
|
clearable,
|
||||||
|
overridenIsFieldEmpty,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</FieldContext.Provider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
@ -1,30 +0,0 @@
|
|||||||
import {
|
|
||||||
FieldContext,
|
|
||||||
GenericFieldContextType,
|
|
||||||
} from '@/object-record/record-field/contexts/FieldContext';
|
|
||||||
|
|
||||||
type FieldContextProviderProps = {
|
|
||||||
children: React.ReactNode;
|
|
||||||
fieldDefinition: GenericFieldContextType['fieldDefinition'];
|
|
||||||
recordId?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const FieldContextProvider = ({
|
|
||||||
children,
|
|
||||||
fieldDefinition,
|
|
||||||
recordId,
|
|
||||||
}: FieldContextProviderProps) => {
|
|
||||||
return (
|
|
||||||
<FieldContext.Provider
|
|
||||||
value={{
|
|
||||||
recordId: recordId ?? '1',
|
|
||||||
isLabelIdentifier: false,
|
|
||||||
hotkeyScope: 'hotkey-scope',
|
|
||||||
fieldDefinition,
|
|
||||||
useUpdateRecord: () => [() => undefined, {}],
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</FieldContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -2,8 +2,11 @@ import { Decorator, Meta, StoryObj } from '@storybook/react';
|
|||||||
import { expect, fn, userEvent, waitFor } from '@storybook/test';
|
import { expect, fn, userEvent, waitFor } from '@storybook/test';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useAddressField } from '@/object-record/record-field/meta-types/hooks/useAddressField';
|
import { useAddressField } from '@/object-record/record-field/meta-types/hooks/useAddressField';
|
||||||
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
|
import { FieldAddressDraftValue } from '@/object-record/record-field/types/FieldInputDraftValue';
|
||||||
|
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import {
|
import {
|
||||||
AddressInput,
|
AddressInput,
|
||||||
AddressInputProps,
|
AddressInputProps,
|
||||||
@ -11,10 +14,6 @@ import {
|
|||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider';
|
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
|
||||||
|
|
||||||
const AddressValueSetterEffect = ({
|
const AddressValueSetterEffect = ({
|
||||||
value,
|
value,
|
||||||
}: {
|
}: {
|
||||||
@ -60,19 +59,23 @@ const AddressInputWithContext = ({
|
|||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContextProvider
|
<FieldContext.Provider
|
||||||
fieldDefinition={{
|
value={{
|
||||||
fieldMetadataId: 'text',
|
fieldDefinition: {
|
||||||
label: 'Address',
|
fieldMetadataId: 'text',
|
||||||
type: FieldMetadataType.ADDRESS,
|
label: 'Address',
|
||||||
iconName: 'IconTag',
|
type: FieldMetadataType.ADDRESS,
|
||||||
metadata: {
|
iconName: 'IconTag',
|
||||||
fieldName: 'Address',
|
metadata: {
|
||||||
placeHolder: 'Enter text',
|
fieldName: 'Address',
|
||||||
objectMetadataNameSingular: 'person',
|
placeHolder: 'Enter text',
|
||||||
|
objectMetadataNameSingular: 'person',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
recordId: recordId ?? '123',
|
||||||
|
hotkeyScope: 'hotkey-scope',
|
||||||
|
isLabelIdentifier: false,
|
||||||
}}
|
}}
|
||||||
recordId={recordId}
|
|
||||||
>
|
>
|
||||||
<AddressValueSetterEffect value={value} />
|
<AddressValueSetterEffect value={value} />
|
||||||
<AddressInput
|
<AddressInput
|
||||||
@ -84,7 +87,7 @@ const AddressInputWithContext = ({
|
|||||||
onTab={onTab}
|
onTab={onTab}
|
||||||
onShiftTab={onShiftTab}
|
onShiftTab={onShiftTab}
|
||||||
/>
|
/>
|
||||||
</FieldContextProvider>
|
</FieldContext.Provider>
|
||||||
<div data-testid="data-field-input-click-outside-div" />
|
<div data-testid="data-field-input-click-outside-div" />
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { useSetRecoilState } from 'recoil';
|
|||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { FieldMetadataType } from '~/generated/graphql';
|
import { FieldMetadataType } from '~/generated/graphql';
|
||||||
|
|
||||||
import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import {
|
import {
|
||||||
@ -50,26 +50,30 @@ const BooleanFieldInputWithContext = ({
|
|||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContextProvider
|
<FieldContext.Provider
|
||||||
fieldDefinition={{
|
value={{
|
||||||
defaultValue: false,
|
fieldDefinition: {
|
||||||
fieldMetadataId: 'boolean',
|
defaultValue: false,
|
||||||
label: 'Boolean',
|
fieldMetadataId: 'boolean',
|
||||||
iconName: 'Icon123',
|
label: 'Boolean',
|
||||||
type: FieldMetadataType.BOOLEAN,
|
iconName: 'Icon123',
|
||||||
metadata: {
|
type: FieldMetadataType.BOOLEAN,
|
||||||
fieldName: 'Boolean',
|
metadata: {
|
||||||
objectMetadataNameSingular: 'person',
|
fieldName: 'Boolean',
|
||||||
|
objectMetadataNameSingular: 'person',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
recordId: recordId ?? '123',
|
||||||
|
hotkeyScope: 'hotkey-scope',
|
||||||
|
isLabelIdentifier: false,
|
||||||
}}
|
}}
|
||||||
recordId={recordId}
|
|
||||||
>
|
>
|
||||||
<BooleanFieldValueSetterEffect
|
<BooleanFieldValueSetterEffect
|
||||||
value={value}
|
value={value}
|
||||||
recordId={recordId ?? ''}
|
recordId={recordId ?? ''}
|
||||||
/>
|
/>
|
||||||
<BooleanFieldInput onSubmit={onSubmit} testId="boolean-field-input" />
|
<BooleanFieldInput onSubmit={onSubmit} testId="boolean-field-input" />
|
||||||
</FieldContextProvider>
|
</FieldContext.Provider>
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { useEffect } from 'react';
|
|||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
import { FieldMetadataType } from '~/generated/graphql';
|
import { FieldMetadataType } from '~/generated/graphql';
|
||||||
|
|
||||||
import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { StorybookFieldInputDropdownFocusIdSetterEffect } from '~/testing/components/StorybookFieldInputDropdownFocusIdSetterEffect';
|
import { StorybookFieldInputDropdownFocusIdSetterEffect } from '~/testing/components/StorybookFieldInputDropdownFocusIdSetterEffect';
|
||||||
@ -77,19 +77,23 @@ const DateFieldInputWithContext = ({
|
|||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContextProvider
|
<FieldContext.Provider
|
||||||
fieldDefinition={{
|
value={{
|
||||||
fieldMetadataId: 'date',
|
fieldDefinition: {
|
||||||
defaultValue: null,
|
fieldMetadataId: 'date',
|
||||||
label: 'Date',
|
defaultValue: null,
|
||||||
type: FieldMetadataType.DATE_TIME,
|
label: 'Date',
|
||||||
iconName: 'IconCalendarEvent',
|
type: FieldMetadataType.DATE_TIME,
|
||||||
metadata: {
|
iconName: 'IconCalendarEvent',
|
||||||
fieldName: 'Date',
|
metadata: {
|
||||||
objectMetadataNameSingular: 'person',
|
fieldName: 'Date',
|
||||||
|
objectMetadataNameSingular: 'person',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
recordId: '123',
|
||||||
|
hotkeyScope: 'hotkey-scope',
|
||||||
|
isLabelIdentifier: false,
|
||||||
}}
|
}}
|
||||||
recordId={recordId}
|
|
||||||
>
|
>
|
||||||
<StorybookFieldInputDropdownFocusIdSetterEffect />
|
<StorybookFieldInputDropdownFocusIdSetterEffect />
|
||||||
<DateFieldValueSetterEffect value={value} />
|
<DateFieldValueSetterEffect value={value} />
|
||||||
@ -98,7 +102,7 @@ const DateFieldInputWithContext = ({
|
|||||||
onEnter={onEnter}
|
onEnter={onEnter}
|
||||||
onClickOutside={onClickOutside}
|
onClickOutside={onClickOutside}
|
||||||
/>
|
/>
|
||||||
</FieldContextProvider>
|
</FieldContext.Provider>
|
||||||
<div data-testid="data-field-input-click-outside-div"></div>
|
<div data-testid="data-field-input-click-outside-div"></div>
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope
|
|||||||
import { FieldMetadataType } from '~/generated/graphql';
|
import { FieldMetadataType } from '~/generated/graphql';
|
||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
|
|
||||||
import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
import { StorybookFieldInputDropdownFocusIdSetterEffect } from '~/testing/components/StorybookFieldInputDropdownFocusIdSetterEffect';
|
import { StorybookFieldInputDropdownFocusIdSetterEffect } from '~/testing/components/StorybookFieldInputDropdownFocusIdSetterEffect';
|
||||||
@ -54,19 +54,23 @@ const NumberFieldInputWithContext = ({
|
|||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContextProvider
|
<FieldContext.Provider
|
||||||
fieldDefinition={{
|
value={{
|
||||||
fieldMetadataId: 'number',
|
fieldDefinition: {
|
||||||
label: 'Number',
|
fieldMetadataId: 'number',
|
||||||
iconName: 'Icon123',
|
label: 'Number',
|
||||||
type: FieldMetadataType.NUMBER,
|
iconName: 'Icon123',
|
||||||
metadata: {
|
type: FieldMetadataType.NUMBER,
|
||||||
fieldName: 'number',
|
metadata: {
|
||||||
placeHolder: 'Enter number',
|
fieldName: 'number',
|
||||||
objectMetadataNameSingular: 'person',
|
placeHolder: 'Enter number',
|
||||||
|
objectMetadataNameSingular: 'person',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
recordId: '123',
|
||||||
|
hotkeyScope: 'hotkey-scope',
|
||||||
|
isLabelIdentifier: false,
|
||||||
}}
|
}}
|
||||||
recordId={recordId}
|
|
||||||
>
|
>
|
||||||
<StorybookFieldInputDropdownFocusIdSetterEffect />
|
<StorybookFieldInputDropdownFocusIdSetterEffect />
|
||||||
<NumberFieldValueSetterEffect value={value} />
|
<NumberFieldValueSetterEffect value={value} />
|
||||||
@ -77,7 +81,7 @@ const NumberFieldInputWithContext = ({
|
|||||||
onTab={onTab}
|
onTab={onTab}
|
||||||
onShiftTab={onShiftTab}
|
onShiftTab={onShiftTab}
|
||||||
/>
|
/>
|
||||||
</FieldContextProvider>
|
</FieldContext.Provider>
|
||||||
<div data-testid="data-field-input-click-outside-div" />
|
<div data-testid="data-field-input-click-outside-div" />
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,15 +3,15 @@ import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
|
||||||
|
|
||||||
import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
|
||||||
|
import { FieldMetadataType } from 'twenty-shared/types';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { FieldRatingValue } from '../../../../types/FieldMetadata';
|
import { FieldRatingValue } from '../../../../types/FieldMetadata';
|
||||||
import { useRatingField } from '../../../hooks/useRatingField';
|
import { useRatingField } from '../../../hooks/useRatingField';
|
||||||
import { RatingFieldInput, RatingFieldInputProps } from '../RatingFieldInput';
|
import { RatingFieldInput, RatingFieldInputProps } from '../RatingFieldInput';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
|
||||||
|
|
||||||
const RatingFieldValueSetterEffect = ({
|
const RatingFieldValueSetterEffect = ({
|
||||||
value,
|
value,
|
||||||
@ -53,22 +53,26 @@ const RatingFieldInputWithContext = ({
|
|||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContextProvider
|
<FieldContext.Provider
|
||||||
fieldDefinition={{
|
value={{
|
||||||
fieldMetadataId: 'rating',
|
fieldDefinition: {
|
||||||
label: 'Rating',
|
fieldMetadataId: 'rating',
|
||||||
type: FieldMetadataType.RATING,
|
label: 'Rating',
|
||||||
iconName: 'Icon123',
|
iconName: 'IconStar',
|
||||||
metadata: {
|
type: FieldMetadataType.RATING,
|
||||||
fieldName: 'Rating',
|
metadata: {
|
||||||
objectMetadataNameSingular: 'person',
|
fieldName: 'rating',
|
||||||
|
objectMetadataNameSingular: 'person',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
recordId: recordId ?? '123',
|
||||||
|
hotkeyScope: 'hotkey-scope',
|
||||||
|
isLabelIdentifier: false,
|
||||||
}}
|
}}
|
||||||
recordId={recordId}
|
|
||||||
>
|
>
|
||||||
<RatingFieldValueSetterEffect value={value} />
|
<RatingFieldValueSetterEffect value={value} />
|
||||||
<RatingFieldInput onSubmit={onSubmit} />
|
<RatingFieldInput onSubmit={onSubmit} />
|
||||||
</FieldContextProvider>
|
</FieldContext.Provider>
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,12 +16,12 @@ import {
|
|||||||
} from '~/testing/mock-data/users';
|
} from '~/testing/mock-data/users';
|
||||||
|
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
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 { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider';
|
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
import { RelationDefinitionType } from '~/generated-metadata/graphql';
|
|
||||||
import { FieldMetadataType } from 'twenty-shared/types';
|
import { FieldMetadataType } from 'twenty-shared/types';
|
||||||
|
import { RelationDefinitionType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
const RelationWorkspaceSetterEffect = () => {
|
const RelationWorkspaceSetterEffect = () => {
|
||||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
||||||
@ -89,13 +89,17 @@ const RelationManyFieldInputWithContext = () => {
|
|||||||
instanceId: 'relation-from-many-field-record-id-people',
|
instanceId: 'relation-from-many-field-record-id-people',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContextProvider
|
<FieldContext.Provider
|
||||||
fieldDefinition={fieldDefinition}
|
value={{
|
||||||
recordId={'recordId'}
|
fieldDefinition,
|
||||||
|
recordId: 'recordId',
|
||||||
|
hotkeyScope: 'hotkey-scope',
|
||||||
|
isLabelIdentifier: false,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<RelationWorkspaceSetterEffect />
|
<RelationWorkspaceSetterEffect />
|
||||||
<RelationFromManyFieldInput />
|
<RelationFromManyFieldInput />
|
||||||
</FieldContextProvider>
|
</FieldContext.Provider>
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
<div data-testid="data-field-input-click-outside-div" />
|
<div data-testid="data-field-input-click-outside-div" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -5,9 +5,7 @@ import { useSetRecoilState } from 'recoil';
|
|||||||
|
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
import { FieldMetadataType } from '~/generated/graphql';
|
|
||||||
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
|
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
|
||||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
@ -17,10 +15,12 @@ import {
|
|||||||
mockedWorkspaceMemberData,
|
mockedWorkspaceMemberData,
|
||||||
} from '~/testing/mock-data/users';
|
} from '~/testing/mock-data/users';
|
||||||
|
|
||||||
import { FieldContextProvider } from '@/object-record/record-field/meta-types/components/FieldContextProvider';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
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 { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
import { FieldMetadataType } from 'twenty-shared/types';
|
||||||
import { getCanvasElementForDropdownTesting } from 'twenty-ui';
|
import { getCanvasElementForDropdownTesting } from 'twenty-ui';
|
||||||
import {
|
import {
|
||||||
RelationToOneFieldInput,
|
RelationToOneFieldInput,
|
||||||
@ -53,7 +53,7 @@ const RelationWorkspaceSetterEffect = () => {
|
|||||||
|
|
||||||
type RelationToOneFieldInputWithContextProps = RelationToOneFieldInputProps & {
|
type RelationToOneFieldInputWithContextProps = RelationToOneFieldInputProps & {
|
||||||
value: number;
|
value: number;
|
||||||
recordId?: string;
|
recordId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const RelationToOneFieldInputWithContext = ({
|
const RelationToOneFieldInputWithContext = ({
|
||||||
@ -69,21 +69,26 @@ const RelationToOneFieldInputWithContext = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<FieldContextProvider
|
<FieldContext.Provider
|
||||||
fieldDefinition={{
|
value={{
|
||||||
fieldMetadataId: 'relation',
|
fieldDefinition: {
|
||||||
label: 'Relation',
|
fieldMetadataId: 'relation',
|
||||||
type: FieldMetadataType.RELATION,
|
label: 'Relation',
|
||||||
iconName: 'IconLink',
|
type: FieldMetadataType.RELATION,
|
||||||
metadata: {
|
iconName: 'IconLink',
|
||||||
fieldName: 'Relation',
|
metadata: {
|
||||||
relationObjectMetadataNamePlural: 'companies',
|
fieldName: 'Relation',
|
||||||
relationObjectMetadataNameSingular: CoreObjectNameSingular.Company,
|
relationObjectMetadataNamePlural: 'companies',
|
||||||
objectMetadataNameSingular: 'person',
|
relationObjectMetadataNameSingular:
|
||||||
relationFieldMetadataId: '20202020-8c37-4163-ba06-1dada334ce3e',
|
CoreObjectNameSingular.Company,
|
||||||
|
objectMetadataNameSingular: 'person',
|
||||||
|
relationFieldMetadataId: '20202020-8c37-4163-ba06-1dada334ce3e',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
recordId: recordId,
|
||||||
|
hotkeyScope: 'hotkey-scope',
|
||||||
|
isLabelIdentifier: false,
|
||||||
}}
|
}}
|
||||||
recordId={recordId}
|
|
||||||
>
|
>
|
||||||
<RecordFieldComponentInstanceContext.Provider
|
<RecordFieldComponentInstanceContext.Provider
|
||||||
value={{
|
value={{
|
||||||
@ -93,7 +98,7 @@ const RelationToOneFieldInputWithContext = ({
|
|||||||
<RelationWorkspaceSetterEffect />
|
<RelationWorkspaceSetterEffect />
|
||||||
<RelationToOneFieldInput onSubmit={onSubmit} onCancel={onCancel} />
|
<RelationToOneFieldInput onSubmit={onSubmit} onCancel={onCancel} />
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
</FieldContextProvider>
|
</FieldContext.Provider>
|
||||||
<div data-testid="data-field-input-click-outside-div" />
|
<div data-testid="data-field-input-click-outside-div" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,17 +2,16 @@ import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
import { FieldMetadataType } from '~/generated/graphql';
|
|
||||||
|
|
||||||
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||||
import { Decorator, Meta, StoryObj } from '@storybook/react';
|
import { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { FieldMetadataType } from '~/generated/graphql';
|
||||||
import { StorybookFieldInputDropdownFocusIdSetterEffect } from '~/testing/components/StorybookFieldInputDropdownFocusIdSetterEffect';
|
import { StorybookFieldInputDropdownFocusIdSetterEffect } from '~/testing/components/StorybookFieldInputDropdownFocusIdSetterEffect';
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
import { FieldContextProvider } from '../../../components/FieldContextProvider';
|
|
||||||
import { useTextField } from '../../../hooks/useTextField';
|
import { useTextField } from '../../../hooks/useTextField';
|
||||||
import { TextFieldInput, TextFieldInputProps } from '../TextFieldInput';
|
import { TextFieldInput, TextFieldInputProps } from '../TextFieldInput';
|
||||||
|
|
||||||
const TextFieldValueSetterEffect = ({ value }: { value: string }) => {
|
const TextFieldValueSetterEffect = ({ value }: { value: string }) => {
|
||||||
const { setFieldValue } = useTextField();
|
const { setFieldValue } = useTextField();
|
||||||
|
|
||||||
@ -49,19 +48,22 @@ const TextFieldInputWithContext = ({
|
|||||||
instanceId: 'record-field-component-instance-id',
|
instanceId: 'record-field-component-instance-id',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContextProvider
|
<FieldContext.Provider
|
||||||
fieldDefinition={{
|
value={{
|
||||||
fieldMetadataId: 'text',
|
recordId: recordId ?? '123',
|
||||||
label: 'Text',
|
fieldDefinition: {
|
||||||
type: FieldMetadataType.TEXT,
|
fieldMetadataId: 'text',
|
||||||
iconName: 'IconTag',
|
label: 'Text',
|
||||||
metadata: {
|
type: FieldMetadataType.TEXT,
|
||||||
fieldName: 'Text',
|
iconName: 'IconText',
|
||||||
placeHolder: 'Enter text',
|
metadata: {
|
||||||
objectMetadataNameSingular: 'person',
|
fieldName: 'text',
|
||||||
|
objectMetadataNameSingular: 'person',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
hotkeyScope: 'hotkey-scope',
|
||||||
|
isLabelIdentifier: false,
|
||||||
}}
|
}}
|
||||||
recordId={recordId}
|
|
||||||
>
|
>
|
||||||
<StorybookFieldInputDropdownFocusIdSetterEffect />
|
<StorybookFieldInputDropdownFocusIdSetterEffect />
|
||||||
<TextFieldValueSetterEffect value={value} />
|
<TextFieldValueSetterEffect value={value} />
|
||||||
@ -72,7 +74,7 @@ const TextFieldInputWithContext = ({
|
|||||||
onTab={onTab}
|
onTab={onTab}
|
||||||
onShiftTab={onShiftTab}
|
onShiftTab={onShiftTab}
|
||||||
/>
|
/>
|
||||||
</FieldContextProvider>
|
</FieldContext.Provider>
|
||||||
<div data-testid="data-field-input-click-outside-div" />
|
<div data-testid="data-field-input-click-outside-div" />
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -25,8 +25,8 @@ import styled from '@emotion/styled';
|
|||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
import { IconPlus } from 'twenty-ui';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { IconPlus } from 'twenty-ui';
|
||||||
|
|
||||||
export const StyledSelectableItem = styled(SelectableItem)`
|
export const StyledSelectableItem = styled(SelectableItem)`
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@ -28,8 +28,8 @@ import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/drop
|
|||||||
import { useClickOustideListenerStates } from '@/ui/utilities/pointer-event/hooks/useClickOustideListenerStates';
|
import { useClickOustideListenerStates } from '@/ui/utilities/pointer-event/hooks/useClickOustideListenerStates';
|
||||||
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||||
|
|
||||||
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
|
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
|
||||||
scope: TableHotkeyScope.CellEditMode,
|
scope: TableHotkeyScope.CellEditMode,
|
||||||
|
|||||||
@ -6,8 +6,6 @@ import { CardComponents } from '@/object-record/record-show/components/CardCompo
|
|||||||
import { FieldsCard } from '@/object-record/record-show/components/FieldsCard';
|
import { FieldsCard } from '@/object-record/record-show/components/FieldsCard';
|
||||||
import { SummaryCard } from '@/object-record/record-show/components/SummaryCard';
|
import { SummaryCard } from '@/object-record/record-show/components/SummaryCard';
|
||||||
import { RecordLayout } from '@/object-record/record-show/types/RecordLayout';
|
import { RecordLayout } from '@/object-record/record-show/types/RecordLayout';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
|
||||||
import { RightDrawerFooter } from '@/ui/layout/right-drawer/components/RightDrawerFooter';
|
import { RightDrawerFooter } from '@/ui/layout/right-drawer/components/RightDrawerFooter';
|
||||||
import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
|
import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
|
||||||
import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId';
|
import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId';
|
||||||
@ -18,7 +16,6 @@ import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
|||||||
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
const StyledShowPageRightContainer = styled.div<{ isMobile: boolean }>`
|
const StyledShowPageRightContainer = styled.div<{ isMobile: boolean }>`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -110,10 +107,6 @@ export const ShowPageSubContainer = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const [recordFromStore] = useRecoilState<ObjectRecord | null>(
|
|
||||||
recordStoreFamilyState(targetableObject.id),
|
|
||||||
);
|
|
||||||
|
|
||||||
const visibleTabs = tabs.filter((tab) => !tab.hide);
|
const visibleTabs = tabs.filter((tab) => !tab.hide);
|
||||||
|
|
||||||
const displaySummaryAndFields =
|
const displaySummaryAndFields =
|
||||||
@ -143,13 +136,13 @@ export const ShowPageSubContainer = ({
|
|||||||
<StyledContentContainer isInRightDrawer={isInRightDrawer}>
|
<StyledContentContainer isInRightDrawer={isInRightDrawer}>
|
||||||
{renderActiveTabContent()}
|
{renderActiveTabContent()}
|
||||||
</StyledContentContainer>
|
</StyledContentContainer>
|
||||||
{isInRightDrawer && recordFromStore && (
|
{isInRightDrawer && (
|
||||||
<RightDrawerFooter
|
<RightDrawerFooter
|
||||||
actions={[
|
actions={[
|
||||||
<RecordShowRightDrawerActionMenu />,
|
<RecordShowRightDrawerActionMenu />,
|
||||||
<RecordShowRightDrawerOpenRecordButton
|
<RecordShowRightDrawerOpenRecordButton
|
||||||
objectNameSingular={targetableObject.targetObjectNameSingular}
|
objectNameSingular={targetableObject.targetObjectNameSingular}
|
||||||
record={recordFromStore}
|
recordId={targetableObject.id}
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user