Update standard fields (#6532)
In this PR: - adding Favorites to Tasks and Notes - fixing inconsistencies between custom object creation and sync of standard fields of custom objects - fixing workspaceCacheVersion not used to invalidate existing datasource
This commit is contained in:
@ -50,6 +50,7 @@ import {
|
||||
CUSTOM_OBJECT_STANDARD_FIELD_IDS,
|
||||
FAVORITE_STANDARD_FIELD_IDS,
|
||||
NOTE_TARGET_STANDARD_FIELD_IDS,
|
||||
TASK_TARGET_STANDARD_FIELD_IDS,
|
||||
TIMELINE_ACTIVITY_STANDARD_FIELD_IDS,
|
||||
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
|
||||
import {
|
||||
@ -255,13 +256,13 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
standardId: BASE_OBJECT_STANDARD_FIELD_IDS.updatedAt,
|
||||
type: FieldMetadataType.DATE_TIME,
|
||||
name: 'updatedAt',
|
||||
label: 'Update date',
|
||||
icon: 'IconCalendar',
|
||||
description: 'Update date',
|
||||
label: 'Last update',
|
||||
icon: 'IconCalendarClock',
|
||||
description: 'Last time the record was changed',
|
||||
isNullable: false,
|
||||
isActive: true,
|
||||
isCustom: false,
|
||||
isSystem: true,
|
||||
isSystem: false,
|
||||
workspaceId: objectMetadataInput.workspaceId,
|
||||
defaultValue: 'now',
|
||||
},
|
||||
@ -269,7 +270,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.createdBy,
|
||||
type: FieldMetadataType.ACTOR,
|
||||
name: 'createdBy',
|
||||
label: 'Created By',
|
||||
label: 'Created by',
|
||||
icon: 'IconCreativeCommonsSa',
|
||||
description: 'The creator of the record',
|
||||
isNullable: false,
|
||||
@ -676,7 +677,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
name: 'noteTargets',
|
||||
label: 'Notes',
|
||||
description: `Notes tied to the ${createdObjectMetadata.labelSingular}`,
|
||||
icon: 'IconCheckbox',
|
||||
icon: 'IconNotes',
|
||||
isNullable: true,
|
||||
},
|
||||
// TO
|
||||
@ -746,7 +747,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
{
|
||||
standardId: createForeignKeyDeterministicUuid({
|
||||
objectId: createdObjectMetadata.id,
|
||||
standardId: NOTE_TARGET_STANDARD_FIELD_IDS.custom,
|
||||
standardId: TASK_TARGET_STANDARD_FIELD_IDS.custom,
|
||||
}),
|
||||
objectMetadataId: taskTargetObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
@ -784,7 +785,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
{
|
||||
standardId: createRelationDeterministicUuid({
|
||||
objectId: createdObjectMetadata.id,
|
||||
standardId: NOTE_TARGET_STANDARD_FIELD_IDS.custom,
|
||||
standardId: TASK_TARGET_STANDARD_FIELD_IDS.custom,
|
||||
}),
|
||||
objectMetadataId: taskTargetObjectMetadata.id,
|
||||
workspaceId: workspaceId,
|
||||
@ -979,8 +980,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
name: 'timelineActivities',
|
||||
label: 'Timeline Activities',
|
||||
description: `Timeline Activities tied to the ${createdObjectMetadata.labelSingular}`,
|
||||
icon: 'IconTimeline',
|
||||
icon: 'IconIconTimelineEvent',
|
||||
isNullable: true,
|
||||
isSystem: true,
|
||||
},
|
||||
// TO
|
||||
{
|
||||
@ -996,7 +998,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
name: createdObjectMetadata.nameSingular,
|
||||
label: createdObjectMetadata.labelSingular,
|
||||
description: `Timeline Activity ${createdObjectMetadata.labelSingular}`,
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
icon: 'IconTimeline',
|
||||
isNullable: true,
|
||||
},
|
||||
]);
|
||||
@ -1100,7 +1102,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
name: createdObjectMetadata.nameSingular,
|
||||
label: createdObjectMetadata.labelSingular,
|
||||
description: `Favorite ${createdObjectMetadata.labelSingular}`,
|
||||
icon: 'IconBuildingSkyscraper',
|
||||
icon: 'IconHeart',
|
||||
isNullable: true,
|
||||
},
|
||||
]);
|
||||
|
||||
@ -2,12 +2,12 @@ import { ObjectType } from 'typeorm';
|
||||
|
||||
import { WorkspaceDynamicRelationMetadataArgsFactory } from 'src/engine/twenty-orm/interfaces/workspace-dynamic-relation-metadata-args.interface';
|
||||
|
||||
import { TypedReflect } from 'src/utils/typed-reflect';
|
||||
import {
|
||||
RelationMetadataType,
|
||||
RelationOnDeleteAction,
|
||||
} from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
|
||||
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
|
||||
import { TypedReflect } from 'src/utils/typed-reflect';
|
||||
|
||||
interface WorkspaceBaseDynamicRelationOptions<TClass> {
|
||||
type: RelationMetadataType;
|
||||
@ -27,6 +27,7 @@ export function WorkspaceDynamicRelation<TClass extends object>(
|
||||
target,
|
||||
propertyKey.toString(),
|
||||
) ?? false;
|
||||
|
||||
const gate = TypedReflect.getMetadata(
|
||||
'workspace:gate-metadata-args',
|
||||
target,
|
||||
|
||||
@ -26,20 +26,20 @@ export class WorkspaceDatasourceFactory {
|
||||
|
||||
public async create(
|
||||
workspaceId: string,
|
||||
cacheVersion: string | null,
|
||||
workspaceSchemaVersion: string | null,
|
||||
): Promise<WorkspaceDataSource> {
|
||||
const desiredCacheVersion =
|
||||
cacheVersion ??
|
||||
const desiredWorkspaceSchemaVersion =
|
||||
workspaceSchemaVersion ??
|
||||
(await this.workspaceCacheVersionService.getVersion(workspaceId));
|
||||
|
||||
if (!desiredCacheVersion) {
|
||||
if (!desiredWorkspaceSchemaVersion) {
|
||||
throw new Error('Cache version not found');
|
||||
}
|
||||
|
||||
const latestCacheVersion =
|
||||
const latestWorkspaceSchemaVersion =
|
||||
await this.workspaceCacheVersionService.getVersion(workspaceId);
|
||||
|
||||
if (latestCacheVersion !== desiredCacheVersion) {
|
||||
if (latestWorkspaceSchemaVersion !== desiredWorkspaceSchemaVersion) {
|
||||
throw new Error('Cache version mismatch');
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ export class WorkspaceDatasourceFactory {
|
||||
}
|
||||
|
||||
const workspaceDataSource = await workspaceDataSourceCacheInstance.execute(
|
||||
`${workspaceId}-${cacheVersion}`,
|
||||
`${workspaceId}-${latestWorkspaceSchemaVersion}`,
|
||||
async () => {
|
||||
const dataSourceMetadata =
|
||||
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceId(
|
||||
|
||||
@ -12,7 +12,6 @@ export class CacheManager<T> {
|
||||
): Promise<T | null> {
|
||||
const [workspaceId] = cacheKey.split('-');
|
||||
|
||||
// If the cacheKey exists, return the cached value
|
||||
if (this.cache.has(cacheKey)) {
|
||||
return this.cache.get(cacheKey)!;
|
||||
}
|
||||
|
||||
@ -203,6 +203,8 @@ export const FAVORITE_STANDARD_FIELD_IDS = {
|
||||
company: '20202020-cff5-4682-8bf9-069169e08279',
|
||||
opportunity: '20202020-dabc-48e1-8318-2781a2b32aa2',
|
||||
workflow: '20202020-b11b-4dc8-999a-6bd0a947b463',
|
||||
task: '20202020-1b1b-4b3b-8b1b-7f8d6a1d7d5c',
|
||||
note: '20202020-1f25-43fe-8b00-af212fdde824',
|
||||
custom: '20202020-855a-4bc8-9861-79deef37011f',
|
||||
};
|
||||
|
||||
@ -272,6 +274,7 @@ export const NOTE_STANDARD_FIELD_IDS = {
|
||||
noteTargets: '20202020-1f25-43fe-8b00-af212fdde823',
|
||||
attachments: '20202020-4986-4c92-bf19-39934b149b16',
|
||||
timelineActivities: '20202020-7030-42f8-929c-1a57b25d6bce',
|
||||
favorites: '20202020-4d1d-41ac-b13b-621631298d67',
|
||||
};
|
||||
|
||||
export const NOTE_TARGET_STANDARD_FIELD_IDS = {
|
||||
@ -334,6 +337,7 @@ export const TASK_STANDARD_FIELD_IDS = {
|
||||
attachments: '20202020-794d-4783-a8ff-cecdb15be139',
|
||||
assignee: '20202020-065a-4f42-a906-e20422c1753f',
|
||||
timelineActivities: '20202020-c778-4278-99ee-23a2837aee64',
|
||||
favorites: '20202020-4d1d-41ac-b13b-621631298d65',
|
||||
};
|
||||
|
||||
export const TASK_TARGET_STANDARD_FIELD_IDS = {
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
||||
import { FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface';
|
||||
import { WorkspaceDynamicRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-dynamic-relation-metadata-args.interface';
|
||||
import { WorkspaceEntityMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-entity-metadata-args.interface';
|
||||
import { WorkspaceFieldMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-field-metadata-args.interface';
|
||||
import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface';
|
||||
import {
|
||||
PartialComputedFieldMetadata,
|
||||
PartialFieldMetadata,
|
||||
} from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
||||
import { WorkspaceEntityMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-entity-metadata-args.interface';
|
||||
import { WorkspaceFieldMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-field-metadata-args.interface';
|
||||
import { WorkspaceDynamicRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-dynamic-relation-metadata-args.interface';
|
||||
import { WorkspaceRelationMetadataArgs } from 'src/engine/twenty-orm/interfaces/workspace-relation-metadata-args.interface';
|
||||
import { WorkspaceSyncContext } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface';
|
||||
|
||||
import { isGatedAndNotEnabled } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-gate-and-not-enabled.util';
|
||||
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
|
||||
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { createDeterministicUuid } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util';
|
||||
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
|
||||
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
|
||||
import { getJoinColumn } from 'src/engine/twenty-orm/utils/get-join-column.util';
|
||||
import { createDeterministicUuid } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util';
|
||||
import { isGatedAndNotEnabled } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-gate-and-not-enabled.util';
|
||||
|
||||
@Injectable()
|
||||
export class StandardFieldFactory {
|
||||
@ -163,9 +163,7 @@ export class StandardFieldFactory {
|
||||
workspaceId: context.workspaceId,
|
||||
isNullable: workspaceFieldMetadataArgs.isNullable,
|
||||
isCustom: workspaceFieldMetadataArgs.isDeprecated ? true : false,
|
||||
isSystem:
|
||||
workspaceEntityMetadataArgs?.isSystem ||
|
||||
workspaceFieldMetadataArgs.isSystem,
|
||||
isSystem: workspaceFieldMetadataArgs.isSystem ?? false,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ export class WorkspaceSyncMetadataService {
|
||||
workspaceFeatureFlagsMap,
|
||||
);
|
||||
|
||||
// 2 - Sync standard fields on custom objects
|
||||
// 2 - Sync standard fields on standard and custom objects
|
||||
const workspaceFieldMigrations =
|
||||
await this.workspaceSyncFieldMetadataService.synchronize(
|
||||
context,
|
||||
|
||||
Reference in New Issue
Block a user