Optimize metadata queries (#7013)

In this PR:

1. Refactor guards to avoid duplicated queries: WorkspaceAuthGuard and
UserAuthGuard only check for existence of workspace and user in the
request without querying the database
This commit is contained in:
Charles Bochet
2024-09-13 19:11:32 +02:00
committed by Charles Bochet
parent cf8b1161cc
commit 523df5398a
132 changed files with 818 additions and 6372 deletions

View File

@ -4,17 +4,6 @@ import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldMetadata } from './FieldMetadata';
export type FieldDefinitionRelationType =
| 'FROM_MANY_OBJECTS'
| 'FROM_ONE_OBJECT'
| 'TO_MANY_OBJECTS'
| 'TO_ONE_OBJECT';
export type RelationDirections = {
from: FieldDefinitionRelationType;
to: FieldDefinitionRelationType;
};
export type FieldDefinition<T extends FieldMetadata> = {
fieldMetadataId: string;
label: string;

View File

@ -3,8 +3,8 @@ import { ThemeColor } from 'twenty-ui';
import { RATING_VALUES } from '@/object-record/record-field/meta-types/constants/RatingValues';
import { ZodHelperLiteral } from '@/object-record/record-field/types/ZodHelperLiteral';
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
import { WithNarrowedStringLiteralProperty } from '~/types/WithNarrowedStringLiteralProperty';
import { RelationDefinitionType } from '~/generated-metadata/graphql';
import { CurrencyCode } from './CurrencyCode';
export type FieldUuidMetadata = {
@ -110,35 +110,17 @@ export type FieldPositionMetadata = {
fieldName: string;
};
export type FieldDefinitionRelationType =
| 'FROM_MANY_OBJECTS'
| 'FROM_ONE_OBJECT'
| 'TO_MANY_OBJECTS'
| 'TO_ONE_OBJECT';
export type FieldRelationMetadata = {
fieldName: string;
objectMetadataNameSingular?: string;
relationFieldMetadataId: string;
relationObjectMetadataNamePlural: string;
relationObjectMetadataNameSingular: string;
relationType?: FieldDefinitionRelationType;
relationType?: RelationDefinitionType;
targetFieldMetadataName?: string;
useEditButton?: boolean;
};
export type FieldRelationOneMetadata = WithNarrowedStringLiteralProperty<
FieldRelationMetadata,
'relationType',
'TO_ONE_OBJECT'
>;
export type FieldRelationManyMetadata = WithNarrowedStringLiteralProperty<
FieldRelationMetadata,
'relationType',
'FROM_MANY_OBJECTS'
>;
export type FieldSelectMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;

View File

@ -1,9 +1,11 @@
import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation';
import { RelationDefinitionType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldMetadata, FieldRelationManyMetadata } from '../FieldMetadata';
import { FieldMetadata } from '../FieldMetadata';
export const isFieldRelationFromManyObjects = (
field: Pick<FieldDefinition<FieldMetadata>, 'type' | 'metadata'>,
): field is FieldDefinition<FieldRelationManyMetadata> =>
isFieldRelation(field) && field.metadata.relationType === 'FROM_MANY_OBJECTS';
): field is FieldDefinition<FieldMetadata> =>
isFieldRelation(field) &&
field.metadata.relationType === RelationDefinitionType.OneToMany;

View File

@ -1,9 +1,11 @@
import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation';
import { RelationDefinitionType } from '~/generated-metadata/graphql';
import { FieldDefinition } from '../FieldDefinition';
import { FieldMetadata, FieldRelationOneMetadata } from '../FieldMetadata';
import { FieldMetadata } from '../FieldMetadata';
export const isFieldRelationToOneObject = (
field: Pick<FieldDefinition<FieldMetadata>, 'type' | 'metadata'>,
): field is FieldDefinition<FieldRelationOneMetadata> =>
isFieldRelation(field) && field.metadata.relationType === 'TO_ONE_OBJECT';
): field is FieldDefinition<FieldMetadata> =>
isFieldRelation(field) &&
field.metadata.relationType === RelationDefinitionType.ManyToOne;

