mirror of
https://github.com/twentyhq/twenty.git
synced 2026-05-19 14:03:12 -04:00
Add applicationId to syncableEntity and fix syncApp deletion (#15170)
## Context - All flatEntity should extend SyncableEntity - SyncableEntity should now have applicationId and application relation - Fix syncApp deletion, should now properly use migration v2 to delete syncable entities
This commit is contained in:
@@ -15,15 +15,14 @@ describe.each(COVERED_APPLICATION_FOLDERS)(
|
||||
expect(existsSync(appPath)).toBe(true);
|
||||
});
|
||||
|
||||
// TODO uncomment when reinstall is fix to cleanup gracefully
|
||||
// afterAll(async () => {
|
||||
// const result = await deleteCommand.execute({
|
||||
// appPath,
|
||||
// askForConfirmation: false,
|
||||
// });
|
||||
afterAll(async () => {
|
||||
const result = await deleteCommand.execute({
|
||||
appPath,
|
||||
askForConfirmation: false,
|
||||
});
|
||||
|
||||
// expect(result.success).toBe(true);
|
||||
// });
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it(`should successfully install ${applicationName} application`, async () => {
|
||||
const result = await syncCommand.execute(appPath);
|
||||
@@ -40,13 +39,10 @@ describe.each(COVERED_APPLICATION_FOLDERS)(
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it.failing(
|
||||
`should successfully re-install ${applicationName} application`,
|
||||
async () => {
|
||||
const result = await syncCommand.execute(appPath);
|
||||
it(`should successfully re-install ${applicationName} application`, async () => {
|
||||
const result = await syncCommand.execute(appPath);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
},
|
||||
);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
import { type MigrationInterface, type QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddApplicationIdToSyncableEntities1760700501795
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'AddApplicationIdToSyncableEntities1760700501795';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."application" DROP CONSTRAINT "FK_eec488855d08b312a869a13ccb1"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."agent" ADD "universalIdentifier" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."role" ADD "universalIdentifier" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."role" ADD "applicationId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewFilter" ADD "applicationId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewFilterGroup" ADD "applicationId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewGroup" ADD "applicationId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewSort" ADD "applicationId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."view" ADD "applicationId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."objectMetadata" ADD "universalIdentifier" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."indexMetadata" ADD "applicationId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."fieldMetadata" ADD "universalIdentifier" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."fieldMetadata" ADD "applicationId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewField" ADD "applicationId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."cronTrigger" ADD "applicationId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."databaseEventTrigger" ADD "applicationId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."routeTrigger" ADD "applicationId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."application" DROP CONSTRAINT "UQ_eec488855d08b312a869a13ccb1"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE UNIQUE INDEX "IDX_0cc4d03dbcc269e77ba4d297fb" ON "core"."agent" ("workspaceId", "universalIdentifier") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE UNIQUE INDEX "IDX_3b7ff27925c0959777682c1adc" ON "core"."role" ("workspaceId", "universalIdentifier") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE UNIQUE INDEX "IDX_3a00d35710f4227ded320fd96d" ON "core"."objectMetadata" ("workspaceId", "universalIdentifier") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE UNIQUE INDEX "IDX_f1c88fdfc3ad8910b17fc1fd73" ON "core"."fieldMetadata" ("workspaceId", "universalIdentifier") `,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."role" ADD CONSTRAINT "FK_7f3b96f15aaf5a27549288d264b" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewFilter" ADD CONSTRAINT "FK_d5651cf33fa56a47cd262a3fb2c" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewFilterGroup" ADD CONSTRAINT "FK_bfc3498b964ef1bfc89b1f2bee3" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewGroup" ADD CONSTRAINT "FK_5aff384532c78fa8a42ceeae282" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewSort" ADD CONSTRAINT "FK_ff8cbebe1704954120df82bf393" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."view" ADD CONSTRAINT "FK_348e25d584c7e51417f4e097941" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."indexMetadata" ADD CONSTRAINT "FK_056363e1599f5b9a0e33323d9da" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."fieldMetadata" ADD CONSTRAINT "FK_05453a954e458e3d91f2ff5043f" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewField" ADD CONSTRAINT "FK_b560ea62a958deff0c6059caa45" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."cronTrigger" ADD CONSTRAINT "FK_817ea28e71e3b19acc258dd7dcd" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."databaseEventTrigger" ADD CONSTRAINT "FK_9acc2804037a5c885633024368d" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."routeTrigger" ADD CONSTRAINT "FK_6edf47a8bfe17a5811998dc7162" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."routeTrigger" DROP CONSTRAINT "FK_6edf47a8bfe17a5811998dc7162"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."databaseEventTrigger" DROP CONSTRAINT "FK_9acc2804037a5c885633024368d"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."cronTrigger" DROP CONSTRAINT "FK_817ea28e71e3b19acc258dd7dcd"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewField" DROP CONSTRAINT "FK_b560ea62a958deff0c6059caa45"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."fieldMetadata" DROP CONSTRAINT "FK_05453a954e458e3d91f2ff5043f"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."indexMetadata" DROP CONSTRAINT "FK_056363e1599f5b9a0e33323d9da"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."view" DROP CONSTRAINT "FK_348e25d584c7e51417f4e097941"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewSort" DROP CONSTRAINT "FK_ff8cbebe1704954120df82bf393"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewGroup" DROP CONSTRAINT "FK_5aff384532c78fa8a42ceeae282"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewFilterGroup" DROP CONSTRAINT "FK_bfc3498b964ef1bfc89b1f2bee3"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewFilter" DROP CONSTRAINT "FK_d5651cf33fa56a47cd262a3fb2c"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."role" DROP CONSTRAINT "FK_7f3b96f15aaf5a27549288d264b"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "core"."IDX_f1c88fdfc3ad8910b17fc1fd73"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "core"."IDX_3a00d35710f4227ded320fd96d"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "core"."IDX_3b7ff27925c0959777682c1adc"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "core"."IDX_0cc4d03dbcc269e77ba4d297fb"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."application" ADD CONSTRAINT "UQ_eec488855d08b312a869a13ccb1" UNIQUE ("serverlessFunctionLayerId")`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."routeTrigger" DROP COLUMN "applicationId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."databaseEventTrigger" DROP COLUMN "applicationId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."cronTrigger" DROP COLUMN "applicationId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewField" DROP COLUMN "applicationId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."fieldMetadata" DROP COLUMN "applicationId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."fieldMetadata" DROP COLUMN "universalIdentifier"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."indexMetadata" DROP COLUMN "applicationId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."objectMetadata" DROP COLUMN "universalIdentifier"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."view" DROP COLUMN "applicationId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewSort" DROP COLUMN "applicationId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewGroup" DROP COLUMN "applicationId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewFilterGroup" DROP COLUMN "applicationId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."viewFilter" DROP COLUMN "applicationId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."role" DROP COLUMN "applicationId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."role" DROP COLUMN "universalIdentifier"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."agent" DROP COLUMN "universalIdentifier"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."application" ADD CONSTRAINT "FK_eec488855d08b312a869a13ccb1" FOREIGN KEY ("serverlessFunctionLayerId") REFERENCES "core"."serverlessFunctionLayer"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -15,20 +15,26 @@ import {
|
||||
ServerlessFunctionManifest,
|
||||
ServerlessFunctionTriggerManifest,
|
||||
} from 'src/engine/core-modules/application/types/application.types';
|
||||
import { ApplicationVariableService } from 'src/engine/core-modules/applicationVariable/application-variable.service';
|
||||
import { AgentService } from 'src/engine/metadata-modules/agent/agent.service';
|
||||
import { CronTriggerV2Service } from 'src/engine/metadata-modules/cron-trigger/services/cron-trigger-v2.service';
|
||||
import { FlatCronTrigger } from 'src/engine/metadata-modules/cron-trigger/types/flat-cron-trigger.type';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
import { DatabaseEventTriggerV2Service } from 'src/engine/metadata-modules/database-event-trigger/services/database-event-trigger-v2.service';
|
||||
import { FlatDatabaseEventTrigger } from 'src/engine/metadata-modules/database-event-trigger/types/flat-database-event-trigger.type';
|
||||
import { ALL_METADATA_NAME } from 'src/engine/metadata-modules/flat-entity/constant/all-metadata-name.constant';
|
||||
import { EMPTY_FLAT_ENTITY_MAPS } from 'src/engine/metadata-modules/flat-entity/constant/empty-flat-entity-maps.constant';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { AllMetadataName } from 'src/engine/metadata-modules/flat-entity/types/all-metadata-name.type';
|
||||
import { getFlatEntitiesByApplicationId } from 'src/engine/metadata-modules/flat-entity/utils/get-flat-entities-by-application-id.util';
|
||||
import { getSubFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/get-sub-flat-entity-maps-or-throw.util';
|
||||
import { ObjectMetadataServiceV2 } from 'src/engine/metadata-modules/object-metadata/object-metadata-v2.service';
|
||||
import { RouteTriggerV2Service } from 'src/engine/metadata-modules/route-trigger/services/route-trigger-v2.service';
|
||||
import { FlatRouteTrigger } from 'src/engine/metadata-modules/route-trigger/types/flat-route-trigger.type';
|
||||
import { ServerlessFunctionLayerService } from 'src/engine/metadata-modules/serverless-function-layer/serverless-function-layer.service';
|
||||
import { ServerlessFunctionV2Service } from 'src/engine/metadata-modules/serverless-function/services/serverless-function-v2.service';
|
||||
import { FlatServerlessFunction } from 'src/engine/metadata-modules/serverless-function/types/flat-serverless-function.type';
|
||||
import { ApplicationVariableService } from 'src/engine/core-modules/applicationVariable/application-variable.service';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
@Injectable()
|
||||
export class ApplicationSyncService {
|
||||
@@ -46,6 +52,7 @@ export class ApplicationSyncService {
|
||||
private readonly databaseEventTriggerV2Service: DatabaseEventTriggerV2Service,
|
||||
private readonly cronTriggerV2Service: CronTriggerV2Service,
|
||||
private readonly routeTriggerV2Service: RouteTriggerV2Service,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
) {}
|
||||
|
||||
public async synchronizeFromManifest({
|
||||
@@ -795,4 +802,109 @@ export class ApplicationSyncService {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async deleteApplication({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
}) {
|
||||
const {
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
flatIndexMaps: existingFlatIndexMetadataMaps,
|
||||
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
|
||||
} = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatIndexMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
const application = await this.applicationService.findByUniversalIdentifier(
|
||||
applicationUniversalIdentifier,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
if (!isDefined(application)) {
|
||||
throw new ApplicationException(
|
||||
`Application with universalIdentifier ${applicationUniversalIdentifier} not found`,
|
||||
ApplicationExceptionCode.ENTITY_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const flatObjectMetadataMapsByApplicationId =
|
||||
getFlatEntitiesByApplicationId(
|
||||
existingFlatObjectMetadataMaps,
|
||||
application.id,
|
||||
);
|
||||
|
||||
const fromFlatObjectMetadataMaps = getSubFlatEntityMapsOrThrow({
|
||||
flatEntityIds: flatObjectMetadataMapsByApplicationId.map((obj) => obj.id),
|
||||
flatEntityMaps: existingFlatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
const flatIndexMetadataMapsByApplicationId = getFlatEntitiesByApplicationId(
|
||||
existingFlatIndexMetadataMaps,
|
||||
application.id,
|
||||
);
|
||||
|
||||
const fromFlatIndexMetadataMaps = getSubFlatEntityMapsOrThrow({
|
||||
flatEntityIds: flatIndexMetadataMapsByApplicationId.map(
|
||||
(field) => field.id,
|
||||
),
|
||||
flatEntityMaps: existingFlatIndexMetadataMaps,
|
||||
});
|
||||
|
||||
const flatFieldMetadataMapsByApplicationId = getFlatEntitiesByApplicationId(
|
||||
existingFlatFieldMetadataMaps,
|
||||
application.id,
|
||||
);
|
||||
|
||||
const fromFlatFieldMetadataMaps = getSubFlatEntityMapsOrThrow({
|
||||
flatEntityIds: flatFieldMetadataMapsByApplicationId.map((idx) => idx.id),
|
||||
flatEntityMaps: existingFlatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
fromToAllFlatEntityMaps: {
|
||||
flatObjectMetadataMaps: {
|
||||
from: fromFlatObjectMetadataMaps,
|
||||
to: EMPTY_FLAT_ENTITY_MAPS,
|
||||
},
|
||||
flatIndexMaps: {
|
||||
from: fromFlatIndexMetadataMaps,
|
||||
to: EMPTY_FLAT_ENTITY_MAPS,
|
||||
},
|
||||
flatFieldMetadataMaps: {
|
||||
from: fromFlatFieldMetadataMaps,
|
||||
to: EMPTY_FLAT_ENTITY_MAPS,
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
buildOptions: {
|
||||
isSystemBuild: true,
|
||||
inferDeletionFromMissingEntities: {
|
||||
...Object.values(ALL_METADATA_NAME).reduce(
|
||||
(acc, metadataName) => ({
|
||||
...acc,
|
||||
[metadataName]: true,
|
||||
}),
|
||||
{} as Partial<Record<AllMetadataName, boolean>>,
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
await this.applicationService.delete(
|
||||
applicationUniversalIdentifier,
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,18 +7,16 @@ import {
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
OneToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
Relation,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
import { ApplicationVariable } from 'src/engine/core-modules/applicationVariable/application-variable.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/agent/agent.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { ServerlessFunctionLayerEntity } from 'src/engine/metadata-modules/serverless-function-layer/serverless-function-layer.entity';
|
||||
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
import { ApplicationVariable } from 'src/engine/core-modules/applicationVariable/application-variable.entity';
|
||||
|
||||
@Entity({ name: 'application', schema: 'core' })
|
||||
@Index('IDX_APPLICATION_WORKSPACE_ID', ['workspaceId'])
|
||||
@@ -58,15 +56,11 @@ export class ApplicationEntity {
|
||||
@Column({ nullable: false, type: 'uuid' })
|
||||
serverlessFunctionLayerId: string;
|
||||
|
||||
@OneToOne(
|
||||
() => ServerlessFunctionLayerEntity,
|
||||
(serverlessFunctionLayer) => serverlessFunctionLayer.application,
|
||||
{
|
||||
onDelete: 'CASCADE',
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: 'serverlessFunctionLayerId' })
|
||||
serverlessFunctionLayer: Relation<ServerlessFunctionLayerEntity>;
|
||||
@ManyToOne(() => Workspace, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'workspaceId' })
|
||||
workspace: Relation<Workspace>;
|
||||
|
||||
@OneToMany(() => AgentEntity, (agent) => agent.application, {
|
||||
onDelete: 'CASCADE',
|
||||
@@ -96,12 +90,6 @@ export class ApplicationEntity {
|
||||
)
|
||||
applicationVariables: Relation<ApplicationVariable[]>;
|
||||
|
||||
@ManyToOne(() => Workspace, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'workspaceId' })
|
||||
workspace: Relation<Workspace>;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ApplicationSyncService } from 'src/engine/core-modules/application/appl
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { ApplicationResolver } from 'src/engine/core-modules/application/application.resolver';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationVariableModule } from 'src/engine/core-modules/applicationVariable/application-variable.module';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AgentEntity } from 'src/engine/metadata-modules/agent/agent.entity';
|
||||
import { AgentModule } from 'src/engine/metadata-modules/agent/agent.module';
|
||||
@@ -16,7 +17,7 @@ import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadat
|
||||
import { RouteTriggerModule } from 'src/engine/metadata-modules/route-trigger/route-trigger.module';
|
||||
import { ServerlessFunctionLayerModule } from 'src/engine/metadata-modules/serverless-function-layer/serverless-function-layer.module';
|
||||
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
|
||||
import { ApplicationVariableModule } from 'src/engine/core-modules/applicationVariable/application-variable.module';
|
||||
import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-v2.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -31,6 +32,7 @@ import { ApplicationVariableModule } from 'src/engine/core-modules/applicationVa
|
||||
DatabaseEventTriggerModule,
|
||||
CronTriggerModule,
|
||||
RouteTriggerModule,
|
||||
WorkspaceMigrationV2Module,
|
||||
],
|
||||
providers: [ApplicationResolver, ApplicationService, ApplicationSyncService],
|
||||
})
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { UseFilters, UseGuards } from '@nestjs/common';
|
||||
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { ApplicationSyncService } from 'src/engine/core-modules/application/application-sync.service';
|
||||
import { ApplicationInput } from 'src/engine/core-modules/application/dtos/application.input';
|
||||
import { DeleteApplicationInput } from 'src/engine/core-modules/application/dtos/deleteApplication.input';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { RequireFeatureFlag } from 'src/engine/guards/feature-flag.guard';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { ApplicationDTO } from 'src/engine/core-modules/application/dtos/application.dto';
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { ApplicationExceptionFilter } from 'src/engine/core-modules/application/application-exception-filter';
|
||||
import { ApplicationSyncService } from 'src/engine/core-modules/application/application-sync.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { ApplicationDTO } from 'src/engine/core-modules/application/dtos/application.dto';
|
||||
import { ApplicationInput } from 'src/engine/core-modules/application/dtos/application.input';
|
||||
import { DeleteApplicationInput } from 'src/engine/core-modules/application/dtos/deleteApplication.input';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { RequireFeatureFlag } from 'src/engine/guards/feature-flag.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
@Resolver()
|
||||
@@ -58,10 +58,10 @@ export class ApplicationResolver {
|
||||
@Args() { packageJson }: DeleteApplicationInput,
|
||||
@AuthWorkspace() { id: workspaceId }: Workspace,
|
||||
) {
|
||||
await this.applicationService.delete(
|
||||
packageJson.universalIdentifier,
|
||||
await this.applicationSyncService.deleteApplication({
|
||||
applicationUniversalIdentifier: packageJson.universalIdentifier,
|
||||
workspaceId,
|
||||
);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { In, Not, Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationVariable } from 'src/engine/core-modules/applicationVariable/application-variable.entity';
|
||||
@@ -37,6 +38,10 @@ export class ApplicationVariableService {
|
||||
>;
|
||||
applicationId: string;
|
||||
}) {
|
||||
if (!isDefined(env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const [key, { value, description, isSecret }] of Object.entries(env)) {
|
||||
await this.applicationVariableRepository.upsert(
|
||||
{
|
||||
|
||||
@@ -12,9 +12,9 @@ import {
|
||||
} from 'typeorm';
|
||||
|
||||
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/workspace-sync/interfaces/syncable-entity.interface';
|
||||
|
||||
import { ModelId } from 'src/engine/core-modules/ai/constants/ai-models.const';
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { ModelConfiguration } from 'src/engine/metadata-modules/agent/types/modelConfiguration';
|
||||
|
||||
@@ -27,12 +27,15 @@ import { AgentHandoffEntity } from './agent-handoff.entity';
|
||||
unique: true,
|
||||
where: '"deletedAt" IS NULL',
|
||||
})
|
||||
export class AgentEntity {
|
||||
export class AgentEntity
|
||||
extends SyncableEntity
|
||||
implements Required<AgentEntity>
|
||||
{
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
standardId?: string;
|
||||
standardId: string | null;
|
||||
|
||||
@Column({ nullable: false })
|
||||
name: string;
|
||||
@@ -58,9 +61,6 @@ export class AgentEntity {
|
||||
@Column({ nullable: false, type: 'uuid' })
|
||||
workspaceId: string;
|
||||
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
applicationId: string | null;
|
||||
|
||||
@Column({ default: false })
|
||||
isCustom: boolean;
|
||||
|
||||
@@ -70,13 +70,6 @@ export class AgentEntity {
|
||||
@JoinColumn({ name: 'workspaceId' })
|
||||
workspace: Relation<Workspace>;
|
||||
|
||||
@ManyToOne(() => ApplicationEntity, (application) => application.agents, {
|
||||
onDelete: 'CASCADE',
|
||||
nullable: true,
|
||||
})
|
||||
@JoinColumn({ name: 'applicationId' })
|
||||
application: Relation<ApplicationEntity> | null;
|
||||
|
||||
@OneToMany(() => AgentChatThreadEntity, (chatThread) => chatThread.agent)
|
||||
chatThreads: Relation<AgentChatThreadEntity[]>;
|
||||
|
||||
@@ -93,7 +86,7 @@ export class AgentEntity {
|
||||
updatedAt: Date;
|
||||
|
||||
@DeleteDateColumn({ type: 'timestamptz' })
|
||||
deletedAt?: Date;
|
||||
deletedAt: Date | null;
|
||||
|
||||
@Column({ nullable: true, type: 'jsonb' })
|
||||
modelConfiguration: ModelConfiguration;
|
||||
|
||||
@@ -21,7 +21,7 @@ export class AgentDTO {
|
||||
id: string;
|
||||
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
standardId?: string;
|
||||
standardId: string | null;
|
||||
|
||||
@IsString()
|
||||
@Field()
|
||||
|
||||
@@ -19,4 +19,7 @@ export class CreateCronTriggerInput {
|
||||
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
@HideField()
|
||||
applicationId?: string;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,10 @@ export const CRON_TRIGGER_ENTITY_RELATION_PROPERTIES = [
|
||||
|
||||
@Entity({ name: 'cronTrigger', schema: 'core' })
|
||||
@Index('IDX_CRON_TRIGGER_WORKSPACE_ID', ['workspaceId'])
|
||||
export class CronTrigger extends SyncableEntity {
|
||||
export class CronTrigger
|
||||
extends SyncableEntity
|
||||
implements Required<CronTrigger>
|
||||
{
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { FlatCronTrigger } from 'src/engine/metadata-modules/cron-trigger/types/flat-cron-trigger.type';
|
||||
import { EMPTY_FLAT_ENTITY_MAPS } from 'src/engine/metadata-modules/flat-entity/constant/empty-flat-entity-maps.constant';
|
||||
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
|
||||
import { WorkspaceFlatMapCache } from 'src/engine/workspace-flat-map-cache/decorators/workspace-flat-map-cache.decorator';
|
||||
import { WorkspaceFlatMapCacheService } from 'src/engine/workspace-flat-map-cache/services/workspace-flat-map-cache.service';
|
||||
|
||||
@@ -42,28 +43,19 @@ export class WorkspaceFlatCronTriggerMapCacheService extends WorkspaceFlatMapCac
|
||||
},
|
||||
});
|
||||
|
||||
const flatCronTriggerMaps = cronTriggers.reduce<
|
||||
FlatEntityMaps<FlatCronTrigger>
|
||||
>((flatEntityMaps, cronTrigger) => {
|
||||
return cronTriggers.reduce((flatCronTriggerMaps, cronTriggerEntity) => {
|
||||
const flatCronTrigger = {
|
||||
...removePropertiesFromRecord(cronTrigger, [
|
||||
...removePropertiesFromRecord(cronTriggerEntity, [
|
||||
...CRON_TRIGGER_ENTITY_RELATION_PROPERTIES,
|
||||
]),
|
||||
universalIdentifier: cronTrigger.universalIdentifier ?? cronTrigger.id,
|
||||
universalIdentifier:
|
||||
cronTriggerEntity.universalIdentifier ?? cronTriggerEntity.id,
|
||||
} satisfies FlatCronTrigger;
|
||||
|
||||
return {
|
||||
byId: {
|
||||
...flatEntityMaps.byId,
|
||||
[flatCronTrigger.id]: flatCronTrigger,
|
||||
},
|
||||
idByUniversalIdentifier: {
|
||||
...flatEntityMaps.idByUniversalIdentifier,
|
||||
[flatCronTrigger.universalIdentifier]: flatCronTrigger.id,
|
||||
},
|
||||
};
|
||||
return addFlatEntityToFlatEntityMapsOrThrow({
|
||||
flatEntity: flatCronTrigger,
|
||||
flatEntityMaps: flatCronTriggerMaps,
|
||||
});
|
||||
}, EMPTY_FLAT_ENTITY_MAPS);
|
||||
|
||||
return flatCronTriggerMaps;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { type CronTrigger } from 'src/engine/metadata-modules/cron-trigger/entities/cron-trigger.entity';
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
import { type ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
import { type ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type';
|
||||
|
||||
@@ -9,9 +10,7 @@ export type CronTriggerEntityRelationProperties =
|
||||
ServerlessFunctionEntity | Workspace
|
||||
>;
|
||||
|
||||
export type FlatCronTrigger = Omit<
|
||||
export type FlatCronTrigger = FlatEntityFrom<
|
||||
CronTrigger,
|
||||
CronTriggerEntityRelationProperties
|
||||
> & {
|
||||
universalIdentifier: string;
|
||||
};
|
||||
>;
|
||||
|
||||
@@ -17,6 +17,7 @@ export const fromCreateCronTriggerInputToFlatCronTrigger = ({
|
||||
universalIdentifier: createCronTriggerInput.universalIdentifier ?? v4(),
|
||||
settings: createCronTriggerInput.settings,
|
||||
serverlessFunctionId: createCronTriggerInput.serverlessFunctionId,
|
||||
applicationId: createCronTriggerInput.applicationId ?? null,
|
||||
workspaceId,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
|
||||
@@ -19,4 +19,7 @@ export class CreateDatabaseEventTriggerInput {
|
||||
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
@HideField()
|
||||
applicationId?: string;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { FlatDatabaseEventTrigger } from 'src/engine/metadata-modules/database-event-trigger/types/flat-database-event-trigger.type';
|
||||
import { EMPTY_FLAT_ENTITY_MAPS } from 'src/engine/metadata-modules/flat-entity/constant/empty-flat-entity-maps.constant';
|
||||
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
|
||||
import { WorkspaceFlatMapCache } from 'src/engine/workspace-flat-map-cache/decorators/workspace-flat-map-cache.decorator';
|
||||
import { WorkspaceFlatMapCacheService } from 'src/engine/workspace-flat-map-cache/services/workspace-flat-map-cache.service';
|
||||
|
||||
@@ -43,29 +44,23 @@ export class WorkspaceFlatDatabaseEventTriggerMapCacheService extends WorkspaceF
|
||||
},
|
||||
});
|
||||
|
||||
const flatDatabaseEventTriggerMaps = databaseEventTriggers.reduce<
|
||||
FlatEntityMaps<FlatDatabaseEventTrigger>
|
||||
>((flatEntityMaps, databaseEventTrigger) => {
|
||||
const flatDatabaseEventTrigger = {
|
||||
...removePropertiesFromRecord(databaseEventTrigger, [
|
||||
...DATABASE_EVENT_TRIGGER_ENTITY_RELATION_PROPERTIES,
|
||||
]),
|
||||
universalIdentifier: databaseEventTrigger.universalIdentifier ?? '',
|
||||
} satisfies FlatDatabaseEventTrigger;
|
||||
return databaseEventTriggers.reduce(
|
||||
(flatDatabaseEventTriggerMaps, databaseEventTriggerEntity) => {
|
||||
const flatDatabaseEventTrigger = {
|
||||
...removePropertiesFromRecord(databaseEventTriggerEntity, [
|
||||
...DATABASE_EVENT_TRIGGER_ENTITY_RELATION_PROPERTIES,
|
||||
]),
|
||||
universalIdentifier:
|
||||
databaseEventTriggerEntity.universalIdentifier ??
|
||||
databaseEventTriggerEntity.id,
|
||||
} satisfies FlatDatabaseEventTrigger;
|
||||
|
||||
return {
|
||||
byId: {
|
||||
...flatEntityMaps.byId,
|
||||
[flatDatabaseEventTrigger.id]: flatDatabaseEventTrigger,
|
||||
},
|
||||
idByUniversalIdentifier: {
|
||||
...flatEntityMaps.idByUniversalIdentifier,
|
||||
[flatDatabaseEventTrigger.universalIdentifier]:
|
||||
flatDatabaseEventTrigger.id,
|
||||
},
|
||||
};
|
||||
}, EMPTY_FLAT_ENTITY_MAPS);
|
||||
|
||||
return flatDatabaseEventTriggerMaps;
|
||||
return addFlatEntityToFlatEntityMapsOrThrow({
|
||||
flatEntity: flatDatabaseEventTrigger,
|
||||
flatEntityMaps: flatDatabaseEventTriggerMaps,
|
||||
});
|
||||
},
|
||||
EMPTY_FLAT_ENTITY_MAPS,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { type DatabaseEventTrigger } from 'src/engine/metadata-modules/database-event-trigger/entities/database-event-trigger.entity';
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
import { type ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
import { type ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type';
|
||||
|
||||
@@ -9,9 +10,7 @@ export type DatabaseEventTriggerEntityRelationProperties =
|
||||
ServerlessFunctionEntity | Workspace
|
||||
>;
|
||||
|
||||
export type FlatDatabaseEventTrigger = Omit<
|
||||
export type FlatDatabaseEventTrigger = FlatEntityFrom<
|
||||
DatabaseEventTrigger,
|
||||
DatabaseEventTriggerEntityRelationProperties
|
||||
> & {
|
||||
universalIdentifier: string;
|
||||
};
|
||||
>;
|
||||
|
||||
@@ -21,5 +21,6 @@ export const fromCreateDatabaseEventTriggerInputToFlatDatabaseEventTrigger = ({
|
||||
workspaceId,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
applicationId: createDatabaseEventTriggerInput.applicationId ?? null,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
import { FieldMetadataDefaultValue } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface';
|
||||
import { FieldMetadataOptions } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-options.interface';
|
||||
import { FieldMetadataSettings } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/workspace-sync/interfaces/syncable-entity.interface';
|
||||
|
||||
import { type FieldStandardOverridesDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-standard-overrides.dto';
|
||||
import { AssignIfIsGivenFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/assign-if-is-given-field-metadata-type.type';
|
||||
@@ -49,10 +50,11 @@ import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities
|
||||
'objectMetadataId',
|
||||
'workspaceId',
|
||||
])
|
||||
// TODO add some documentation about this entity
|
||||
export class FieldMetadataEntity<
|
||||
TFieldMetadataType extends FieldMetadataType = FieldMetadataType,
|
||||
> implements Required<FieldMetadataEntity>
|
||||
TFieldMetadataType extends FieldMetadataType = FieldMetadataType,
|
||||
>
|
||||
extends SyncableEntity
|
||||
implements Required<FieldMetadataEntity>
|
||||
{
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { type AgentEntity } from 'src/engine/metadata-modules/agent/agent.entity';
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
|
||||
export const agentEntityRelationProperties = [
|
||||
'workspace',
|
||||
@@ -11,9 +12,7 @@ export const agentEntityRelationProperties = [
|
||||
export type AgentEntityRelationProperties =
|
||||
(typeof agentEntityRelationProperties)[number];
|
||||
|
||||
export type FlatAgent = Omit<
|
||||
export type FlatAgent = FlatEntityFrom<
|
||||
AgentEntity,
|
||||
AgentEntityRelationProperties | 'createdAt' | 'updatedAt' | 'deletedAt'
|
||||
> & {
|
||||
universalIdentifier: string;
|
||||
};
|
||||
>;
|
||||
|
||||
@@ -4,4 +4,5 @@ import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/f
|
||||
export const EMPTY_FLAT_ENTITY_MAPS = {
|
||||
byId: {},
|
||||
idByUniversalIdentifier: {},
|
||||
universalIdentifiersByApplicationId: {},
|
||||
} as const satisfies FlatEntityMaps<FlatEntity>;
|
||||
|
||||
@@ -3,4 +3,5 @@ import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/f
|
||||
export type FlatEntityMaps<T extends FlatEntity> = {
|
||||
byId: Partial<Record<string, T>>;
|
||||
idByUniversalIdentifier: Partial<Record<string, string>>;
|
||||
universalIdentifiersByApplicationId: Partial<Record<string, string[]>>;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,22 @@
|
||||
export interface FlatEntity {
|
||||
import { type SyncableEntity } from 'src/engine/workspace-manager/workspace-sync/interfaces/syncable-entity.interface';
|
||||
|
||||
import { type ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { type ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type';
|
||||
import { type NonNullableProperties } from 'src/types/non-nullable-properties.type';
|
||||
|
||||
export type SyncableEntityRelationProperties =
|
||||
ExtractRecordTypeOrmRelationProperties<SyncableEntity, ApplicationEntity>;
|
||||
|
||||
export interface FlatEntity
|
||||
extends NonNullableProperties<
|
||||
Omit<SyncableEntity, SyncableEntityRelationProperties | 'applicationId'>
|
||||
> {
|
||||
id: string;
|
||||
universalIdentifier: string;
|
||||
applicationId: string | null;
|
||||
}
|
||||
|
||||
export type FlatEntityFrom<
|
||||
TEntity extends SyncableEntity,
|
||||
TEntityRelationProperties extends keyof TEntity,
|
||||
> = FlatEntity &
|
||||
Omit<TEntity, TEntityRelationProperties | SyncableEntityRelationProperties>;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isDefined } from 'class-validator';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import {
|
||||
FlatEntityMapsException,
|
||||
@@ -32,5 +32,20 @@ export const addFlatEntityToFlatEntityMapsOrThrow = <T extends FlatEntity>({
|
||||
...flatEntityMaps.idByUniversalIdentifier,
|
||||
[flatEntity.universalIdentifier]: flatEntity.id,
|
||||
},
|
||||
universalIdentifiersByApplicationId: {
|
||||
...flatEntityMaps.universalIdentifiersByApplicationId,
|
||||
...(isDefined(flatEntity.applicationId)
|
||||
? {
|
||||
[flatEntity.applicationId]: Array.from(
|
||||
new Set([
|
||||
...(flatEntityMaps.universalIdentifiersByApplicationId?.[
|
||||
flatEntity.applicationId
|
||||
] ?? []),
|
||||
flatEntity.universalIdentifier,
|
||||
]),
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
|
||||
|
||||
import {
|
||||
@@ -31,10 +32,36 @@ export const deleteFlatEntityFromFlatEntityMapsOrThrow = <
|
||||
flatEntityMaps.idByUniversalIdentifier,
|
||||
).filter(([_universalIdentifier, id]) => id !== entityToDeleteId);
|
||||
|
||||
const updatedUniversalIdentifiersByApplicationIdEntries = Object.entries(
|
||||
flatEntityMaps.universalIdentifiersByApplicationId,
|
||||
)
|
||||
.map(([applicationId, universalIdentifiers]) => {
|
||||
const stillPresentUniversalIdentifiers = universalIdentifiers?.filter(
|
||||
(universalIdentifier) =>
|
||||
updatedIdByUniversalIdentifierEntries.some(
|
||||
([existingUniversalIdentifier]) =>
|
||||
existingUniversalIdentifier === universalIdentifier,
|
||||
),
|
||||
);
|
||||
|
||||
if (
|
||||
isDefined(stillPresentUniversalIdentifiers) ||
|
||||
isEmpty(stillPresentUniversalIdentifiers)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return [applicationId, stillPresentUniversalIdentifiers];
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
return {
|
||||
byId: removePropertiesFromRecord(flatEntityMaps.byId, [entityToDeleteId]),
|
||||
idByUniversalIdentifier: Object.fromEntries(
|
||||
updatedIdByUniversalIdentifierEntries,
|
||||
),
|
||||
universalIdentifiersByApplicationId: Object.fromEntries(
|
||||
updatedUniversalIdentifiersByApplicationIdEntries,
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
|
||||
export const getFlatEntitiesByApplicationId = <T extends FlatEntity>(
|
||||
maps: FlatEntityMaps<T>,
|
||||
applicationId: string,
|
||||
): T[] => {
|
||||
const universalIdentifiers =
|
||||
maps.universalIdentifiersByApplicationId[applicationId];
|
||||
|
||||
if (!isDefined(universalIdentifiers)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return universalIdentifiers
|
||||
.map((universalId) => {
|
||||
const id = maps.idByUniversalIdentifier[universalId];
|
||||
|
||||
if (!isDefined(id)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const entity = maps.byId[id];
|
||||
|
||||
if (!isDefined(entity)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (entity.applicationId !== applicationId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return entity;
|
||||
})
|
||||
.filter(isDefined);
|
||||
};
|
||||
@@ -43,7 +43,7 @@ export const getFlatFieldMetadataMock = <T extends FieldMetadataType>(
|
||||
standardId: null,
|
||||
standardOverrides: null,
|
||||
workspaceId: faker.string.uuid(),
|
||||
|
||||
applicationId: faker.string.uuid(),
|
||||
relationTargetFieldMetadataId: null,
|
||||
relationTargetObjectMetadataId: null,
|
||||
...overrides,
|
||||
|
||||
@@ -62,5 +62,6 @@ export const getRelationTargetFlatFieldMetadataMock = ({
|
||||
...overrides,
|
||||
defaultValue: null,
|
||||
options: null,
|
||||
applicationId: faker.string.uuid(),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -104,6 +104,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"result": {
|
||||
"flatFieldMetadatas": [
|
||||
{
|
||||
"applicationId": null,
|
||||
"createdAt": Any<ClockDate>,
|
||||
"defaultValue": null,
|
||||
"description": "new field description",
|
||||
@@ -137,6 +138,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"workspaceId": Any<String>,
|
||||
},
|
||||
{
|
||||
"applicationId": null,
|
||||
"createdAt": Any<ClockDate>,
|
||||
"defaultValue": null,
|
||||
"description": null,
|
||||
@@ -172,6 +174,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"workspaceId": Any<String>,
|
||||
},
|
||||
{
|
||||
"applicationId": null,
|
||||
"createdAt": Any<ClockDate>,
|
||||
"defaultValue": null,
|
||||
"description": "new field description",
|
||||
@@ -205,6 +208,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"workspaceId": Any<String>,
|
||||
},
|
||||
{
|
||||
"applicationId": null,
|
||||
"createdAt": Any<ClockDate>,
|
||||
"defaultValue": null,
|
||||
"description": null,
|
||||
@@ -242,6 +246,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
],
|
||||
"indexMetadatas": [
|
||||
{
|
||||
"applicationId": null,
|
||||
"createdAt": Any<ClockDate>,
|
||||
"flatIndexFieldMetadatas": [
|
||||
{
|
||||
@@ -265,6 +270,7 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"workspaceId": Any<String>,
|
||||
},
|
||||
{
|
||||
"applicationId": null,
|
||||
"createdAt": Any<ClockDate>,
|
||||
"flatIndexFieldMetadatas": [
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ export const FIELD_METADATA_RELATION_PROPERTIES = [
|
||||
'indexFieldMetadatas',
|
||||
'object',
|
||||
'viewFields',
|
||||
'application',
|
||||
'viewFilters',
|
||||
'viewGroups',
|
||||
] as const satisfies (keyof FieldMetadataEntity)[];
|
||||
|
||||
@@ -44,6 +44,7 @@ export const generateIndexForFlatFieldMetadata = ({
|
||||
universalIdentifier: indexId,
|
||||
updatedAt: createdAt,
|
||||
workspaceId,
|
||||
applicationId: null,
|
||||
},
|
||||
flatObjectMetadata,
|
||||
},
|
||||
|
||||
@@ -54,6 +54,7 @@ export const getDefaultFlatFieldMetadata = ({
|
||||
updatedAt: createdAt,
|
||||
isUIReadOnly: createFieldInput.isUIReadOnly ?? false,
|
||||
morphId: null,
|
||||
applicationId: null,
|
||||
viewFilterIds: [],
|
||||
viewGroupIds: [],
|
||||
} as const satisfies FlatFieldMetadata;
|
||||
|
||||
@@ -71,6 +71,7 @@ export const recomputeViewGroupsOnEnumFlatFieldMetadataIsNullableUpdate = ({
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
viewId,
|
||||
applicationId: toFlatFieldMetadata.applicationId,
|
||||
});
|
||||
} else if (isDefined(emptyValueFlatViewGroup)) {
|
||||
sideEffectResult.flatViewGroupsToDelete.push(emptyValueFlatViewGroup);
|
||||
|
||||
@@ -109,6 +109,7 @@ export const recomputeViewGroupsOnFlatFieldMetadataOptionsUpdate = ({
|
||||
isVisible: true,
|
||||
fieldValue: option.value,
|
||||
position: viewGroupHighestPosition + createdOptionIndex + 1,
|
||||
applicationId: fromFlatFieldMetadata.applicationId,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -23,6 +23,7 @@ export const getFlatIndexMetadataMock = (
|
||||
name: 'defaultFlatIndexMetadataName',
|
||||
updatedAt: createdAt,
|
||||
workspaceId: faker.string.uuid(),
|
||||
applicationId: faker.string.uuid(),
|
||||
...overrides,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
import { type IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity';
|
||||
import { type IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
import { type ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type';
|
||||
@@ -9,6 +10,7 @@ export type IndexMetadataRelationProperties =
|
||||
MetadataEntitiesRelationTarget
|
||||
>;
|
||||
|
||||
// Can't use FlatEntityFrom here because IndexFieldMetadataEntity is not a SyncableEntity
|
||||
export type FlatIndexFieldMetadata = Omit<
|
||||
IndexFieldMetadataEntity,
|
||||
ExtractRecordTypeOrmRelationProperties<
|
||||
@@ -17,7 +19,7 @@ export type FlatIndexFieldMetadata = Omit<
|
||||
>
|
||||
>;
|
||||
|
||||
export type FlatIndexMetadata = Omit<
|
||||
export type FlatIndexMetadata = FlatEntityFrom<
|
||||
IndexMetadataEntity,
|
||||
IndexMetadataRelationProperties
|
||||
> & {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { CacheStorageService } from 'src/engine/core-modules/cache-storage/servi
|
||||
import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum';
|
||||
import { EMPTY_FLAT_ENTITY_MAPS } from 'src/engine/metadata-modules/flat-entity/constant/empty-flat-entity-maps.constant';
|
||||
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
|
||||
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { fromObjectMetadataEntityToFlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-object-metadata-entity-to-flat-object-metadata.util';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
@@ -53,24 +54,17 @@ export class WorkspaceFlatObjectMetadataMapCacheService extends WorkspaceFlatMap
|
||||
relations: ['fields', 'indexMetadatas', 'views'],
|
||||
});
|
||||
|
||||
const flatObjectMetadataMaps = objectMetadatas.reduce<
|
||||
FlatEntityMaps<FlatObjectMetadata>
|
||||
>((flatEntityMaps, object) => {
|
||||
const flatObjectMetadata =
|
||||
fromObjectMetadataEntityToFlatObjectMetadata(object);
|
||||
return objectMetadatas.reduce(
|
||||
(flatObjectMetadataMaps, objectMetadataEntity) => {
|
||||
const flatObjectMetadata =
|
||||
fromObjectMetadataEntityToFlatObjectMetadata(objectMetadataEntity);
|
||||
|
||||
return {
|
||||
byId: {
|
||||
...flatEntityMaps.byId,
|
||||
[flatObjectMetadata.id]: flatObjectMetadata,
|
||||
},
|
||||
idByUniversalIdentifier: {
|
||||
...flatEntityMaps.idByUniversalIdentifier,
|
||||
[flatObjectMetadata.universalIdentifier]: flatObjectMetadata.id,
|
||||
},
|
||||
};
|
||||
}, EMPTY_FLAT_ENTITY_MAPS);
|
||||
|
||||
return flatObjectMetadataMaps;
|
||||
return addFlatEntityToFlatEntityMapsOrThrow({
|
||||
flatEntity: flatObjectMetadata,
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
});
|
||||
},
|
||||
EMPTY_FLAT_ENTITY_MAPS,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { type ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type';
|
||||
import { type MetadataEntitiesRelationTarget } from 'src/engine/workspace-manager/workspace-migration-v2/types/metadata-entities-relation-targets.type';
|
||||
@@ -18,11 +19,10 @@ type ObjectMetadataRelationProperties = ExtractRecordTypeOrmRelationProperties<
|
||||
MetadataEntitiesRelationTarget
|
||||
>;
|
||||
|
||||
export type FlatObjectMetadata = Omit<
|
||||
export type FlatObjectMetadata = FlatEntityFrom<
|
||||
ObjectMetadataEntity,
|
||||
ObjectMetadataRelationProperties | 'dataSourceId'
|
||||
> & {
|
||||
universalIdentifier: string;
|
||||
fieldMetadataIds: string[];
|
||||
indexMetadataIds: string[];
|
||||
viewIds: string[];
|
||||
|
||||
@@ -48,6 +48,7 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre
|
||||
buildDefaultFlatFieldMetadatasForCustomObject({
|
||||
flatObjectMetadata: {
|
||||
id: objectMetadataId,
|
||||
applicationId: createObjectInput.applicationId ?? null,
|
||||
},
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
@@ -66,6 +66,7 @@ export const recomputeViewFieldIdentifierAfterFlatObjectIdentifierUpdate = ({
|
||||
deletedAt: null,
|
||||
universalIdentifier: viewFieldId,
|
||||
aggregateOperation: null,
|
||||
applicationId: existingFlatObjectMetadata.applicationId,
|
||||
};
|
||||
|
||||
accumulator.flatViewFieldToCreate.push(flatViewFieldToCreate);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
import { type RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
|
||||
export const roleEntityRelationProperties = [
|
||||
@@ -10,9 +11,7 @@ export const roleEntityRelationProperties = [
|
||||
export type RoleEntityRelationProperties =
|
||||
(typeof roleEntityRelationProperties)[number];
|
||||
|
||||
export type FlatRole = Omit<
|
||||
export type FlatRole = FlatEntityFrom<
|
||||
RoleEntity,
|
||||
RoleEntityRelationProperties | 'createdAt' | 'updatedAt'
|
||||
> & {
|
||||
universalIdentifier: string;
|
||||
};
|
||||
>;
|
||||
|
||||
@@ -20,5 +20,6 @@ export const fromRoleEntityToFlatRole = (role: RoleEntity): FlatRole => {
|
||||
canBeAssignedToApiKeys: role.canBeAssignedToApiKeys,
|
||||
workspaceId: role.workspaceId,
|
||||
universalIdentifier: role.standardId || role.id,
|
||||
applicationId: role.applicationId ?? null,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
import { type ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { type ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { type ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type';
|
||||
@@ -10,9 +11,7 @@ export type ViewFieldEntityRelationProperties =
|
||||
FieldMetadataEntity | ViewEntity | Workspace
|
||||
>;
|
||||
|
||||
export type FlatViewField = Omit<
|
||||
export type FlatViewField = FlatEntityFrom<
|
||||
ViewFieldEntity,
|
||||
ViewFieldEntityRelationProperties
|
||||
> & {
|
||||
universalIdentifier: string;
|
||||
};
|
||||
>;
|
||||
|
||||
@@ -29,10 +29,12 @@ export const fromCreateViewFieldInputToFlatViewFieldToCreate = ({
|
||||
createdAt: createdAt,
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
universalIdentifier: viewFieldId,
|
||||
universalIdentifier:
|
||||
createViewFieldInput.universalIdentifier ?? viewFieldId,
|
||||
isVisible: createViewFieldInput.isVisible ?? true,
|
||||
size: createViewFieldInput.size ?? DEFAULT_VIEW_FIELD_SIZE,
|
||||
position: createViewFieldInput.position ?? 0,
|
||||
aggregateOperation: createViewFieldInput.aggregateOperation ?? null,
|
||||
applicationId: createViewFieldInput.applicationId ?? null,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
import { type ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity';
|
||||
import { type ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity';
|
||||
import { type ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
@@ -11,9 +12,7 @@ export type ViewFilterEntityRelationProperties =
|
||||
FieldMetadataEntity | ViewEntity | ViewFilterGroupEntity | Workspace
|
||||
>;
|
||||
|
||||
export type FlatViewFilter = Omit<
|
||||
export type FlatViewFilter = FlatEntityFrom<
|
||||
ViewFilterEntity,
|
||||
ViewFilterEntityRelationProperties
|
||||
> & {
|
||||
universalIdentifier: string;
|
||||
};
|
||||
>;
|
||||
|
||||
@@ -36,12 +36,14 @@ export const fromCreateViewFilterInputToFlatViewFilterToCreate = ({
|
||||
createdAt: createdAt,
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
universalIdentifier: viewFilterId,
|
||||
universalIdentifier:
|
||||
createViewFilterInput.universalIdentifier ?? viewFilterId,
|
||||
operand: createViewFilterInput.operand ?? ViewFilterOperand.CONTAINS,
|
||||
value: value,
|
||||
viewFilterGroupId: createViewFilterInput.viewFilterGroupId ?? null,
|
||||
positionInViewFilterGroup:
|
||||
createViewFilterInput.positionInViewFilterGroup ?? null,
|
||||
subFieldName: createViewFilterInput.subFieldName ?? null,
|
||||
applicationId: createViewFilterInput.applicationId ?? null,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
import { type ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity';
|
||||
import { type ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { type ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type';
|
||||
@@ -10,9 +11,7 @@ export type ViewGroupEntityRelationProperties =
|
||||
FieldMetadataEntity | ViewEntity | Workspace
|
||||
>;
|
||||
|
||||
export type FlatViewGroup = Omit<
|
||||
export type FlatViewGroup = FlatEntityFrom<
|
||||
ViewGroupEntity,
|
||||
ViewGroupEntityRelationProperties
|
||||
> & {
|
||||
universalIdentifier: string;
|
||||
};
|
||||
>;
|
||||
|
||||
@@ -28,9 +28,11 @@ export const fromCreateViewGroupInputToFlatViewGroupToCreate = ({
|
||||
createdAt: createdAt,
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
universalIdentifier: viewGroupId,
|
||||
universalIdentifier:
|
||||
createViewGroupInput.universalIdentifier ?? viewGroupId,
|
||||
isVisible: createViewGroupInput.isVisible ?? true,
|
||||
fieldValue: createViewGroupInput.fieldValue,
|
||||
position: createViewGroupInput.position ?? 0,
|
||||
applicationId: createViewGroupInput.applicationId ?? null,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { type Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { type ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { type ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity';
|
||||
@@ -20,8 +21,10 @@ export type ViewEntityRelationProperties =
|
||||
| Workspace
|
||||
>;
|
||||
|
||||
export type FlatView = Omit<ViewEntity, ViewEntityRelationProperties> & {
|
||||
universalIdentifier: string;
|
||||
export type FlatView = FlatEntityFrom<
|
||||
ViewEntity,
|
||||
ViewEntityRelationProperties
|
||||
> & {
|
||||
viewFieldIds: string[];
|
||||
viewFilterIds: string[];
|
||||
viewGroupIds: string[];
|
||||
|
||||
@@ -20,9 +20,10 @@ export const fromCreateViewInputToFlatViewToCreate = ({
|
||||
);
|
||||
|
||||
const createdAt = new Date();
|
||||
const viewId = createViewInput.id ?? v4();
|
||||
|
||||
return {
|
||||
id: createViewInput.id ?? v4(),
|
||||
id: viewId,
|
||||
objectMetadataId,
|
||||
workspaceId,
|
||||
name: createViewInput.name,
|
||||
@@ -42,9 +43,10 @@ export const fromCreateViewInputToFlatViewToCreate = ({
|
||||
openRecordIn: createViewInput.openRecordIn ?? ViewOpenRecordIn.SIDE_PANEL,
|
||||
position: createViewInput.position ?? 0,
|
||||
type: createViewInput.type ?? ViewType.TABLE,
|
||||
universalIdentifier: v4(),
|
||||
universalIdentifier: createViewInput.universalIdentifier ?? viewId,
|
||||
viewFieldIds: [],
|
||||
viewFilterIds: [],
|
||||
viewGroupIds: [],
|
||||
applicationId: createViewInput.applicationId ?? null,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
@@ -11,8 +10,9 @@ import {
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/workspace-sync/interfaces/syncable-entity.interface';
|
||||
|
||||
import { type WorkspaceEntityDuplicateCriteria } from 'src/engine/api/graphql/workspace-query-builder/types/workspace-entity-duplicate-criteria.type';
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
|
||||
@@ -30,16 +30,16 @@ import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entit
|
||||
'namePlural',
|
||||
'workspaceId',
|
||||
])
|
||||
export class ObjectMetadataEntity implements Required<ObjectMetadataEntity> {
|
||||
export class ObjectMetadataEntity
|
||||
extends SyncableEntity
|
||||
implements Required<ObjectMetadataEntity>
|
||||
{
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
standardId: string | null;
|
||||
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
applicationId: string | null;
|
||||
|
||||
@Column({ nullable: false, type: 'uuid' })
|
||||
dataSourceId: string;
|
||||
|
||||
@@ -137,13 +137,6 @@ export class ObjectMetadataEntity implements Required<ObjectMetadataEntity> {
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt: Date;
|
||||
|
||||
@ManyToOne(() => ApplicationEntity, (application) => application.objects, {
|
||||
onDelete: 'CASCADE',
|
||||
nullable: true,
|
||||
})
|
||||
@JoinColumn({ name: 'applicationId' })
|
||||
application: Relation<ApplicationEntity> | null;
|
||||
|
||||
@OneToMany(
|
||||
() => ObjectPermissionEntity,
|
||||
(objectPermission) => objectPermission.objectMetadata,
|
||||
|
||||
@@ -12,7 +12,7 @@ import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-mana
|
||||
|
||||
type BuildDefaultFlatFieldMetadataForCustomObjectArgs = {
|
||||
workspaceId: string;
|
||||
flatObjectMetadata: Pick<FlatObjectMetadata, 'id'>;
|
||||
flatObjectMetadata: Pick<FlatObjectMetadata, 'id' | 'applicationId'>;
|
||||
};
|
||||
|
||||
export type DefaultFlatFieldForCustomObjectMaps = ReturnType<
|
||||
@@ -21,7 +21,7 @@ export type DefaultFlatFieldForCustomObjectMaps = ReturnType<
|
||||
// This could be replaced totally by an import schema + its transpilation when it's ready
|
||||
export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
workspaceId,
|
||||
flatObjectMetadata: { id: objectMetadataId },
|
||||
flatObjectMetadata: { id: objectMetadataId, applicationId },
|
||||
}: BuildDefaultFlatFieldMetadataForCustomObjectArgs) => {
|
||||
const createdAt = new Date();
|
||||
const idField: FlatFieldMetadata<FieldMetadataType.UUID> = {
|
||||
@@ -58,6 +58,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
relationTargetObjectMetadataId: null,
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId: applicationId ?? null,
|
||||
};
|
||||
|
||||
const nameField: FlatFieldMetadata<FieldMetadataType.TEXT> = {
|
||||
@@ -94,6 +95,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
relationTargetObjectMetadataId: null,
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId: applicationId ?? null,
|
||||
};
|
||||
|
||||
const createdAtField: FlatFieldMetadata<FieldMetadataType.DATE_TIME> = {
|
||||
@@ -130,6 +132,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
relationTargetObjectMetadataId: null,
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId: applicationId ?? null,
|
||||
};
|
||||
|
||||
const updatedAtField: FlatFieldMetadata<FieldMetadataType.DATE_TIME> = {
|
||||
@@ -166,6 +169,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
relationTargetObjectMetadataId: null,
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId: applicationId ?? null,
|
||||
};
|
||||
|
||||
const deletedAtField: FlatFieldMetadata<FieldMetadataType.DATE_TIME> = {
|
||||
@@ -202,6 +206,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
relationTargetObjectMetadataId: null,
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId: applicationId ?? null,
|
||||
};
|
||||
|
||||
const createdByField: FlatFieldMetadata<FieldMetadataType.ACTOR> = {
|
||||
@@ -237,6 +242,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
relationTargetObjectMetadataId: null,
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId: applicationId ?? null,
|
||||
};
|
||||
|
||||
const positionField: FlatFieldMetadata<FieldMetadataType.POSITION> = {
|
||||
@@ -273,6 +279,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
relationTargetObjectMetadataId: null,
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId: applicationId ?? null,
|
||||
};
|
||||
|
||||
const searchVectorField: FlatFieldMetadata<FieldMetadataType.TS_VECTOR> = {
|
||||
@@ -312,6 +319,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
generatedType: 'STORED',
|
||||
},
|
||||
morphId: null,
|
||||
applicationId: applicationId ?? null,
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -44,6 +44,7 @@ export const buildDefaultIndexesForCustomObject = ({
|
||||
universalIdentifier: tsFlatVectorIndexId,
|
||||
updatedAt: createdAt,
|
||||
workspaceId,
|
||||
applicationId: flatObjectMetadata.applicationId ?? null,
|
||||
},
|
||||
flatObjectMetadata,
|
||||
});
|
||||
|
||||
@@ -97,6 +97,7 @@ const generateSourceFlatFieldMetadata = ({
|
||||
]),
|
||||
workspaceId,
|
||||
morphId: null,
|
||||
applicationId: sourceFlatObjectMetadata.applicationId ?? null,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -165,6 +166,7 @@ const generateTargetFlatFieldMetadata = ({
|
||||
targetFlatObjectMetadata.id,
|
||||
standardId,
|
||||
]),
|
||||
applicationId: sourceFlatObjectMetadata.applicationId ?? null,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/workspace-sync/interfaces/syncable-entity.interface';
|
||||
|
||||
import { FieldPermissionEntity } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.entity';
|
||||
import { ObjectPermissionEntity } from 'src/engine/metadata-modules/object-permission/object-permission.entity';
|
||||
import { PermissionFlagEntity } from 'src/engine/metadata-modules/permission-flag/permission-flag.entity';
|
||||
@@ -16,7 +18,7 @@ import { RoleTargetsEntity } from 'src/engine/metadata-modules/role/role-targets
|
||||
|
||||
@Entity('role')
|
||||
@Unique('IDX_ROLE_LABEL_WORKSPACE_ID_UNIQUE', ['label', 'workspaceId'])
|
||||
export class RoleEntity {
|
||||
export class RoleEntity extends SyncableEntity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
|
||||
@@ -34,4 +34,7 @@ export class CreateRouteTriggerInput {
|
||||
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
@HideField()
|
||||
applicationId?: string;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { CacheStorageService } from 'src/engine/core-modules/cache-storage/servi
|
||||
import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum';
|
||||
import { EMPTY_FLAT_ENTITY_MAPS } from 'src/engine/metadata-modules/flat-entity/constant/empty-flat-entity-maps.constant';
|
||||
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
|
||||
import {
|
||||
ROUTE_TRIGGER_ENTITY_RELATION_PROPERTIES,
|
||||
RouteTrigger,
|
||||
@@ -42,28 +43,19 @@ export class WorkspaceFlatRouteTriggerMapCacheService extends WorkspaceFlatMapCa
|
||||
},
|
||||
});
|
||||
|
||||
const flatRouteTriggerMaps = routeTriggers.reduce<
|
||||
FlatEntityMaps<FlatRouteTrigger>
|
||||
>((flatEntityMaps, routeTrigger) => {
|
||||
return routeTriggers.reduce((flatRouteTriggerMaps, routeTriggerEntity) => {
|
||||
const flatRouteTrigger = {
|
||||
...removePropertiesFromRecord(routeTrigger, [
|
||||
...removePropertiesFromRecord(routeTriggerEntity, [
|
||||
...ROUTE_TRIGGER_ENTITY_RELATION_PROPERTIES,
|
||||
]),
|
||||
universalIdentifier: routeTrigger.universalIdentifier ?? '',
|
||||
universalIdentifier:
|
||||
routeTriggerEntity.universalIdentifier ?? routeTriggerEntity.id,
|
||||
} satisfies FlatRouteTrigger;
|
||||
|
||||
return {
|
||||
byId: {
|
||||
...flatEntityMaps.byId,
|
||||
[flatRouteTrigger.id]: flatRouteTrigger,
|
||||
},
|
||||
idByUniversalIdentifier: {
|
||||
...flatEntityMaps.idByUniversalIdentifier,
|
||||
[flatRouteTrigger.universalIdentifier]: flatRouteTrigger.id,
|
||||
},
|
||||
};
|
||||
return addFlatEntityToFlatEntityMapsOrThrow({
|
||||
flatEntity: flatRouteTrigger,
|
||||
flatEntityMaps: flatRouteTriggerMaps,
|
||||
});
|
||||
}, EMPTY_FLAT_ENTITY_MAPS);
|
||||
|
||||
return flatRouteTriggerMaps;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { type Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
import { type RouteTrigger } from 'src/engine/metadata-modules/route-trigger/route-trigger.entity';
|
||||
import { type ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
import { type ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type';
|
||||
@@ -9,9 +10,7 @@ export type RouteTriggerEntityRelationProperties =
|
||||
ServerlessFunctionEntity | Workspace
|
||||
>;
|
||||
|
||||
export type FlatRouteTrigger = Omit<
|
||||
export type FlatRouteTrigger = FlatEntityFrom<
|
||||
RouteTrigger,
|
||||
RouteTriggerEntityRelationProperties
|
||||
> & {
|
||||
universalIdentifier: string;
|
||||
};
|
||||
>;
|
||||
|
||||
@@ -23,5 +23,6 @@ export const fromCreateRouteTriggerInputToFlatRouteTrigger = ({
|
||||
workspaceId,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
applicationId: createRouteTriggerInput.applicationId ?? null,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
OneToMany,
|
||||
OneToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
Relation,
|
||||
UpdateDateColumn,
|
||||
@@ -11,7 +10,6 @@ import {
|
||||
|
||||
import { PackageJson } from 'src/engine/core-modules/application/types/application.types';
|
||||
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
|
||||
@Entity('serverlessFunctionLayer')
|
||||
export class ServerlessFunctionLayerEntity {
|
||||
@@ -39,15 +37,6 @@ export class ServerlessFunctionLayerEntity {
|
||||
)
|
||||
serverlessFunctions: Relation<ServerlessFunctionEntity[]>;
|
||||
|
||||
@OneToOne(
|
||||
() => ApplicationEntity,
|
||||
(application) => application.serverlessFunctionLayer,
|
||||
{
|
||||
nullable: true,
|
||||
},
|
||||
)
|
||||
application: Relation<ApplicationEntity> | null;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
@@ -18,9 +18,8 @@ import { SyncableEntity } from 'src/engine/workspace-manager/workspace-sync/inte
|
||||
import { CronTrigger } from 'src/engine/metadata-modules/cron-trigger/entities/cron-trigger.entity';
|
||||
import { DatabaseEventTrigger } from 'src/engine/metadata-modules/database-event-trigger/entities/database-event-trigger.entity';
|
||||
import { RouteTrigger } from 'src/engine/metadata-modules/route-trigger/route-trigger.entity';
|
||||
import { ServerlessFunctionEntityRelationProperties } from 'src/engine/metadata-modules/serverless-function/types/flat-serverless-function.type';
|
||||
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { ServerlessFunctionLayerEntity } from 'src/engine/metadata-modules/serverless-function-layer/serverless-function-layer.entity';
|
||||
import { ServerlessFunctionEntityRelationProperties } from 'src/engine/metadata-modules/serverless-function/types/flat-serverless-function.type';
|
||||
|
||||
const DEFAULT_SERVERLESS_TIMEOUT_SECONDS = 300; // 5 minutes
|
||||
|
||||
@@ -66,9 +65,6 @@ export class ServerlessFunctionEntity
|
||||
@Column({ nullable: false, type: 'uuid' })
|
||||
workspaceId: string;
|
||||
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
applicationId: string | null;
|
||||
|
||||
@Column({ nullable: true, type: 'text' })
|
||||
checksum: string | null;
|
||||
|
||||
@@ -84,17 +80,6 @@ export class ServerlessFunctionEntity
|
||||
@JoinColumn({ name: 'serverlessFunctionLayerId' })
|
||||
serverlessFunctionLayer: Relation<ServerlessFunctionLayerEntity>;
|
||||
|
||||
@ManyToOne(
|
||||
() => ApplicationEntity,
|
||||
(application) => application.serverlessFunctions,
|
||||
{
|
||||
onDelete: 'CASCADE',
|
||||
nullable: true,
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: 'applicationId' })
|
||||
application: Relation<ApplicationEntity> | null;
|
||||
|
||||
@OneToMany(
|
||||
() => CronTrigger,
|
||||
(cronTrigger) => cronTrigger.serverlessFunction,
|
||||
|
||||
@@ -9,6 +9,7 @@ import { CacheStorageService } from 'src/engine/core-modules/cache-storage/servi
|
||||
import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum';
|
||||
import { EMPTY_FLAT_ENTITY_MAPS } from 'src/engine/metadata-modules/flat-entity/constant/empty-flat-entity-maps.constant';
|
||||
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
|
||||
import {
|
||||
SERVERLESS_FUNCTION_ENTITY_RELATION_PROPERTIES,
|
||||
ServerlessFunctionEntity,
|
||||
@@ -43,29 +44,23 @@ export class WorkspaceFlatServerlessFunctionMapCacheService extends WorkspaceFla
|
||||
withDeleted: true,
|
||||
});
|
||||
|
||||
const flatServerlessFunctionMaps = serverlessFunctions.reduce<
|
||||
FlatEntityMaps<FlatServerlessFunction>
|
||||
>((flatEntityMaps, serverlessFunction) => {
|
||||
const flatServerlessFunction = {
|
||||
...removePropertiesFromRecord(serverlessFunction, [
|
||||
...SERVERLESS_FUNCTION_ENTITY_RELATION_PROPERTIES,
|
||||
]),
|
||||
universalIdentifier: serverlessFunction.universalIdentifier ?? '',
|
||||
} satisfies FlatServerlessFunction;
|
||||
return serverlessFunctions.reduce(
|
||||
(flatServerlessFunctionMaps, serverlessFunctionEntity) => {
|
||||
const flatServerlessFunction = {
|
||||
...removePropertiesFromRecord(serverlessFunctionEntity, [
|
||||
...SERVERLESS_FUNCTION_ENTITY_RELATION_PROPERTIES,
|
||||
]),
|
||||
universalIdentifier:
|
||||
serverlessFunctionEntity.universalIdentifier ??
|
||||
serverlessFunctionEntity.id,
|
||||
} satisfies FlatServerlessFunction;
|
||||
|
||||
return {
|
||||
byId: {
|
||||
...flatEntityMaps.byId,
|
||||
[flatServerlessFunction.id]: flatServerlessFunction,
|
||||
},
|
||||
idByUniversalIdentifier: {
|
||||
...flatEntityMaps.idByUniversalIdentifier,
|
||||
[flatServerlessFunction.universalIdentifier]:
|
||||
flatServerlessFunction.id,
|
||||
},
|
||||
};
|
||||
}, EMPTY_FLAT_ENTITY_MAPS);
|
||||
|
||||
return flatServerlessFunctionMaps;
|
||||
return addFlatEntityToFlatEntityMapsOrThrow({
|
||||
flatEntity: flatServerlessFunction,
|
||||
flatEntityMaps: flatServerlessFunctionMaps,
|
||||
});
|
||||
},
|
||||
EMPTY_FLAT_ENTITY_MAPS,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { type Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { type CronTrigger } from 'src/engine/metadata-modules/cron-trigger/entities/cron-trigger.entity';
|
||||
import { type DatabaseEventTrigger } from 'src/engine/metadata-modules/database-event-trigger/entities/database-event-trigger.entity';
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
|
||||
import { type RouteTrigger } from 'src/engine/metadata-modules/route-trigger/route-trigger.entity';
|
||||
import { type ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
import { type ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type';
|
||||
import { type ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { type ServerlessFunctionLayerEntity } from 'src/engine/metadata-modules/serverless-function-layer/serverless-function-layer.entity';
|
||||
import { type ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
import { type ServerlessFunctionCode } from 'src/engine/metadata-modules/serverless-function/types/serverless-function-code.type';
|
||||
import { type ExtractRecordTypeOrmRelationProperties } from 'src/engine/workspace-manager/workspace-migration-v2/types/extract-record-typeorm-relation-properties.type';
|
||||
|
||||
export type ServerlessFunctionEntityRelationProperties =
|
||||
ExtractRecordTypeOrmRelationProperties<
|
||||
@@ -15,14 +15,12 @@ export type ServerlessFunctionEntityRelationProperties =
|
||||
| DatabaseEventTrigger
|
||||
| RouteTrigger
|
||||
| Workspace
|
||||
| ApplicationEntity
|
||||
| ServerlessFunctionLayerEntity
|
||||
>;
|
||||
|
||||
export type FlatServerlessFunction = Omit<
|
||||
export type FlatServerlessFunction = FlatEntityFrom<
|
||||
ServerlessFunctionEntity,
|
||||
ServerlessFunctionEntityRelationProperties
|
||||
> & {
|
||||
universalIdentifier: string;
|
||||
code?: ServerlessFunctionCode;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
import { Field, HideField, InputType } from '@nestjs/graphql';
|
||||
|
||||
import {
|
||||
IsBoolean,
|
||||
@@ -45,4 +45,10 @@ export class CreateViewFieldInput {
|
||||
@IsEnum(AggregateOperations)
|
||||
@Field(() => AggregateOperations, { nullable: true })
|
||||
aggregateOperation?: AggregateOperations;
|
||||
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
@HideField()
|
||||
applicationId?: string;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
import { Field, HideField, InputType } from '@nestjs/graphql';
|
||||
|
||||
import GraphQLJSON from 'graphql-type-json';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
import {
|
||||
IsDefined,
|
||||
IsEnum,
|
||||
@@ -10,6 +8,8 @@ import {
|
||||
IsString,
|
||||
IsUUID,
|
||||
} from 'class-validator';
|
||||
import GraphQLJSON from 'graphql-type-json';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { ViewFilterValue } from 'src/engine/metadata-modules/view-filter/types/view-filter-value.type';
|
||||
@@ -52,4 +52,10 @@ export class CreateViewFilterInput {
|
||||
@IsUUID()
|
||||
@Field(() => UUIDScalarType, { nullable: false })
|
||||
viewId: string;
|
||||
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
@HideField()
|
||||
applicationId?: string;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
import { Field, HideField, InputType } from '@nestjs/graphql';
|
||||
|
||||
import {
|
||||
IsBoolean,
|
||||
@@ -38,4 +38,10 @@ export class CreateViewGroupInput {
|
||||
@IsUUID()
|
||||
@Field(() => UUIDScalarType, { nullable: false })
|
||||
viewId: string;
|
||||
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
@HideField()
|
||||
applicationId?: string;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,10 @@ import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entit
|
||||
@Index('IDX_VIEW_GROUP_VIEW_ID', ['viewId'], {
|
||||
where: '"deletedAt" IS NULL',
|
||||
})
|
||||
export class ViewGroupEntity extends SyncableEntity {
|
||||
export class ViewGroupEntity
|
||||
extends SyncableEntity
|
||||
implements Required<ViewGroupEntity>
|
||||
{
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
import { Field, HideField, InputType } from '@nestjs/graphql';
|
||||
|
||||
import {
|
||||
IsBoolean,
|
||||
@@ -90,4 +90,10 @@ export class CreateViewInput {
|
||||
@IsUUID()
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
calendarFieldMetadataId?: string;
|
||||
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
@HideField()
|
||||
applicationId?: string;
|
||||
}
|
||||
|
||||
@@ -127,6 +127,14 @@ export class WorkspaceMigrationBuildOrchestratorService {
|
||||
...flatFieldMetadataMaps?.from.idByUniversalIdentifier,
|
||||
...flatFieldMetadataMaps?.to.idByUniversalIdentifier,
|
||||
},
|
||||
universalIdentifiersByApplicationId: {
|
||||
...dependencyAllFlatEntityMaps?.flatFieldMetadataMaps
|
||||
?.universalIdentifiersByApplicationId,
|
||||
...flatFieldMetadataMaps?.from
|
||||
.universalIdentifiersByApplicationId,
|
||||
...flatFieldMetadataMaps?.to
|
||||
.universalIdentifiersByApplicationId,
|
||||
},
|
||||
},
|
||||
},
|
||||
///
|
||||
|
||||
@@ -8,6 +8,8 @@ export type PartialIndexMetadata = Omit<
|
||||
| 'createdAt'
|
||||
| 'updatedAt'
|
||||
| 'universalIdentifier'
|
||||
| 'application'
|
||||
| 'applicationId'
|
||||
> & {
|
||||
columns: string[];
|
||||
};
|
||||
|
||||
@@ -15,4 +15,5 @@ export const ADMIN_ROLE: StandardRoleDefinition = {
|
||||
canBeAssignedToUsers: true,
|
||||
canBeAssignedToAgents: false,
|
||||
canBeAssignedToApiKeys: true,
|
||||
applicationId: null, // TODO: Replace with Twenty application ID
|
||||
};
|
||||
|
||||
@@ -15,4 +15,5 @@ export const DATA_MANIPULATOR_ROLE: StandardRoleDefinition = {
|
||||
canBeAssignedToUsers: false,
|
||||
canBeAssignedToAgents: true,
|
||||
canBeAssignedToApiKeys: false,
|
||||
applicationId: null, // TODO: Replace with Twenty application ID
|
||||
};
|
||||
|
||||
@@ -15,4 +15,5 @@ export const DATA_NAVIGATOR_ROLE: StandardRoleDefinition = {
|
||||
canBeAssignedToUsers: false,
|
||||
canBeAssignedToAgents: true,
|
||||
canBeAssignedToApiKeys: false,
|
||||
applicationId: null, // TODO: Replace with Twenty application ID
|
||||
};
|
||||
|
||||
@@ -17,4 +17,5 @@ export const WORKFLOW_MANAGER_ROLE: StandardRoleDefinition = {
|
||||
canBeAssignedToAgents: true,
|
||||
canBeAssignedToApiKeys: false,
|
||||
permissionFlags: [PermissionFlagType.WORKFLOWS],
|
||||
applicationId: null, // TODO: Replace with Twenty application ID
|
||||
};
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Column, Index } from 'typeorm';
|
||||
import { Column, Index, JoinColumn, ManyToOne, Relation } from 'typeorm';
|
||||
|
||||
import type { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
|
||||
@Index(['workspaceId', 'universalIdentifier'], {
|
||||
unique: true,
|
||||
@@ -6,4 +8,14 @@ import { Column, Index } from 'typeorm';
|
||||
export abstract class SyncableEntity {
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
universalIdentifier: string | null;
|
||||
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
applicationId: string | null;
|
||||
|
||||
@ManyToOne('ApplicationEntity', {
|
||||
onDelete: 'CASCADE',
|
||||
nullable: true,
|
||||
})
|
||||
@JoinColumn({ name: 'applicationId' })
|
||||
application: Relation<ApplicationEntity>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export type NonNullableProperties<T> = {
|
||||
[P in keyof T]: NonNullable<T[P]>;
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { type FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { type ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { type IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity';
|
||||
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
@@ -49,6 +50,9 @@ export const getMockFieldMetadataEntity = <
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
isActive: true,
|
||||
application: {} as ApplicationEntity,
|
||||
applicationId: faker.string.uuid(),
|
||||
universalIdentifier: faker.string.uuid(),
|
||||
...overrides,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
import { type ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { type DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
|
||||
@@ -41,8 +42,9 @@ export const getMockObjectMetadataEntity = (
|
||||
objectPermissions: [],
|
||||
shortcut: null,
|
||||
standardId: null,
|
||||
applicationId: null,
|
||||
application: null,
|
||||
universalIdentifier: faker.string.uuid(),
|
||||
applicationId: faker.string.uuid(),
|
||||
application: {} as ApplicationEntity,
|
||||
targetRelationFields: [],
|
||||
standardOverrides: null,
|
||||
targetTableName: faker.string.uuid(),
|
||||
|
||||
@@ -5,6 +5,7 @@ import { type Repository } from 'typeorm';
|
||||
|
||||
import { ToolAdapterService } from 'src/engine/core-modules/ai/services/tool-adapter.service';
|
||||
import { ToolService } from 'src/engine/core-modules/ai/services/tool.service';
|
||||
import { type ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
|
||||
import { CreateRecordService } from 'src/engine/core-modules/record-crud/services/create-record.service';
|
||||
import { DeleteRecordService } from 'src/engine/core-modules/record-crud/services/delete-record.service';
|
||||
import { FindRecordsService } from 'src/engine/core-modules/record-crud/services/find-records.service';
|
||||
@@ -210,7 +211,10 @@ export const createAgentToolTestModule =
|
||||
icon: 'IconTest',
|
||||
isCustom: false,
|
||||
applicationId: null,
|
||||
application: null,
|
||||
application: {} as ApplicationEntity,
|
||||
standardId: null,
|
||||
deletedAt: null,
|
||||
universalIdentifier: testAgentId,
|
||||
description: 'Test agent for integration tests',
|
||||
prompt: 'You are a test agent',
|
||||
modelId: 'gpt-4o',
|
||||
|
||||
Reference in New Issue
Block a user