add new @WorkspaceIsSearchable decorator + updates services + add migration command (#10507)

closes https://github.com/twentyhq/core-team-issues/issues/345
This commit is contained in:
Etienne
2025-02-27 13:57:07 +01:00
committed by GitHub
parent 17dbb634ca
commit 39543872e6
54 changed files with 297 additions and 145 deletions

View File

@ -2,17 +2,17 @@ import chalk from 'chalk';
import { Repository } from 'typeorm';
import {
ActiveWorkspacesMigrationCommandOptions,
ActiveWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/active-workspaces-migration-command.runner';
MaintainedWorkspacesMigrationCommandOptions,
MaintainedWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/maintained-workspaces-migration-command.runner';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
export abstract class BatchActiveWorkspacesMigrationCommandRunner<
export abstract class BatchMaintainedWorkspacesMigrationCommandRunner<
Options extends
ActiveWorkspacesMigrationCommandOptions = ActiveWorkspacesMigrationCommandOptions,
> extends ActiveWorkspacesMigrationCommandRunner<Options> {
MaintainedWorkspacesMigrationCommandOptions = MaintainedWorkspacesMigrationCommandOptions,
> extends MaintainedWorkspacesMigrationCommandRunner<Options> {
constructor(
protected readonly workspaceRepository: Repository<Workspace>,
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
@ -20,7 +20,7 @@ export abstract class BatchActiveWorkspacesMigrationCommandRunner<
super(workspaceRepository, twentyORMGlobalManager);
}
async runMigrationCommandOnActiveWorkspaces(
async runMigrationCommandOnMaintainedWorkspaces(
_passedParams: string[],
_options: Options,
activeWorkspaceIds: string[],

View File

@ -10,16 +10,16 @@ import {
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
export type ActiveWorkspacesMigrationCommandOptions =
export type MaintainedWorkspacesMigrationCommandOptions =
MigrationCommandOptions & {
workspaceId?: string;
startFromWorkspaceId?: string;
workspaceCountLimit?: number;
};
export abstract class ActiveWorkspacesMigrationCommandRunner<
export abstract class MaintainedWorkspacesMigrationCommandRunner<
Options extends
ActiveWorkspacesMigrationCommandOptions = ActiveWorkspacesMigrationCommandOptions,
MaintainedWorkspacesMigrationCommandOptions = MaintainedWorkspacesMigrationCommandOptions,
> extends MigrationCommandRunner<Options> {
private workspaceIds: string[] = [];
private startFromWorkspaceId: string | undefined;
@ -124,14 +124,14 @@ export abstract class ActiveWorkspacesMigrationCommandRunner<
this.logger.log(chalk.yellow('Dry run mode: No changes will be applied'));
}
await this.runMigrationCommandOnActiveWorkspaces(
await this.runMigrationCommandOnMaintainedWorkspaces(
passedParams,
options,
activeWorkspaceIds,
);
}
protected abstract runMigrationCommandOnActiveWorkspaces(
protected abstract runMigrationCommandOnMaintainedWorkspaces(
passedParams: string[],
options: Options,
activeWorkspaceIds: string[],

View File

@ -6,9 +6,9 @@ import { In, Repository } from 'typeorm';
import { isCommandLogger } from 'src/database/commands/logger';
import {
ActiveWorkspacesMigrationCommandOptions,
ActiveWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/active-workspaces-migration-command.runner';
MaintainedWorkspacesMigrationCommandOptions,
MaintainedWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/maintained-workspaces-migration-command.runner';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service';
@ -20,7 +20,7 @@ import { ViewWorkspaceEntity } from 'src/modules/view/standard-objects/view.work
name: 'upgrade-0.42:fix-body-v2-view-field-position',
description: 'Make bodyV2 field position to match body field position',
})
export class FixBodyV2ViewFieldPositionCommand extends ActiveWorkspacesMigrationCommandRunner {
export class FixBodyV2ViewFieldPositionCommand extends MaintainedWorkspacesMigrationCommandRunner {
constructor(
@InjectRepository(Workspace, 'core')
protected readonly workspaceRepository: Repository<Workspace>,
@ -32,9 +32,9 @@ export class FixBodyV2ViewFieldPositionCommand extends ActiveWorkspacesMigration
super(workspaceRepository, twentyORMGlobalManager);
}
async runMigrationCommandOnActiveWorkspaces(
async runMigrationCommandOnMaintainedWorkspaces(
_passedParam: string[],
options: ActiveWorkspacesMigrationCommandOptions,
options: MaintainedWorkspacesMigrationCommandOptions,
workspaceIds: string[],
): Promise<void> {
this.logger.log('Running command to fix bodyV2 field position');

View File

@ -4,11 +4,11 @@ import chalk from 'chalk';
import { Repository } from 'typeorm';
import { CommandLogger } from 'src/database/commands/logger';
import {
ActiveWorkspacesMigrationCommandOptions,
ActiveWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/active-workspaces-migration-command.runner';
import { MigrationCommand } from 'src/database/commands/migration-command/decorators/migration-command.decorator';
import {
MaintainedWorkspacesMigrationCommandOptions,
MaintainedWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/maintained-workspaces-migration-command.runner';
import { settings } from 'src/engine/constants/settings';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
@ -20,7 +20,7 @@ import { ViewWorkspaceEntity } from 'src/modules/view/standard-objects/view.work
description: 'Limit amount of view field.',
version: '0.42',
})
export class LimitAmountOfViewFieldCommand extends ActiveWorkspacesMigrationCommandRunner {
export class LimitAmountOfViewFieldCommand extends MaintainedWorkspacesMigrationCommandRunner {
protected readonly logger: CommandLogger;
constructor(
@ -95,9 +95,9 @@ export class LimitAmountOfViewFieldCommand extends ActiveWorkspacesMigrationComm
}
}
async runMigrationCommandOnActiveWorkspaces(
async runMigrationCommandOnMaintainedWorkspaces(
_passedParam: string[],
options: ActiveWorkspacesMigrationCommandOptions,
options: MaintainedWorkspacesMigrationCommandOptions,
workspaceIds: string[],
): Promise<void> {
this.logger.log(`Running limit-amount-of-view-field command`);

View File

@ -7,11 +7,11 @@ import { FieldMetadataType, isDefined } from 'twenty-shared';
import { Repository } from 'typeorm';
import { isCommandLogger } from 'src/database/commands/logger';
import {
ActiveWorkspacesMigrationCommandOptions,
ActiveWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/active-workspaces-migration-command.runner';
import { MigrationCommand } from 'src/database/commands/migration-command/decorators/migration-command.decorator';
import {
MaintainedWorkspacesMigrationCommandOptions,
MaintainedWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/maintained-workspaces-migration-command.runner';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
@ -59,7 +59,7 @@ type ProcessRichTextFieldsArgs = {
};
type MigrateRichTextFieldCommandOptions =
ActiveWorkspacesMigrationCommandOptions & {
MaintainedWorkspacesMigrationCommandOptions & {
force?: boolean;
};
@ -68,7 +68,7 @@ type MigrateRichTextFieldCommandOptions =
description: 'Migrate RICH_TEXT fields to new composite structure',
version: '0.42',
})
export class MigrateRichTextFieldCommand extends ActiveWorkspacesMigrationCommandRunner<MigrateRichTextFieldCommandOptions> {
export class MigrateRichTextFieldCommand extends MaintainedWorkspacesMigrationCommandRunner<MigrateRichTextFieldCommandOptions> {
private options: MigrateRichTextFieldCommandOptions;
constructor(
@ -99,7 +99,7 @@ export class MigrateRichTextFieldCommand extends ActiveWorkspacesMigrationComman
return val ?? false;
}
async runMigrationCommandOnActiveWorkspaces(
async runMigrationCommandOnMaintainedWorkspaces(
_passedParam: string[],
options: MigrateRichTextFieldCommandOptions,
workspaceIds: string[],

View File

@ -5,11 +5,11 @@ import { FieldMetadataType } from 'twenty-shared';
import { IsNull, Repository } from 'typeorm';
import { CommandLogger } from 'src/database/commands/logger';
import {
ActiveWorkspacesMigrationCommandOptions,
ActiveWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/active-workspaces-migration-command.runner';
import { MigrationCommand } from 'src/database/commands/migration-command/decorators/migration-command.decorator';
import {
MaintainedWorkspacesMigrationCommandOptions,
MaintainedWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/maintained-workspaces-migration-command.runner';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service';
@ -20,7 +20,7 @@ import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.
description: 'Add context to actor composite type.',
version: '0.42',
})
export class StandardizationOfActorCompositeContextTypeCommand extends ActiveWorkspacesMigrationCommandRunner {
export class StandardizationOfActorCompositeContextTypeCommand extends MaintainedWorkspacesMigrationCommandRunner {
protected readonly logger;
constructor(
@ -40,9 +40,9 @@ export class StandardizationOfActorCompositeContextTypeCommand extends ActiveWor
this.logger.setVerbose(false);
}
async runMigrationCommandOnActiveWorkspaces(
async runMigrationCommandOnMaintainedWorkspaces(
_passedParam: string[],
options: ActiveWorkspacesMigrationCommandOptions,
options: MaintainedWorkspacesMigrationCommandOptions,
workspaceIds: string[],
): Promise<void> {
this.logger.log(`Running add-context-to-actor-composite-type command`);

View File

@ -1,7 +1,7 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { MigrationCommandModule } from 'src/database/commands/migration-command/miration-command.module';
import { MigrationCommandModule } from 'src/database/commands/migration-command/migration-command.module';
import { FixBodyV2ViewFieldPositionCommand } from 'src/database/commands/upgrade-version/0-42/0-42-fix-body-v2-view-field-position.command';
import { LimitAmountOfViewFieldCommand } from 'src/database/commands/upgrade-version/0-42/0-42-limit-amount-of-view-field';
import { MigrateRichTextFieldCommand } from 'src/database/commands/upgrade-version/0-42/0-42-migrate-rich-text-field.command';

View File

@ -5,11 +5,11 @@ import { Repository } from 'typeorm';
import { v4 } from 'uuid';
import { isCommandLogger } from 'src/database/commands/logger';
import {
ActiveWorkspacesMigrationCommandOptions,
ActiveWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/active-workspaces-migration-command.runner';
import { MigrationCommand } from 'src/database/commands/migration-command/decorators/migration-command.decorator';
import {
MaintainedWorkspacesMigrationCommandOptions,
MaintainedWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/maintained-workspaces-migration-command.runner';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { FieldMetadataDefaultOption } from 'src/engine/metadata-modules/field-metadata/dtos/options.input';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
@ -29,7 +29,7 @@ import { ViewWorkspaceEntity } from 'src/modules/view/standard-objects/view.work
description: 'Add tasks assigned to me view',
version: '0.43',
})
export class AddTasksAssignedToMeViewCommand extends ActiveWorkspacesMigrationCommandRunner {
export class AddTasksAssignedToMeViewCommand extends MaintainedWorkspacesMigrationCommandRunner {
constructor(
@InjectRepository(Workspace, 'core')
protected readonly workspaceRepository: Repository<Workspace>,
@ -43,9 +43,9 @@ export class AddTasksAssignedToMeViewCommand extends ActiveWorkspacesMigrationCo
super(workspaceRepository, twentyORMGlobalManager);
}
async runMigrationCommandOnActiveWorkspaces(
async runMigrationCommandOnMaintainedWorkspaces(
_passedParam: string[],
options: ActiveWorkspacesMigrationCommandOptions,
options: MaintainedWorkspacesMigrationCommandOptions,
workspaceIds: string[],
): Promise<void> {
this.logger.log('Running command to create many to one relations');

View File

@ -0,0 +1,74 @@
import { InjectRepository } from '@nestjs/typeorm';
import chalk from 'chalk';
import { Repository } from 'typeorm';
import { MigrationCommand } from 'src/database/commands/migration-command/decorators/migration-command.decorator';
import {
MaintainedWorkspacesMigrationCommandOptions,
MaintainedWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/maintained-workspaces-migration-command.runner';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
@MigrationCommand({
name: 'migrate-is-searchable-for-custom-object-metadata',
description: 'Set isSearchable true for custom object metadata',
version: '0.43',
})
export class MigrateIsSearchableForCustomObjectMetadataCommand extends MaintainedWorkspacesMigrationCommandRunner {
constructor(
@InjectRepository(Workspace, 'core')
protected readonly workspaceRepository: Repository<Workspace>,
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
@InjectRepository(ObjectMetadataEntity, 'metadata')
protected readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
) {
super(workspaceRepository, twentyORMGlobalManager);
}
async runMigrationCommandOnMaintainedWorkspaces(
_passedParam: string[],
_options: MaintainedWorkspacesMigrationCommandOptions,
workspaceIds: string[],
): Promise<void> {
this.logger.log(
chalk.green(
'Running command to set isSearchable true for custom object metadata',
),
);
for (const [index, workspaceId] of workspaceIds.entries()) {
await this.processWorkspace(workspaceId, index, workspaceIds.length);
}
this.logger.log(chalk.green('Command completed!'));
}
private async processWorkspace(
workspaceId: string,
index: number,
total: number,
): Promise<void> {
try {
this.logger.log(
`Running command for workspace ${workspaceId} ${index + 1}/${total}`,
);
await this.objectMetadataRepository.update(
{
workspaceId,
isCustom: true,
},
{
isSearchable: true,
},
);
} catch (error) {
this.logger.log(
chalk.red(`Error in workspace ${workspaceId} - ${error.message}`),
);
}
}
}

View File

@ -7,11 +7,11 @@ import { In, Repository } from 'typeorm';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { isCommandLogger } from 'src/database/commands/logger';
import {
ActiveWorkspacesMigrationCommandOptions,
ActiveWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/active-workspaces-migration-command.runner';
import { MigrationCommand } from 'src/database/commands/migration-command/decorators/migration-command.decorator';
import {
MaintainedWorkspacesMigrationCommandOptions,
MaintainedWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/maintained-workspaces-migration-command.runner';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
@ -26,7 +26,7 @@ import { isFieldMetadataOfType } from 'src/engine/utils/is-field-metadata-of-typ
description: 'Migrate relations to field metadata',
version: '0.43',
})
export class MigrateRelationsToFieldMetadataCommand extends ActiveWorkspacesMigrationCommandRunner {
export class MigrateRelationsToFieldMetadataCommand extends MaintainedWorkspacesMigrationCommandRunner {
constructor(
@InjectRepository(Workspace, 'core')
protected readonly workspaceRepository: Repository<Workspace>,
@ -37,9 +37,9 @@ export class MigrateRelationsToFieldMetadataCommand extends ActiveWorkspacesMigr
super(workspaceRepository, twentyORMGlobalManager);
}
async runMigrationCommandOnActiveWorkspaces(
async runMigrationCommandOnMaintainedWorkspaces(
_passedParam: string[],
options: ActiveWorkspacesMigrationCommandOptions,
options: MaintainedWorkspacesMigrationCommandOptions,
workspaceIds: string[],
): Promise<void> {
this.logger.log('Running command to create many to one relations');

View File

@ -3,11 +3,11 @@ import { InjectRepository } from '@nestjs/typeorm';
import chalk from 'chalk';
import { Repository } from 'typeorm';
import {
ActiveWorkspacesMigrationCommandOptions,
ActiveWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/active-workspaces-migration-command.runner';
import { MigrationCommand } from 'src/database/commands/migration-command/decorators/migration-command.decorator';
import {
MaintainedWorkspacesMigrationCommandOptions,
MaintainedWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/maintained-workspaces-migration-command.runner';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
@ -24,7 +24,7 @@ import { SEARCH_FIELDS_FOR_TASKS } from 'src/modules/task/standard-objects/task.
description: 'Migrate search vector on note and task entities',
version: '0.43',
})
export class MigrateSearchVectorOnNoteAndTaskEntitiesCommand extends ActiveWorkspacesMigrationCommandRunner {
export class MigrateSearchVectorOnNoteAndTaskEntitiesCommand extends MaintainedWorkspacesMigrationCommandRunner {
constructor(
@InjectRepository(Workspace, 'core')
protected readonly workspaceRepository: Repository<Workspace>,
@ -40,9 +40,9 @@ export class MigrateSearchVectorOnNoteAndTaskEntitiesCommand extends ActiveWorks
super(workspaceRepository, twentyORMGlobalManager);
}
async runMigrationCommandOnActiveWorkspaces(
async runMigrationCommandOnMaintainedWorkspaces(
_passedParam: string[],
options: ActiveWorkspacesMigrationCommandOptions,
options: MaintainedWorkspacesMigrationCommandOptions,
workspaceIds: string[],
): Promise<void> {
this.logger.log(

View File

@ -3,7 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import chalk from 'chalk';
import { In, Repository } from 'typeorm';
import { BatchActiveWorkspacesMigrationCommandRunner } from 'src/database/commands/migration-command/batch-active-workspaces-migration-command.runner';
import { BatchMaintainedWorkspacesMigrationCommandRunner } from 'src/database/commands/migration-command/batch-maintained-workspaces-migration-command.runner';
import { MigrationCommand } from 'src/database/commands/migration-command/decorators/migration-command.decorator';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
@ -17,7 +17,7 @@ import { ViewOpenRecordInType } from 'src/modules/view/standard-objects/view.wor
'Update default view record opening on workflow objects to record page',
version: '0.43',
})
export class UpdateDefaultViewRecordOpeningOnWorkflowObjectsCommand extends BatchActiveWorkspacesMigrationCommandRunner {
export class UpdateDefaultViewRecordOpeningOnWorkflowObjectsCommand extends BatchMaintainedWorkspacesMigrationCommandRunner {
constructor(
@InjectRepository(Workspace, 'core')
protected readonly workspaceRepository: Repository<Workspace>,

View File

@ -1,9 +1,10 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { MigrationCommandModule } from 'src/database/commands/migration-command/miration-command.module';
import { MigrationCommandModule } from 'src/database/commands/migration-command/migration-command.module';
import { StandardizationOfActorCompositeContextTypeCommand } from 'src/database/commands/upgrade-version/0-42/0-42-standardization-of-actor-composite-context-type';
import { AddTasksAssignedToMeViewCommand } from 'src/database/commands/upgrade-version/0-43/0-43-add-tasks-assigned-to-me-view.command';
import { MigrateIsSearchableForCustomObjectMetadataCommand } from 'src/database/commands/upgrade-version/0-43/0-43-migrate-is-searchable-for-custom-object-metadata.command';
import { MigrateRelationsToFieldMetadataCommand } from 'src/database/commands/upgrade-version/0-43/0-43-migrate-relations-to-field-metadata.command';
import { MigrateSearchVectorOnNoteAndTaskEntitiesCommand } from 'src/database/commands/upgrade-version/0-43/0-43-migrate-search-vector-on-note-and-task-entities.command';
import { UpdateDefaultViewRecordOpeningOnWorkflowObjectsCommand } from 'src/database/commands/upgrade-version/0-43/0-43-update-default-view-record-opening-on-workflow-objects.command';
@ -33,6 +34,7 @@ import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/wor
providers: [
AddTasksAssignedToMeViewCommand,
MigrateSearchVectorOnNoteAndTaskEntitiesCommand,
MigrateIsSearchableForCustomObjectMetadataCommand,
UpdateDefaultViewRecordOpeningOnWorkflowObjectsCommand,
StandardizationOfActorCompositeContextTypeCommand,
MigrateRelationsToFieldMetadataCommand,

View File

@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddIsSearchableColumnInObjectMetadataTable1740478150675
implements MigrationInterface
{
name = 'AddIsSearchableColumnInObjectMetadataTable1740478150675';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "metadata"."objectMetadata" ADD "isSearchable" boolean NOT NULL DEFAULT false`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "metadata"."objectMetadata" DROP COLUMN "isSearchable"`,
);
}
}

View File

@ -19,6 +19,7 @@ export const mockPersonObjectMetadata = (
isActive: true,
isSystem: false,
isAuditLogged: true,
isSearchable: true,
duplicateCriteria: duplicateCriteria,
fromRelations: [],
toRelations: [],

View File

@ -6,6 +6,7 @@ import { WorkspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/work
import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface';
import { FindDuplicatesResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/factories/find-duplicates-resolver.factory';
import { SearchResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/factories/search-resolver-factory';
@Injectable()
export class WorkspaceResolverBuilderService {
@ -18,6 +19,8 @@ export class WorkspaceResolverBuilderService {
switch (methodName) {
case FindDuplicatesResolverFactory.methodName:
return isDefined(objectMetadata.duplicateCriteria);
case SearchResolverFactory.methodName:
return objectMetadata.isSearchable;
default:
return true;
}

View File

@ -7,22 +7,22 @@ import { Command } from 'nest-commander';
import { Repository } from 'typeorm';
import {
ActiveWorkspacesMigrationCommandOptions,
ActiveWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/active-workspaces-migration-command.runner';
MaintainedWorkspacesMigrationCommandOptions,
MaintainedWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/maintained-workspaces-migration-command.runner';
import { BillingCustomer } from 'src/engine/core-modules/billing/entities/billing-customer.entity';
import { StripeSubscriptionService } from 'src/engine/core-modules/billing/stripe/services/stripe-subscription.service';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
interface SyncCustomerDataCommandOptions
extends ActiveWorkspacesMigrationCommandOptions {}
extends MaintainedWorkspacesMigrationCommandOptions {}
@Command({
name: 'billing:sync-customer-data',
description: 'Sync customer data from Stripe for all active workspaces',
})
export class BillingSyncCustomerDataCommand extends ActiveWorkspacesMigrationCommandRunner {
export class BillingSyncCustomerDataCommand extends MaintainedWorkspacesMigrationCommandRunner {
constructor(
@InjectRepository(Workspace, 'core')
protected readonly workspaceRepository: Repository<Workspace>,
@ -34,7 +34,7 @@ export class BillingSyncCustomerDataCommand extends ActiveWorkspacesMigrationCom
super(workspaceRepository, twentyORMGlobalManager);
}
async runMigrationCommandOnActiveWorkspaces(
async runMigrationCommandOnMaintainedWorkspaces(
_passedParam: string[],
options: SyncCustomerDataCommandOptions,
workspaceIds: string[],

View File

@ -20,6 +20,7 @@ const mockObjectMetadata: ObjectMetadataInterface = {
isActive: true,
isRemote: false,
isAuditLogged: true,
isSearchable: true,
};
describe('objectRecordChangedValues', () => {

View File

@ -18,6 +18,7 @@ export const mockObjectMetadataItemsWithFieldMaps: ObjectMetadataItemWithFieldMa
isActive: true,
isSystem: false,
isAuditLogged: true,
isSearchable: true,
fromRelations: [],
toRelations: [],
labelIdentifierFieldMetadataId: 'nameFieldMetadataId',
@ -76,6 +77,7 @@ export const mockObjectMetadataItemsWithFieldMaps: ObjectMetadataItemWithFieldMa
isActive: true,
isSystem: false,
isAuditLogged: true,
isSearchable: true,
fromRelations: [],
toRelations: [],
labelIdentifierFieldMetadataId: 'nameFieldMetadataId',
@ -153,6 +155,7 @@ export const mockObjectMetadataItemsWithFieldMaps: ObjectMetadataItemWithFieldMa
isActive: true,
isSystem: false,
isAuditLogged: true,
isSearchable: true,
fromRelations: [],
toRelations: [],
labelIdentifierFieldMetadataId: 'nameFieldMetadataId',
@ -230,6 +233,7 @@ export const mockObjectMetadataItemsWithFieldMaps: ObjectMetadataItemWithFieldMa
isActive: true,
isSystem: true,
isAuditLogged: true,
isSearchable: false,
fromRelations: [],
toRelations: [],
labelIdentifierFieldMetadataId: '',

View File

@ -19,7 +19,7 @@ describe('GlobalSearchService', () => {
});
describe('filterObjectMetadataItems', () => {
it('should return searchable object metadata items -- TODO isSearchable only', () => {
it('should return searchable object metadata items', () => {
const objectMetadataItems = service.filterObjectMetadataItems(
mockObjectMetadataItemsWithFieldMaps,
[],

View File

@ -22,20 +22,9 @@ export class GlobalSearchService {
excludedObjectNameSingulars: string[] | undefined,
) {
return objectMetadataItemWithFieldMaps.filter(
({ nameSingular, isSystem, isRemote, isCustom }) => {
if (excludedObjectNameSingulars?.includes(nameSingular)) {
return false;
}
//TODO - #345 issue - IsSearchable decorator
if (isSystem || isRemote) {
return false;
}
({ nameSingular, isSearchable }) => {
return (
isCustom ||
['company', 'person', 'opportunity', 'note', 'task'].includes(
nameSingular,
)
!excludedObjectNameSingulars?.includes(nameSingular) && isSearchable
);
},
);

View File

@ -24,6 +24,7 @@ export interface ObjectMetadataInterface {
isActive: boolean;
isRemote: boolean;
isAuditLogged: boolean;
isSearchable: boolean;
duplicateCriteria?: WorkspaceEntityDuplicateCriteria[];
labelIdentifierFieldMetadataId?: string | null;
imageIdentifierFieldMetadataId?: string | null;

View File

@ -69,6 +69,9 @@ export class ObjectMetadataDTO {
@FilterableField()
isSystem: boolean;
@FilterableField()
isSearchable: boolean;
@HideField()
workspaceId: string;

View File

@ -70,6 +70,9 @@ export class ObjectMetadataEntity implements ObjectMetadataInterface {
@Column({ default: true })
isAuditLogged: boolean;
@Column({ default: false })
isSearchable: boolean;
@Column({ type: 'jsonb', nullable: true })
duplicateCriteria?: WorkspaceEntityDuplicateCriteria[];

View File

@ -120,6 +120,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
isCustom: !objectMetadataInput.isRemote,
isSystem: false,
isRemote: objectMetadataInput.isRemote,
isSearchable: !objectMetadataInput.isRemote,
fields: objectMetadataInput.isRemote
? []
: buildDefaultFieldsForCustomObject(objectMetadataInput.workspaceId),

View File

@ -37,6 +37,11 @@ export function WorkspaceEntity(
'workspace:duplicate-criteria-metadata-args',
target,
);
const isSearchable =
TypedReflect.getMetadata(
'workspace:is-searchable-metadata-args',
target,
) ?? false;
const objectName = convertClassNameToObjectMetadataName(target.name);
@ -57,6 +62,7 @@ export function WorkspaceEntity(
isSystem,
gate,
duplicateCriteria,
isSearchable,
});
};
}

View File

@ -0,0 +1,11 @@
import { TypedReflect } from 'src/utils/typed-reflect';
export function WorkspaceIsSearchable() {
return function (target: any): void {
TypedReflect.defineMetadata(
'workspace:is-searchable-metadata-args',
true,
target,
);
};
}

View File

@ -72,4 +72,9 @@ export interface WorkspaceEntityMetadataArgs {
* Duplicate criteria.
*/
readonly duplicateCriteria?: WorkspaceEntityDuplicateCriteria[];
/**
* Is searchable object.
*/
readonly isSearchable: boolean;
}

View File

@ -4,9 +4,9 @@ import { Command, Option } from 'nest-commander';
import { Repository } from 'typeorm';
import {
ActiveWorkspacesMigrationCommandOptions,
ActiveWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/active-workspaces-migration-command.runner';
MaintainedWorkspacesMigrationCommandOptions,
MaintainedWorkspacesMigrationCommandRunner,
} from 'src/database/commands/migration-command/maintained-workspaces-migration-command.runner';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
@ -16,7 +16,7 @@ import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/works
import { SyncWorkspaceLoggerService } from './services/sync-workspace-logger.service';
interface RunWorkspaceMigrationsOptions
extends ActiveWorkspacesMigrationCommandOptions {
extends MaintainedWorkspacesMigrationCommandOptions {
force?: boolean;
}
@ -24,7 +24,7 @@ interface RunWorkspaceMigrationsOptions
name: 'workspace:sync-metadata',
description: 'Sync metadata',
})
export class SyncWorkspaceMetadataCommand extends ActiveWorkspacesMigrationCommandRunner {
export class SyncWorkspaceMetadataCommand extends MaintainedWorkspacesMigrationCommandRunner {
constructor(
@InjectRepository(Workspace, 'core')
protected readonly workspaceRepository: Repository<Workspace>,
@ -37,7 +37,7 @@ export class SyncWorkspaceMetadataCommand extends ActiveWorkspacesMigrationComma
super(workspaceRepository, twentyORMGlobalManager);
}
async runMigrationCommandOnActiveWorkspaces(
async runMigrationCommandOnMaintainedWorkspaces(
_passedParam: string[],
options: RunWorkspaceMigrationsOptions,
workspaceIds: string[],

View File

@ -20,6 +20,7 @@ import { WorkspaceFieldIndex } from 'src/engine/twenty-orm/decorators/workspace-
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { WorkspaceIsDeprecated } from 'src/engine/twenty-orm/decorators/workspace-is-deprecated.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSearchable } from 'src/engine/twenty-orm/decorators/workspace-is-searchable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceIsUnique } from 'src/engine/twenty-orm/decorators/workspace-is-unique.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@ -59,6 +60,7 @@ export const SEARCH_FIELDS_FOR_COMPANY: FieldTypeAndNameMetadata[] = [
labelIdentifierStandardId: COMPANY_STANDARD_FIELD_IDS.name,
})
@WorkspaceDuplicateCriteria([['name'], ['domainNamePrimaryLinkUrl']])
@WorkspaceIsSearchable()
export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceField({
standardId: COMPANY_STANDARD_FIELD_IDS.name,

View File

@ -16,6 +16,7 @@ import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-enti
import { WorkspaceFieldIndex } from 'src/engine/twenty-orm/decorators/workspace-field-index.decorator';
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSearchable } from 'src/engine/twenty-orm/decorators/workspace-is-searchable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { NOTE_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
@ -48,6 +49,7 @@ export const SEARCH_FIELDS_FOR_NOTES: FieldTypeAndNameMetadata[] = [
shortcut: 'N',
labelIdentifierStandardId: NOTE_STANDARD_FIELD_IDS.title,
})
@WorkspaceIsSearchable()
export class NoteWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceField({
standardId: NOTE_STANDARD_FIELD_IDS.position,

View File

@ -18,6 +18,7 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field
import { WorkspaceIsDeprecated } from 'src/engine/twenty-orm/decorators/workspace-is-deprecated.decorator';
import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSearchable } from 'src/engine/twenty-orm/decorators/workspace-is-searchable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
@ -53,6 +54,7 @@ export const SEARCH_FIELDS_FOR_OPPORTUNITY: FieldTypeAndNameMetadata[] = [
labelIdentifierStandardId: OPPORTUNITY_STANDARD_FIELD_IDS.name,
})
@WorkspaceIsNotAuditLogged()
@WorkspaceIsSearchable()
export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceField({
standardId: OPPORTUNITY_STANDARD_FIELD_IDS.name,

View File

@ -21,6 +21,7 @@ import { WorkspaceFieldIndex } from 'src/engine/twenty-orm/decorators/workspace-
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { WorkspaceIsDeprecated } from 'src/engine/twenty-orm/decorators/workspace-is-deprecated.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSearchable } from 'src/engine/twenty-orm/decorators/workspace-is-searchable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceIsUnique } from 'src/engine/twenty-orm/decorators/workspace-is-unique.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
@ -68,6 +69,7 @@ export const SEARCH_FIELDS_FOR_PERSON: FieldTypeAndNameMetadata[] = [
['linkedinLinkPrimaryLinkUrl'],
['emailsPrimaryEmail'],
])
@WorkspaceIsSearchable()
export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceField({
standardId: PERSON_STANDARD_FIELD_IDS.name,

View File

@ -16,6 +16,7 @@ import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-enti
import { WorkspaceFieldIndex } from 'src/engine/twenty-orm/decorators/workspace-field-index.decorator';
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSearchable } from 'src/engine/twenty-orm/decorators/workspace-is-searchable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
@ -51,6 +52,7 @@ export const SEARCH_FIELDS_FOR_TASKS: FieldTypeAndNameMetadata[] = [
shortcut: 'T',
labelIdentifierStandardId: TASK_STANDARD_FIELD_IDS.title,
})
@WorkspaceIsSearchable()
export class TaskWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceField({
standardId: TASK_STANDARD_FIELD_IDS.position,

View File

@ -15,6 +15,7 @@ export interface ReflectMetadataTypeMap {
['workspace:is-unique-metadata-args']: true;
['workspace:duplicate-criteria-metadata-args']: WorkspaceEntityDuplicateCriteria[];
['environment-variables']: EnvironmentVariablesMetadataMap;
['workspace:is-searchable-metadata-args']: boolean;
}
export class TypedReflect {