View File

@ -1,6 +1,7 @@
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
import { RelationDefinitionType } from '~/generated-metadata/graphql';
import {
csvDownloader,
displayedExportProgress,
@ -35,7 +36,10 @@ describe('generateCsv', () => {
{ label: 'Nested', metadata: { fieldName: 'nested' } },
{
label: 'Relation',
metadata: { fieldName: 'relation', relationType: 'TO_ONE_OBJECT' },
metadata: {
fieldName: 'relation',
relationType: RelationDefinitionType.ManyToOne,
},
},
] as ColumnDefinition<FieldMetadata>[];
const rows = [

View File

@ -9,6 +9,7 @@ import {
} from '@/object-record/record-index/options/hooks/useTableData';
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { RelationDefinitionType } from '~/generated-metadata/graphql';
import { FieldMetadataType } from '~/generated/graphql';
import { isDefined } from '~/utils/isDefined';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
@ -43,7 +44,7 @@ export const generateCsv: GenerateExport = ({
const columnsToExport = columns.filter(
(col) =>
!('relationType' in col.metadata && col.metadata.relationType) ||
col.metadata.relationType === 'TO_ONE_OBJECT',
col.metadata.relationType === RelationDefinitionType.ManyToOne,
);
const objectIdColumn: ColumnDefinition<FieldMetadata> = {

View File

@ -7,6 +7,7 @@ import { Task } from '@/activities/types/Task';
import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord';
import { useLabelIdentifierFieldMetadataItem } from '@/object-metadata/hooks/useLabelIdentifierFieldMetadataItem';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
@ -56,6 +57,8 @@ export const RecordShowContainer = ({
objectNameSingular,
});
const { objectMetadataItems } = useObjectMetadataItems();
const { labelIdentifierFieldMetadataItem } =
useLabelIdentifierFieldMetadataItem({
objectNameSingular,
@ -119,7 +122,7 @@ export const RecordShowContainer = ({
const availableFieldMetadataItems = objectMetadataItem.fields
.filter(
(fieldMetadataItem) =>
isFieldCellSupported(fieldMetadataItem) &&
isFieldCellSupported(fieldMetadataItem, objectMetadataItems) &&
fieldMetadataItem.id !== labelIdentifierFieldMetadataItem?.id,
)
.sort((fieldMetadataItemA, fieldMetadataItemB) =>

View File

@ -1,7 +1,7 @@
import { useCallback, useContext } from 'react';
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import { useCallback, useContext } from 'react';
import {
IconChevronDown,
IconComponent,
@ -11,6 +11,7 @@ import {
} from 'twenty-ui';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
import { RecordChip } from '@/object-record/components/RecordChip';
@ -37,6 +38,7 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { AnimatedEaseInOut } from '@/ui/utilities/animation/components/AnimatedEaseInOut';
import { RelationDefinitionType } from '~/generated-metadata/graphql';
const StyledListItem = styled(RecordDetailRecordsListItem)<{
isDropdownOpen?: boolean;
@ -89,12 +91,14 @@ export const RecordDetailRelationRecordsListItem = ({
relationType,
} = fieldDefinition.metadata as FieldRelationMetadata;
const isToOneObject = relationType === 'TO_ONE_OBJECT';
const isToOneObject = relationType === RelationDefinitionType.ManyToOne;
const { objectMetadataItem: relationObjectMetadataItem } =
useObjectMetadataItem({
objectNameSingular: relationObjectMetadataNameSingular,
});
const { objectMetadataItems } = useObjectMetadataItems();
const persistField = usePersistField();
const { updateOneRecord: updateOneRelationRecord } = useUpdateOneRecord({
@ -111,7 +115,7 @@ export const RecordDetailRelationRecordsListItem = ({
const availableRelationFieldMetadataItems = relationObjectMetadataItem.fields
.filter(
(fieldMetadataItem) =>
isFieldCellSupported(fieldMetadataItem) &&
isFieldCellSupported(fieldMetadataItem, objectMetadataItems) &&
fieldMetadataItem.id !==
relationObjectMetadataItem.labelIdentifierFieldMetadataId &&
fieldMetadataItem.id !== relationFieldMetadataId,

View File

@ -32,6 +32,7 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { FilterQueryParams } from '@/views/hooks/internal/useViewFromQueryParams';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import { RelationDefinitionType } from '~/generated-metadata/graphql';
type RecordDetailRelationSectionProps = {
loading: boolean;
@ -67,8 +68,8 @@ export const RecordDetailRelationSection = ({
>(recordStoreFamilySelector({ recordId, fieldName }));
// TODO: use new relation type
const isToOneObject = relationType === 'TO_ONE_OBJECT';
const isFromManyObjects = relationType === 'FROM_MANY_OBJECTS';
const isToOneObject = relationType === RelationDefinitionType.ManyToOne;
const isToManyObjects = RelationDefinitionType.OneToMany;
const relationRecords: ObjectRecord[] =
fieldValue && isToOneObject
@ -160,7 +161,7 @@ export const RecordDetailRelationSection = ({
<RecordDetailSectionHeader
title={fieldDefinition.label}
link={
isFromManyObjects
isToManyObjects
? {
to: filterLinkHref,
label: `All (${relationRecords.length})`,

View File

@ -34,22 +34,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: {
__typename: 'relation',
id: '0cf72416-3d94-4d94-abf3-7dc9d734435b',
relationType: 'ONE_TO_MANY',
fromObjectMetadata: {
__typename: 'object',
id: '79c2d29c-76f6-432f-91c9-df1259b73d95',
dataSourceId: '0fd9fd54-0e8d-4f78-911c-76b33436a768',
nameSingular: 'company',
namePlural: 'companies',
isSystem: false,
isRemote: false,
},
fromFieldMetadataId: '7b281010-5f47-4771-b3f5-f4bcd24ed1b5',
},
defaultValue: null,
options: null,
relationDefinition: {
@ -94,8 +78,6 @@ export const mockPerformance = {
isNullable: false,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: "''",
options: null,
relationDefinition: null,
@ -114,8 +96,6 @@ export const mockPerformance = {
isNullable: false,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: "''",
options: null,
relationDefinition: null,
@ -134,22 +114,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: {
__typename: 'relation',
id: 'd76f949d-023d-4b45-a71e-f39e3b1562ba',
relationType: 'ONE_TO_MANY',
toObjectMetadata: {
__typename: 'object',
id: '82222ca2-dd40-44ec-b8c5-eb0eca9ec625',
dataSourceId: '0fd9fd54-0e8d-4f78-911c-76b33436a768',
nameSingular: 'activityTarget',
namePlural: 'activityTargets',
isSystem: true,
isRemote: false,
},
toFieldMetadataId: 'f5f515cc-6d8a-44c3-b2d4-f04b9868a9c5',
},
toRelationMetadata: null,
defaultValue: null,
options: null,
relationDefinition: {
@ -194,22 +158,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: {
__typename: 'relation',
id: 'a5a61d23-8ac9-4014-9441-ec3a1781a661',
relationType: 'ONE_TO_MANY',
toObjectMetadata: {
__typename: 'object',
id: '494b9b7c-a44e-4d52-b274-cdfb0e322165',
dataSourceId: '0fd9fd54-0e8d-4f78-911c-76b33436a768',
nameSingular: 'opportunity',
namePlural: 'opportunities',
isSystem: false,
isRemote: false,
},
toFieldMetadataId: '86559a6f-6afc-4d5c-9bed-fc74d063791b',
},
toRelationMetadata: null,
defaultValue: null,
options: null,
relationDefinition: {
@ -254,22 +202,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: {
__typename: 'relation',
id: '456f7875-b48c-4795-a0c7-a69d7339afee',
relationType: 'ONE_TO_MANY',
toObjectMetadata: {
__typename: 'object',
id: 'eba13fca-57b7-470c-8c23-a0e640e04ffb',
dataSourceId: '0fd9fd54-0e8d-4f78-911c-76b33436a768',
nameSingular: 'calendarEventParticipant',
namePlural: 'calendarEventParticipants',
isSystem: true,
isRemote: false,
},
toFieldMetadataId: 'c1cdebda-b514-4487-9b9c-aa59d8fca8eb',
},
toRelationMetadata: null,
defaultValue: null,
options: null,
relationDefinition: {
@ -314,8 +246,6 @@ export const mockPerformance = {
isNullable: false,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: 'now',
options: null,
relationDefinition: null,
@ -334,22 +264,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: {
__typename: 'relation',
id: '31542774-fb15-4d01-b00b-8fc94887f458',
relationType: 'ONE_TO_MANY',
toObjectMetadata: {
__typename: 'object',
id: 'f08422e2-14cd-4966-9cd3-bce0302cc56f',
dataSourceId: '0fd9fd54-0e8d-4f78-911c-76b33436a768',
nameSingular: 'favorite',
namePlural: 'favorites',
isSystem: true,
isRemote: false,
},
toFieldMetadataId: '67d28b17-ff3c-49b4-a6da-1354be9634b0',
},
toRelationMetadata: null,
defaultValue: null,
options: null,
relationDefinition: {
@ -394,8 +308,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: {
primaryLinkUrl: "''",
primaryLinkLabel: "''",
@ -417,22 +329,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: {
__typename: 'relation',
id: 'c0cc3456-afa4-46e0-820d-2db0b63a8273',
relationType: 'ONE_TO_MANY',
toObjectMetadata: {
__typename: 'object',
id: '0e3c9a9d-8a60-4671-a466-7b840a422da2',
dataSourceId: '0fd9fd54-0e8d-4f78-911c-76b33436a768',
nameSingular: 'attachment',
namePlural: 'attachments',
isSystem: true,
isRemote: false,
},
toFieldMetadataId: 'a920a0d6-8e71-4ab8-90b9-ab540e04732a',
},
toRelationMetadata: null,
defaultValue: null,
options: null,
relationDefinition: {
@ -477,8 +373,6 @@ export const mockPerformance = {
isNullable: false,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: "''",
options: null,
relationDefinition: null,
@ -497,8 +391,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: null,
options: null,
relationDefinition: null,
@ -517,8 +409,6 @@ export const mockPerformance = {
isNullable: false,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: "''",
options: null,
relationDefinition: null,
@ -537,8 +427,6 @@ export const mockPerformance = {
isNullable: false,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: "''",
options: null,
relationDefinition: null,
@ -557,8 +445,6 @@ export const mockPerformance = {
isNullable: false,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: 'now',
options: null,
relationDefinition: null,
@ -577,8 +463,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: null,
options: null,
relationDefinition: null,
@ -597,22 +481,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: {
__typename: 'relation',
id: '25150feb-fcd7-407e-b5fa-ffe58a0450ac',
relationType: 'ONE_TO_MANY',
toObjectMetadata: {
__typename: 'object',
id: '83b5ff3e-975e-4dc9-ba4d-c645a0d8afb2',
dataSourceId: '0fd9fd54-0e8d-4f78-911c-76b33436a768',
nameSingular: 'timelineActivity',
namePlural: 'timelineActivities',
isSystem: true,
isRemote: false,
},
toFieldMetadataId: '556a12d4-ef0a-4232-963f-0f317f4c5ef5',
},
toRelationMetadata: null,
defaultValue: null,
options: null,
relationDefinition: {
@ -657,8 +525,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: {
lastName: "''",
firstName: "''",
@ -680,8 +546,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: {
primaryLinkUrl: "''",
primaryLinkLabel: "''",
@ -703,22 +567,6 @@ export const mockPerformance = {
isNullable: true,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: {
__typename: 'relation',
id: 'e2eb7156-6e65-4bf8-922b-670179744f27',
relationType: 'ONE_TO_MANY',
toObjectMetadata: {
__typename: 'object',
id: 'ffd8e640-84b7-4ed6-99e9-14def0f9d82b',
dataSourceId: '0fd9fd54-0e8d-4f78-911c-76b33436a768',
nameSingular: 'messageParticipant',
namePlural: 'messageParticipants',
isSystem: true,
isRemote: false,
},
toFieldMetadataId: '8c4593a1-ad40-4681-92fe-43ad4fe60205',
},
toRelationMetadata: null,
defaultValue: null,
options: null,
relationDefinition: {
@ -763,8 +611,6 @@ export const mockPerformance = {
isNullable: false,
createdAt: '2024-05-16T10:54:27.788Z',
updatedAt: '2024-05-16T10:54:27.788Z',
fromRelationMetadata: null,
toRelationMetadata: null,
defaultValue: 'uuid',
options: null,
relationDefinition: null,

View File

@ -6,7 +6,10 @@ import { useOpenSpreadsheetImportDialog } from '@/spreadsheet-import/hooks/useOp
import { SpreadsheetImportDialogOptions } from '@/spreadsheet-import/types';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import {
FieldMetadataType,
RelationDefinitionType,
} from '~/generated-metadata/graphql';
export const useOpenObjectRecordsSpreasheetImportDialog = (
objectNameSingular: string,
@ -37,7 +40,8 @@ export const useOpenObjectRecordsSpreasheetImportDialog = (
(!fieldMetadataItem.isSystem || fieldMetadataItem.name === 'id') &&
fieldMetadataItem.name !== 'createdAt' &&
(fieldMetadataItem.type !== FieldMetadataType.Relation ||
fieldMetadataItem.toRelationMetadata),
fieldMetadataItem.relationDefinition?.direction ===
RelationDefinitionType.ManyToOne),
)
.sort((fieldMetadataItemA, fieldMetadataItemB) =>
fieldMetadataItemA.name.localeCompare(fieldMetadataItemB.name),

View File

@ -2,14 +2,14 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'
import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation';
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
import { TABLE_COLUMNS_DENY_LIST } from '@/object-record/relation-picker/constants/TableColumnsDenyList';
import { RelationDefinitionType } from '~/generated-metadata/graphql';
export const filterAvailableTableColumns = (
columnDefinition: ColumnDefinition<FieldMetadata>,
): boolean => {
if (
isFieldRelation(columnDefinition) &&
columnDefinition.metadata?.relationType !== 'TO_ONE_OBJECT' &&
columnDefinition.metadata?.relationType !== 'FROM_MANY_OBJECTS'
columnDefinition.metadata?.relationType !== RelationDefinitionType.ManyToOne
) {
return false;
}

View File

@ -4,10 +4,7 @@ import { generateEmptyFieldValue } from '@/object-record/utils/generateEmptyFiel
import { v4 } from 'uuid';
export const generateDefaultFieldValue = (
fieldMetadataItem: Pick<
FieldMetadataItem,
'defaultValue' | 'type' | 'fromRelationMetadata'
>,
fieldMetadataItem: Pick<FieldMetadataItem, 'defaultValue' | 'type'>,
) => {
const defaultValue = isFieldValueEmpty({
fieldValue: fieldMetadataItem.defaultValue,

View File

@ -1,10 +1,11 @@
import { isNonEmptyString } from '@sniptt/guards';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import {
FieldMetadataType,
RelationDefinitionType,
} from '~/generated-metadata/graphql';
export const generateEmptyFieldValue = (
fieldMetadataItem: Pick<FieldMetadataItem, 'type' | 'fromRelationMetadata'>,
fieldMetadataItem: Pick<FieldMetadataItem, 'type' | 'relationDefinition'>,
) => {
switch (fieldMetadataItem.type) {
case FieldMetadataType.Email:
@ -62,10 +63,8 @@ export const generateEmptyFieldValue = (
}
case FieldMetadataType.Relation: {
if (
!isNonEmptyString(
fieldMetadataItem.fromRelationMetadata?.toObjectMetadata
?.nameSingular,
)
fieldMetadataItem.relationDefinition?.direction ===
RelationDefinitionType.ManyToOne
) {
return null;
}

View File

@ -1,12 +1,16 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isObjectMetadataAvailableForRelation } from '@/object-metadata/utils/isObjectMetadataAvailableForRelation';
import {
FieldMetadataType,
RelationMetadataType,
RelationDefinitionType,
} from '~/generated-metadata/graphql';
export const isFieldCellSupported = (fieldMetadataItem: FieldMetadataItem) => {
export const isFieldCellSupported = (
fieldMetadataItem: FieldMetadataItem,
objectMetadataItems: ObjectMetadataItem[],
) => {
if (
[
FieldMetadataType.Uuid,
@ -18,17 +22,17 @@ export const isFieldCellSupported = (fieldMetadataItem: FieldMetadataItem) => {
}
if (fieldMetadataItem.type === FieldMetadataType.Relation) {
const relationMetadata =
fieldMetadataItem.fromRelationMetadata ??
fieldMetadataItem.toRelationMetadata;
const relationObjectMetadataItem =
fieldMetadataItem.fromRelationMetadata?.toObjectMetadata ??
fieldMetadataItem.toRelationMetadata?.fromObjectMetadata;
const relationObjectMetadataItemId =
fieldMetadataItem.relationDefinition?.targetObjectMetadata.id;
const relationObjectMetadataItem = objectMetadataItems.find(
(item) => item.id === relationObjectMetadataItemId,
);
// Hack to display targets on Notes and Tasks
if (
fieldMetadataItem.fromRelationMetadata?.toObjectMetadata?.nameSingular ===
CoreObjectNameSingular.NoteTarget &&
fieldMetadataItem.relationDefinition?.targetObjectMetadata
?.nameSingular === CoreObjectNameSingular.NoteTarget &&
fieldMetadataItem.relationDefinition?.sourceObjectMetadata
.nameSingular === CoreObjectNameSingular.Note
) {
@ -36,8 +40,8 @@ export const isFieldCellSupported = (fieldMetadataItem: FieldMetadataItem) => {
}
if (
fieldMetadataItem.fromRelationMetadata?.toObjectMetadata?.nameSingular ===
CoreObjectNameSingular.TaskTarget &&
fieldMetadataItem.relationDefinition?.targetObjectMetadata
?.nameSingular === CoreObjectNameSingular.TaskTarget &&
fieldMetadataItem.relationDefinition?.sourceObjectMetadata
.nameSingular === CoreObjectNameSingular.Task
) {
@ -45,9 +49,10 @@ export const isFieldCellSupported = (fieldMetadataItem: FieldMetadataItem) => {
}
if (
!relationMetadata ||
!fieldMetadataItem.relationDefinition ||
// TODO: Many to many relations are not supported yet.
relationMetadata.relationType === RelationMetadataType.ManyToMany ||
fieldMetadataItem.relationDefinition.direction ===
RelationDefinitionType.ManyToMany ||
!relationObjectMetadataItem ||
!isObjectMetadataAvailableForRelation(relationObjectMetadataItem)
) {

View File

@ -1,8 +1,8 @@
import { isString } from '@sniptt/guards';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isFieldRelationToOneValue } from '@/object-record/record-field/types/guards/isFieldRelationToOneValue';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { RelationDefinitionType } from '~/generated-metadata/graphql';
import { FieldMetadataType } from '~/generated/graphql';
import { isDefined } from '~/utils/isDefined';
import { getUrlHostName } from '~/utils/url/getUrlHostName';
@ -29,7 +29,8 @@ export const sanitizeRecordInput = ({
if (
fieldMetadataItem.type === FieldMetadataType.Relation &&
isFieldRelationToOneValue(fieldValue)
fieldMetadataItem.relationDefinition?.direction ===
RelationDefinitionType.ManyToOne
) {
const relationIdFieldName = `${fieldMetadataItem.name}Id`;
const relationIdFieldMetadataItem = objectMetadataItem.fields.find(
@ -41,6 +42,14 @@ export const sanitizeRecordInput = ({
: undefined;
}
if (
fieldMetadataItem.type === FieldMetadataType.Relation &&
fieldMetadataItem.relationDefinition?.direction ===
RelationDefinitionType.OneToMany
) {
return undefined;
}
return [fieldName, fieldValue];
})
.filter(isDefined),