1630 extensibility twenty cli ability to create edit and delete fields (#15501)

As title

- adds decorators in twenty-sdk
- update twenty-cli load-manifest to it gets @FieldMetadata infos +
testing
- update twenty-server so it CRUD fields properly, using
universalIdentifier
- Fix UI so we can update managed objects records
- move FieldMetadata items from twenty-server to twenty-shared
This commit is contained in:
martmull
2025-11-05 17:50:06 +01:00
committed by GitHub
parent 9fef0752a1
commit abde3c04ac
123 changed files with 1235 additions and 289 deletions
@@ -1,11 +1,13 @@
import { FieldMetadataType } from 'twenty-shared/types';
import {
FieldMetadataType,
DateDisplayFormat,
RelationOnDeleteAction,
} from 'twenty-shared/types';
import { DateDisplayFormat } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/relation-metadata/relation-on-delete-action.type';
export const ATTACHMENT_FLAT_FIELDS_MOCK = {
name: getFlatFieldMetadataMock({
@@ -1,11 +1,13 @@
import { FieldMetadataType } from 'twenty-shared/types';
import {
FieldMetadataType,
DateDisplayFormat,
RelationOnDeleteAction,
} from 'twenty-shared/types';
import { DateDisplayFormat } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/relation-metadata/relation-on-delete-action.type';
export const COMPANY_FLAT_FIELDS_MOCK = {
name: getFlatFieldMetadataMock({
@@ -1,11 +1,13 @@
import { FieldMetadataType } from 'twenty-shared/types';
import {
FieldMetadataType,
DateDisplayFormat,
RelationOnDeleteAction,
} from 'twenty-shared/types';
import { DateDisplayFormat } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/relation-metadata/relation-on-delete-action.type';
export const FAVORITE_FLAT_FIELDS_MOCK = {
position: getFlatFieldMetadataMock({
@@ -1,6 +1,5 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { FieldMetadataType, DateDisplayFormat } from 'twenty-shared/types';
import { DateDisplayFormat } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
@@ -1,6 +1,5 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { FieldMetadataType, DateDisplayFormat } from 'twenty-shared/types';
import { DateDisplayFormat } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
@@ -1,11 +1,13 @@
import { FieldMetadataType } from 'twenty-shared/types';
import {
FieldMetadataType,
DateDisplayFormat,
RelationOnDeleteAction,
} from 'twenty-shared/types';
import { DateDisplayFormat } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/relation-metadata/relation-on-delete-action.type';
export const NOTETARGET_FLAT_FIELDS_MOCK = {
id: getFlatFieldMetadataMock({
@@ -1,11 +1,13 @@
import { FieldMetadataType } from 'twenty-shared/types';
import {
FieldMetadataType,
DateDisplayFormat,
RelationOnDeleteAction,
} from 'twenty-shared/types';
import { DateDisplayFormat } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/relation-metadata/relation-on-delete-action.type';
export const OPPORTUNITY_FLAT_FIELDS_MOCK = {
name: getFlatFieldMetadataMock({
@@ -1,11 +1,13 @@
import { FieldMetadataType } from 'twenty-shared/types';
import {
FieldMetadataType,
DateDisplayFormat,
RelationOnDeleteAction,
} from 'twenty-shared/types';
import { DateDisplayFormat } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/relation-metadata/relation-on-delete-action.type';
export const PERSON_FLAT_FIELDS_MOCK = {
name: getFlatFieldMetadataMock({
@@ -1,11 +1,13 @@
import { FieldMetadataType } from 'twenty-shared/types';
import {
FieldMetadataType,
DateDisplayFormat,
RelationOnDeleteAction,
} from 'twenty-shared/types';
import { DateDisplayFormat } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/relation-metadata/relation-on-delete-action.type';
export const TASK_FLAT_FIELDS_MOCK = {
position: getFlatFieldMetadataMock({
@@ -1,11 +1,13 @@
import { FieldMetadataType } from 'twenty-shared/types';
import {
FieldMetadataType,
DateDisplayFormat,
RelationOnDeleteAction,
} from 'twenty-shared/types';
import { DateDisplayFormat } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/relation-metadata/relation-on-delete-action.type';
export const TASKTARGET_FLAT_FIELDS_MOCK = {
id: getFlatFieldMetadataMock({
@@ -1,11 +1,13 @@
import { FieldMetadataType } from 'twenty-shared/types';
import {
FieldMetadataType,
DateDisplayFormat,
RelationOnDeleteAction,
} from 'twenty-shared/types';
import { DateDisplayFormat } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/relation-metadata/relation-on-delete-action.type';
export const TIMELINEACTIVITY_FLAT_FIELDS_MOCK = {
happensAt: getFlatFieldMetadataMock({
@@ -1,5 +1,8 @@
import { msg } from '@lingui/core/macro';
import { FieldMetadataType } from 'twenty-shared/types';
import {
FieldMetadataType,
type FieldMetadataOptions,
} from 'twenty-shared/types';
import {
assertUnreachable,
isDefined,
@@ -7,8 +10,6 @@ import {
} from 'twenty-shared/utils';
import { v4 } from 'uuid';
import { type FieldMetadataOptions } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-options.interface';
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { generateRatingOptions } from 'src/engine/metadata-modules/field-metadata/utils/generate-rating-optionts.util';
@@ -1,4 +1,8 @@
import { FieldMetadataType, RelationType } from 'twenty-shared/types';
import {
FieldMetadataType,
RelationType,
RelationOnDeleteAction,
} from 'twenty-shared/types';
import { v4 } from 'uuid';
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
@@ -9,7 +13,6 @@ import { generateIndexForFlatFieldMetadata } from 'src/engine/metadata-modules/f
import { getDefaultFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/relation-metadata/relation-on-delete-action.type';
import { computeMetadataNameFromLabel } from 'src/engine/metadata-modules/utils/validate-name-and-label-are-sync-or-throw.util';
type ComputeFieldMetadataRelationSettingsForRelationTypeArgs = {
@@ -43,19 +43,20 @@ export const getDefaultFlatFieldMetadata = ({
objectMetadataId: createFieldInput.objectMetadataId,
relationTargetFieldMetadataId: null,
relationTargetObjectMetadataId: null,
standardId: null,
standardId: createFieldInput.standardId ?? null,
standardOverrides: null,
type: createFieldInput.type,
universalIdentifier: fieldMetadataId,
universalIdentifier:
createFieldInput.universalIdentifier ?? fieldMetadataId,
workspaceId,
options: null,
options: createFieldInput.options ?? null,
defaultValue: defaultValue ?? generateDefaultValue(createFieldInput.type),
settings: settings ?? null,
createdAt,
updatedAt: createdAt,
isUIReadOnly: createFieldInput.isUIReadOnly ?? false,
morphId: null,
applicationId: null,
applicationId: createFieldInput.applicationId ?? null,
viewFilterIds: [],
viewGroupIds: [],
kanbanAggregateOperationViewIds: [],
@@ -5,12 +5,11 @@ import {
FieldMetadataType,
type EnumFieldMetadataType,
type NonNullableRequired,
type FieldMetadataOptions,
} from 'twenty-shared/types';
import { assertUnreachable, isDefined } from 'twenty-shared/utils';
import { z } from 'zod';
import { type FieldMetadataOptions } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-options.interface';
import {
type FieldMetadataComplexOption,
type FieldMetadataDefaultOption,