Fix remote object read-only + remove relations (#4921)

- Set `readOnly` boolean in table row context. Preventing updates and
deletion
- Show page is null for remote objects. No need for complicated design
since this is temporary?
- Relation creations are now behind a feature flag for remote objects
- Refetch objects and views after syncing objects

---------

Co-authored-by: Thomas Trompette <thomast@twenty.com>
This commit is contained in:
Thomas Trompette
2024-04-11 17:58:02 +02:00
committed by GitHub
parent fc56775c2a
commit f332213e0d
29 changed files with 275 additions and 158 deletions

View File

@ -7,7 +7,12 @@ import { InjectRepository } from '@nestjs/typeorm';
import console from 'console';
import { FindManyOptions, FindOneOptions, Repository } from 'typeorm';
import {
DataSource,
FindManyOptions,
FindOneOptions,
Repository,
} from 'typeorm';
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
import { Query, QueryOptions } from '@ptc-org/nestjs-query-core';
@ -46,9 +51,14 @@ import {
createForeignKeyDeterministicUuid,
createRelationDeterministicUuid,
} from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util';
import { buildWorkspaceMigrationsForCustomObject } from 'src/engine/metadata-modules/object-metadata/utils/build-workspace-migrations-for-custom-object.util';
import { buildWorkspaceMigrationsForRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/build-workspace-migrations-for-remote-object.util';
import { createWorkspaceMigrationsForCustomObject } from 'src/engine/metadata-modules/object-metadata/utils/create-workspace-migrations-for-custom-object.util';
import { createWorkspaceMigrationsForRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/create-workspace-migrations-for-remote-object.util';
import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import {
FeatureFlagEntity,
FeatureFlagKeys,
} from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
import { ObjectMetadataEntity } from './object-metadata.entity';
@ -70,6 +80,8 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
private readonly typeORMService: TypeORMService,
private readonly workspaceMigrationService: WorkspaceMigrationService,
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
@InjectRepository(FeatureFlagEntity, 'core')
private readonly featureFlagRepository: Repository<FeatureFlagEntity>,
) {
super(objectMetadataRepository);
}
@ -322,27 +334,6 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
[],
});
const { eventObjectMetadata } = await this.createEventRelation(
objectMetadataInput.workspaceId,
createdObjectMetadata,
);
const { activityTargetObjectMetadata } =
await this.createActivityTargetRelation(
objectMetadataInput.workspaceId,
createdObjectMetadata,
);
const { favoriteObjectMetadata } = await this.createFavoriteRelation(
objectMetadataInput.workspaceId,
createdObjectMetadata,
);
const { attachmentObjectMetadata } = await this.createAttachmentRelation(
objectMetadataInput.workspaceId,
createdObjectMetadata,
);
const dataSourceMetadata =
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
createdObjectMetadata.workspaceId,
@ -351,27 +342,12 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
const workspaceDataSource =
await this.typeORMService.connectToDataSource(dataSourceMetadata);
await this.workspaceMigrationService.createCustomMigration(
generateMigrationName(`create-${createdObjectMetadata.nameSingular}`),
createdObjectMetadata.workspaceId,
isCustom
? buildWorkspaceMigrationsForCustomObject(
createdObjectMetadata,
activityTargetObjectMetadata,
attachmentObjectMetadata,
eventObjectMetadata,
favoriteObjectMetadata,
)
: await buildWorkspaceMigrationsForRemoteObject(
createdObjectMetadata,
activityTargetObjectMetadata,
attachmentObjectMetadata,
eventObjectMetadata,
favoriteObjectMetadata,
lastDataSourceMetadata.schema,
objectMetadataInput.remoteTablePrimaryKeyColumnType ?? 'uuid',
workspaceDataSource,
),
await this.createObjectRelationsMetadataAndMigrations(
objectMetadataInput,
createdObjectMetadata,
lastDataSourceMetadata,
workspaceDataSource,
objectMetadataInput.isRemote,
);
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
@ -483,6 +459,67 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
await this.objectMetadataRepository.delete({ workspaceId });
}
private async createObjectRelationsMetadataAndMigrations(
objectMetadataInput: CreateObjectInput,
createdObjectMetadata: ObjectMetadataEntity,
lastDataSourceMetadata: DataSourceEntity,
workspaceDataSource: DataSource | undefined,
isRemoteObject: boolean = false,
) {
const isRelationEnabledForRemoteObjects =
await this.isRelationEnabledForRemoteObjects(
objectMetadataInput.workspaceId,
);
if (isRemoteObject && !isRelationEnabledForRemoteObjects) {
return;
}
const { eventObjectMetadata } = await this.createEventRelation(
objectMetadataInput.workspaceId,
createdObjectMetadata,
);
const { activityTargetObjectMetadata } =
await this.createActivityTargetRelation(
objectMetadataInput.workspaceId,
createdObjectMetadata,
);
const { favoriteObjectMetadata } = await this.createFavoriteRelation(
objectMetadataInput.workspaceId,
createdObjectMetadata,
);
const { attachmentObjectMetadata } = await this.createAttachmentRelation(
objectMetadataInput.workspaceId,
createdObjectMetadata,
);
return this.workspaceMigrationService.createCustomMigration(
generateMigrationName(`create-${createdObjectMetadata.nameSingular}`),
createdObjectMetadata.workspaceId,
isRemoteObject
? await createWorkspaceMigrationsForRemoteObject(
createdObjectMetadata,
activityTargetObjectMetadata,
attachmentObjectMetadata,
eventObjectMetadata,
favoriteObjectMetadata,
lastDataSourceMetadata.schema,
objectMetadataInput.remoteTablePrimaryKeyColumnType ?? 'uuid',
workspaceDataSource,
)
: createWorkspaceMigrationsForCustomObject(
createdObjectMetadata,
activityTargetObjectMetadata,
attachmentObjectMetadata,
eventObjectMetadata,
favoriteObjectMetadata,
),
);
}
private async createActivityTargetRelation(
workspaceId: string,
createdObjectMetadata: ObjectMetadataEntity,
@ -855,4 +892,14 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
return { favoriteObjectMetadata };
}
private async isRelationEnabledForRemoteObjects(workspaceId: string) {
const featureFlag = await this.featureFlagRepository.findOneBy({
workspaceId,
key: FeatureFlagKeys.IsRelationForRemoteObjectsEnabled,
value: true,
});
return featureFlag && featureFlag.value;
}
}