Activity as standard object (#6219)

In this PR I layout the first steps to migrate Activity to a traditional
Standard objects

Since this is a big transition, I'd rather split it into several
deployments / PRs

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/012e2bbf-9d1b-4723-aaf6-269ef588b050">

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: bosiraphael <71827178+bosiraphael@users.noreply.github.com>
Co-authored-by: Weiko <corentin@twenty.com>
Co-authored-by: Faisal-imtiyaz123 <142205282+Faisal-imtiyaz123@users.noreply.github.com>
Co-authored-by: Prateek Jain <prateekj1171998@gmail.com>
This commit is contained in:
Félix Malfait
2024-07-31 15:36:11 +02:00
committed by GitHub
parent defcee2a02
commit 80c0fc7ff1
239 changed files with 18418 additions and 8671 deletions

View File

@ -8,6 +8,7 @@ import { DataSeedDemoWorkspaceModule } from 'src/database/commands/data-seed-dem
import { DataSeedWorkspaceCommand } from 'src/database/commands/data-seed-dev-workspace.command';
import { ConfirmationQuestion } from 'src/database/commands/questions/confirmation.question';
import { UpgradeTo0_23CommandModule } from 'src/database/commands/upgrade-version/0-23/0-23-upgrade-version.module';
import { UpgradeVersionModule } from 'src/database/commands/upgrade-version/upgrade-version.module';
import { WorkspaceAddTotalCountCommand } from 'src/database/commands/workspace-add-total-count.command';
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
@ -44,8 +45,8 @@ import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/worksp
ObjectMetadataModule,
DataSeedDemoWorkspaceModule,
WorkspaceCacheVersionModule,
// Upgrades
UpgradeTo0_23CommandModule,
UpgradeVersionModule,
],
providers: [
DataSeedWorkspaceCommand,

View File

@ -0,0 +1,464 @@
import { Logger } from '@nestjs/common';
import chalk from 'chalk';
import { Command, CommandRunner, Option } from 'nest-commander';
import { QueryRunner } from 'typeorm';
import { v4 } from 'uuid';
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { notesAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view';
import { tasksAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view';
import { tasksByStatusView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-by-status.view';
import { WorkspaceStatusService } from 'src/engine/workspace-manager/workspace-status/services/workspace-status.service';
import { ActivityWorkspaceEntity } from 'src/modules/activity/standard-objects/activity.workspace-entity';
import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity';
import { NoteTargetWorkspaceEntity } from 'src/modules/note/standard-objects/note-target.workspace-entity';
import { NoteWorkspaceEntity } from 'src/modules/note/standard-objects/note.workspace-entity';
import { TaskTargetWorkspaceEntity } from 'src/modules/task/standard-objects/task-target.workspace-entity';
import { TaskWorkspaceEntity } from 'src/modules/task/standard-objects/task.workspace-entity';
import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity';
interface UpdateActivitiesCommandOptions {
workspaceId?: string;
}
type CoreLogicFunction = (params: {
workspaceId: string;
queryRunner?: QueryRunner;
schema?: string;
}) => Promise<void>;
@Command({
name: 'migrate-0.23:update-activities-type',
description: 'Migrate Activity object to Note and Task objects',
})
export class UpdateActivitiesCommand extends CommandRunner {
private readonly logger = new Logger(UpdateActivitiesCommand.name);
constructor(
private readonly workspaceStatusService: WorkspaceStatusService,
private readonly typeORMService: TypeORMService,
private readonly dataSourceService: DataSourceService,
private readonly workspaceCacheVersionService: WorkspaceCacheVersionService,
private readonly objectMetadataService: ObjectMetadataService,
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
) {
super();
}
@Option({
flags: '-w, --workspace-id [workspace_id]',
description: 'workspace id. Command runs on all workspaces if not provided',
required: false,
})
parseWorkspaceId(value: string): string {
return value;
}
async run(
_passedParam: string[],
options: UpdateActivitiesCommandOptions,
): Promise<void> {
const updateActivities = async ({
workspaceId,
queryRunner,
schema,
}: {
workspaceId: string;
queryRunner: QueryRunner;
schema: string;
}): Promise<void> => {
/***********************
// Transfer Activities to NOTE + Tasks
***********************/
const activityRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace<ActivityWorkspaceEntity>(
workspaceId,
'activity',
);
const noteRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace<NoteWorkspaceEntity>(
workspaceId,
'note',
);
const noteTargetRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace<NoteTargetWorkspaceEntity>(
workspaceId,
'noteTarget',
);
const taskRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace<TaskWorkspaceEntity>(
workspaceId,
'task',
);
const taskTargetRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace<TaskTargetWorkspaceEntity>(
workspaceId,
'taskTarget',
);
const timelineActivityRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace<TimelineActivityWorkspaceEntity>(
workspaceId,
'timelineActivity',
);
const attachmentRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace<AttachmentWorkspaceEntity>(
workspaceId,
'attachment',
);
const objectMetadata =
await this.objectMetadataService.findManyWithinWorkspace(workspaceId);
const noteObjectMetadataId = objectMetadata.find(
(object) => object.nameSingular === 'note',
)?.id;
const taskObjectMetadataId = objectMetadata.find(
(object) => object.nameSingular === 'task',
)?.id;
const activityObjectMetadataId = objectMetadata.find(
(object) => object.nameSingular === 'activity',
)?.id;
const activitiesToTransfer = await activityRepository.find({
order: { createdAt: 'ASC' },
relations: ['activityTargets'],
});
for (let i = 0; i < activitiesToTransfer.length; i++) {
const activity = activitiesToTransfer[i];
if (activity.type === 'Note') {
const note = noteRepository.create({
id: activity.id,
title: activity.title,
body: activity.body,
createdAt: activity.createdAt,
updatedAt: activity.updatedAt,
position: i,
});
await noteRepository.save(note);
if (activity.activityTargets && activity.activityTargets.length > 0) {
const noteTargets = activity.activityTargets.map(
(activityTarget) => {
const { activityId, ...activityTargetData } = activityTarget;
return noteTargetRepository.create({
noteId: activityId,
...activityTargetData,
});
},
);
await noteTargetRepository.save(noteTargets);
}
await timelineActivityRepository.update(
{
linkedObjectMetadataId: activityObjectMetadataId,
linkedRecordId: activity.id,
},
{
linkedObjectMetadataId: noteObjectMetadataId,
},
);
await attachmentRepository.update(
{
activityId: activity.id,
},
{
activityId: null,
noteId: activity.id,
},
);
} else if (activity.type === 'Task') {
const task = taskRepository.create({
id: activity.id,
title: activity.title,
body: activity.body,
status: activity.completedAt ? 'DONE' : 'TODO',
dueAt: activity.dueAt,
assigneeId: activity.assigneeId,
position: i,
createdAt: activity.createdAt,
updatedAt: activity.updatedAt,
});
await taskRepository.save(task);
if (activity.activityTargets && activity.activityTargets.length > 0) {
const taskTargets = activity.activityTargets.map(
(activityTarget) => {
const { activityId, ...activityTargetData } = activityTarget;
return taskTargetRepository.create({
taskId: activityId,
...activityTargetData,
});
},
);
await taskTargetRepository.save(taskTargets);
}
await timelineActivityRepository.update(
{
linkedObjectMetadataId: activityObjectMetadataId,
linkedRecordId: activity.id,
},
{
linkedObjectMetadataId: taskObjectMetadataId,
},
);
await attachmentRepository.update(
{
activityId: activity.id,
},
{
activityId: null,
taskId: activity.id,
},
);
} else {
throw new Error(`Unknown activity type: ${activity.type}`);
}
}
// Hack to make sure the command is indempotent and return if one of the view exists
const viewExists = await queryRunner.manager
.createQueryBuilder()
.select()
.from(`${schema}.view`, 'view')
.where('name = :name', { name: 'All Notes' })
.getRawOne();
if (!viewExists) {
await this.createViews(
objectMetadata,
queryRunner,
schema,
workspaceId,
);
}
};
return this.sharedBoilerplate(_passedParam, options, updateActivities);
}
private async createViews(
objectMetadata: ObjectMetadataEntity[],
queryRunner: QueryRunner,
schema: string,
workspaceId: string,
) {
const objectMetadataMap = objectMetadata.reduce((acc, object) => {
acc[object.standardId ?? ''] = {
id: object.id,
fields: object.fields.reduce((acc, field) => {
acc[field.standardId ?? ''] = field.id;
return acc;
}, {}),
};
return acc;
}, {}) as Record<string, ObjectMetadataEntity>;
const viewDefinitions = [
await notesAllView(objectMetadataMap),
await tasksAllView(objectMetadataMap),
await tasksByStatusView(objectMetadataMap),
];
const viewDefinitionsWithId = viewDefinitions.map((viewDefinition) => ({
...viewDefinition,
id: v4(),
}));
await queryRunner.manager
.createQueryBuilder()
.insert()
.into(`${schema}.view`, [
'id',
'name',
'objectMetadataId',
'type',
'key',
'position',
'icon',
'kanbanFieldMetadataId',
])
.values(
viewDefinitionsWithId.map(
({
id,
name,
objectMetadataId,
type,
key,
position,
icon,
kanbanFieldMetadataId,
}) => ({
id,
name,
objectMetadataId,
type,
key,
position,
icon,
kanbanFieldMetadataId,
}),
),
)
.returning('*')
.execute();
for (const viewDefinition of viewDefinitionsWithId) {
if (viewDefinition.fields && viewDefinition.fields.length > 0) {
await queryRunner.manager
.createQueryBuilder()
.insert()
.into(`${schema}.viewField`, [
'fieldMetadataId',
'position',
'isVisible',
'size',
'viewId',
])
.values(
viewDefinition.fields.map((field) => ({
fieldMetadataId: field.fieldMetadataId,
position: field.position,
isVisible: field.isVisible,
size: field.size,
viewId: viewDefinition.id,
})),
)
.execute();
}
if (viewDefinition.filters && viewDefinition.filters.length > 0) {
await queryRunner.manager
.createQueryBuilder()
.insert()
.into(`${schema}.viewFilter`, [
'fieldMetadataId',
'displayValue',
'operand',
'value',
'viewId',
])
.values(
viewDefinition.filters.map((filter: any) => ({
fieldMetadataId: filter.fieldMetadataId,
displayValue: filter.displayValue,
operand: filter.operand,
value: filter.value,
viewId: viewDefinition.id,
})),
)
.execute();
}
await this.workspaceCacheVersionService.incrementVersion(workspaceId);
}
}
// This is an attempt to do something more generic that could be reused in every command
// Next step if it works well for a few command is to isolated it into a file so
// it can be reused and not copy-pasted.
async sharedBoilerplate(
_passedParam: string[],
options: UpdateActivitiesCommandOptions,
coreLogic: CoreLogicFunction,
) {
const workspaceIds = options.workspaceId
? [options.workspaceId]
: await this.workspaceStatusService.getActiveWorkspaceIds();
if (!workspaceIds.length) {
this.logger.log(chalk.yellow('No workspace found'));
return;
}
this.logger.log(
chalk.green(`Running command on ${workspaceIds.length} workspaces`),
);
const requiresQueryRunner =
coreLogic.toString().includes('queryRunner') ||
coreLogic.toString().includes('schema');
for (const workspaceId of workspaceIds) {
try {
if (requiresQueryRunner) {
await this.executeWithQueryRunner(workspaceId, coreLogic);
} else {
await coreLogic({ workspaceId });
}
this.logger.log(
chalk.green(`Running command on workspace ${workspaceId} done`),
);
} catch (error) {
this.logger.error(
`Migration failed for workspace ${workspaceId}: ${error.message}, ${error.stack}`,
);
}
}
this.logger.log(chalk.green(`Command completed!`));
}
private async executeWithQueryRunner(
workspaceId: string,
coreLogic: CoreLogicFunction,
) {
const dataSourceMetadatas =
await this.dataSourceService.getDataSourcesMetadataFromWorkspaceId(
workspaceId,
);
for (const dataSourceMetadata of dataSourceMetadatas) {
const workspaceDataSource =
await this.typeORMService.connectToDataSource(dataSourceMetadata);
if (workspaceDataSource) {
const queryRunner = workspaceDataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
await coreLogic({
workspaceId,
queryRunner,
schema: dataSourceMetadata.schema,
});
await queryRunner.commitTransaction();
} catch (error) {
await queryRunner.rollbackTransaction();
this.logger.log(
chalk.red(`Running command on workspace ${workspaceId} failed`),
);
throw error;
} finally {
await queryRunner.release();
}
}
}
}
}

View File

@ -4,6 +4,7 @@ import { MigrateDomainNameFromTextToLinksCommand } from 'src/database/commands/u
import { MigrateLinkFieldsToLinksCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-link-fields-to-links.command';
import { MigrateMessageChannelSyncStatusEnumCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-message-channel-sync-status-enum.command';
import { SetWorkspaceActivationStatusCommand } from 'src/database/commands/upgrade-version/0-23/0-23-set-workspace-activation-status.command';
import { UpdateActivitiesCommand } from 'src/database/commands/upgrade-version/0-23/0-23-update-activities.command';
interface Options {
workspaceId?: string;
@ -19,6 +20,7 @@ export class UpgradeTo0_23Command extends CommandRunner {
private readonly migrateDomainNameFromTextToLinks: MigrateDomainNameFromTextToLinksCommand,
private readonly migrateMessageChannelSyncStatusEnumCommand: MigrateMessageChannelSyncStatusEnumCommand,
private readonly setWorkspaceActivationStatusCommand: SetWorkspaceActivationStatusCommand,
private readonly updateActivitiesCommand: UpdateActivitiesCommand,
) {
super();
}
@ -41,5 +43,6 @@ export class UpgradeTo0_23Command extends CommandRunner {
options,
);
await this.setWorkspaceActivationStatusCommand.run(_passedParam, options);
await this.updateActivitiesCommand.run(_passedParam, options);
}
}

View File

@ -5,6 +5,7 @@ import { MigrateDomainNameFromTextToLinksCommand } from 'src/database/commands/u
import { MigrateLinkFieldsToLinksCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-link-fields-to-links.command';
import { MigrateMessageChannelSyncStatusEnumCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-message-channel-sync-status-enum.command';
import { SetWorkspaceActivationStatusCommand } from 'src/database/commands/upgrade-version/0-23/0-23-set-workspace-activation-status.command';
import { UpdateActivitiesCommand } from 'src/database/commands/upgrade-version/0-23/0-23-update-activities.command';
import { UpgradeTo0_23Command } from 'src/database/commands/upgrade-version/0-23/0-23-upgrade-version.command';
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
@ -13,6 +14,7 @@ import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-s
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module';
import { WorkspaceStatusModule } from 'src/engine/workspace-manager/workspace-status/workspace-manager.module';
import { ViewModule } from 'src/modules/view/view.module';
@ -29,12 +31,14 @@ import { ViewModule } from 'src/modules/view/view.module';
TypeORMModule,
ViewModule,
BillingModule,
ObjectMetadataModule,
],
providers: [
MigrateLinkFieldsToLinksCommand,
MigrateDomainNameFromTextToLinksCommand,
MigrateMessageChannelSyncStatusEnumCommand,
SetWorkspaceActivationStatusCommand,
UpdateActivitiesCommand,
UpgradeTo0_23Command,
],
})

View File

@ -0,0 +1,128 @@
import { Logger } from '@nestjs/common';
import { isUndefined } from '@nestjs/common/utils/shared.utils';
import * as fs from 'fs';
import * as path from 'path';
import chalk from 'chalk';
import { Command, CommandRunner, Option } from 'nest-commander';
import * as semver from 'semver';
import { MigrateDomainNameFromTextToLinksCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-domain-to-links.command';
import { MigrateLinkFieldsToLinksCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-link-fields-to-links.command';
import { MigrateMessageChannelSyncStatusEnumCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-message-channel-sync-status-enum.command';
import { SetWorkspaceActivationStatusCommand } from 'src/database/commands/upgrade-version/0-23/0-23-set-workspace-activation-status.command';
import { UpdateActivitiesCommand } from 'src/database/commands/upgrade-version/0-23/0-23-update-activities.command';
interface UpgradeCommandOptions {
workspaceId?: string;
}
type VersionUpgradeMap = {
[version: string]: CommandRunner[];
};
@Command({
name: 'upgrade-version',
description: 'Upgrade to a specific version',
})
export class UpgradeVersionCommand extends CommandRunner {
private readonly logger = new Logger(UpgradeVersionCommand.name);
constructor(
private readonly migrateLinkFieldsToLinksCommand: MigrateLinkFieldsToLinksCommand,
private readonly migrateDomainNameFromTextToLinksCommand: MigrateDomainNameFromTextToLinksCommand,
private readonly migrateMessageChannelSyncStatusEnumCommand: MigrateMessageChannelSyncStatusEnumCommand,
private readonly setWorkspaceActivationStatusCommand: SetWorkspaceActivationStatusCommand,
private readonly updateActivitiesCommand: UpdateActivitiesCommand,
) {
super();
}
@Option({
flags: '-v, --version <version>',
description: 'Version to upgrade to',
required: true,
})
parseVersion(value: string): string {
return value;
}
@Option({
flags: '-w, --workspace-id [workspace_id]',
description: 'workspace id. Command runs on all workspaces if not provided',
required: false,
})
parseWorkspaceId(value: string): string {
return value;
}
async run(
passedParams: string[],
options: UpgradeCommandOptions & { version: string },
): Promise<void> {
const { version, ...upgradeOptions } = options;
const versionUpgradeMap = {
'0.23': [
this.migrateLinkFieldsToLinksCommand,
this.migrateDomainNameFromTextToLinksCommand,
this.migrateMessageChannelSyncStatusEnumCommand,
this.setWorkspaceActivationStatusCommand,
this.updateActivitiesCommand,
],
};
await this.validateVersions(version, versionUpgradeMap);
if (!versionUpgradeMap[version]) {
throw new Error(
`No migration commands found for version ${version}. This could mean there were no database changes required for this version.`,
);
}
for (const command of versionUpgradeMap[version]) {
await command.run(passedParams, upgradeOptions);
}
this.logger.log(chalk.green(`Successfully upgraded to version ${version}`));
}
private async getCurrentCodeVersion(): Promise<string> {
const packageJsonPath = path.join(process.cwd(), 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
return packageJson.version;
}
private async validateVersions(
targetVersion: string,
versionUpgradeMap: VersionUpgradeMap,
): Promise<void> {
const currentVersion = await this.getCurrentCodeVersion();
const cleanCurrentVersion = semver.coerce(currentVersion);
const cleanTargetVersion = semver.coerce(targetVersion);
if (!cleanCurrentVersion || !cleanTargetVersion) {
throw new Error(
`Invalid version format. Current Code: ${currentVersion}, Target: ${targetVersion}`,
);
}
const targetMajorMinor = `${cleanTargetVersion.major}.${cleanTargetVersion.minor}`;
if (
semver.gt(cleanTargetVersion, cleanCurrentVersion) &&
isUndefined(versionUpgradeMap[targetMajorMinor])
) {
throw new Error(
`Cannot upgrade to ${cleanTargetVersion}. Your current code version is ${cleanCurrentVersion}. Please update your codebase or upgrade your Docker image first.`,
);
}
this.logger.log(
`Current Code Version: ${currentVersion}, Target: ${targetVersion}`,
);
}
}

View File

@ -0,0 +1,62 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { DataSeedDemoWorkspaceModule } from 'src/database/commands/data-seed-demo-workspace/data-seed-demo-workspace.module';
import { MigrateDomainNameFromTextToLinksCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-domain-to-links.command';
import { MigrateLinkFieldsToLinksCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-link-fields-to-links.command';
import { MigrateMessageChannelSyncStatusEnumCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-message-channel-sync-status-enum.command';
import { SetWorkspaceActivationStatusCommand } from 'src/database/commands/upgrade-version/0-23/0-23-set-workspace-activation-status.command';
import { UpdateActivitiesCommand } from 'src/database/commands/upgrade-version/0-23/0-23-update-activities.command';
import { UpgradeVersionCommand } from 'src/database/commands/upgrade-version/upgrade-version.command';
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module';
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
import { WorkspaceStatusModule } from 'src/engine/workspace-manager/workspace-status/workspace-manager.module';
import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module';
import { ViewModule } from 'src/modules/view/view.module';
@Module({
imports: [
WorkspaceManagerModule,
DataSourceModule,
TypeORMModule,
TypeOrmModule.forFeature(
[Workspace, BillingSubscription, FeatureFlagEntity],
'core',
),
TypeOrmModule.forFeature(
[FieldMetadataEntity, ObjectMetadataEntity],
'metadata',
),
WorkspaceModule,
WorkspaceDataSourceModule,
WorkspaceSyncMetadataModule,
WorkspaceStatusModule,
ObjectMetadataModule,
DataSeedDemoWorkspaceModule,
WorkspaceCacheVersionModule,
FieldMetadataModule,
ViewModule,
BillingModule,
],
providers: [
UpgradeVersionCommand,
MigrateLinkFieldsToLinksCommand,
MigrateDomainNameFromTextToLinksCommand,
MigrateMessageChannelSyncStatusEnumCommand,
SetWorkspaceActivationStatusCommand,
UpdateActivitiesCommand,
],
})
export class UpgradeVersionModule {}

View File

@ -1,5 +1,7 @@
import { DataSource } from 'typeorm';
import { WorkspaceActivationStatus } from 'src/engine/core-modules/workspace/workspace.entity';
const tableName = 'workspace';
export const seedWorkspaces = async (
@ -16,6 +18,7 @@ export const seedWorkspaces = async (
'domainName',
'inviteHash',
'logo',
'activationStatus',
])
.orIgnore()
.values([
@ -25,6 +28,7 @@ export const seedWorkspaces = async (
domainName: 'demo.dev',
inviteHash: 'demo.dev-invite-hash',
logo: 'https://twentyhq.github.io/placeholder-images/workspaces/apple-logo.png',
activationStatus: WorkspaceActivationStatus.ACTIVE,
},
])
.execute();