Deprecate FieldMetadataInterface (#13264)
# Introduction
From the moment replaced the FieldMetadataInterface definition to:
```ts
import { FieldMetadataType } from 'twenty-shared/types';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
export type FieldMetadataInterface<
T extends FieldMetadataType = FieldMetadataType,
> = FieldMetadataEntity<T>;
```
After this PR merge will create a new one removing the type and
replacing it to `FieldMetadataEntity`.
Did not renamed it here to avoid conflicts on naming + type issues fixs
within the same PR
## Field metadata entity RELATION or MORPH
Relations fields cannot be null for those field metadata entity instance
anymore, but are never for the others see
`packages/twenty-server/src/engine/metadata-modules/field-metadata/types/field-metadata-entity-test.type.ts`
( introduced TypeScript tests )
## Concerns
- TS_VECTOR is the most at risk with the `generatedType` and
`asExpression` removal from interface
## What's next
- `FielMetadataInterface` removal and rename ( see introduction )
- Depcrecating `ObjectMetadataInterface`
- Refactor `FieldMetadataEntity` optional fiels to be nullable only
- TO DIG `never` occurences on settings, defaultValue etc
- Some interfaces will be replaced by the `FlatFieldMetadata` when
deprecating the current sync and comparators tools
This commit is contained in:
+45
-25
@@ -13,17 +13,27 @@ export class TimelineActivityRepository {
|
||||
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
) {}
|
||||
|
||||
async upsertOne(
|
||||
name: string,
|
||||
properties: Partial<ObjectRecord>,
|
||||
objectName: string,
|
||||
recordId: string,
|
||||
workspaceId: string,
|
||||
workspaceMemberId?: string,
|
||||
linkedRecordCachedName?: string,
|
||||
linkedRecordId?: string,
|
||||
linkedObjectMetadataId?: string,
|
||||
) {
|
||||
async upsertOne({
|
||||
name,
|
||||
objectName,
|
||||
properties,
|
||||
recordId,
|
||||
workspaceId,
|
||||
linkedObjectMetadataId,
|
||||
linkedRecordCachedName,
|
||||
linkedRecordId,
|
||||
workspaceMemberId,
|
||||
}: {
|
||||
name: string;
|
||||
properties: Partial<ObjectRecord>;
|
||||
objectName: string;
|
||||
recordId: string;
|
||||
workspaceId: string;
|
||||
workspaceMemberId?: string;
|
||||
linkedRecordCachedName?: string;
|
||||
linkedRecordId?: string;
|
||||
linkedObjectMetadataId: string | null;
|
||||
}) {
|
||||
const recentTimelineActivity = await this.findRecentTimelineActivity(
|
||||
name,
|
||||
objectName,
|
||||
@@ -58,17 +68,17 @@ export class TimelineActivityRepository {
|
||||
);
|
||||
}
|
||||
|
||||
return this.insertTimelineActivity(
|
||||
return this.insertTimelineActivity({
|
||||
name,
|
||||
properties,
|
||||
objectName,
|
||||
recordId,
|
||||
workspaceMemberId,
|
||||
linkedRecordCachedName ?? '',
|
||||
linkedRecordCachedName: linkedRecordCachedName ?? '',
|
||||
linkedRecordId,
|
||||
linkedObjectMetadataId,
|
||||
workspaceId,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private async findRecentTimelineActivity(
|
||||
@@ -131,17 +141,27 @@ export class TimelineActivityRepository {
|
||||
});
|
||||
}
|
||||
|
||||
private async insertTimelineActivity(
|
||||
name: string,
|
||||
properties: Partial<ObjectRecord>,
|
||||
objectName: string,
|
||||
recordId: string,
|
||||
workspaceMemberId: string | undefined,
|
||||
linkedRecordCachedName: string,
|
||||
linkedRecordId: string | undefined,
|
||||
linkedObjectMetadataId: string | undefined,
|
||||
workspaceId: string,
|
||||
) {
|
||||
private async insertTimelineActivity({
|
||||
linkedObjectMetadataId,
|
||||
linkedRecordCachedName,
|
||||
linkedRecordId,
|
||||
name,
|
||||
objectName,
|
||||
properties,
|
||||
recordId,
|
||||
workspaceId,
|
||||
workspaceMemberId,
|
||||
}: {
|
||||
name: string;
|
||||
properties: Partial<ObjectRecord>;
|
||||
objectName: string;
|
||||
recordId: string;
|
||||
workspaceMemberId: string | undefined;
|
||||
linkedRecordCachedName: string;
|
||||
linkedRecordId: string | undefined;
|
||||
linkedObjectMetadataId: string | null;
|
||||
workspaceId: string;
|
||||
}) {
|
||||
const timelineActivityTypeORMRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
|
||||
workspaceId,
|
||||
|
||||
@@ -14,7 +14,7 @@ type TimelineActivity = Omit<ObjectRecordNonDestructiveEvent, 'properties'> & {
|
||||
objectName?: string;
|
||||
linkedRecordCachedName?: string;
|
||||
linkedRecordId?: string;
|
||||
linkedObjectMetadataId?: string;
|
||||
linkedObjectMetadataId?: string | null;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
properties: Record<string, any>; // more relaxed conditions than for internal events
|
||||
};
|
||||
@@ -50,17 +50,28 @@ export class TimelineActivityService {
|
||||
if (!timelineActivities || timelineActivities.length === 0) return;
|
||||
|
||||
for (const timelineActivity of timelineActivities) {
|
||||
await this.timelineActivityRepository.upsertOne(
|
||||
timelineActivity.name,
|
||||
timelineActivity.properties,
|
||||
timelineActivity.objectName ?? event.objectMetadata.nameSingular,
|
||||
timelineActivity.recordId,
|
||||
const {
|
||||
name,
|
||||
properties,
|
||||
recordId,
|
||||
linkedObjectMetadataId,
|
||||
linkedRecordCachedName,
|
||||
linkedRecordId,
|
||||
objectName,
|
||||
workspaceMemberId,
|
||||
} = timelineActivity;
|
||||
|
||||
await this.timelineActivityRepository.upsertOne({
|
||||
linkedObjectMetadataId: linkedObjectMetadataId ?? null,
|
||||
name,
|
||||
objectName: objectName ?? event.objectMetadata.nameSingular,
|
||||
properties,
|
||||
recordId,
|
||||
workspaceId,
|
||||
timelineActivity.workspaceMemberId,
|
||||
timelineActivity.linkedRecordCachedName,
|
||||
timelineActivity.linkedRecordId,
|
||||
timelineActivity.linkedObjectMetadataId,
|
||||
);
|
||||
linkedRecordCachedName,
|
||||
linkedRecordId,
|
||||
workspaceMemberId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+71
-35
@@ -56,44 +56,80 @@ describe('generateFakeFormResponse', () => {
|
||||
objectMetadataMaps: mockObjectMetadataMaps,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
name: {
|
||||
isLeaf: true,
|
||||
label: 'Name',
|
||||
type: FieldMetadataType.TEXT,
|
||||
value: 'My text',
|
||||
icon: undefined,
|
||||
},
|
||||
age: {
|
||||
isLeaf: true,
|
||||
label: 'Age',
|
||||
type: FieldMetadataType.NUMBER,
|
||||
value: 20,
|
||||
icon: undefined,
|
||||
},
|
||||
company: {
|
||||
isLeaf: false,
|
||||
label: 'Company',
|
||||
value: {
|
||||
_outputSchemaType: 'RECORD',
|
||||
fields: {},
|
||||
object: {
|
||||
isLeaf: true,
|
||||
label: 'Company',
|
||||
fieldIdName: 'id',
|
||||
icon: 'test-company-icon',
|
||||
nameSingular: 'company',
|
||||
value: 'A company',
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
{
|
||||
"age": {
|
||||
"icon": undefined,
|
||||
"isLeaf": true,
|
||||
"label": "Age",
|
||||
"type": "NUMBER",
|
||||
"value": 20,
|
||||
},
|
||||
"company": {
|
||||
"isLeaf": false,
|
||||
"label": "Company",
|
||||
"value": {
|
||||
"_outputSchemaType": "RECORD",
|
||||
"fields": {
|
||||
"domainName": {
|
||||
"icon": "test-field-icon",
|
||||
"isLeaf": false,
|
||||
"label": "Domain Name",
|
||||
"type": "LINKS",
|
||||
"value": {
|
||||
"primaryLinkLabel": {
|
||||
"isLeaf": true,
|
||||
"label": "Primary Link Label",
|
||||
"type": "TEXT",
|
||||
"value": "My text",
|
||||
},
|
||||
"primaryLinkUrl": {
|
||||
"isLeaf": true,
|
||||
"label": "Primary Link Url",
|
||||
"type": "TEXT",
|
||||
"value": "My text",
|
||||
},
|
||||
"secondaryLinks": {
|
||||
"isLeaf": true,
|
||||
"label": "Secondary Links",
|
||||
"type": "RAW_JSON",
|
||||
"value": null,
|
||||
},
|
||||
},
|
||||
},
|
||||
"name": {
|
||||
"icon": "test-field-icon",
|
||||
"isLeaf": true,
|
||||
"label": "Name",
|
||||
"type": "TEXT",
|
||||
"value": "My text",
|
||||
},
|
||||
},
|
||||
date: {
|
||||
isLeaf: true,
|
||||
label: 'Date',
|
||||
type: FieldMetadataType.DATE,
|
||||
value: 'mm/dd/yyyy',
|
||||
icon: undefined,
|
||||
"object": {
|
||||
"fieldIdName": "id",
|
||||
"icon": "test-company-icon",
|
||||
"isLeaf": true,
|
||||
"label": "Company",
|
||||
"nameSingular": "company",
|
||||
"value": "A company",
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
"date": {
|
||||
"icon": undefined,
|
||||
"isLeaf": true,
|
||||
"label": "Date",
|
||||
"type": "DATE",
|
||||
"value": "mm/dd/yyyy",
|
||||
},
|
||||
"name": {
|
||||
"icon": undefined,
|
||||
"isLeaf": true,
|
||||
"label": "Name",
|
||||
"type": "TEXT",
|
||||
"value": "My text",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
+41
-12
@@ -1,71 +1,100 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||
|
||||
import { shouldGenerateFieldFakeValue } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/should-generate-field-fake-value';
|
||||
import { getMockFieldMetadataEntity } from 'src/utils/__test__/get-field-metadata-entity.mock';
|
||||
|
||||
describe('shouldGenerateFieldFakeValue', () => {
|
||||
it('should return true for active non-system fields', () => {
|
||||
const field = {
|
||||
const field = getMockFieldMetadataEntity({
|
||||
workspaceId: '20202020-0000-0000-0000-000000000000',
|
||||
objectMetadataId: '20202020-0000-0000-0000-000000000001',
|
||||
id: '20202020-0000-0000-0000-000000000002',
|
||||
isSystem: false,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.TEXT,
|
||||
name: 'testField',
|
||||
label: 'Test Field',
|
||||
isNullable: true,
|
||||
isLabelSyncedWithName: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
} as FieldMetadataInterface;
|
||||
});
|
||||
|
||||
expect(shouldGenerateFieldFakeValue(field)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for system id field', () => {
|
||||
const field = {
|
||||
const field = getMockFieldMetadataEntity({
|
||||
workspaceId: '20202020-0000-0000-0000-000000000000',
|
||||
objectMetadataId: '20202020-0000-0000-0000-000000000001',
|
||||
id: '20202020-0000-0000-0000-000000000003',
|
||||
isSystem: true,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.UUID,
|
||||
name: 'id',
|
||||
label: 'ID',
|
||||
isNullable: false,
|
||||
isLabelSyncedWithName: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
} as FieldMetadataInterface;
|
||||
});
|
||||
|
||||
expect(shouldGenerateFieldFakeValue(field)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for inactive fields', () => {
|
||||
const field = {
|
||||
const field = getMockFieldMetadataEntity({
|
||||
workspaceId: '20202020-0000-0000-0000-000000000000',
|
||||
objectMetadataId: '20202020-0000-0000-0000-000000000001',
|
||||
id: '20202020-0000-0000-0000-000000000004',
|
||||
isSystem: false,
|
||||
isActive: false,
|
||||
type: FieldMetadataType.TEXT,
|
||||
name: 'testField',
|
||||
label: 'Test Field',
|
||||
isNullable: true,
|
||||
isLabelSyncedWithName: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
} as FieldMetadataInterface;
|
||||
});
|
||||
|
||||
expect(shouldGenerateFieldFakeValue(field)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for system fields (except id)', () => {
|
||||
const field = {
|
||||
const field = getMockFieldMetadataEntity({
|
||||
workspaceId: '20202020-0000-0000-0000-000000000000',
|
||||
objectMetadataId: '20202020-0000-0000-0000-000000000001',
|
||||
id: '20202020-0000-0000-0000-000000000005',
|
||||
isSystem: true,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.TEXT,
|
||||
name: 'testField',
|
||||
label: 'Test Field',
|
||||
isNullable: true,
|
||||
isLabelSyncedWithName: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
} as FieldMetadataInterface;
|
||||
});
|
||||
|
||||
expect(shouldGenerateFieldFakeValue(field)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for relation fields', () => {
|
||||
const field = {
|
||||
const field = getMockFieldMetadataEntity({
|
||||
workspaceId: '20202020-0000-0000-0000-000000000000',
|
||||
objectMetadataId: '20202020-0000-0000-0000-000000000001',
|
||||
id: '20202020-0000-0000-0000-000000000006',
|
||||
isSystem: false,
|
||||
isActive: true,
|
||||
type: FieldMetadataType.RELATION,
|
||||
name: 'testField',
|
||||
label: 'Test Field',
|
||||
isNullable: true,
|
||||
isLabelSyncedWithName: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
} as FieldMetadataInterface;
|
||||
});
|
||||
|
||||
expect(shouldGenerateFieldFakeValue(field)).toBe(false);
|
||||
});
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ export const generateObjectRecordFields = ({
|
||||
acc[field.name] = generateFakeField({
|
||||
type: field.type,
|
||||
label: field.label,
|
||||
icon: field.icon,
|
||||
icon: field.icon ?? undefined,
|
||||
});
|
||||
|
||||
return acc;
|
||||
@@ -49,7 +49,7 @@ export const generateObjectRecordFields = ({
|
||||
|
||||
acc[field.name] = {
|
||||
isLeaf: false,
|
||||
icon: field.icon,
|
||||
icon: field.icon ?? undefined,
|
||||
label: field.label,
|
||||
value: generateFakeObjectRecord({
|
||||
objectMetadataInfo: {
|
||||
|
||||
+6
-5
@@ -1,18 +1,19 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
|
||||
const isManyToOneRelationField = (field: FieldMetadataInterface) =>
|
||||
const isManyToOneRelationField = (field: FieldMetadataEntity) =>
|
||||
(field as FieldMetadataEntity<FieldMetadataType.RELATION>).settings
|
||||
?.relationType === 'MANY_TO_ONE';
|
||||
|
||||
export const shouldGenerateFieldFakeValue = (field: FieldMetadataInterface) => {
|
||||
// TODO refactor
|
||||
export const shouldGenerateFieldFakeValue = <T extends FieldMetadataType>(
|
||||
field: FieldMetadataEntity<T>,
|
||||
) => {
|
||||
return (
|
||||
field.isActive &&
|
||||
(!field.isSystem || field.name === 'id' || field.name === 'userEmail') &&
|
||||
(field.type !== FieldMetadataType.RELATION ||
|
||||
isManyToOneRelationField(field))
|
||||
isManyToOneRelationField(field as unknown as FieldMetadataEntity))
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user