[Morph] frontend basics init (#13822)
Basic setup for frontend work on morph relations. FieldMetadata definition and related adjustments
This commit is contained in:
@@ -80,6 +80,27 @@ export const FIND_MANY_OBJECT_METADATA_ITEMS = gql`
|
||||
name
|
||||
}
|
||||
}
|
||||
morphRelations {
|
||||
type
|
||||
sourceObjectMetadata {
|
||||
id
|
||||
nameSingular
|
||||
namePlural
|
||||
}
|
||||
targetObjectMetadata {
|
||||
id
|
||||
nameSingular
|
||||
namePlural
|
||||
}
|
||||
sourceFieldMetadata {
|
||||
id
|
||||
name
|
||||
}
|
||||
targetFieldMetadata {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -2,6 +2,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI
|
||||
import { type FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||
import { type FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { type FieldMetadataItem } from '../types/FieldMetadataItem';
|
||||
import { getFieldButtonIcon } from '@/object-record/record-field/utils/getFieldButtonIcon';
|
||||
|
||||
@@ -22,10 +23,20 @@ export const formatFieldMetadataItemAsFieldDefinition = ({
|
||||
|
||||
const relationFieldMetadataId = field.relation?.targetFieldMetadata.id;
|
||||
|
||||
const isRelation = field.type === FieldMetadataType.RELATION;
|
||||
const isMorphRelation = field.type === FieldMetadataType.MORPH_RELATION;
|
||||
|
||||
const relationType = isRelation
|
||||
? field.relation?.type
|
||||
: isMorphRelation
|
||||
? field.morphRelations?.[0]?.type
|
||||
: undefined;
|
||||
|
||||
const fieldDefintionMetadata = {
|
||||
fieldName: field.name,
|
||||
placeHolder: field.label,
|
||||
relationType: field.relation?.type,
|
||||
relationType,
|
||||
morphRelations: isMorphRelation ? field.morphRelations : [],
|
||||
relationFieldMetadataId,
|
||||
relationObjectMetadataNameSingular:
|
||||
relationObjectMetadataItem?.nameSingular ?? '',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { type FieldMetadataItemRelation } from '@/object-metadata/types/FieldMetadataItemRelation';
|
||||
import { type RATING_VALUES } from '@/object-record/record-field/meta-types/constants/RatingValues';
|
||||
import { type ZodHelperLiteral } from '@/object-record/record-field/types/ZodHelperLiteral';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
@@ -139,6 +140,7 @@ export type FieldPositionMetadata = BaseFieldMetadata & {
|
||||
settings?: null;
|
||||
};
|
||||
|
||||
// for later: refactor this in order to directly use relation without mapping
|
||||
export type FieldRelationMetadata = BaseFieldMetadata & {
|
||||
relationFieldMetadataId: string;
|
||||
relationObjectMetadataNamePlural: string;
|
||||
@@ -150,6 +152,13 @@ export type FieldRelationMetadata = BaseFieldMetadata & {
|
||||
settings?: null;
|
||||
};
|
||||
|
||||
export type FieldMorphRelationMetadata = BaseFieldMetadata & {
|
||||
morphRelations: FieldMetadataItemRelation[];
|
||||
relationType: RelationType;
|
||||
useEditButton?: boolean;
|
||||
settings?: null;
|
||||
};
|
||||
|
||||
export type FieldSelectMetadata = BaseFieldMetadata & {
|
||||
options: { label: string; color: ThemeColor; value: string }[];
|
||||
isNullable: boolean;
|
||||
@@ -190,6 +199,7 @@ export type FieldMetadata =
|
||||
| FieldPhoneMetadata
|
||||
| FieldRatingMetadata
|
||||
| FieldRelationMetadata
|
||||
| FieldMorphRelationMetadata
|
||||
| FieldRichTextMetadata
|
||||
| FieldSelectMetadata
|
||||
| FieldMultiSelectMetadata
|
||||
|
||||
+22
-19
@@ -15,6 +15,7 @@ import {
|
||||
type FieldLinkMetadata,
|
||||
type FieldLinksMetadata,
|
||||
type FieldMetadata,
|
||||
type FieldMorphRelationMetadata,
|
||||
type FieldMultiSelectMetadata,
|
||||
type FieldNumberMetadata,
|
||||
type FieldPhoneMetadata,
|
||||
@@ -61,25 +62,27 @@ type AssertFieldMetadataFunction = <
|
||||
? FieldPhoneMetadata
|
||||
: E extends 'RELATION'
|
||||
? FieldRelationMetadata
|
||||
: E extends 'TEXT'
|
||||
? FieldTextMetadata
|
||||
: E extends 'UUID'
|
||||
? FieldUuidMetadata
|
||||
: E extends 'ADDRESS'
|
||||
? FieldAddressMetadata
|
||||
: E extends 'RAW_JSON'
|
||||
? FieldRawJsonMetadata
|
||||
: E extends 'RICH_TEXT_V2'
|
||||
? FieldRichTextV2Metadata
|
||||
: E extends 'RICH_TEXT'
|
||||
? FieldRichTextMetadata
|
||||
: E extends 'ACTOR'
|
||||
? FieldActorMetadata
|
||||
: E extends 'ARRAY'
|
||||
? FieldArrayMetadata
|
||||
: E extends 'PHONES'
|
||||
? FieldPhonesMetadata
|
||||
: never,
|
||||
: E extends 'MORPH_RELATION'
|
||||
? FieldMorphRelationMetadata
|
||||
: E extends 'TEXT'
|
||||
? FieldTextMetadata
|
||||
: E extends 'UUID'
|
||||
? FieldUuidMetadata
|
||||
: E extends 'ADDRESS'
|
||||
? FieldAddressMetadata
|
||||
: E extends 'RAW_JSON'
|
||||
? FieldRawJsonMetadata
|
||||
: E extends 'RICH_TEXT_V2'
|
||||
? FieldRichTextV2Metadata
|
||||
: E extends 'RICH_TEXT'
|
||||
? FieldRichTextMetadata
|
||||
: E extends 'ACTOR'
|
||||
? FieldActorMetadata
|
||||
: E extends 'ARRAY'
|
||||
? FieldArrayMetadata
|
||||
: E extends 'PHONES'
|
||||
? FieldPhonesMetadata
|
||||
: never,
|
||||
>(
|
||||
fieldType: E,
|
||||
fieldTypeGuard: (
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { type FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||
import {
|
||||
type FieldMetadata,
|
||||
type FieldMorphRelationMetadata,
|
||||
} from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const isFieldMorphRelation = (
|
||||
field: Pick<FieldDefinition<FieldMetadata>, 'type'>,
|
||||
): field is FieldDefinition<FieldMorphRelationMetadata> =>
|
||||
field.type === FieldMetadataType.MORPH_RELATION;
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import { isFieldMorphRelation } from '@/object-record/record-field/types/guards/isFieldMorphRelation';
|
||||
import { RelationType } from '~/generated-metadata/graphql';
|
||||
import { type FieldDefinition } from '../FieldDefinition';
|
||||
import {
|
||||
type FieldMetadata,
|
||||
type FieldMorphRelationMetadata,
|
||||
} from '../FieldMetadata';
|
||||
|
||||
export const isFieldMorphRelationManyToOneObject = (
|
||||
field: Pick<FieldDefinition<FieldMetadata>, 'type' | 'metadata'>,
|
||||
): field is FieldDefinition<FieldMorphRelationMetadata> =>
|
||||
isFieldMorphRelation(field) &&
|
||||
field.metadata.morphRelations?.[0].type === RelationType.MANY_TO_ONE;
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import { isFieldMorphRelation } from '@/object-record/record-field/types/guards/isFieldMorphRelation';
|
||||
import { RelationType } from '~/generated-metadata/graphql';
|
||||
import { type FieldDefinition } from '../FieldDefinition';
|
||||
import {
|
||||
type FieldMetadata,
|
||||
type FieldMorphRelationMetadata,
|
||||
} from '../FieldMetadata';
|
||||
|
||||
export const isFieldMorphRelationOneToManyObjects = (
|
||||
field: Pick<FieldDefinition<FieldMetadata>, 'type' | 'metadata'>,
|
||||
): field is FieldDefinition<FieldMorphRelationMetadata> =>
|
||||
isFieldMorphRelation(field) &&
|
||||
field.metadata.morphRelations?.[0].type === RelationType.ONE_TO_MANY;
|
||||
+7
@@ -20,6 +20,7 @@ import { isFieldFullName } from '@/object-record/record-field/types/guards/isFie
|
||||
import { isFieldFullNameValue } from '@/object-record/record-field/types/guards/isFieldFullNameValue';
|
||||
import { isFieldLinks } from '@/object-record/record-field/types/guards/isFieldLinks';
|
||||
import { isFieldLinksValue } from '@/object-record/record-field/types/guards/isFieldLinksValue';
|
||||
import { isFieldMorphRelation } from '@/object-record/record-field/types/guards/isFieldMorphRelation';
|
||||
import { isFieldMultiSelect } from '@/object-record/record-field/types/guards/isFieldMultiSelect';
|
||||
import { isFieldMultiSelectValue } from '@/object-record/record-field/types/guards/isFieldMultiSelectValue';
|
||||
import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber';
|
||||
@@ -80,6 +81,12 @@ export const isFieldValueEmpty = ({
|
||||
return isValueEmpty(fieldValue);
|
||||
}
|
||||
|
||||
if (isFieldMorphRelation(fieldDefinition)) {
|
||||
return isArray(fieldValue)
|
||||
? !isNonEmptyArray(fieldValue)
|
||||
: isValueEmpty(fieldValue);
|
||||
}
|
||||
|
||||
if (isFieldMultiSelect(fieldDefinition) || isFieldArray(fieldDefinition)) {
|
||||
return (
|
||||
!isFieldArrayValue(fieldValue) ||
|
||||
|
||||
+1
@@ -232,6 +232,7 @@ describe('useRecordData', () => {
|
||||
relationObjectMetadataNamePlural: '',
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationType: undefined,
|
||||
morphRelations: [],
|
||||
targetFieldMetadataName: '',
|
||||
settings: {
|
||||
displayFormat: 'RELATIVE',
|
||||
|
||||
+11
-9
@@ -104,6 +104,16 @@ export const SettingsDataModelFieldPreview = ({
|
||||
previewRecord?.id ??
|
||||
`${objectMetadataItem.nameSingular}-${fieldName}-${fieldMetadataItem.relation?.type}-${relationObjectMetadataItem?.nameSingular}-preview`;
|
||||
|
||||
const metadata = {
|
||||
fieldName,
|
||||
objectMetadataNameSingular: objectMetadataItem.nameSingular,
|
||||
relationObjectMetadataNameSingular:
|
||||
relationObjectMetadataItem?.nameSingular || '',
|
||||
options: fieldMetadataItem.options ?? [],
|
||||
settings: fieldMetadataItem.settings,
|
||||
relationType: fieldMetadataItem.relation?.type,
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<RecordFieldComponentInstanceContext.Provider
|
||||
@@ -139,15 +149,7 @@ export const SettingsDataModelFieldPreview = ({
|
||||
iconName: 'FieldIcon',
|
||||
fieldMetadataId: fieldMetadataItem.id || '',
|
||||
label: fieldMetadataItem.label,
|
||||
metadata: {
|
||||
fieldName,
|
||||
objectMetadataNameSingular: objectMetadataItem.nameSingular,
|
||||
relationObjectMetadataNameSingular:
|
||||
relationObjectMetadataItem?.nameSingular,
|
||||
options: fieldMetadataItem.options ?? [],
|
||||
settings: fieldMetadataItem.settings,
|
||||
relationType: fieldMetadataItem.relation?.type,
|
||||
},
|
||||
metadata,
|
||||
defaultValue: fieldMetadataItem.defaultValue,
|
||||
},
|
||||
isRecordFieldReadOnly:
|
||||
|
||||
Reference in New Issue
Block a user