Remove sync-metadata and IS_WORKSPACE_CREATION_V2_ENABLED feature flag (#16997)

# Introduction
Followup of
https://github.com/twentyhq/twenty/pull/17001#pullrequestreview-3638508738
close https://github.com/twentyhq/core-team-issues/issues/1910

We've completely decom the `sync-metadata` in production. We're now then
removing its implementation in favor of the v2.

## TODO:
- [x] Remove sync-metadata implem and commands
- [x] Remove workspace decorators 
- [x] Type each deprecated field to deprecated on their workspaceEntity
- [x] Remove the `workspace-sync-metadata` folder entirely
- [x] remove workspace migration
- [x] workspace migration removal migration
- [x] remove the `v2` references from workspace manager file names
- [x] remove the `v2` references from workspace manager modules
- [ ] Double check impact on translation file path updates


## Note
- Removed the gate logic
- Remains some service v2 naming, serverless needs to be migrated on v2
fully
- Removed workspaceMigration service app health consumption, making it
always returning up ( no more down ) cc @FelixMalfait ( quite obsolete
health check now, will require complete refactor once we introduce inter
app dependency etc )
This commit is contained in:
Paul Rastoin
2026-01-08 16:45:12 +01:00
committed by GitHub
parent f1aee7fd18
commit 942d2fef83
629 changed files with 1985 additions and 21492 deletions
@@ -1,220 +0,0 @@
import { Test, type TestingModule } from '@nestjs/testing';
import { getDataSourceToken, getRepositoryToken } from '@nestjs/typeorm';
import { type DataSource, type Repository } from 'typeorm';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { AgentService } from 'src/engine/metadata-modules/ai/ai-agent/agent.service';
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.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 { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity';
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.service';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { TwentyStandardApplicationService } from 'src/engine/workspace-manager/twenty-standard-application/services/twenty-standard-application.service';
import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service';
import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service';
describe('WorkspaceManagerService', () => {
let service: WorkspaceManagerService;
let workspaceMigrationRepository: Repository<WorkspaceMigrationEntity>;
let dataSourceRepository: Repository<DataSourceEntity>;
let roleTargetRepository: Repository<RoleTargetEntity>;
let roleRepository: Repository<RoleEntity>;
let serverlessFunctionRepository: Repository<ServerlessFunctionEntity>;
let mockDataSource: jest.Mocked<DataSource>;
let objectMetadataService: ObjectMetadataService;
beforeEach(async () => {
mockDataSource = {
transaction: jest.fn(),
} as any;
const module: TestingModule = await Test.createTestingModule({
providers: [
WorkspaceManagerService,
WorkspaceMigrationService,
DataSourceService,
{
provide: getDataSourceToken(),
useValue: mockDataSource,
},
{
provide: getRepositoryToken(WorkspaceEntity),
useValue: {},
},
{
provide: getRepositoryToken(UserWorkspaceEntity),
useValue: {},
},
{
provide: getRepositoryToken(FieldMetadataEntity),
useValue: {
delete: jest.fn(),
},
},
{
provide: getRepositoryToken(ObjectMetadataEntity),
useValue: {
delete: jest.fn(),
},
},
{
provide: getRepositoryToken(WorkspaceMigrationEntity),
useValue: {
delete: jest.fn(),
},
},
{
provide: getRepositoryToken(DataSourceEntity),
useValue: {
delete: jest.fn(),
},
},
{
provide: getRepositoryToken(RoleTargetEntity),
useValue: {
delete: jest.fn(),
},
},
{
provide: getRepositoryToken(RoleEntity),
useValue: {
delete: jest.fn(),
},
},
{
provide: getRepositoryToken(ServerlessFunctionEntity),
useValue: {
delete: jest.fn(),
},
},
{
provide: PermissionsService,
useValue: {},
},
{
provide: FeatureFlagService,
useValue: {},
},
{
provide: RoleService,
useValue: {},
},
{
provide: ApplicationService,
useValue: {},
},
{
provide: UserRoleService,
useValue: {},
},
{
provide: WorkspaceDataSourceService,
useValue: {
deleteWorkspaceDBSchema: jest.fn(),
},
},
{
provide: WorkspaceSyncMetadataService,
useValue: {},
},
{
provide: ObjectMetadataService,
useValue: {
deleteWorkspaceAllObjectMetadata: jest.fn(),
},
},
{
provide: TwentyStandardApplicationService,
useValue: {
synchronizeTwentyStandardApplicationOrThrow: jest.fn(),
},
},
{
provide: AgentService,
useValue: {
createOneAgent: jest
.fn()
.mockResolvedValue({ id: 'mock-agent-id' }),
},
},
{
provide: GlobalWorkspaceOrmManager,
useValue: {
getDataSourceForWorkspace: jest.fn().mockResolvedValue({
transaction: jest.fn(),
}),
},
},
{
provide: WorkspaceManyOrAllFlatEntityMapsCacheService,
useValue: {
invalidateEntireCache: jest.fn(),
},
},
],
}).compile();
service = module.get<WorkspaceManagerService>(WorkspaceManagerService);
workspaceMigrationRepository = module.get<
Repository<WorkspaceMigrationEntity>
>(getRepositoryToken(WorkspaceMigrationEntity));
dataSourceRepository = module.get<Repository<DataSourceEntity>>(
getRepositoryToken(DataSourceEntity),
);
roleTargetRepository = module.get<Repository<RoleTargetEntity>>(
getRepositoryToken(RoleTargetEntity),
);
roleRepository = module.get<Repository<RoleEntity>>(
getRepositoryToken(RoleEntity),
);
serverlessFunctionRepository = module.get<
Repository<ServerlessFunctionEntity>
>(getRepositoryToken(ServerlessFunctionEntity));
objectMetadataService = module.get<ObjectMetadataService>(
ObjectMetadataService,
);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('delete', () => {
it('should delete all the workspace metadata tables and workspace schema', async () => {
await service.delete('workspace-id');
expect(
objectMetadataService.deleteWorkspaceAllObjectMetadata,
).toHaveBeenCalled();
expect(workspaceMigrationRepository.delete).toHaveBeenCalledWith({
workspaceId: 'workspace-id',
});
expect(dataSourceRepository.delete).toHaveBeenCalledWith({
workspaceId: 'workspace-id',
});
expect(roleTargetRepository.delete).toHaveBeenCalledWith({
workspaceId: 'workspace-id',
});
expect(roleRepository.delete).toHaveBeenCalledWith({
workspaceId: 'workspace-id',
});
expect(serverlessFunctionRepository.delete).toHaveBeenCalledWith({
workspaceId: 'workspace-id',
});
});
});
});
@@ -25,7 +25,7 @@ import { TimelineActivitySeederService } from 'src/engine/workspace-manager/dev-
import { DevSeederMetadataService } from 'src/engine/workspace-manager/dev-seeder/metadata/services/dev-seeder-metadata.service';
import { DevSeederService } from 'src/engine/workspace-manager/dev-seeder/services/dev-seeder.service';
import { TwentyStandardApplicationModule } from 'src/engine/workspace-manager/twenty-standard-application/twenty-standard-application.module';
import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-v2.module';
import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module';
@Module({
imports: [
@@ -46,7 +46,7 @@ import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspa
ObjectPermissionModule,
WorkspaceManyOrAllFlatEntityMapsCacheModule,
WorkspaceCacheModule,
WorkspaceMigrationV2Module,
WorkspaceMigrationModule,
TwentyStandardApplicationModule,
],
exports: [DevSeederService],
@@ -1,270 +0,0 @@
import { isString } from '@sniptt/guards';
import { type DataSource, type QueryRunner } from 'typeorm';
import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity';
import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity';
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
import { ViewKey } from 'src/engine/metadata-modules/view/enums/view-key.enum';
import { ViewOpenRecordIn } from 'src/engine/metadata-modules/view/enums/view-open-record-in';
import { ViewType } from 'src/engine/metadata-modules/view/enums/view-type.enum';
import { ViewVisibility } from 'src/engine/metadata-modules/view/enums/view-visibility.enum';
import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type';
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
import { shouldSeedWorkspaceFavorite } from 'src/engine/utils/should-seed-workspace-favorite';
import { prefillWorkspaceFavorites } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-workspace-favorites';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { calendarEventsAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/calendar-events-all.view';
import { companiesAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view';
import { dashboardsAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/dashboards-all.view';
import { messageThreadsAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/message-threads-all.view';
import { messagesAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/messages-all.view';
import { notesAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view';
import { opportunitiesAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/opportunities-all.view';
import { opportunitiesByStageView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-by-stage.view';
import { peopleAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/people-all.view';
import { tasksAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view';
import { tasksAssignedToMeView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-assigned-to-me';
import { tasksByStatusView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-by-status.view';
import { timelineActivitiesAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/timeline-activities-all.view';
import { workflowRunsAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-runs-all.view';
import { workflowVersionsAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-versions-all.view';
import { workflowsAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/workflows-all.view';
import { workspaceMembersAllView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/workspace-members-all.view';
type PrefillCoreViewsArgs = {
coreDataSource: DataSource;
workspaceId: string;
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
featureFlags?: Record<string, boolean>;
workspaceSchemaName: string;
twentyStandardFlatApplication: FlatApplication;
};
// This is a temporary function to build the object metadata items from the flat maps.
// We should use the maps in the seeders instead.
const buildObjectMetadataItemsFromFlatMaps = (
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
): ObjectMetadataEntity[] => {
return Object.values(flatObjectMetadataMaps.byId)
.filter((flatObjectMetadata) => flatObjectMetadata !== undefined)
.map((flatObjectMetadata) => {
const fields = getFlatFieldsFromFlatObjectMetadata(
flatObjectMetadata,
flatFieldMetadataMaps,
);
return {
...flatObjectMetadata,
fields,
} as unknown as ObjectMetadataEntity;
});
};
export const prefillCoreViews = async ({
coreDataSource,
workspaceId,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
workspaceSchemaName,
twentyStandardFlatApplication,
}: PrefillCoreViewsArgs): Promise<ViewEntity[]> => {
const objectMetadataItems = buildObjectMetadataItemsFromFlatMaps(
flatObjectMetadataMaps,
flatFieldMetadataMaps,
);
const views = [
companiesAllView,
peopleAllView,
opportunitiesAllView,
opportunitiesByStageView,
notesAllView,
tasksAllView,
tasksAssignedToMeView,
tasksByStatusView,
workflowsAllView,
workflowVersionsAllView,
workflowRunsAllView,
dashboardsAllView,
workspaceMembersAllView,
messagesAllView,
messageThreadsAllView,
calendarEventsAllView,
timelineActivitiesAllView,
].map((seeder) =>
seeder({
objectMetadataItems,
useCoreNaming: true,
twentyStandardFlatApplication,
}),
);
const queryRunner = coreDataSource.createQueryRunner();
await queryRunner.connect();
try {
await queryRunner.startTransaction();
const createdViews = await createCoreViews(
queryRunner,
workspaceId,
views,
twentyStandardFlatApplication,
);
await prefillWorkspaceFavorites(
createdViews
.filter(
(view) =>
view.key === 'INDEX' &&
shouldSeedWorkspaceFavorite(
view.objectMetadataId,
objectMetadataItems,
),
)
.map((view) => view.id),
queryRunner.manager as WorkspaceEntityManager,
workspaceSchemaName,
);
await queryRunner.commitTransaction();
return createdViews;
} catch (error) {
if (queryRunner.isTransactionActive) {
try {
await queryRunner.rollbackTransaction();
} catch (error) {
// eslint-disable-next-line no-console
console.trace(`Failed to rollback transaction: ${error.message}`);
}
}
throw error;
} finally {
await queryRunner.release();
}
};
export const createCoreViews = async (
queryRunner: QueryRunner,
workspaceId: string,
viewDefinitions: ViewDefinition[],
twentyStandardFlatApplication: FlatApplication,
): Promise<ViewEntity[]> => {
const coreViews: Partial<ViewEntity>[] = viewDefinitions.map(
({
id,
name,
objectMetadataId,
type,
key,
position,
icon,
isCustom,
openRecordIn,
mainGroupByFieldMetadataId,
kanbanAggregateOperation,
kanbanAggregateOperationFieldMetadataId,
applicationId,
universalIdentifier,
}) => ({
id,
name: isString(name) ? name : name.message || '',
objectMetadataId,
type: type === 'kanban' ? ViewType.KANBAN : ViewType.TABLE,
key: key === ViewKey.INDEX ? ViewKey.INDEX : null,
position,
icon,
isCompact: false,
isCustom: isCustom ?? false,
openRecordIn:
openRecordIn === ViewOpenRecordInType.RECORD_PAGE
? ViewOpenRecordIn.RECORD_PAGE
: ViewOpenRecordIn.SIDE_PANEL,
kanbanAggregateOperation,
kanbanAggregateOperationFieldMetadataId,
mainGroupByFieldMetadataId,
workspaceId,
anyFieldFilterValue: null,
visibility: ViewVisibility.WORKSPACE,
applicationId,
universalIdentifier,
}),
);
const viewRepository = queryRunner.manager.getRepository(ViewEntity);
const createdViews = await viewRepository.save(coreViews);
for (const viewDefinition of viewDefinitions) {
if (viewDefinition.fields && viewDefinition.fields.length > 0) {
const coreViewFields: Partial<ViewFieldEntity>[] =
viewDefinition.fields.map((field) => ({
fieldMetadataId: field.fieldMetadataId,
position: field.position,
isVisible: field.isVisible,
size: field.size,
viewId: viewDefinition.id,
workspaceId,
applicationId: twentyStandardFlatApplication.id,
universalIdentifier: field.universalIdentifier,
}));
const viewFieldRepository =
queryRunner.manager.getRepository(ViewFieldEntity);
await viewFieldRepository.save(coreViewFields);
}
if (viewDefinition.filters && viewDefinition.filters.length > 0) {
const coreViewFilters: Partial<ViewFilterEntity>[] =
viewDefinition.filters.map((filter) => ({
fieldMetadataId: filter.fieldMetadataId,
viewId: viewDefinition.id,
operand: filter.operand,
value: filter.value,
workspaceId,
applicationId: twentyStandardFlatApplication.id,
universalIdentifier: filter.universalIdentifier,
}));
const viewFilterRepository =
queryRunner.manager.getRepository(ViewFilterEntity);
await viewFilterRepository.save(coreViewFilters);
}
if (
'groups' in viewDefinition &&
viewDefinition.groups &&
viewDefinition.groups.length > 0
) {
const coreViewGroups: Partial<ViewGroupEntity>[] =
viewDefinition.groups.map((group) => ({
fieldMetadataId: group.fieldMetadataId,
isVisible: group.isVisible,
fieldValue: group.fieldValue,
position: group.position,
viewId: viewDefinition.id,
workspaceId,
applicationId: twentyStandardFlatApplication.id,
universalIdentifier: group.universalIdentifier,
}));
const viewGroupRepository =
queryRunner.manager.getRepository(ViewGroupEntity);
await viewGroupRepository.save(coreViewGroups);
}
}
return createdViews;
};
@@ -1,46 +0,0 @@
import { type MessageDescriptor } from '@lingui/core';
import { type ViewFilterOperand } from 'twenty-shared/types';
import { type AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
import { type ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type';
export interface ViewDefinition {
id?: string;
name: string | MessageDescriptor;
objectMetadataId: string;
type: string;
key: string | null;
position: number;
applicationId: string;
universalIdentifier: string;
icon?: string;
isCustom?: boolean;
openRecordIn?: ViewOpenRecordInType;
kanbanAggregateOperation?: AggregateOperations;
kanbanAggregateOperationFieldMetadataId?: string;
mainGroupByFieldMetadataId?: string;
calendarFieldMetadataId?: string;
calendarLayout?: string;
fields?: {
universalIdentifier: string;
fieldMetadataId: string;
position: number;
isVisible: boolean;
size: number;
aggregateOperation?: AggregateOperations;
}[];
filters?: {
universalIdentifier: string;
fieldMetadataId: string;
displayValue: string;
operand: ViewFilterOperand;
value: string;
}[];
groups?: {
universalIdentifier: string;
fieldMetadataId: string;
isVisible: boolean;
fieldValue: string;
position: number;
}[];
}
@@ -1,160 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
CALENDAR_EVENT_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const calendarEventsAllView = ({
objectMetadataItems,
twentyStandardFlatApplication,
useCoreNaming,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const calendarEventObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.calendarEvent,
);
if (!calendarEventObjectMetadata) {
throw new Error('CalendarEvent object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Calendar Events',
objectMetadataId: calendarEventObjectMetadata.id ?? '',
type: 'calendar',
key: 'INDEX',
position: 0,
icon: 'IconCalendar',
calendarFieldMetadataId:
calendarEventObjectMetadata.fields.find(
(field) =>
field.standardId === CALENDAR_EVENT_STANDARD_FIELD_IDS.startsAt,
)?.id ?? '',
calendarLayout: 'MONTH',
filters: [],
fields: [
{
fieldMetadataId:
calendarEventObjectMetadata.fields.find(
(field) =>
field.standardId === CALENDAR_EVENT_STANDARD_FIELD_IDS.title,
)?.id ?? '',
position: 0,
isVisible: true,
size: DEFAULT_VIEW_FIELD_SIZE,
universalIdentifier:
STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields
.title.universalIdentifier,
},
{
fieldMetadataId:
calendarEventObjectMetadata.fields.find(
(field) =>
field.standardId === CALENDAR_EVENT_STANDARD_FIELD_IDS.startsAt,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields
.startsAt.universalIdentifier,
},
{
fieldMetadataId:
calendarEventObjectMetadata.fields.find(
(field) =>
field.standardId === CALENDAR_EVENT_STANDARD_FIELD_IDS.endsAt,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields
.endsAt.universalIdentifier,
},
{
fieldMetadataId:
calendarEventObjectMetadata.fields.find(
(field) =>
field.standardId === CALENDAR_EVENT_STANDARD_FIELD_IDS.isFullDay,
)?.id ?? '',
position: 3,
isVisible: true,
size: 100,
universalIdentifier:
STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields
.isFullDay.universalIdentifier,
},
{
fieldMetadataId:
calendarEventObjectMetadata.fields.find(
(field) =>
field.standardId === CALENDAR_EVENT_STANDARD_FIELD_IDS.location,
)?.id ?? '',
position: 4,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields
.location.universalIdentifier,
},
{
fieldMetadataId:
calendarEventObjectMetadata.fields.find(
(field) =>
field.standardId ===
CALENDAR_EVENT_STANDARD_FIELD_IDS.conferenceLink,
)?.id ?? '',
position: 5,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields
.conferenceLink.universalIdentifier,
},
{
fieldMetadataId:
calendarEventObjectMetadata.fields.find(
(field) =>
field.standardId === CALENDAR_EVENT_STANDARD_FIELD_IDS.isCanceled,
)?.id ?? '',
position: 6,
isVisible: true,
size: 100,
universalIdentifier:
STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields
.isCanceled.universalIdentifier,
},
{
fieldMetadataId:
calendarEventObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.createdAt,
)?.id ?? '',
position: 7,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields
.createdAt.universalIdentifier,
},
],
};
};
@@ -1,156 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
COMPANY_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const companiesAllView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const companyObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.company,
);
if (!companyObjectMetadata) {
throw new Error('Company object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.company.views.allCompanies.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Companies',
objectMetadataId: companyObjectMetadata.id ?? '',
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconList',
filters: [],
fields: [
{
fieldMetadataId:
companyObjectMetadata.fields.find(
(field) => field.standardId === COMPANY_STANDARD_FIELD_IDS.name,
)?.id ?? '',
position: 0,
isVisible: true,
size: DEFAULT_VIEW_FIELD_SIZE,
universalIdentifier:
STANDARD_OBJECTS.company.views.allCompanies.viewFields.name
.universalIdentifier,
},
{
fieldMetadataId:
companyObjectMetadata.fields.find(
(field) =>
field.standardId === COMPANY_STANDARD_FIELD_IDS.domainName,
)?.id ?? '',
position: 1,
isVisible: true,
size: 100,
aggregateOperation: AggregateOperations.COUNT,
universalIdentifier:
STANDARD_OBJECTS.company.views.allCompanies.viewFields.domainName
.universalIdentifier,
},
{
fieldMetadataId:
companyObjectMetadata.fields.find(
(field) =>
field.standardId === COMPANY_STANDARD_FIELD_IDS.createdBy,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.company.views.allCompanies.viewFields.createdBy
.universalIdentifier,
},
{
fieldMetadataId:
companyObjectMetadata.fields.find(
(field) =>
field.standardId === COMPANY_STANDARD_FIELD_IDS.accountOwner,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.company.views.allCompanies.viewFields.accountOwner
.universalIdentifier,
},
{
fieldMetadataId:
companyObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.createdAt,
)?.id ?? '',
position: 4,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.company.views.allCompanies.viewFields.createdAt
.universalIdentifier,
},
{
fieldMetadataId:
companyObjectMetadata.fields.find(
(field) =>
field.standardId === COMPANY_STANDARD_FIELD_IDS.employees,
)?.id ?? '',
position: 5,
isVisible: true,
size: 150,
aggregateOperation: AggregateOperations.MAX,
universalIdentifier:
STANDARD_OBJECTS.company.views.allCompanies.viewFields.employees
.universalIdentifier,
},
{
fieldMetadataId:
companyObjectMetadata.fields.find(
(field) =>
field.standardId === COMPANY_STANDARD_FIELD_IDS.linkedinLink,
)?.id ?? '',
position: 6,
isVisible: true,
size: 170,
aggregateOperation: AggregateOperations.PERCENTAGE_EMPTY,
universalIdentifier:
STANDARD_OBJECTS.company.views.allCompanies.viewFields.linkedinLink
.universalIdentifier,
},
{
fieldMetadataId:
companyObjectMetadata.fields.find(
(field) => field.standardId === COMPANY_STANDARD_FIELD_IDS.address,
)?.id ?? '',
position: 7,
isVisible: true,
size: 170,
aggregateOperation: AggregateOperations.COUNT_NOT_EMPTY,
universalIdentifier:
STANDARD_OBJECTS.company.views.allCompanies.viewFields.address
.universalIdentifier,
},
],
};
};
@@ -1 +0,0 @@
export const DEFAULT_VIEW_FIELD_SIZE = 180;
@@ -1,101 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
DASHBOARD_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const dashboardsAllView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const dashboardObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.dashboard,
);
if (!dashboardObjectMetadata) {
throw new Error('Dashboard object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.dashboard.views.allDashboards.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Dashboards',
objectMetadataId: dashboardObjectMetadata.id ?? '',
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconLayoutDashboard',
openRecordIn: ViewOpenRecordInType.RECORD_PAGE,
filters: [],
fields: [
{
fieldMetadataId:
dashboardObjectMetadata.fields.find(
(field) => field.standardId === DASHBOARD_STANDARD_FIELD_IDS.title,
)?.id ?? '',
position: 0,
isVisible: true,
size: 200,
universalIdentifier:
STANDARD_OBJECTS.dashboard.views.allDashboards.viewFields.title
.universalIdentifier,
},
{
fieldMetadataId:
dashboardObjectMetadata.fields.find(
(field) =>
field.standardId === DASHBOARD_STANDARD_FIELD_IDS.createdBy,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.dashboard.views.allDashboards.viewFields.createdBy
.universalIdentifier,
},
{
fieldMetadataId:
dashboardObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.createdAt,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.dashboard.views.allDashboards.viewFields.createdAt
.universalIdentifier,
},
{
fieldMetadataId:
dashboardObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.updatedAt,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.dashboard.views.allDashboards.viewFields.updatedAt
.universalIdentifier,
},
],
};
};
@@ -1,75 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
MESSAGE_THREAD_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const messageThreadsAllView = ({
objectMetadataItems,
twentyStandardFlatApplication,
useCoreNaming,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const messageThreadObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.messageThread,
);
if (!messageThreadObjectMetadata) {
throw new Error('MessageThread object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.messageThread.views.allMessageThreads.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Message Threads',
objectMetadataId: messageThreadObjectMetadata.id ?? '',
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconList',
filters: [],
fields: [
{
fieldMetadataId:
messageThreadObjectMetadata.fields.find(
(field) =>
field.standardId === MESSAGE_THREAD_STANDARD_FIELD_IDS.messages,
)?.id ?? '',
position: 0,
isVisible: true,
size: DEFAULT_VIEW_FIELD_SIZE,
universalIdentifier:
STANDARD_OBJECTS.messageThread.views.allMessageThreads.viewFields
.messages.universalIdentifier,
},
{
fieldMetadataId:
messageThreadObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.createdAt,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.messageThread.views.allMessageThreads.viewFields
.createdAt.universalIdentifier,
},
],
};
};
@@ -1,139 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
MESSAGE_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const messagesAllView = ({
objectMetadataItems,
twentyStandardFlatApplication,
useCoreNaming,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const messageObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.message,
);
if (!messageObjectMetadata) {
throw new Error('Message object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.message.views.allMessages.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Messages',
objectMetadataId: messageObjectMetadata.id ?? '',
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconList',
filters: [],
fields: [
{
fieldMetadataId:
messageObjectMetadata.fields.find(
(field) => field.standardId === MESSAGE_STANDARD_FIELD_IDS.subject,
)?.id ?? '',
position: 0,
isVisible: true,
size: DEFAULT_VIEW_FIELD_SIZE,
universalIdentifier:
STANDARD_OBJECTS.message.views.allMessages.viewFields.subject
.universalIdentifier,
},
{
fieldMetadataId:
messageObjectMetadata.fields.find(
(field) =>
field.standardId === MESSAGE_STANDARD_FIELD_IDS.messageThread,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.message.views.allMessages.viewFields.messageThread
.universalIdentifier,
},
{
fieldMetadataId:
messageObjectMetadata.fields.find(
(field) =>
field.standardId ===
MESSAGE_STANDARD_FIELD_IDS.messageParticipants,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.message.views.allMessages.viewFields
.messageParticipants.universalIdentifier,
},
{
fieldMetadataId:
messageObjectMetadata.fields.find(
(field) =>
field.standardId === MESSAGE_STANDARD_FIELD_IDS.receivedAt,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.message.views.allMessages.viewFields.receivedAt
.universalIdentifier,
},
{
fieldMetadataId:
messageObjectMetadata.fields.find(
(field) =>
field.standardId === MESSAGE_STANDARD_FIELD_IDS.headerMessageId,
)?.id ?? '',
position: 4,
isVisible: true,
size: 180,
universalIdentifier:
STANDARD_OBJECTS.message.views.allMessages.viewFields.headerMessageId
.universalIdentifier,
},
{
fieldMetadataId:
messageObjectMetadata.fields.find(
(field) => field.standardId === MESSAGE_STANDARD_FIELD_IDS.text,
)?.id ?? '',
position: 5,
isVisible: true,
size: 200,
universalIdentifier:
STANDARD_OBJECTS.message.views.allMessages.viewFields.text
.universalIdentifier,
},
{
fieldMetadataId:
messageObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.createdAt,
)?.id ?? '',
position: 6,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.message.views.allMessages.viewFields.createdAt
.universalIdentifier,
},
],
};
};
@@ -1,119 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
NOTE_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const notesAllView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const noteObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.note,
);
if (!noteObjectMetadata) {
throw new Error('Note object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.note.views.allNotes.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Notes',
objectMetadataId: noteObjectMetadata.id,
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconNotes',
filters: [],
fields: [
{
fieldMetadataId:
noteObjectMetadata.fields.find(
(field) => field.standardId === NOTE_STANDARD_FIELD_IDS.title,
)?.id ?? '',
position: 0,
isVisible: true,
size: 210,
universalIdentifier:
STANDARD_OBJECTS.note.views.allNotes.viewFields.title
.universalIdentifier,
},
{
fieldMetadataId:
noteObjectMetadata.fields.find(
(field) => field.standardId === NOTE_STANDARD_FIELD_IDS.noteTargets,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.note.views.allNotes.viewFields.noteTargets
.universalIdentifier,
},
{
fieldMetadataId:
noteObjectMetadata.fields.find(
(field) => field.standardId === NOTE_STANDARD_FIELD_IDS.bodyV2,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.note.views.allNotes.viewFields.bodyV2
.universalIdentifier,
},
{
fieldMetadataId:
noteObjectMetadata.fields.find(
(field) => field.standardId === NOTE_STANDARD_FIELD_IDS.createdBy,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.note.views.allNotes.viewFields.createdBy
.universalIdentifier,
},
{
fieldMetadataId:
noteObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.createdAt,
)?.id ?? '',
position: 4,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.note.views.allNotes.viewFields.createdAt
.universalIdentifier,
},
/*
TODO: Add later, since we don't have real-time it probably doesn't work well?
{
fieldMetadataId:
objectMetadataMap[STANDARD_OBJECT_IDS.note].fields[.updatedAt
],
position: 0,
isVisible: true,
size: 210},
*/
],
};
};
@@ -1,126 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import { OPPORTUNITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const opportunitiesAllView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const opportunityObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.opportunity,
);
if (!opportunityObjectMetadata) {
throw new Error('Opportunity object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.opportunity.views.allOpportunities.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Opportunities',
objectMetadataId: opportunityObjectMetadata.id,
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconList',
filters: [],
fields: [
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) => field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.name,
)?.id ?? '',
position: 0,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.allOpportunities.viewFields.name
.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.amount,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
aggregateOperation: AggregateOperations.AVG,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.allOpportunities.viewFields.amount
.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.createdBy,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.allOpportunities.viewFields
.createdBy.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.closeDate,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
aggregateOperation: AggregateOperations.MIN,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.allOpportunities.viewFields
.closeDate.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.company,
)?.id ?? '',
position: 4,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.allOpportunities.viewFields.company
.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId ===
OPPORTUNITY_STANDARD_FIELD_IDS.pointOfContact,
)?.id ?? '',
position: 5,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.allOpportunities.viewFields
.pointOfContact.universalIdentifier,
},
],
};
};
@@ -1,202 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import { OPPORTUNITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const opportunitiesByStageView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const opportunityObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.opportunity,
);
if (!opportunityObjectMetadata) {
throw new Error('Opportunity object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.opportunity.views.byStage.universalIdentifier;
const stageFieldMetadataId =
opportunityObjectMetadata.fields.find(
(field) => field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.stage,
)?.id ?? '';
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`By Stage` : 'By Stage',
objectMetadataId: opportunityObjectMetadata.id,
type: 'kanban',
key: null,
position: 2,
icon: 'IconLayoutKanban',
kanbanAggregateOperation: AggregateOperations.SUM,
kanbanAggregateOperationFieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) => field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.amount,
)?.id ?? '',
filters: [],
mainGroupByFieldMetadataId: stageFieldMetadataId,
fields: [
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) => field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.name,
)?.id ?? '',
position: 0,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.byStage.viewFields.name
.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.amount,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.byStage.viewFields.amount
.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.createdBy,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.byStage.viewFields.createdBy
.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.closeDate,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.byStage.viewFields.closeDate
.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.company,
)?.id ?? '',
position: 4,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.byStage.viewFields.company
.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId ===
OPPORTUNITY_STANDARD_FIELD_IDS.pointOfContact,
)?.id ?? '',
position: 5,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.byStage.viewFields.pointOfContact
.universalIdentifier,
},
],
groups: [
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.stage,
)?.id ?? '',
isVisible: true,
fieldValue: 'NEW',
position: 0,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.byStage.viewGroups!.new
.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.stage,
)?.id ?? '',
isVisible: true,
fieldValue: 'SCREENING',
position: 1,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.byStage.viewGroups!.screening
.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.stage,
)?.id ?? '',
isVisible: true,
fieldValue: 'MEETING',
position: 2,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.byStage.viewGroups!.meeting
.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.stage,
)?.id ?? '',
isVisible: true,
fieldValue: 'PROPOSAL',
position: 3,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.byStage.viewGroups!.proposal
.universalIdentifier,
},
{
fieldMetadataId:
opportunityObjectMetadata.fields.find(
(field) =>
field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.stage,
)?.id ?? '',
isVisible: true,
fieldValue: 'CUSTOMER',
position: 4,
universalIdentifier:
STANDARD_OBJECTS.opportunity.views.byStage.viewGroups!.customer
.universalIdentifier,
},
],
};
};
@@ -1,174 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
PERSON_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const peopleAllView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const personObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.person,
);
if (!personObjectMetadata) {
throw new Error('Person object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.person.views.allPeople.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All People',
objectMetadataId: personObjectMetadata.id,
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconList',
filters: [],
fields: [
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.name,
)?.id ?? '',
position: 0,
isVisible: true,
size: 210,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.name
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.emails,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
aggregateOperation: AggregateOperations.COUNT_UNIQUE_VALUES,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.emails
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.createdBy,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.createdBy
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.company,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.company
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.phones,
)?.id ?? '',
position: 4,
isVisible: true,
size: 150,
aggregateOperation: AggregateOperations.PERCENTAGE_EMPTY,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.phones
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.createdAt,
)?.id ?? '',
position: 5,
isVisible: true,
size: 150,
aggregateOperation: AggregateOperations.MIN,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.createdAt
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.city,
)?.id ?? '',
position: 6,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.city
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.jobTitle,
)?.id ?? '',
position: 7,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.jobTitle
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) =>
field.standardId === PERSON_STANDARD_FIELD_IDS.linkedinLink,
)?.id ?? '',
position: 8,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.linkedinLink
.universalIdentifier,
},
{
fieldMetadataId:
personObjectMetadata.fields.find(
(field) => field.standardId === PERSON_STANDARD_FIELD_IDS.xLink,
)?.id ?? '',
position: 9,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.person.views.allPeople.viewFields.xLink
.universalIdentifier,
},
],
};
};
@@ -1,164 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
TASK_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const tasksAllView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const taskObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.task,
);
if (!taskObjectMetadata) {
throw new Error('Task object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.task.views.allTasks.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Tasks',
objectMetadataId: taskObjectMetadata.id,
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconList',
filters: [] /* [
{
fieldMetadataId:
objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[
TASK_STANDARD_FIELD_IDS.type
],
displayValue: 'Task',
operand: 'is',
value: '["TASK"]'},
],*/,
fields: [
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.title,
)?.id ?? '',
position: 0,
isVisible: true,
size: 210,
universalIdentifier:
STANDARD_OBJECTS.task.views.allTasks.viewFields.title
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.status,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.allTasks.viewFields.status
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.taskTargets,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.allTasks.viewFields.taskTargets
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.createdBy,
)?.id ?? '',
position: 4,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.allTasks.viewFields.createdBy
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.dueAt,
)?.id ?? '',
position: 5,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.allTasks.viewFields.dueAt
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.assignee,
)?.id ?? '',
position: 6,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.allTasks.viewFields.assignee
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.bodyV2,
)?.id ?? '',
position: 7,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.allTasks.viewFields.bodyV2
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.createdAt,
)?.id ?? '',
position: 8,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.allTasks.viewFields.createdAt
.universalIdentifier,
},
/*
TODO: Add later, since we don't have real-time it probably doesn't work well?
{
fieldMetadataId:
objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[.updatedAt
],
position: 0,
isVisible: true,
size: 210},
*/
],
};
};
@@ -1,212 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { ViewFilterOperand } from 'twenty-shared/types';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
TASK_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const tasksAssignedToMeView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const taskObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.task,
);
if (!taskObjectMetadata) {
throw new Error('Task object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.task.views.assignedToMe.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`Assigned to Me` : 'Assigned to Me',
objectMetadataId: taskObjectMetadata.id,
type: 'table',
key: null,
position: 2,
icon: 'IconUserCircle',
mainGroupByFieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.status,
)?.id ?? '',
filters: [
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.assignee,
)?.id ?? '',
displayValue: 'Me',
operand: ViewFilterOperand.IS,
value: JSON.stringify({
isCurrentWorkspaceMemberSelected: true,
selectedRecordIds: [],
}),
universalIdentifier:
STANDARD_OBJECTS.task.views.assignedToMe.viewFilters!.assigneeIsMe
.universalIdentifier,
},
],
fields: [
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.title,
)?.id ?? '',
position: 0,
isVisible: true,
size: 210,
universalIdentifier:
STANDARD_OBJECTS.task.views.assignedToMe.viewFields.title
.universalIdentifier,
},
/*{
fieldMetadataId:
objectMetadataStandardIdToIdMap[STANDARD_OBJECT_IDS.task].fields[
TASK_STANDARD_FIELD_IDS.status
],
position: 2,
isVisible: true,
size: 150},*/
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.taskTargets,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.assignedToMe.viewFields.taskTargets
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.createdBy,
)?.id ?? '',
position: 4,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.assignedToMe.viewFields.createdBy
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.dueAt,
)?.id ?? '',
position: 5,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.assignedToMe.viewFields.dueAt
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.assignee,
)?.id ?? '',
position: 6,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.assignedToMe.viewFields.assignee
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.bodyV2,
)?.id ?? '',
position: 7,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.assignedToMe.viewFields.bodyV2
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.createdAt,
)?.id ?? '',
position: 8,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.assignedToMe.viewFields.createdAt
.universalIdentifier,
},
],
groups: [
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.status,
)?.id ?? '',
isVisible: true,
fieldValue: 'TODO',
position: 0,
universalIdentifier:
STANDARD_OBJECTS.task.views.assignedToMe.viewGroups!.todo
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.status,
)?.id ?? '',
isVisible: true,
fieldValue: 'IN_PROGRESS',
position: 1,
universalIdentifier:
STANDARD_OBJECTS.task.views.assignedToMe.viewGroups!.inProgress
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.status,
)?.id ?? '',
isVisible: true,
fieldValue: 'DONE',
position: 2,
universalIdentifier:
STANDARD_OBJECTS.task.views.assignedToMe.viewGroups!.done
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.status,
)?.id ?? '',
isVisible: true,
fieldValue: '',
position: 3,
universalIdentifier:
STANDARD_OBJECTS.task.views.assignedToMe.viewGroups!.empty
.universalIdentifier,
},
],
};
};
@@ -1,170 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
TASK_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const tasksByStatusView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const taskObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.task,
);
if (!taskObjectMetadata) {
throw new Error('Task object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.task.views.byStatus.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`By Status` : 'By Status',
objectMetadataId: taskObjectMetadata.id,
type: 'kanban',
key: null,
position: 1,
icon: 'IconLayoutKanban',
mainGroupByFieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.status,
)?.id ?? '',
filters: [] /* [
{
fieldMetadataId:
objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[
TASK_STANDARD_FIELD_IDS.type
],
displayValue: 'Task',
operand: 'is',
value: '["TASK"]'},
],*/,
fields: [
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.title,
)?.id ?? '',
position: 0,
isVisible: true,
size: 210,
universalIdentifier:
STANDARD_OBJECTS.task.views.byStatus.viewFields.title
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.status,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.byStatus.viewFields.status
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.dueAt,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.byStatus.viewFields.dueAt
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.assignee,
)?.id ?? '',
position: 4,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.byStatus.viewFields.assignee
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.createdAt,
)?.id ?? '',
position: 6,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.task.views.byStatus.viewFields.createdAt
.universalIdentifier,
},
/*
TODO: Add later, since we don't have real-time it probably doesn't work well?
{
fieldMetadataId:
objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[.updatedAt
],
position: 0,
isVisible: true,
size: 210},
*/
],
groups: [
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.status,
)?.id ?? '',
isVisible: true,
fieldValue: 'TODO',
position: 0,
universalIdentifier:
STANDARD_OBJECTS.task.views.byStatus.viewGroups!.todo
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.status,
)?.id ?? '',
isVisible: true,
fieldValue: 'IN_PROGRESS',
position: 1,
universalIdentifier:
STANDARD_OBJECTS.task.views.byStatus.viewGroups!.inProgress
.universalIdentifier,
},
{
fieldMetadataId:
taskObjectMetadata.fields.find(
(field) => field.standardId === TASK_STANDARD_FIELD_IDS.status,
)?.id ?? '',
isVisible: true,
fieldValue: 'DONE',
position: 2,
universalIdentifier:
STANDARD_OBJECTS.task.views.byStatus.viewGroups!.done
.universalIdentifier,
},
],
};
};
@@ -1,120 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import { TIMELINE_ACTIVITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const timelineActivitiesAllView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const timelineActivityObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.timelineActivity,
);
if (!timelineActivityObjectMetadata) {
throw new Error('TimelineActivity object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.timelineActivity.views.allTimelineActivities
.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming
? msg`All {objectLabelPlural}`
: 'All Timeline Activities',
objectMetadataId: timelineActivityObjectMetadata.id,
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconList',
openRecordIn: ViewOpenRecordInType.RECORD_PAGE,
filters: [],
fields: [
{
fieldMetadataId:
timelineActivityObjectMetadata.fields.find(
(field) =>
field.standardId === TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.name,
)?.id ?? '',
position: 0,
isVisible: true,
size: DEFAULT_VIEW_FIELD_SIZE,
universalIdentifier:
STANDARD_OBJECTS.timelineActivity.views.allTimelineActivities
.viewFields.name.universalIdentifier,
},
{
fieldMetadataId:
timelineActivityObjectMetadata.fields.find(
(field) =>
field.standardId ===
TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.happensAt,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.timelineActivity.views.allTimelineActivities
.viewFields.happensAt.universalIdentifier,
},
{
fieldMetadataId:
timelineActivityObjectMetadata.fields.find(
(field) =>
field.standardId ===
TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.properties,
)?.id ?? '',
position: 2,
isVisible: true,
size: 200,
universalIdentifier:
STANDARD_OBJECTS.timelineActivity.views.allTimelineActivities
.viewFields.properties.universalIdentifier,
},
{
fieldMetadataId:
timelineActivityObjectMetadata.fields.find(
(field) =>
field.standardId ===
TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.workspaceMember,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.timelineActivity.views.allTimelineActivities
.viewFields.workspaceMember.universalIdentifier,
},
{
fieldMetadataId:
timelineActivityObjectMetadata.fields.find(
(field) =>
field.standardId ===
TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.linkedRecordCachedName,
)?.id ?? '',
position: 4,
isVisible: true,
size: 200,
universalIdentifier:
STANDARD_OBJECTS.timelineActivity.views.allTimelineActivities
.viewFields.linkedRecordCachedName.universalIdentifier,
},
],
};
};
@@ -1,126 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import { WORKFLOW_RUN_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const workflowRunsAllView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const workflowRunObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.workflowRun,
);
if (!workflowRunObjectMetadata) {
throw new Error('Workflow run object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Workflow Runs',
objectMetadataId: workflowRunObjectMetadata.id,
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconHistoryToggle',
openRecordIn: ViewOpenRecordInType.RECORD_PAGE,
filters: [],
fields: [
{
fieldMetadataId:
workflowRunObjectMetadata.fields.find(
(field) =>
field.standardId === WORKFLOW_RUN_STANDARD_FIELD_IDS.name,
)?.id ?? '',
position: 0,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.viewFields.name
.universalIdentifier,
},
{
fieldMetadataId:
workflowRunObjectMetadata.fields.find(
(field) =>
field.standardId === WORKFLOW_RUN_STANDARD_FIELD_IDS.workflow,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.viewFields.workflow
.universalIdentifier,
},
{
fieldMetadataId:
workflowRunObjectMetadata.fields.find(
(field) =>
field.standardId === WORKFLOW_RUN_STANDARD_FIELD_IDS.status,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.viewFields.status
.universalIdentifier,
},
{
fieldMetadataId:
workflowRunObjectMetadata.fields.find(
(field) =>
field.standardId === WORKFLOW_RUN_STANDARD_FIELD_IDS.startedAt,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.viewFields
.startedAt.universalIdentifier,
},
{
fieldMetadataId:
workflowRunObjectMetadata.fields.find(
(field) =>
field.standardId === WORKFLOW_RUN_STANDARD_FIELD_IDS.createdBy,
)?.id ?? '',
position: 4,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.viewFields
.createdBy.universalIdentifier,
},
{
fieldMetadataId:
workflowRunObjectMetadata.fields.find(
(field) =>
field.standardId ===
WORKFLOW_RUN_STANDARD_FIELD_IDS.workflowVersion,
)?.id ?? '',
position: 5,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.viewFields
.workflowVersion.universalIdentifier,
},
],
};
};
@@ -1,118 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
WORKFLOW_VERSION_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const workflowVersionsAllView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const workflowVersionObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.workflowVersion,
);
if (!workflowVersionObjectMetadata) {
throw new Error('Workflow version object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.workflowVersion.views.allWorkflowVersions
.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming
? msg`All {objectLabelPlural}`
: 'All Workflow Versions',
objectMetadataId: workflowVersionObjectMetadata.id,
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconVersions',
openRecordIn: ViewOpenRecordInType.RECORD_PAGE,
filters: [],
fields: [
{
fieldMetadataId:
workflowVersionObjectMetadata.fields.find(
(field) =>
field.standardId === WORKFLOW_VERSION_STANDARD_FIELD_IDS.name,
)?.id ?? '',
position: 0,
isVisible: true,
size: 210,
universalIdentifier:
STANDARD_OBJECTS.workflowVersion.views.allWorkflowVersions.viewFields
.name.universalIdentifier,
},
{
fieldMetadataId:
workflowVersionObjectMetadata.fields.find(
(field) =>
field.standardId === WORKFLOW_VERSION_STANDARD_FIELD_IDS.workflow,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflowVersion.views.allWorkflowVersions.viewFields
.workflow.universalIdentifier,
},
{
fieldMetadataId:
workflowVersionObjectMetadata.fields.find(
(field) =>
field.standardId === WORKFLOW_VERSION_STANDARD_FIELD_IDS.status,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflowVersion.views.allWorkflowVersions.viewFields
.status.universalIdentifier,
},
{
fieldMetadataId:
workflowVersionObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.updatedAt,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflowVersion.views.allWorkflowVersions.viewFields
.updatedAt.universalIdentifier,
},
{
fieldMetadataId:
workflowVersionObjectMetadata.fields.find(
(field) =>
field.standardId === WORKFLOW_VERSION_STANDARD_FIELD_IDS.runs,
)?.id ?? '',
position: 4,
isVisible: false,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflowVersion.views.allWorkflowVersions.viewFields
.runs.universalIdentifier,
},
],
};
};
@@ -1,126 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
WORKFLOW_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const workflowsAllView = ({
objectMetadataItems,
useCoreNaming = false,
twentyStandardFlatApplication,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const workflowObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.workflow,
);
if (!workflowObjectMetadata) {
throw new Error('Workflow object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.workflow.views.allWorkflows.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Workflows',
objectMetadataId: workflowObjectMetadata.id,
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconSettingsAutomation',
openRecordIn: ViewOpenRecordInType.RECORD_PAGE,
filters: [],
fields: [
{
fieldMetadataId:
workflowObjectMetadata.fields.find(
(field) => field.standardId === WORKFLOW_STANDARD_FIELD_IDS.name,
)?.id ?? '',
position: 0,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflow.views.allWorkflows.viewFields.name
.universalIdentifier,
},
{
fieldMetadataId:
workflowObjectMetadata.fields.find(
(field) =>
field.standardId === WORKFLOW_STANDARD_FIELD_IDS.statuses,
)?.id ?? '',
position: 1,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflow.views.allWorkflows.viewFields.statuses
.universalIdentifier,
},
{
fieldMetadataId:
workflowObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.updatedAt,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflow.views.allWorkflows.viewFields.updatedAt
.universalIdentifier,
},
{
fieldMetadataId:
workflowObjectMetadata.fields.find(
(field) =>
field.standardId === WORKFLOW_STANDARD_FIELD_IDS.createdBy,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflow.views.allWorkflows.viewFields.createdBy
.universalIdentifier,
},
{
fieldMetadataId:
workflowObjectMetadata.fields.find(
(field) =>
field.standardId === WORKFLOW_STANDARD_FIELD_IDS.versions,
)?.id ?? '',
position: 4,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflow.views.allWorkflows.viewFields.versions
.universalIdentifier,
},
{
fieldMetadataId:
workflowObjectMetadata.fields.find(
(field) => field.standardId === WORKFLOW_STANDARD_FIELD_IDS.runs,
)?.id ?? '',
position: 5,
isVisible: false,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workflow.views.allWorkflows.viewFields.runs
.universalIdentifier,
},
],
};
};
@@ -1,174 +0,0 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { v4 } from 'uuid';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface';
import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE';
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import {
BASE_OBJECT_STANDARD_FIELD_IDS,
WORKSPACE_MEMBER_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
export const workspaceMembersAllView = ({
objectMetadataItems,
twentyStandardFlatApplication,
useCoreNaming,
}: {
objectMetadataItems: ObjectMetadataEntity[];
useCoreNaming?: boolean;
twentyStandardFlatApplication: FlatApplication;
}): ViewDefinition => {
const workspaceMemberObjectMetadata = objectMetadataItems.find(
(object) => object.standardId === STANDARD_OBJECT_IDS.workspaceMember,
);
if (!workspaceMemberObjectMetadata) {
throw new Error('WorkspaceMember object metadata not found');
}
const viewUniversalIdentifier =
STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers
.universalIdentifier;
return {
id: v4(),
universalIdentifier: viewUniversalIdentifier,
applicationId: twentyStandardFlatApplication.id,
name: useCoreNaming
? msg`All {objectLabelPlural}`
: 'All Workspace Members',
objectMetadataId: workspaceMemberObjectMetadata.id ?? '',
type: 'table',
key: 'INDEX',
position: 0,
icon: 'IconList',
filters: [],
fields: [
{
fieldMetadataId:
workspaceMemberObjectMetadata.fields.find(
(field) =>
field.standardId === WORKSPACE_MEMBER_STANDARD_FIELD_IDS.name,
)?.id ?? '',
position: 0,
isVisible: true,
size: DEFAULT_VIEW_FIELD_SIZE,
universalIdentifier:
STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields
.name.universalIdentifier,
},
{
fieldMetadataId:
workspaceMemberObjectMetadata.fields.find(
(field) =>
field.standardId ===
WORKSPACE_MEMBER_STANDARD_FIELD_IDS.userEmail,
)?.id ?? '',
position: 1,
isVisible: true,
size: 180,
universalIdentifier:
STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields
.userEmail.universalIdentifier,
},
{
fieldMetadataId:
workspaceMemberObjectMetadata.fields.find(
(field) =>
field.standardId ===
WORKSPACE_MEMBER_STANDARD_FIELD_IDS.avatarUrl,
)?.id ?? '',
position: 2,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields
.avatarUrl.universalIdentifier,
},
{
fieldMetadataId:
workspaceMemberObjectMetadata.fields.find(
(field) =>
field.standardId ===
WORKSPACE_MEMBER_STANDARD_FIELD_IDS.colorScheme,
)?.id ?? '',
position: 3,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields
.colorScheme.universalIdentifier,
},
{
fieldMetadataId:
workspaceMemberObjectMetadata.fields.find(
(field) =>
field.standardId === WORKSPACE_MEMBER_STANDARD_FIELD_IDS.locale,
)?.id ?? '',
position: 4,
isVisible: true,
size: 120,
universalIdentifier:
STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields
.locale.universalIdentifier,
},
{
fieldMetadataId:
workspaceMemberObjectMetadata.fields.find(
(field) =>
field.standardId === WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timeZone,
)?.id ?? '',
position: 5,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields
.timeZone.universalIdentifier,
},
{
fieldMetadataId:
workspaceMemberObjectMetadata.fields.find(
(field) =>
field.standardId ===
WORKSPACE_MEMBER_STANDARD_FIELD_IDS.dateFormat,
)?.id ?? '',
position: 6,
isVisible: true,
size: 120,
universalIdentifier:
STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields
.dateFormat.universalIdentifier,
},
{
fieldMetadataId:
workspaceMemberObjectMetadata.fields.find(
(field) =>
field.standardId ===
WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timeFormat,
)?.id ?? '',
position: 7,
isVisible: true,
size: 120,
universalIdentifier:
STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields
.timeFormat.universalIdentifier,
},
{
fieldMetadataId:
workspaceMemberObjectMetadata.fields.find(
(field) =>
field.standardId === BASE_OBJECT_STANDARD_FIELD_IDS.createdAt,
)?.id ?? '',
position: 8,
isVisible: true,
size: 150,
universalIdentifier:
STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields
.createdAt.universalIdentifier,
},
],
};
};
@@ -1,4 +1,4 @@
import { HELPER_AGENT } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-agents/agents/helper-agent';
import { HELPER_AGENT } from 'src/engine/workspace-manager/workspace-migration/constant/standard-agent-ids';
export const STANDARD_AGENT = {
helper: {
@@ -30,7 +30,7 @@ import {
WORKFLOW_STANDARD_FIELD_IDS,
WORKFLOW_VERSION_STANDARD_FIELD_IDS,
WORKSPACE_MEMBER_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
} from 'src/engine/workspace-manager/workspace-migration/constant/standard-field-ids';
export const STANDARD_OBJECTS = {
attachment: {
@@ -1,4 +1,4 @@
import { ADMIN_ROLE } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-roles/roles/admin-role';
import { ADMIN_ROLE } from 'src/engine/metadata-modules/role/constants/admin-role';
export const STANDARD_ROLE = {
admin: { universalIdentifier: ADMIN_ROLE.standardId },
@@ -14,9 +14,9 @@ import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/works
import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant';
import { TWENTY_STANDARD_ALL_METADATA_NAME } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-all-metadata-name.constant';
import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant';
import { WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2';
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-validate-build-and-run-service';
import { FromToAllFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
import { FromToAllFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/favorite.workspace-entity';
@Injectable()
@@ -117,7 +117,7 @@ export class TwentyStandardApplicationService {
);
if (isDefined(validateAndBuildResult)) {
throw new WorkspaceMigrationBuilderExceptionV2(
throw new WorkspaceMigrationBuilderException(
validateAndBuildResult,
'Multiple validation errors occurred while synchronizing twenty-standard application',
);
@@ -1,9 +1,9 @@
import { Module } from '@nestjs/common';
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-v2.module';
import { GlobalWorkspaceDataSourceModule } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.module';
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module';
import { TwentyStandardApplicationService } from './services/twenty-standard-application.service';
@@ -12,7 +12,7 @@ import { TwentyStandardApplicationService } from './services/twenty-standard-app
imports: [
ApplicationModule,
WorkspaceCacheModule,
WorkspaceMigrationV2Module,
WorkspaceMigrationModule,
GlobalWorkspaceDataSourceModule,
],
exports: [TwentyStandardApplicationService],
@@ -12,7 +12,7 @@ import {
createStandardFieldFlatMetadata,
} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util';
import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util';
import { SEARCH_FIELDS_FOR_COMPANY } from 'src/modules/company/standard-objects/company.workspace-entity';
export const buildCompanyStandardFlatFieldMetadatas = ({
@@ -11,7 +11,7 @@ import {
createStandardFieldFlatMetadata,
} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util';
import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util';
import { SEARCH_FIELDS_FOR_DASHBOARD } from 'src/modules/dashboard/standard-objects/dashboard.workspace-entity';
export const buildDashboardStandardFlatFieldMetadatas = ({
@@ -11,7 +11,7 @@ import {
createStandardFieldFlatMetadata,
} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util';
import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util';
import { SEARCH_FIELDS_FOR_NOTES } from 'src/modules/note/standard-objects/note.workspace-entity';
export const buildNoteStandardFlatFieldMetadatas = ({
@@ -12,7 +12,7 @@ import {
createStandardFieldFlatMetadata,
} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util';
import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util';
import { SEARCH_FIELDS_FOR_OPPORTUNITY } from 'src/modules/opportunity/standard-objects/opportunity.workspace-entity';
export const buildOpportunityStandardFlatFieldMetadatas = ({
@@ -12,7 +12,7 @@ import {
createStandardFieldFlatMetadata,
} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util';
import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util';
import { SEARCH_FIELDS_FOR_PERSON } from 'src/modules/person/standard-objects/person.workspace-entity';
export const buildPersonStandardFlatFieldMetadatas = ({
@@ -12,7 +12,7 @@ import {
createStandardFieldFlatMetadata,
} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util';
import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util';
import { SEARCH_FIELDS_FOR_TASKS } from 'src/modules/task/standard-objects/task.workspace-entity';
export const buildTaskStandardFlatFieldMetadatas = ({
@@ -12,7 +12,7 @@ import {
type CreateStandardFieldArgs,
} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util';
import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util';
import { TIMELINE_ACTIVITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { TIMELINE_ACTIVITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-migration/constant/standard-field-ids';
export const buildTimelineActivityStandardFlatFieldMetadatas = ({
now,
@@ -12,7 +12,7 @@ import {
createStandardFieldFlatMetadata,
} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util';
import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util';
import { SEARCH_FIELDS_FOR_WORKFLOW_RUNS } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
export const buildWorkflowRunStandardFlatFieldMetadatas = ({
@@ -11,7 +11,7 @@ import {
createStandardFieldFlatMetadata,
} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util';
import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util';
import { SEARCH_FIELDS_FOR_WORKFLOWS } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
export const buildWorkflowStandardFlatFieldMetadatas = ({
@@ -12,7 +12,7 @@ import {
createStandardFieldFlatMetadata,
} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util';
import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util';
import { SEARCH_FIELDS_FOR_WORKFLOW_VERSIONS } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
export const buildWorkflowVersionStandardFlatFieldMetadatas = ({
@@ -12,7 +12,7 @@ import {
createStandardFieldFlatMetadata,
} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util';
import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util';
import {
SEARCH_FIELDS_FOR_WORKSPACE_MEMBER,
WorkspaceMemberNumberFormatEnum,
@@ -1,7 +1,7 @@
import { Column, Index, JoinColumn, ManyToOne, type Relation } from 'typeorm';
import type { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
import { WorkspaceRelatedEntity } from 'src/engine/workspace-manager/workspace-sync/types/workspace-related-entity';
import { WorkspaceRelatedEntity } from 'src/engine/workspace-manager/types/workspace-related-entity';
@Index(['workspaceId', 'universalIdentifier'], {
unique: true,
@@ -3,7 +3,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
import {
type FieldTypeAndNameMetadata,
getTsVectorColumnExpressionFromFields,
} from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
} from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util';
const nameTextField = { name: 'name', type: FieldMetadataType.TEXT };
const nameFullNameField = {
@@ -8,15 +8,11 @@ import {
computeCompositeColumnName,
} from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
import {
WorkspaceMigrationException,
WorkspaceMigrationExceptionCode,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.exception';
import {
isSearchableFieldType,
type SearchableFieldType,
} from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-searchable-field.util';
import { isSearchableSubfield } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-searchable-subfield.util';
} from 'src/engine/workspace-manager/utils/is-searchable-field.util';
import { isSearchableSubfield } from 'src/engine/workspace-manager/utils/is-searchable-subfield.util';
export type FieldTypeAndNameMetadata = {
name: string;
@@ -51,9 +47,8 @@ const getColumnExpressionsFromField = (
);
if (!compositeType) {
throw new WorkspaceMigrationException(
throw new Error(
`Composite type not found for field metadata type: ${fieldMetadataTypeAndName.type}`,
WorkspaceMigrationExceptionCode.INVALID_FIELD_METADATA,
);
}
@@ -10,18 +10,16 @@ import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-s
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity';
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
import { RoleModule } from 'src/engine/metadata-modules/role/role.module';
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module';
import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module';
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
import { DevSeederModule } from 'src/engine/workspace-manager/dev-seeder/dev-seeder.module';
import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-v2.module';
import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module';
import { TwentyStandardApplicationModule } from 'src/engine/workspace-manager/twenty-standard-application/twenty-standard-application.module';
import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module';
import { WorkspaceManagerService } from './workspace-manager.service';
@@ -29,11 +27,9 @@ import { WorkspaceManagerService } from './workspace-manager.service';
imports: [
WorkspaceDataSourceModule,
WorkspaceMigrationModule,
WorkspaceMigrationV2Module,
ObjectMetadataModule,
DevSeederModule,
DataSourceModule,
WorkspaceSyncMetadataModule,
FeatureFlagModule,
PermissionsModule,
AiAgentModule,
@@ -5,30 +5,22 @@ import { DataSource, Repository } from 'typeorm';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { fromApplicationEntityToFlatApplication } from 'src/engine/core-modules/application/utils/from-application-entity-to-flat-application.util';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { type DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity';
import { ADMIN_ROLE } from 'src/engine/metadata-modules/role/constants/admin-role';
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.service';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { prefillCompanies } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-companies';
import { prefillCoreViews } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-core-views';
import { prefillPeople } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-people';
import { prefillWorkflows } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-workflows';
import { standardObjectsPrefillData } from 'src/engine/workspace-manager/standard-objects-prefill-data/standard-objects-prefill-data';
import { TwentyStandardApplicationService } from 'src/engine/workspace-manager/twenty-standard-application/services/twenty-standard-application.service';
import { ADMIN_ROLE } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-roles/roles/admin-role';
import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service';
@Injectable()
export class WorkspaceManagerService {
@@ -38,7 +30,6 @@ export class WorkspaceManagerService {
@InjectDataSource()
private readonly coreDataSource: DataSource,
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
private readonly workspaceMigrationService: WorkspaceMigrationService,
private readonly objectMetadataService: ObjectMetadataService,
private readonly dataSourceService: DataSourceService,
@InjectRepository(UserWorkspaceEntity)
@@ -56,8 +47,6 @@ export class WorkspaceManagerService {
private readonly serverlessFunctionRepository: Repository<ServerlessFunctionEntity>,
private readonly applicationService: ApplicationService,
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
private readonly featureFlagService: FeatureFlagService,
private readonly workspaceSyncMetadataService: WorkspaceSyncMetadataService,
) {}
public async init({
@@ -81,58 +70,26 @@ export class WorkspaceManagerService {
);
const dataSourceMetadataCreationStart = performance.now();
const dataSourceMetadata =
await this.dataSourceService.createDataSourceMetadata(
await this.dataSourceService.createDataSourceMetadata(
workspaceId,
schemaName,
);
await this.applicationService.createTwentyStandardApplication({
workspaceId,
});
await this.twentyStandardApplicationService.synchronizeTwentyStandardApplicationOrThrow(
{
workspaceId,
schemaName,
);
},
);
const featureFlags =
await this.featureFlagService.getWorkspaceFeatureFlagsMap(workspaceId);
const twentyStandardApplication =
await this.applicationService.createTwentyStandardApplication({
workspaceId,
});
const isV2SyncEnabled =
featureFlags[FeatureFlagKey.IS_WORKSPACE_CREATION_V2_ENABLED];
if (isV2SyncEnabled) {
await this.twentyStandardApplicationService.synchronizeTwentyStandardApplicationOrThrow(
{
workspaceId,
},
);
await this.prefillCreatedWorkspaceRecords({
workspaceId,
schemaName,
});
} else {
await this.workspaceSyncMetadataService.synchronize({
workspaceId,
dataSourceId: dataSourceMetadata.id,
featureFlags,
});
const prefillStandardObjectsStart = performance.now();
await this.prefillWorkspaceWithStandardObjectsRecords({
dataSourceMetadata,
workspaceId,
featureFlags,
twentyStandardFlatApplication: fromApplicationEntityToFlatApplication(
twentyStandardApplication,
),
});
const prefillStandardObjectsEnd = performance.now();
this.logger.log(
`Prefill standard objects took ${prefillStandardObjectsEnd - prefillStandardObjectsStart}ms`,
);
}
await this.prefillCreatedWorkspaceRecords({
workspaceId,
schemaName,
});
const dataSourceMetadataCreationEnd = performance.now();
@@ -204,43 +161,6 @@ export class WorkspaceManagerService {
}
}
private async prefillWorkspaceWithStandardObjectsRecords({
dataSourceMetadata,
workspaceId,
featureFlags,
twentyStandardFlatApplication,
}: {
dataSourceMetadata: DataSourceEntity;
workspaceId: string;
featureFlags: Record<string, boolean>;
twentyStandardFlatApplication: FlatApplication;
}) {
const { flatObjectMetadataMaps, flatFieldMetadataMaps } =
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
{
workspaceId,
flatMapsKeys: ['flatObjectMetadataMaps', 'flatFieldMetadataMaps'],
},
);
await standardObjectsPrefillData(
this.coreDataSource,
dataSourceMetadata.schema,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
);
await prefillCoreViews({
twentyStandardFlatApplication,
coreDataSource: this.coreDataSource,
workspaceId,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
workspaceSchemaName: dataSourceMetadata.schema,
featureFlags,
});
}
/**
* @deprecated Should be removed once AddWorkspaceForeignKeysMigrationCommand has been run successfully in production
* As we will be able to rely on foreignKey delete cascading
@@ -261,7 +181,6 @@ export class WorkspaceManagerService {
workspaceId,
});
await this.workspaceMigrationService.deleteAllWithinWorkspace(workspaceId);
await this.dataSourceService.delete(workspaceId);
}
@@ -1,12 +0,0 @@
import { WorkspaceMigrationIndexFactory } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-index.factory';
import { WorkspaceMigrationFieldRelationFactory } from './workspace-migration-field-relation.factory';
import { WorkspaceMigrationFieldFactory } from './workspace-migration-field.factory';
import { WorkspaceMigrationObjectFactory } from './workspace-migration-object.factory';
export const workspaceMigrationBuilderFactories = [
WorkspaceMigrationObjectFactory,
WorkspaceMigrationFieldFactory,
WorkspaceMigrationFieldRelationFactory,
WorkspaceMigrationIndexFactory,
];
@@ -1,91 +0,0 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { type IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
import { createIndexMigration } from 'src/engine/workspace-manager/workspace-migration-builder/factories/utils/workspace-migration-index.factory.utils';
import { getMockFieldMetadataEntity } from 'src/utils/__test__/get-field-metadata-entity.mock';
describe('WorkspaceMigrationIndexFactory', () => {
it('should create index migrations for simple fields', async () => {
const simpleField = getMockFieldMetadataEntity({
workspaceId: '20202020-0000-0000-0000-000000000000',
objectMetadataId: '20202020-0000-0000-0000-000000000001',
id: 'f1',
type: FieldMetadataType.TEXT,
name: 'simpleField',
label: 'Simple Field',
isNullable: true,
isLabelSyncedWithName: true,
createdAt: new Date(),
updatedAt: new Date(),
});
const objectMetadata = {
id: '20202020-0000-0000-0000-000000000002',
workspaceId: '20202020-0000-0000-0000-000000000000',
nameSingular: 'Test',
fields: [simpleField],
isCustom: false,
};
const indexMetadata = {
name: 'idx_simple',
isUnique: true,
indexType: 'BTREE',
indexWhereClause: null,
indexFieldMetadatas: [{ fieldMetadataId: 'f1', order: 0 }],
} as IndexMetadataEntity;
const map = new Map([[objectMetadata, [indexMetadata]]]);
const result = (await createIndexMigration(map)) as any;
expect(result).toHaveLength(1);
const firstMigration = result[0].migrations[0];
expect(firstMigration.action).toBe('alter_indexes');
expect(firstMigration.indexes[0].name).toBe('idx_simple');
expect(firstMigration.indexes[0].columns).toEqual(['simpleField']);
expect(firstMigration.indexes[0].type).toBe('BTREE');
expect(firstMigration.indexes[0].isUnique).toBe(true);
expect(firstMigration.indexes[0].where).toBeNull();
});
it('should create index migrations for relation fields', async () => {
const relationField = getMockFieldMetadataEntity({
workspaceId: '20202020-0000-0000-0000-000000000000',
objectMetadataId: '20202020-0000-0000-0000-000000000001',
id: 'f2',
type: FieldMetadataType.RELATION,
name: 'author',
label: 'Author',
isNullable: true,
isLabelSyncedWithName: true,
createdAt: new Date(),
updatedAt: new Date(),
settings: {
relationType: RelationType.MANY_TO_ONE,
joinColumnName: 'authorId',
},
});
const objectMetadata = {
id: '20202020-0000-0000-0000-000000000003',
workspaceId: '20202020-0000-0000-0000-000000000000',
nameSingular: 'Attachment',
fields: [relationField],
isCustom: false,
};
const indexMetadata = {
name: 'idx_rel',
isUnique: false,
indexType: 'BTREE',
indexWhereClause: null,
indexFieldMetadatas: [{ fieldMetadataId: 'f2', order: 0 }],
} as IndexMetadataEntity;
const map = new Map([[objectMetadata, [indexMetadata]]]);
const result = (await createIndexMigration(map)) as any;
const firstMigration = result[0].migrations[0];
expect(firstMigration.indexes[0].columns).toEqual(['authorId']);
});
});
@@ -1,162 +0,0 @@
import {
type CompositeType,
compositeTypeDefinitions,
FieldMetadataType,
} from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
import { type IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { generateMigrationName } from 'src/engine/metadata-modules/workspace-migration/utils/generate-migration-name.util';
import {
type WorkspaceMigrationEntity,
WorkspaceMigrationIndexActionType,
WorkspaceMigrationTableActionType,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
import { isFieldMetadataEntityOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
export const createIndexMigration = async (
indexMetadataByObjectMetadataMap: Map<
Pick<
ObjectMetadataEntity,
'id' | 'workspaceId' | 'nameSingular' | 'isCustom'
> & {
fields: Pick<FieldMetadataEntity, 'id' | 'name' | 'type' | 'settings'>[];
},
IndexMetadataEntity[]
>,
): Promise<Partial<WorkspaceMigrationEntity>[]> => {
const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = [];
for (const [
objectMetadata,
indexMetadataCollection,
] of indexMetadataByObjectMetadataMap) {
const targetTable = computeObjectTargetTable(objectMetadata);
const fieldsById = Object.fromEntries(
objectMetadata.fields.map((field) => [field.id, field]),
);
const indexes = indexMetadataCollection.map((indexMetadata) => {
const columns = indexMetadata.indexFieldMetadatas
.sort((a, b) => a.order - b.order)
.map((indexFieldMetadata) => {
const fieldMetadata = fieldsById[indexFieldMetadata.fieldMetadataId];
if (!fieldMetadata) {
throw new Error(
`Field metadata with id ${indexFieldMetadata.fieldMetadataId} not found in object metadata with id ${objectMetadata.id}`,
);
}
if (
isFieldMetadataEntityOfType(
fieldMetadata,
FieldMetadataType.RELATION,
) ||
isFieldMetadataEntityOfType(
fieldMetadata,
FieldMetadataType.MORPH_RELATION,
)
) {
if (!fieldMetadata.settings) {
throw new Error(
`Join column name is not supported for relation fields`,
);
}
return fieldMetadata.settings.joinColumnName;
}
if (!isCompositeFieldMetadataType(fieldMetadata.type)) {
return fieldMetadata.name;
}
const compositeType = compositeTypeDefinitions.get(
fieldMetadata.type,
) as CompositeType;
const columns = compositeType.properties
.filter((property) => property.isIncludedInUniqueConstraint)
.map((property) =>
computeCompositeColumnName(fieldMetadata, property),
);
return columns;
})
.flat()
.filter(isDefined);
return {
name: indexMetadata.name,
action: WorkspaceMigrationIndexActionType.CREATE,
isUnique: indexMetadata.isUnique,
columns,
type: indexMetadata.indexType,
where: indexMetadata.indexWhereClause,
};
});
workspaceMigrations.push({
workspaceId: objectMetadata.workspaceId,
name: generateMigrationName(
`create-${objectMetadata.nameSingular}-indexes`,
),
isCustom: false,
migrations: [
{
name: targetTable,
action: WorkspaceMigrationTableActionType.ALTER_INDEXES,
indexes,
},
],
});
}
return workspaceMigrations;
};
export const deleteIndexMigration = async (
indexMetadataByObjectMetadataMap: Map<
ObjectMetadataEntity,
IndexMetadataEntity[]
>,
): Promise<Partial<WorkspaceMigrationEntity>[]> => {
const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = [];
for (const [
objectMetadata,
indexMetadataCollection,
] of indexMetadataByObjectMetadataMap) {
const targetTable = computeObjectTargetTable(objectMetadata);
const indexes = indexMetadataCollection.map((indexMetadata) => ({
name: indexMetadata.name,
action: WorkspaceMigrationIndexActionType.DROP,
columns: [],
isUnique: indexMetadata.isUnique,
}));
workspaceMigrations.push({
workspaceId: objectMetadata.workspaceId,
name: generateMigrationName(
`delete-${objectMetadata.nameSingular}-indexes`,
),
isCustom: false,
migrations: [
{
name: targetTable,
action: WorkspaceMigrationTableActionType.ALTER_INDEXES,
indexes,
},
],
});
}
return workspaceMigrations;
};
@@ -1,411 +0,0 @@
import { Injectable } from '@nestjs/common';
import { FieldMetadataType } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { WorkspaceMigrationBuilderAction } from 'src/engine/workspace-manager/workspace-migration-builder/interfaces/workspace-migration-builder-action.interface';
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { generateMigrationName } from 'src/engine/metadata-modules/workspace-migration/utils/generate-migration-name.util';
import {
WorkspaceMigrationColumnActionType,
type WorkspaceMigrationEntity,
type WorkspaceMigrationTableAction,
WorkspaceMigrationTableActionType,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import { WorkspaceMigrationFactory } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.factory';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
import { isFieldMetadataEntityOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
import { type FieldMetadataUpdate } from 'src/engine/workspace-manager/workspace-migration-builder/factories/workspace-migration-field.factory';
@Injectable()
export class WorkspaceMigrationFieldRelationFactory {
constructor(
private readonly workspaceMigrationFactory: WorkspaceMigrationFactory,
) {}
async create(
originalObjectMetadataCollection: ObjectMetadataEntity[],
fieldMetadataCollection: FieldMetadataEntity<
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
>[],
action:
| WorkspaceMigrationBuilderAction.CREATE
| WorkspaceMigrationBuilderAction.DELETE,
): Promise<Partial<WorkspaceMigrationEntity>[]>;
async create(
originalObjectMetadataCollection: ObjectMetadataEntity[],
fieldMetadataUpdateCollection: FieldMetadataUpdate<
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
>[],
action: WorkspaceMigrationBuilderAction.UPDATE,
): Promise<Partial<WorkspaceMigrationEntity>[]>;
/**
* Deletion of the relation is handled by field deletion
*/
async create(
originalObjectMetadataCollection: ObjectMetadataEntity[],
fieldMetadataCollectionOrFieldMetadataUpdateCollection:
| FieldMetadataEntity<
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
>[]
| FieldMetadataUpdate<
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
>[],
action: WorkspaceMigrationBuilderAction,
): Promise<Partial<WorkspaceMigrationEntity>[]> {
const originalObjectMetadataMap = originalObjectMetadataCollection.reduce(
(result, currentObject) => {
result[currentObject.id] = currentObject;
return result;
},
{} as Record<string, ObjectMetadataEntity>,
);
switch (action) {
case WorkspaceMigrationBuilderAction.CREATE:
return this.createFieldRelationMigration(
originalObjectMetadataMap,
fieldMetadataCollectionOrFieldMetadataUpdateCollection as FieldMetadataEntity<FieldMetadataType.RELATION>[],
);
case WorkspaceMigrationBuilderAction.UPDATE:
return this.updateFieldRelationMigration(
originalObjectMetadataMap,
fieldMetadataCollectionOrFieldMetadataUpdateCollection as FieldMetadataUpdate<FieldMetadataType.RELATION>[],
);
case WorkspaceMigrationBuilderAction.DELETE:
return this.deleteFieldRelationMigration(
originalObjectMetadataMap,
fieldMetadataCollectionOrFieldMetadataUpdateCollection as FieldMetadataEntity<FieldMetadataType.RELATION>[],
);
default:
return [];
}
}
private async updateFieldRelationMigration(
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
fieldMetadataUpdateCollection: FieldMetadataUpdate<FieldMetadataType.RELATION>[],
): Promise<Partial<WorkspaceMigrationEntity>[]> {
const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = [];
for (const {
altered: sourceFieldMetadata,
} of fieldMetadataUpdateCollection) {
const sourceObjectMetadata =
originalObjectMetadataMap[sourceFieldMetadata.objectMetadataId];
const targetObjectMetadata =
originalObjectMetadataMap[
sourceFieldMetadata.relationTargetObjectMetadataId
];
if (!sourceObjectMetadata) {
throw new Error(
`ObjectMetadata with id ${sourceFieldMetadata.objectMetadataId} not found`,
);
}
if (!sourceFieldMetadata.settings) {
throw new Error(
`FieldMetadata for relation with id ${sourceFieldMetadata.id} has no settings`,
);
}
if (
sourceFieldMetadata.settings.relationType !== RelationType.MANY_TO_ONE
) {
continue;
}
if (!sourceFieldMetadata.settings.joinColumnName) {
throw new Error(
`FieldMetadata with id ${sourceFieldMetadata.id} has no join column name in settings`,
);
}
if (!targetObjectMetadata) {
throw new Error(
`ObjectMetadata with id ${sourceFieldMetadata.relationTargetObjectMetadataId} not found`,
);
}
const targetFieldMetadata = targetObjectMetadata.fields.find(
(field) =>
field.id === sourceFieldMetadata.relationTargetFieldMetadataId,
);
if (!targetFieldMetadata) {
throw new Error(
`FieldMetadata with id ${sourceFieldMetadata.relationTargetFieldMetadataId} not found`,
);
}
if (
!isFieldMetadataEntityOfType(
targetFieldMetadata,
FieldMetadataType.RELATION,
)
) {
throw new Error(
`FieldMetadata with id ${sourceFieldMetadata.relationTargetFieldMetadataId} is not a relation`,
);
}
if (!targetFieldMetadata.settings) {
throw new Error(
`FieldMetadata for relation with id ${sourceFieldMetadata.id} has no settings`,
);
}
const migrations: WorkspaceMigrationTableAction[] = [
{
name: computeObjectTargetTable(sourceObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.DROP_FOREIGN_KEY,
columnName: sourceFieldMetadata.settings.joinColumnName,
},
],
},
{
name: computeObjectTargetTable(sourceObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
columnName: sourceFieldMetadata.settings.joinColumnName,
referencedTableName:
computeObjectTargetTable(targetObjectMetadata),
referencedTableColumnName: 'id',
onDelete: sourceFieldMetadata.settings.onDelete,
},
],
},
];
workspaceMigrations.push({
workspaceId: sourceFieldMetadata.workspaceId,
name: generateMigrationName(
`update-relation-from-${sourceObjectMetadata.nameSingular}-to-${targetObjectMetadata.nameSingular}`,
),
isCustom: false,
migrations,
});
}
return workspaceMigrations;
}
private async createFieldRelationMigration(
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
fieldRelationMetadataCollection: FieldMetadataEntity<FieldMetadataType.RELATION>[],
): Promise<Partial<WorkspaceMigrationEntity>[]> {
const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = [];
for (const sourceFieldMetadata of fieldRelationMetadataCollection) {
const sourceObjectMetadata =
originalObjectMetadataMap[sourceFieldMetadata.objectMetadataId];
const targetObjectMetadata =
originalObjectMetadataMap[
sourceFieldMetadata.relationTargetObjectMetadataId
];
if (!sourceObjectMetadata) {
throw new Error(
`ObjectMetadata with id ${sourceFieldMetadata.objectMetadataId} not found`,
);
}
if (!sourceFieldMetadata.settings) {
throw new Error(
`FieldMetadata for relation with id ${sourceFieldMetadata.id} has no settings`,
);
}
if (
sourceFieldMetadata.settings.relationType !== RelationType.MANY_TO_ONE
) {
continue;
}
if (!sourceFieldMetadata.settings.joinColumnName) {
throw new Error(
`FieldMetadata with id ${sourceFieldMetadata.id} has no join column name in settings`,
);
}
if (!targetObjectMetadata) {
throw new Error(
`ObjectMetadata with id ${sourceFieldMetadata.relationTargetObjectMetadataId} not found`,
);
}
const targetFieldMetadata = targetObjectMetadata.fields.find(
(field) =>
field.id === sourceFieldMetadata.relationTargetFieldMetadataId,
);
if (!targetFieldMetadata) {
throw new Error(
`FieldMetadata with id ${sourceFieldMetadata.relationTargetFieldMetadataId} not found`,
);
}
if (
!isFieldMetadataEntityOfType(
targetFieldMetadata,
FieldMetadataType.RELATION,
)
) {
throw new Error(
`FieldMetadata with id ${sourceFieldMetadata.relationTargetFieldMetadataId} is not a relation`,
);
}
const migrations: WorkspaceMigrationTableAction[] = [
{
name: computeObjectTargetTable(sourceObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
...this.workspaceMigrationFactory.createColumnActions(
WorkspaceMigrationColumnActionType.CREATE,
sourceFieldMetadata,
),
],
},
{
name: computeObjectTargetTable(sourceObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY,
columnName: sourceFieldMetadata.settings.joinColumnName,
referencedTableName:
computeObjectTargetTable(targetObjectMetadata),
referencedTableColumnName: 'id',
onDelete: sourceFieldMetadata.settings.onDelete,
},
],
},
];
workspaceMigrations.push({
workspaceId: sourceFieldMetadata.workspaceId,
name: generateMigrationName(
`create-relation-from-${sourceObjectMetadata.nameSingular}-to-${targetObjectMetadata.nameSingular}`,
),
isCustom: false,
migrations,
});
}
return workspaceMigrations;
}
private async deleteFieldRelationMigration(
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
fieldRelationMetadataCollection: FieldMetadataEntity<FieldMetadataType.RELATION>[],
): Promise<Partial<WorkspaceMigrationEntity>[]> {
const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = [];
for (const sourceFieldMetadata of fieldRelationMetadataCollection) {
const sourceObjectMetadata =
originalObjectMetadataMap[sourceFieldMetadata.objectMetadataId];
const targetObjectMetadata =
originalObjectMetadataMap[
sourceFieldMetadata.relationTargetObjectMetadataId
];
if (!sourceObjectMetadata) {
throw new Error(
`ObjectMetadata with id ${sourceFieldMetadata.objectMetadataId} not found`,
);
}
if (!sourceFieldMetadata.settings) {
throw new Error(
`FieldMetadata for relation with id ${sourceFieldMetadata.id} has no settings`,
);
}
if (
sourceFieldMetadata.settings.relationType !== RelationType.MANY_TO_ONE
) {
// Only MANY_TO_ONE relations deletion have consequences on the database schema
continue;
}
if (!targetObjectMetadata) {
throw new Error(
`ObjectMetadata with id ${sourceFieldMetadata.relationTargetObjectMetadataId} not found`,
);
}
const targetFieldMetadata = targetObjectMetadata.fields.find(
(field) =>
field.id === sourceFieldMetadata.relationTargetFieldMetadataId,
);
if (!targetFieldMetadata) {
throw new Error(
`FieldMetadata with id ${sourceFieldMetadata.relationTargetFieldMetadataId} not found`,
);
}
if (
!isFieldMetadataEntityOfType(
targetFieldMetadata,
FieldMetadataType.RELATION,
)
) {
throw new Error(
`FieldMetadata with id ${sourceFieldMetadata.relationTargetFieldMetadataId} is not a relation`,
);
}
if (!sourceFieldMetadata.settings.joinColumnName) {
throw new Error(
`FieldMetadata for relation with id ${sourceFieldMetadata.id} has no join column name, it should not generate a workspace migration`,
);
}
const migrations: WorkspaceMigrationTableAction[] = [
{
name: computeObjectTargetTable(sourceObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.DROP_FOREIGN_KEY,
columnName: sourceFieldMetadata.settings.joinColumnName,
},
],
},
{
name: computeObjectTargetTable(sourceObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.DROP,
columnName: sourceFieldMetadata.settings.joinColumnName,
},
],
},
];
workspaceMigrations.push({
workspaceId: sourceFieldMetadata.workspaceId,
name: generateMigrationName(
`update-relation-from-${sourceObjectMetadata.nameSingular}-to-${targetObjectMetadata.nameSingular}`,
),
isCustom: false,
migrations,
});
}
return workspaceMigrations;
}
}
@@ -1,260 +0,0 @@
import { Injectable } from '@nestjs/common';
import diff from 'microdiff';
import { FieldMetadataType } from 'twenty-shared/types';
import { WorkspaceMigrationBuilderAction } from 'src/engine/workspace-manager/workspace-migration-builder/interfaces/workspace-migration-builder-action.interface';
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { generateMigrationName } from 'src/engine/metadata-modules/workspace-migration/utils/generate-migration-name.util';
import {
type WorkspaceMigrationColumnAction,
WorkspaceMigrationColumnActionType,
type WorkspaceMigrationEntity,
type WorkspaceMigrationTableAction,
WorkspaceMigrationTableActionType,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import { WorkspaceMigrationFactory } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.factory';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
export interface FieldMetadataUpdate<
Type extends FieldMetadataType = FieldMetadataType,
> {
current: FieldMetadataEntity<Type>;
altered: FieldMetadataEntity<Type>;
}
@Injectable()
export class WorkspaceMigrationFieldFactory {
constructor(
private readonly workspaceMigrationFactory: WorkspaceMigrationFactory,
) {}
async create(
originalObjectMetadataCollection: ObjectMetadataEntity[],
fieldMetadataCollection: FieldMetadataEntity[],
action:
| WorkspaceMigrationBuilderAction.CREATE
| WorkspaceMigrationBuilderAction.DELETE,
): Promise<Partial<WorkspaceMigrationEntity>[]>;
async create(
originalObjectMetadataCollection: ObjectMetadataEntity[],
fieldMetadataUpdateCollection: FieldMetadataUpdate[],
action: WorkspaceMigrationBuilderAction.UPDATE,
): Promise<Partial<WorkspaceMigrationEntity>[]>;
async create(
originalObjectMetadataCollection: ObjectMetadataEntity[],
fieldMetadataCollectionOrFieldMetadataUpdateCollection:
| FieldMetadataEntity[]
| FieldMetadataUpdate[],
action: WorkspaceMigrationBuilderAction,
): Promise<Partial<WorkspaceMigrationEntity>[]> {
const originalObjectMetadataMap = originalObjectMetadataCollection.reduce(
(result, currentObject) => {
result[currentObject.id] = currentObject;
return result;
},
{} as Record<string, ObjectMetadataEntity>,
);
switch (action) {
case WorkspaceMigrationBuilderAction.CREATE:
return await this.createFieldMigration(
originalObjectMetadataMap,
fieldMetadataCollectionOrFieldMetadataUpdateCollection as FieldMetadataEntity[],
);
case WorkspaceMigrationBuilderAction.UPDATE:
return await this.updateFieldMigration(
originalObjectMetadataMap,
fieldMetadataCollectionOrFieldMetadataUpdateCollection as FieldMetadataUpdate[],
);
case WorkspaceMigrationBuilderAction.DELETE:
return await this.deleteFieldMigration(
originalObjectMetadataMap,
fieldMetadataCollectionOrFieldMetadataUpdateCollection as FieldMetadataEntity[],
);
default:
return [];
}
}
private async createFieldMigration(
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
fieldMetadataCollection: FieldMetadataEntity[],
): Promise<Partial<WorkspaceMigrationEntity>[]> {
const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = [];
if (fieldMetadataCollection.length === 0) {
return [];
}
const fieldMetadataCollectionGroupByObjectMetadataId =
fieldMetadataCollection.reduce(
(result, currentFieldMetadata) => {
result[currentFieldMetadata.objectMetadataId] = [
...(result[currentFieldMetadata.objectMetadataId] || []),
currentFieldMetadata,
];
return result;
},
{} as Record<string, FieldMetadataEntity[]>,
);
for (const objectMetadataId in fieldMetadataCollectionGroupByObjectMetadataId) {
const fieldMetadataCollection =
fieldMetadataCollectionGroupByObjectMetadataId[objectMetadataId];
const columns: WorkspaceMigrationColumnAction[] = [];
const objectMetadata =
originalObjectMetadataMap[fieldMetadataCollection[0]?.objectMetadataId];
for (const fieldMetadata of fieldMetadataCollection) {
columns.push(
...this.workspaceMigrationFactory.createColumnActions(
WorkspaceMigrationColumnActionType.CREATE,
fieldMetadata,
),
);
}
workspaceMigrations.push({
workspaceId: objectMetadata.workspaceId,
name: generateMigrationName(
`create-${objectMetadata.nameSingular}-fields`,
),
isCustom: objectMetadata.isCustom,
migrations: [
{
name: computeObjectTargetTable(
originalObjectMetadataMap[objectMetadataId],
),
action: WorkspaceMigrationTableActionType.ALTER,
columns,
},
],
});
}
return workspaceMigrations;
}
private async updateFieldMigration(
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
fieldMetadataUpdateCollection: FieldMetadataUpdate[],
): Promise<Partial<WorkspaceMigrationEntity>[]> {
const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = [];
if (fieldMetadataUpdateCollection.length === 0) {
return [];
}
for (const fieldMetadataUpdate of fieldMetadataUpdateCollection) {
const columnActions = this.workspaceMigrationFactory.createColumnActions(
WorkspaceMigrationColumnActionType.ALTER,
fieldMetadataUpdate.current,
fieldMetadataUpdate.altered,
);
const isMigrationNeeded = columnActions.reduce(
(result, currentColumnAction) => {
if (
currentColumnAction.action ===
WorkspaceMigrationColumnActionType.CREATE ||
currentColumnAction.action ===
WorkspaceMigrationColumnActionType.DROP
) {
return true;
}
if (
currentColumnAction.action ===
WorkspaceMigrationColumnActionType.ALTER
) {
return (
diff(
currentColumnAction.currentColumnDefinition,
currentColumnAction.alteredColumnDefinition,
).length > 0
);
}
return result;
},
false,
);
if (isMigrationNeeded) {
const migrations: WorkspaceMigrationTableAction[] = [
{
name: computeObjectTargetTable(
originalObjectMetadataMap[
fieldMetadataUpdate.current.objectMetadataId
],
),
action: WorkspaceMigrationTableActionType.ALTER,
columns: this.workspaceMigrationFactory.createColumnActions(
WorkspaceMigrationColumnActionType.ALTER,
fieldMetadataUpdate.current,
fieldMetadataUpdate.altered,
),
},
];
workspaceMigrations.push({
workspaceId: fieldMetadataUpdate.current.workspaceId,
name: generateMigrationName(
`update-${fieldMetadataUpdate.altered.name}`,
),
isCustom: fieldMetadataUpdate.altered.isCustom,
migrations,
});
}
}
return workspaceMigrations;
}
private async deleteFieldMigration(
originalObjectMetadataMap: Record<string, ObjectMetadataEntity>,
fieldMetadataCollection: FieldMetadataEntity[],
): Promise<Partial<WorkspaceMigrationEntity>[]> {
const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = [];
for (const fieldMetadata of fieldMetadataCollection) {
// We're skipping relation fields, because they're just representation and not real columns
if (fieldMetadata.type === FieldMetadataType.RELATION) {
continue;
}
const migrations: WorkspaceMigrationTableAction[] = [
{
name: computeObjectTargetTable(
originalObjectMetadataMap[fieldMetadata.objectMetadataId],
),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.DROP,
columnName: fieldMetadata.name,
},
],
},
];
workspaceMigrations.push({
workspaceId: fieldMetadata.workspaceId,
name: generateMigrationName(`delete-${fieldMetadata.name}`),
isCustom: fieldMetadata.isCustom,
migrations,
});
}
return workspaceMigrations;
}
}
@@ -1,59 +0,0 @@
import { Injectable } from '@nestjs/common';
import { WorkspaceMigrationBuilderAction } from 'src/engine/workspace-manager/workspace-migration-builder/interfaces/workspace-migration-builder-action.interface';
import { type IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { type WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import {
createIndexMigration,
deleteIndexMigration,
} from 'src/engine/workspace-manager/workspace-migration-builder/factories/utils/workspace-migration-index.factory.utils';
@Injectable()
export class WorkspaceMigrationIndexFactory {
constructor() {}
async create(
originalObjectMetadataCollection: ObjectMetadataEntity[],
indexMetadataCollection: IndexMetadataEntity[],
action: WorkspaceMigrationBuilderAction,
): Promise<Partial<WorkspaceMigrationEntity>[]> {
const originalObjectMetadataMap = Object.fromEntries(
originalObjectMetadataCollection.map((obj) => [obj.id, obj]),
);
const indexMetadataByObjectMetadataMap = new Map<
ObjectMetadataEntity,
IndexMetadataEntity[]
>();
indexMetadataCollection.forEach((currentIndexMetadata) => {
const objectMetadata =
originalObjectMetadataMap[currentIndexMetadata.objectMetadataId];
if (!objectMetadata) {
throw new Error(
`Object metadata with id ${currentIndexMetadata.objectMetadataId} not found`,
);
}
if (!indexMetadataByObjectMetadataMap.has(objectMetadata)) {
indexMetadataByObjectMetadataMap.set(objectMetadata, []);
}
indexMetadataByObjectMetadataMap
?.get(objectMetadata)
?.push(currentIndexMetadata);
});
switch (action) {
case WorkspaceMigrationBuilderAction.CREATE:
return createIndexMigration(indexMetadataByObjectMetadataMap);
case WorkspaceMigrationBuilderAction.DELETE:
return deleteIndexMigration(indexMetadataByObjectMetadataMap);
default:
return [];
}
}
}
@@ -1,163 +0,0 @@
import { Injectable } from '@nestjs/common';
import { FieldMetadataType } from 'twenty-shared/types';
import { WorkspaceMigrationBuilderAction } from 'src/engine/workspace-manager/workspace-migration-builder/interfaces/workspace-migration-builder-action.interface';
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { generateMigrationName } from 'src/engine/metadata-modules/workspace-migration/utils/generate-migration-name.util';
import {
WorkspaceMigrationColumnActionType,
type WorkspaceMigrationEntity,
type WorkspaceMigrationTableAction,
WorkspaceMigrationTableActionType,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import { WorkspaceMigrationFactory } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.factory';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
export interface ObjectMetadataUpdate {
current: ObjectMetadataEntity;
altered: ObjectMetadataEntity;
}
@Injectable()
export class WorkspaceMigrationObjectFactory {
constructor(
private readonly workspaceMigrationFactory: WorkspaceMigrationFactory,
) {}
async create(
objectMetadataCollection: ObjectMetadataEntity[],
action: WorkspaceMigrationBuilderAction.CREATE,
): Promise<Partial<WorkspaceMigrationEntity>[]>;
async create(
objectMetadataUpdateCollection: ObjectMetadataUpdate[],
action: WorkspaceMigrationBuilderAction.UPDATE,
): Promise<Partial<WorkspaceMigrationEntity>[]>;
async create(
objectMetadataCollection: ObjectMetadataEntity[],
action: WorkspaceMigrationBuilderAction.DELETE,
): Promise<Partial<WorkspaceMigrationEntity>[]>;
async create(
objectMetadataCollectionOrObjectMetadataUpdateCollection:
| ObjectMetadataEntity[]
| ObjectMetadataUpdate[],
action: WorkspaceMigrationBuilderAction,
): Promise<Partial<WorkspaceMigrationEntity>[]> {
switch (action) {
case WorkspaceMigrationBuilderAction.CREATE:
return this.createObjectMigration(
objectMetadataCollectionOrObjectMetadataUpdateCollection as ObjectMetadataEntity[],
);
case WorkspaceMigrationBuilderAction.UPDATE:
return this.updateObjectMigration(
objectMetadataCollectionOrObjectMetadataUpdateCollection as ObjectMetadataUpdate[],
);
case WorkspaceMigrationBuilderAction.DELETE:
return this.deleteObjectMigration(
objectMetadataCollectionOrObjectMetadataUpdateCollection as ObjectMetadataEntity[],
);
default:
return [];
}
}
private async createObjectMigration(
objectMetadataCollection: ObjectMetadataEntity[],
): Promise<Partial<WorkspaceMigrationEntity>[]> {
const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = [];
for (const objectMetadata of objectMetadataCollection) {
const migrations: WorkspaceMigrationTableAction[] = [
{
name: computeObjectTargetTable(objectMetadata),
action: WorkspaceMigrationTableActionType.CREATE,
},
];
for (const field of objectMetadata.fields) {
if (field.type === FieldMetadataType.RELATION) {
continue;
}
migrations.push({
name: computeObjectTargetTable(objectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: this.workspaceMigrationFactory.createColumnActions(
WorkspaceMigrationColumnActionType.CREATE,
field,
),
});
}
workspaceMigrations.push({
workspaceId: objectMetadata.workspaceId,
name: generateMigrationName(`create-${objectMetadata.nameSingular}`),
isCustom: objectMetadata.isCustom,
migrations,
});
}
return workspaceMigrations;
}
private async updateObjectMigration(
objectMetadataUpdateCollection: ObjectMetadataUpdate[],
): Promise<Partial<WorkspaceMigrationEntity>[]> {
const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = [];
for (const objectMetadataUpdate of objectMetadataUpdateCollection) {
const oldTableName = computeObjectTargetTable(
objectMetadataUpdate.current,
);
const newTableName = computeObjectTargetTable(
objectMetadataUpdate.altered,
);
if (oldTableName !== newTableName) {
workspaceMigrations.push({
workspaceId: objectMetadataUpdate.current.workspaceId,
name: generateMigrationName(
`rename-${objectMetadataUpdate.current.nameSingular}`,
),
isCustom: objectMetadataUpdate.altered.isCustom,
migrations: [
{
name: oldTableName,
newName: newTableName,
action: WorkspaceMigrationTableActionType.ALTER,
},
],
});
}
}
return workspaceMigrations;
}
private async deleteObjectMigration(
objectMetadataCollection: ObjectMetadataEntity[],
): Promise<Partial<WorkspaceMigrationEntity>[]> {
const workspaceMigrations: Partial<WorkspaceMigrationEntity>[] = [];
for (const objectMetadata of objectMetadataCollection) {
workspaceMigrations.push({
workspaceId: objectMetadata.workspaceId,
name: generateMigrationName(`delete-${objectMetadata.nameSingular}`),
isCustom: objectMetadata.isCustom,
migrations: [
{
name: computeObjectTargetTable(objectMetadata),
action: WorkspaceMigrationTableActionType.DROP,
columns: [],
} satisfies WorkspaceMigrationTableAction,
],
});
}
return workspaceMigrations;
}
}
@@ -1,5 +0,0 @@
export enum WorkspaceMigrationBuilderAction {
CREATE = 'create',
UPDATE = 'update',
DELETE = 'delete',
}
@@ -1,13 +0,0 @@
import { Module } from '@nestjs/common';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module';
import { workspaceMigrationBuilderFactories } from './factories';
@Module({
imports: [WorkspaceMigrationModule, FeatureFlagModule],
providers: [...workspaceMigrationBuilderFactories],
exports: [...workspaceMigrationBuilderFactories],
})
export class WorkspaceMigrationBuilderModule {}
@@ -1,37 +0,0 @@
import { Command, CommandRunner, Option } from 'nest-commander';
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service';
interface ExecuteWorkspaceMigrationsOptions {
workspaceId: string;
}
@Command({
name: 'workspace:apply-pending-migrations',
description: 'Apply pending migrations',
})
export class WorkspaceExecutePendingMigrationsCommand extends CommandRunner {
constructor(
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
) {
super();
}
async run(
_passedParam: string[],
options: ExecuteWorkspaceMigrationsOptions,
): Promise<void> {
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
options.workspaceId,
);
}
@Option({
flags: '-w, --workspace-id [workspace_id]',
description: 'workspace id',
required: true,
})
parseWorkspaceId(value: string): string {
return value;
}
}
@@ -1,11 +0,0 @@
import { Module } from '@nestjs/common';
import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.module';
import { WorkspaceExecutePendingMigrationsCommand } from './workspace-execute-pending-migrations.command';
@Module({
imports: [WorkspaceMigrationRunnerModule],
providers: [WorkspaceExecutePendingMigrationsCommand],
})
export class WorkspaceMigrationRunnerCommandsModule {}
@@ -1,101 +0,0 @@
import { Test, type TestingModule } from '@nestjs/testing';
import { DataSource, type QueryRunner, TableColumn } from 'typeorm';
import {
WorkspaceMigrationColumnActionType,
type WorkspaceMigrationColumnAlter,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import { WorkspaceMigrationEnumService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service';
describe('WorkspaceMigrationEnumService', () => {
let service: WorkspaceMigrationEnumService;
let queryRunner: QueryRunner;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
WorkspaceMigrationEnumService,
{
provide: DataSource,
useValue: {
createQueryRunner: () => ({
query: jest.fn(),
addColumn: jest.fn(),
}),
},
},
],
}).compile();
service = module.get<WorkspaceMigrationEnumService>(
WorkspaceMigrationEnumService,
);
queryRunner = module.get(DataSource).createQueryRunner();
});
describe('alterEnum', () => {
it('should handle enum column alteration with renamed values', async () => {
const mockMigrationColumn: WorkspaceMigrationColumnAlter = {
action: WorkspaceMigrationColumnActionType.ALTER,
currentColumnDefinition: {
columnName: 'status',
columnType: 'enum',
enum: ['ACTIVE', 'INACTIVE'],
isNullable: false,
defaultValue: 'ACTIVE',
},
alteredColumnDefinition: {
columnName: 'status',
columnType: 'enum',
enum: [
{ from: 'ACTIVE', to: 'ENABLED' },
{ from: 'INACTIVE', to: 'DISABLED' },
],
isNullable: false,
defaultValue: 'ENABLED',
},
};
jest.spyOn(queryRunner, 'query').mockImplementation((query: string) => {
if (query.includes('information_schema.columns')) {
return Promise.resolve([{ udt_name: 'test_status_enum' }]);
}
if (query.includes('SELECT id')) {
return Promise.resolve([
{ id: '1', status: 'ACTIVE' },
{ id: '2', status: 'INACTIVE' },
]);
}
return Promise.resolve();
});
await service.alterEnum(
queryRunner,
'test_schema',
'test_table',
mockMigrationColumn,
);
expect(queryRunner.query).toHaveBeenCalledWith(
expect.stringContaining('information_schema.columns'),
['test_schema', 'test_table', 'status'],
);
expect(queryRunner.query).toHaveBeenCalledWith(
expect.stringContaining('ALTER TYPE'),
);
expect(queryRunner.addColumn).toHaveBeenCalledWith(
'test_schema.test_table',
new TableColumn({
name: 'status',
type: 'enum',
enum: ['ENABLED', 'DISABLED'],
isNullable: false,
default: 'ENABLED',
enumName: 'test_table_status_enum',
}),
);
});
});
});
@@ -1,372 +0,0 @@
import { Injectable } from '@nestjs/common';
import { isDefined } from 'twenty-shared/utils';
import { type QueryRunner, TableColumn } from 'typeorm';
import {
type WorkspaceMigrationColumnAction,
WorkspaceMigrationColumnActionType,
type WorkspaceMigrationColumnAlter,
type WorkspaceMigrationColumnCreate,
type WorkspaceMigrationColumnCreateForeignKey,
type WorkspaceMigrationColumnDrop,
type WorkspaceMigrationColumnDropForeignKey,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import { WorkspaceMigrationEnumService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service';
import { WorkspaceMigrationTypeService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-type.service';
import { type PostgresQueryRunner } from 'src/engine/workspace-manager/workspace-migration-runner/types/postgres-query-runner.type';
import { computePostgresEnumName } from 'src/engine/workspace-manager/workspace-migration-runner/utils/compute-postgres-enum-name.util';
import { convertOnDeleteActionToOnDelete } from 'src/engine/workspace-manager/workspace-migration-runner/utils/convert-on-delete-action-to-on-delete.util';
import { typeormBuildCreateColumnSql } from 'src/engine/workspace-manager/workspace-migration-runner/utils/internal/typeorm-build-create-column-sql.util';
import { removeSqlDDLInjection } from 'src/engine/workspace-manager/workspace-migration-runner/utils/remove-sql-injection.util';
@Injectable()
export class WorkspaceMigrationColumnService {
constructor(
private readonly workspaceMigrationEnumService: WorkspaceMigrationEnumService,
private readonly workspaceMigrationTypeService: WorkspaceMigrationTypeService,
) {}
public async handleColumnChanges(
queryRunner: PostgresQueryRunner,
schemaName: string,
tableName: string,
columnMigrations?: WorkspaceMigrationColumnAction[],
) {
if (!columnMigrations || columnMigrations.length === 0) {
return;
}
const columnsByAction = this.groupColumnsByAction(columnMigrations);
if (columnsByAction.create.length > 0) {
await this.handleCreateColumns(
queryRunner,
schemaName,
tableName,
columnsByAction.create,
);
}
if (columnsByAction.drop.length > 0) {
await this.handleDropColumns(
queryRunner,
schemaName,
tableName,
columnsByAction.drop,
);
}
if (columnsByAction.alter.length > 0) {
for (const column of columnsByAction.alter) {
await this.alterColumn(queryRunner, schemaName, tableName, column);
}
}
if (columnsByAction.createForeignKey.length > 0) {
for (const column of columnsByAction.createForeignKey) {
await this.createForeignKey(queryRunner, schemaName, tableName, column);
}
}
if (columnsByAction.dropForeignKey.length > 0) {
for (const column of columnsByAction.dropForeignKey) {
await this.dropForeignKey(queryRunner, schemaName, tableName, column);
}
}
}
private groupColumnsByAction(
columnMigrations: WorkspaceMigrationColumnAction[],
) {
return columnMigrations.reduce(
(acc, column) => {
switch (column.action) {
case WorkspaceMigrationColumnActionType.CREATE:
acc.create.push(column as WorkspaceMigrationColumnCreate);
break;
case WorkspaceMigrationColumnActionType.ALTER:
acc.alter.push(column as WorkspaceMigrationColumnAlter);
break;
case WorkspaceMigrationColumnActionType.CREATE_FOREIGN_KEY:
acc.createForeignKey.push(
column as WorkspaceMigrationColumnCreateForeignKey,
);
break;
case WorkspaceMigrationColumnActionType.DROP_FOREIGN_KEY:
acc.dropForeignKey.push(
column as WorkspaceMigrationColumnDropForeignKey,
);
break;
case WorkspaceMigrationColumnActionType.DROP:
acc.drop.push(column as WorkspaceMigrationColumnDrop);
break;
}
return acc;
},
{
create: [] as WorkspaceMigrationColumnCreate[],
alter: [] as WorkspaceMigrationColumnAlter[],
createForeignKey: [] as WorkspaceMigrationColumnCreateForeignKey[],
dropForeignKey: [] as WorkspaceMigrationColumnDropForeignKey[],
drop: [] as WorkspaceMigrationColumnDrop[],
},
);
}
public createTableColumnFromMigration(
tableName: string,
column: WorkspaceMigrationColumnCreate,
): TableColumn {
const enumName = column.enum?.length
? `${tableName}_${column.columnName}_enum`
: undefined;
return new TableColumn({
name: column.columnName,
type: column.columnType,
default: column.defaultValue,
isPrimary: column.columnName === 'id',
enum: column.enum?.filter(
(value): value is string => typeof value === 'string',
),
enumName: enumName,
isArray: column.isArray,
isNullable: column.isNullable,
asExpression: column.asExpression,
generatedType: column.generatedType,
});
}
public async handleCreateColumns(
queryRunner: PostgresQueryRunner,
schemaName: string,
tableName: string,
createColumnMigrations: WorkspaceMigrationColumnCreate[],
) {
for (const createColumnMigration of createColumnMigrations) {
// TODO: remove once refactor is complete, id column is already created during table creation
if (createColumnMigration.columnName === 'id') {
continue;
}
if (isDefined(createColumnMigration.enum)) {
const enumName = computePostgresEnumName({
tableName,
columnName: createColumnMigration.columnName,
});
const joinedEnumValues = createColumnMigration.enum
.map((value) => removeSqlDDLInjection(value.toString()))
.map((value) => `'${value}'`)
.join(',');
// TODO: remove once drop table as been refactored to remove the enum types
await queryRunner.query(`DROP TYPE IF EXISTS "${enumName}"`);
await queryRunner.query(
`CREATE TYPE "${enumName}" AS ENUM (${joinedEnumValues})`,
);
}
await queryRunner.query(
`ALTER TABLE "${schemaName}"."${tableName}" ADD ${typeormBuildCreateColumnSql(
{
table: { name: tableName },
column: {
name: createColumnMigration.columnName,
type: createColumnMigration.columnType,
precision:
createColumnMigration.columnType === 'timestamptz'
? 3
: undefined,
isArray: createColumnMigration.isArray ?? false,
isNullable: createColumnMigration.isNullable,
default: createColumnMigration.defaultValue,
asExpression: createColumnMigration.asExpression,
generatedType: createColumnMigration.generatedType,
},
},
)}`,
);
if (createColumnMigration.columnName === 'id') {
const pkName = queryRunner.connection.namingStrategy.primaryKeyName(
tableName,
[createColumnMigration.columnName],
);
await queryRunner.query(
`ALTER TABLE "${schemaName}"."${tableName} ADD CONSTRAINT "${pkName}" PRIMARY KEY (${removeSqlDDLInjection(createColumnMigration.columnName)})`,
);
}
}
}
public async handleDropColumns(
queryRunner: PostgresQueryRunner,
schemaName: string,
tableName: string,
dropColumns: WorkspaceMigrationColumnDrop[],
) {
if (dropColumns.length === 0) return;
const columnNames = dropColumns.map((column) => column.columnName);
await queryRunner.dropColumns(`${schemaName}.${tableName}`, columnNames);
}
public async alterColumn(
queryRunner: PostgresQueryRunner,
schemaName: string,
tableName: string,
migrationColumn: WorkspaceMigrationColumnAlter,
) {
const enumValues = migrationColumn.alteredColumnDefinition.enum;
// TODO: Maybe we can do something better if we can recreate the old `TableColumn` object
if (enumValues) {
// This is returning the old enum values to avoid TypeORM dropping the enum type
await this.workspaceMigrationEnumService.alterEnum(
queryRunner,
schemaName,
tableName,
migrationColumn,
);
return;
}
if (
migrationColumn.currentColumnDefinition.columnType !==
migrationColumn.alteredColumnDefinition.columnType
) {
await this.workspaceMigrationTypeService.alterType(
queryRunner,
schemaName,
tableName,
migrationColumn,
);
migrationColumn.currentColumnDefinition.columnType =
migrationColumn.alteredColumnDefinition.columnType;
return;
}
await queryRunner.changeColumn(
`${schemaName}.${tableName}`,
new TableColumn({
name: migrationColumn.currentColumnDefinition.columnName,
type: migrationColumn.currentColumnDefinition.columnType,
default: migrationColumn.currentColumnDefinition.defaultValue,
enum: migrationColumn.currentColumnDefinition.enum?.filter(
(value): value is string => typeof value === 'string',
),
isArray: migrationColumn.currentColumnDefinition.isArray,
isNullable: migrationColumn.currentColumnDefinition.isNullable,
/* For now unique constraints are created at a higher level
as we need to handle soft-delete and a bug on empty strings
*/
// isUnique: migrationColumn.currentColumnDefinition.isUnique,
}),
new TableColumn({
name: migrationColumn.alteredColumnDefinition.columnName,
type: migrationColumn.alteredColumnDefinition.columnType,
default: migrationColumn.alteredColumnDefinition.defaultValue,
enum: migrationColumn.currentColumnDefinition.enum?.filter(
(value): value is string => typeof value === 'string',
),
isArray: migrationColumn.alteredColumnDefinition.isArray,
isNullable: migrationColumn.alteredColumnDefinition.isNullable,
asExpression: migrationColumn.alteredColumnDefinition.asExpression,
generatedType: migrationColumn.alteredColumnDefinition.generatedType,
/* For now unique constraints are created at a higher level
as we need to handle soft-delete and a bug on empty strings
*/
// isUnique: migrationColumn.alteredColumnDefinition.isUnique,
}),
);
}
private async createForeignKey(
queryRunner: PostgresQueryRunner,
schemaName: string,
tableName: string,
migrationColumn: WorkspaceMigrationColumnCreateForeignKey,
) {
// Code reference:
// https://github.com/typeorm/typeorm/blob/master/src/driver/postgres/PostgresQueryRunner.ts#L2894
const foreignKeyName = queryRunner.connection.namingStrategy.foreignKeyName(
tableName,
[migrationColumn.columnName],
`${schemaName}.${migrationColumn.referencedTableName}`,
[migrationColumn.referencedTableColumnName],
);
let sql =
`ALTER TABLE "${schemaName}"."${tableName}" ADD CONSTRAINT "${
foreignKeyName
}" FOREIGN KEY ("${removeSqlDDLInjection(migrationColumn.columnName)}") ` +
`REFERENCES "${schemaName}"."${removeSqlDDLInjection(migrationColumn.referencedTableName)}"("${removeSqlDDLInjection(migrationColumn.referencedTableColumnName)}")`;
if (migrationColumn.onDelete)
sql += ` ON DELETE ${convertOnDeleteActionToOnDelete(migrationColumn.onDelete)}`;
await queryRunner.query(sql);
}
private async dropForeignKey(
queryRunner: PostgresQueryRunner,
schemaName: string,
tableName: string,
migrationColumn: WorkspaceMigrationColumnDropForeignKey,
) {
const foreignKeyName = await this.getForeignKeyName(
queryRunner,
schemaName,
tableName,
migrationColumn.columnName,
);
if (!foreignKeyName) {
throw new Error(
`Foreign key not found for column ${migrationColumn.columnName}`,
);
}
await queryRunner.dropForeignKey(
`${schemaName}.${tableName}`,
foreignKeyName,
);
}
private async getForeignKeyName(
queryRunner: QueryRunner,
schemaName: string,
tableName: string,
columnName: string,
): Promise<string | undefined> {
const foreignKeys = await queryRunner.query(
`
SELECT
tc.constraint_name AS constraint_name
FROM
information_schema.table_constraints AS tc
JOIN
information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
AND tc.table_schema = kcu.table_schema
WHERE
tc.constraint_type = 'FOREIGN KEY'
AND tc.table_schema = $1
AND tc.table_name = $2
AND kcu.column_name = $3
`,
[schemaName, tableName, columnName],
);
return foreignKeys[0]?.constraint_name;
}
}
@@ -1,259 +0,0 @@
import { Injectable } from '@nestjs/common';
import { isDefined } from 'class-validator';
import { type QueryRunner, TableColumn } from 'typeorm';
import { v4 } from 'uuid';
import { serializeDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/serialize-default-value';
import { unserializeDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/unserialize-default-value';
import {
type WorkspaceMigrationColumnAlter,
type WorkspaceMigrationRenamedEnum,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import {
WorkspaceMigrationException,
WorkspaceMigrationExceptionCode,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.exception';
@Injectable()
export class WorkspaceMigrationEnumService {
async alterEnum(
queryRunner: QueryRunner,
schemaName: string,
tableName: string,
migrationColumn: WorkspaceMigrationColumnAlter,
) {
const oldEnumTypeName = await this.getEnumTypeName(
queryRunner,
schemaName,
tableName,
migrationColumn.currentColumnDefinition.columnName,
);
// Rename column name
if (
migrationColumn.currentColumnDefinition.columnName !==
migrationColumn.alteredColumnDefinition.columnName
) {
await this.renameColumn(
queryRunner,
schemaName,
tableName,
migrationColumn.currentColumnDefinition.columnName,
migrationColumn.alteredColumnDefinition.columnName,
);
}
const columnDefinition = migrationColumn.alteredColumnDefinition;
const tempEnumTypeName = `${oldEnumTypeName}_temp`;
const newEnumTypeName = `${tableName}_${columnDefinition.columnName}_enum`;
const enumValues =
columnDefinition.enum?.map((enumValue) => {
if (typeof enumValue === 'string') {
return enumValue;
}
return enumValue.to;
}) ?? [];
const renamedEnumValues = columnDefinition.enum?.filter(
(enumValue): enumValue is WorkspaceMigrationRenamedEnum =>
typeof enumValue !== 'string',
);
const oldColumnName = `old_${v4()}`;
// Rename old column
await this.renameColumn(
queryRunner,
schemaName,
tableName,
columnDefinition.columnName,
oldColumnName,
);
await this.renameEnumType(
queryRunner,
schemaName,
oldEnumTypeName,
tempEnumTypeName,
);
await queryRunner.addColumn(
`${schemaName}.${tableName}`,
new TableColumn({
name: columnDefinition.columnName,
type: columnDefinition.columnType,
default: columnDefinition.defaultValue,
enum: enumValues,
enumName: newEnumTypeName,
isArray: columnDefinition.isArray,
isNullable: columnDefinition.isNullable,
isUnique: columnDefinition.isUnique,
}),
);
await this.migrateEnumValues(
queryRunner,
schemaName,
migrationColumn,
tableName,
oldColumnName,
enumValues,
renamedEnumValues,
);
// Drop old column
await queryRunner.query(`
ALTER TABLE "${schemaName}"."${tableName}"
DROP COLUMN "${oldColumnName}"
`);
// Drop temp enum type
await this.dropOldEnumType(queryRunner, schemaName, tempEnumTypeName);
}
private async renameColumn(
queryRunner: QueryRunner,
schemaName: string,
tableName: string,
oldColumnName: string,
newColumnName: string,
) {
await queryRunner.query(`
ALTER TABLE "${schemaName}"."${tableName}"
RENAME COLUMN "${oldColumnName}" TO "${newColumnName}"
`);
}
private migrateEnumValue({
value,
renamedEnumValues,
allEnumValues,
defaultValueFallback,
}: {
value: string;
renamedEnumValues?: WorkspaceMigrationRenamedEnum[];
allEnumValues?: string[];
defaultValueFallback?: string;
}) {
if (renamedEnumValues?.find((enumVal) => enumVal?.from === value)?.to) {
return renamedEnumValues?.find((enumVal) => enumVal?.from === value)?.to;
}
if (allEnumValues?.includes(value)) {
const isDestinationOfRename = renamedEnumValues?.some(
(enumVal) => enumVal.to === value,
);
if (!isDestinationOfRename) {
return value;
}
}
if (isDefined(defaultValueFallback)) {
return defaultValueFallback;
}
return null;
}
private async migrateEnumValues(
queryRunner: QueryRunner,
schemaName: string,
migrationColumn: WorkspaceMigrationColumnAlter,
tableName: string,
oldColumnName: string,
enumValues: string[],
renamedEnumValues?: WorkspaceMigrationRenamedEnum[],
) {
const columnDefinition = migrationColumn.alteredColumnDefinition;
const values = await queryRunner.query(
`SELECT id, "${oldColumnName}" FROM "${schemaName}"."${tableName}"`,
);
for (const value of values) {
let val = value[oldColumnName];
if (/^\{.*\}$/.test(val)) {
val = serializeDefaultValue(
val
.slice(1, -1)
.split(',')
.map((v: string) => v.trim())
.map((v: string) =>
this.migrateEnumValue({
value: v,
renamedEnumValues: renamedEnumValues,
allEnumValues: enumValues,
}),
)
.filter((v: string | null) => isDefined(v)),
);
} else if (typeof val === 'string') {
const migratedValue = this.migrateEnumValue({
value: val,
renamedEnumValues: renamedEnumValues,
allEnumValues: enumValues,
defaultValueFallback: columnDefinition.isNullable
? null
: unserializeDefaultValue(columnDefinition.defaultValue),
});
val = isDefined(migratedValue) ? `'${migratedValue}'` : null;
}
await queryRunner.query(`
UPDATE "${schemaName}"."${tableName}"
SET "${columnDefinition.columnName}" = ${val}
WHERE id='${value.id}'
`);
}
}
private async dropOldEnumType(
queryRunner: QueryRunner,
schemaName: string,
oldEnumTypeName: string,
) {
await queryRunner.query(
`DROP TYPE IF EXISTS "${schemaName}"."${oldEnumTypeName}"`,
);
}
private async renameEnumType(
queryRunner: QueryRunner,
schemaName: string,
oldEnumTypeName: string,
newEnumTypeName: string,
) {
await queryRunner.query(`
ALTER TYPE "${schemaName}"."${oldEnumTypeName}"
RENAME TO "${newEnumTypeName}"
`);
}
private async getEnumTypeName(
queryRunner: QueryRunner,
schemaName: string,
tableName: string,
columnName: string,
): Promise<string> {
const [result] = await queryRunner.query(
`SELECT udt_name, data_type FROM information_schema.columns WHERE table_schema = $1 AND table_name = $2 AND column_name = $3`,
[schemaName, tableName, columnName],
);
if (!result) {
throw new WorkspaceMigrationException(
`Enum type name not found for column ${columnName} in table ${tableName} while trying to alter enum`,
WorkspaceMigrationExceptionCode.ENUM_TYPE_NAME_NOT_FOUND,
);
}
const enumTypeName =
result.data_type === 'ARRAY'
? result.udt_name.replace(/^_/, '')
: result.udt_name;
return enumTypeName;
}
}
@@ -1,38 +0,0 @@
import { Injectable } from '@nestjs/common';
import { type QueryRunner } from 'typeorm';
import { type WorkspaceMigrationColumnAlter } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
@Injectable()
export class WorkspaceMigrationTypeService {
constructor() {}
async alterType(
queryRunner: QueryRunner,
schemaName: string,
tableName: string,
migrationColumn: WorkspaceMigrationColumnAlter,
) {
const columnDefinition = migrationColumn.alteredColumnDefinition;
const computedColumnType = ` ${columnDefinition.columnType}${
columnDefinition.columnType === 'timestamptz' ? `(3)` : ''
}`;
// Update the column type
// If casting is not possible, the query will fail
await queryRunner.query(`
ALTER TABLE "${schemaName}"."${tableName}"
ALTER COLUMN "${columnDefinition.columnName}" TYPE ${computedColumnType}
USING "${columnDefinition.columnName}"::${computedColumnType}
`);
// Update the column default value
if (columnDefinition.defaultValue) {
await queryRunner.query(`
ALTER TABLE "${schemaName}"."${tableName}"
ALTER COLUMN "${columnDefinition.columnName}" SET DEFAULT ${columnDefinition.defaultValue}::${columnDefinition.columnType};
`);
}
}
}
@@ -1,9 +0,0 @@
import { type QueryRunner } from 'typeorm';
export type PostgresQueryRunner = QueryRunner & {
connection: QueryRunner['connection'] & {
driver: QueryRunner['connection']['driver'] & {
uuidGenerator: () => string;
};
};
};
@@ -1,95 +0,0 @@
import { typeormBuildCreateColumnSql } from './typeorm-build-create-column-sql.util';
describe('typeormBuildCreateColumnSql', () => {
const table = { name: 'my_table' };
it('should generate SQL for a simple text column', () => {
const column = {
name: 'col1',
type: 'text',
isArray: false,
isNullable: false,
default: undefined,
generatedType: undefined,
asExpression: undefined,
};
const sql = typeormBuildCreateColumnSql({ table, column });
expect(sql).toBe('"col1" text NOT NULL');
});
it('should generate SQL for a text[] (array) column', () => {
const column = {
name: 'col2',
type: 'text',
isArray: true,
isNullable: true,
default: undefined,
generatedType: undefined,
asExpression: undefined,
};
const sql = typeormBuildCreateColumnSql({ table, column });
expect(sql).toBe('"col2" text[]');
});
it('should generate SQL for an enum column', () => {
const column = {
name: 'col3',
type: 'enum',
isArray: false,
isNullable: true,
default: undefined,
generatedType: undefined,
asExpression: undefined,
};
const sql = typeormBuildCreateColumnSql({ table, column });
expect(sql).toBe('"col3" "my_table_col3_enum"');
});
it('should generate SQL for an enum[] (array) column', () => {
const column = {
name: 'col4',
type: 'enum',
isArray: true,
isNullable: false,
default: undefined,
generatedType: undefined,
asExpression: undefined,
};
const sql = typeormBuildCreateColumnSql({ table, column });
expect(sql).toBe('"col4" "my_table_col4_enum"[] NOT NULL');
});
it('should include default and nullability', () => {
const column = {
name: 'col5',
type: 'text',
isArray: false,
isNullable: false,
default: "'default'",
generatedType: undefined,
asExpression: undefined,
};
const sql = typeormBuildCreateColumnSql({ table, column });
expect(sql).toBe('"col5" text NOT NULL DEFAULT \'default\'');
});
it('should include generatedType and asExpression', () => {
const column = {
name: 'col6',
type: 'text',
isArray: false,
isNullable: true,
default: undefined,
generatedType: 'STORED' as const,
asExpression: 'lower(col6)',
};
const sql = typeormBuildCreateColumnSql({ table, column });
expect(sql).toBe('"col6" text GENERATED ALWAYS AS (lower(col6)) STORED');
});
});
@@ -1,48 +0,0 @@
// This code is from TypeORM and is used to build the SQL for creating a column
import { type Table, type TableColumn } from 'typeorm';
import { computePostgresEnumName } from 'src/engine/workspace-manager/workspace-migration-runner/utils/compute-postgres-enum-name.util';
// Do not modify: https://github.com/typeorm/typeorm/blob/master/src/driver/postgres/PostgresQueryRunner.ts#L4713
export const typeormBuildCreateColumnSql = ({
table,
column,
}: {
table: Pick<Table, 'name'>;
column: Pick<
TableColumn,
| 'name'
| 'type'
| 'isArray'
| 'isNullable'
| 'default'
| 'generatedType'
| 'asExpression'
| 'precision'
>;
}): string => {
let columnSql = '"' + column.name + '"';
if (column.type === 'enum' || column.type === 'simple-enum') {
columnSql += ` "${computePostgresEnumName({
tableName: table.name,
columnName: column.name,
})}"`;
} else {
columnSql += ' ' + column.type;
if (column.precision) columnSql += `(${column.precision})`;
}
if (column.isArray) columnSql += '[]';
if (column.generatedType === 'STORED' && column.asExpression) {
columnSql += ` GENERATED ALWAYS AS (${column.asExpression}) STORED`;
}
if (column.isNullable !== true) columnSql += ' NOT NULL';
if (column.default !== undefined && column.default !== null)
columnSql += ' DEFAULT ' + column.default;
return columnSql;
};
@@ -1,10 +0,0 @@
import { type TableColumnOptions } from 'typeorm';
export const tableDefaultColumns = (): TableColumnOptions[] => [
{
name: 'id',
type: 'uuid',
isPrimary: true,
default: 'public.uuid_generate_v4()',
},
];
@@ -1,21 +0,0 @@
import { Module } from '@nestjs/common';
import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module';
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
import { WorkspaceMigrationColumnService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-column.service';
import { WorkspaceMigrationEnumService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service';
import { WorkspaceMigrationTypeService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-type.service';
import { WorkspaceMigrationRunnerService } from './workspace-migration-runner.service';
@Module({
imports: [WorkspaceDataSourceModule, WorkspaceMigrationModule],
providers: [
WorkspaceMigrationRunnerService,
WorkspaceMigrationEnumService,
WorkspaceMigrationTypeService,
WorkspaceMigrationColumnService,
],
exports: [WorkspaceMigrationRunnerService],
})
export class WorkspaceMigrationRunnerModule {}
@@ -1,415 +0,0 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectDataSource } from '@nestjs/typeorm';
import { msg } from '@lingui/core/macro';
import { isDefined } from 'twenty-shared/utils';
import { DataSource, type QueryRunner, Table, type TableColumn } from 'typeorm';
import {
IndexMetadataException,
IndexMetadataExceptionCode,
} from 'src/engine/metadata-modules/index-metadata/index-field-metadata.exception';
import { IndexType } from 'src/engine/metadata-modules/index-metadata/types/indexType.types';
import {
type WorkspaceMigrationColumnAction,
WorkspaceMigrationColumnActionType,
type WorkspaceMigrationColumnCreate,
type WorkspaceMigrationForeignTable,
type WorkspaceMigrationIndexAction,
WorkspaceMigrationIndexActionType,
type WorkspaceMigrationTableAction,
WorkspaceMigrationTableActionType,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.service';
import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util';
import { WorkspaceMigrationColumnService } from 'src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-column.service';
import { type PostgresQueryRunner } from 'src/engine/workspace-manager/workspace-migration-runner/types/postgres-query-runner.type';
import { tableDefaultColumns } from 'src/engine/workspace-manager/workspace-migration-runner/utils/table-default-column.util';
export const RELATION_MIGRATION_PRIORITY_PREFIX = '1000';
@Injectable()
export class WorkspaceMigrationRunnerService {
private readonly logger = new Logger(WorkspaceMigrationRunnerService.name);
constructor(
@InjectDataSource()
private readonly coreDataSource: DataSource,
private readonly workspaceMigrationService: WorkspaceMigrationService,
private readonly workspaceMigrationColumnService: WorkspaceMigrationColumnService,
) {}
public async executeMigrationFromPendingMigrationsWithinTransaction(
workspaceId: string,
transactionQueryRunner: QueryRunner,
): Promise<WorkspaceMigrationTableAction[]> {
const pendingMigrations =
await this.workspaceMigrationService.getPendingMigrations(
workspaceId,
transactionQueryRunner,
);
if (pendingMigrations.length === 0) {
return [];
}
const migrationActionsWithParent = pendingMigrations.flatMap(
(pendingMigration) =>
(pendingMigration.migrations || []).map((tableAction) => ({
tableAction,
parentMigrationId: pendingMigration.id,
})),
);
const schemaName = getWorkspaceSchemaName(workspaceId);
await transactionQueryRunner.query(
`SET LOCAL search_path TO ${schemaName}`,
);
// temporary fix to skip view migrations issue during upgrade 1.8 -> 1.10
const migrationActionsWithParentTmp = [
...migrationActionsWithParent.filter(
({ tableAction }) => tableAction.name !== 'view',
),
...migrationActionsWithParent.filter(
({ tableAction }) => tableAction.name === 'view',
),
];
for (const {
tableAction,
parentMigrationId,
} of migrationActionsWithParentTmp) {
await this.handleTableChanges(
transactionQueryRunner as PostgresQueryRunner,
schemaName,
tableAction,
);
await transactionQueryRunner.query(
`UPDATE "core"."workspaceMigration" SET "appliedAt" = NOW() WHERE "id" = $1 AND "workspaceId" = $2`,
[parentMigrationId, workspaceId],
);
}
return migrationActionsWithParentTmp.map((item) => item.tableAction);
}
public async executeMigrationFromPendingMigrations(
workspaceId: string,
): Promise<WorkspaceMigrationTableAction[]> {
const queryRunner = this.coreDataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const result =
await this.executeMigrationFromPendingMigrationsWithinTransaction(
workspaceId,
queryRunner,
);
await queryRunner.commitTransaction();
return result;
} catch (error) {
this.logger.error(
`Error executing migration: ${error.message}`,
error.stack,
);
if (queryRunner.isTransactionActive) {
try {
await queryRunner.rollbackTransaction();
} catch (error) {
// eslint-disable-next-line no-console
console.trace(`Failed to rollback transaction: ${error.message}`);
}
}
throw error;
} finally {
await queryRunner.release();
}
}
private async handleTableChanges(
queryRunner: PostgresQueryRunner,
schemaName: string,
tableMigration: WorkspaceMigrationTableAction,
) {
switch (tableMigration.action) {
case WorkspaceMigrationTableActionType.CREATE:
await this.createTable(
queryRunner,
schemaName,
tableMigration.name,
tableMigration.columns,
);
break;
case WorkspaceMigrationTableActionType.ALTER: {
if (tableMigration.newName) {
await this.renameTable(
queryRunner,
schemaName,
tableMigration.name,
tableMigration.newName,
);
break;
}
if (tableMigration.columns && tableMigration.columns.length > 0) {
await this.workspaceMigrationColumnService.handleColumnChanges(
queryRunner,
schemaName,
tableMigration.newName ?? tableMigration.name,
tableMigration.columns,
);
break;
}
break;
}
case WorkspaceMigrationTableActionType.DROP:
await queryRunner.dropTable(`${schemaName}.${tableMigration.name}`);
break;
case 'create_foreign_table':
await this.createForeignTable(
queryRunner,
schemaName,
tableMigration.name,
tableMigration?.foreignTable,
);
break;
case 'drop_foreign_table':
await queryRunner.query(
`DROP FOREIGN TABLE ${schemaName}."${tableMigration.name}"`,
);
break;
case WorkspaceMigrationTableActionType.ALTER_FOREIGN_TABLE:
await this.alterForeignTable(
queryRunner,
schemaName,
tableMigration.name,
tableMigration.columns,
);
break;
case WorkspaceMigrationTableActionType.ALTER_INDEXES:
if (tableMigration.indexes && tableMigration.indexes.length > 0) {
const tableName = tableMigration.newName ?? tableMigration.name;
await this.handleIndexesChanges(
queryRunner,
schemaName,
tableName,
tableMigration.indexes,
);
}
break;
default:
throw new Error(
`Migration table action ${tableMigration.action} not supported`,
);
}
}
private async handleIndexesChanges(
queryRunner: QueryRunner,
schemaName: string,
tableName: string,
indexes: WorkspaceMigrationIndexAction[],
) {
for (const index of indexes) {
switch (index.action) {
case WorkspaceMigrationIndexActionType.CREATE:
await this.createIndex(queryRunner, schemaName, tableName, index);
break;
case WorkspaceMigrationIndexActionType.DROP:
await this.dropIndex(queryRunner, schemaName, tableName, index.name);
break;
default:
throw new Error(`Migration index action not supported`);
}
}
}
private async createIndex(
queryRunner: QueryRunner,
schemaName: string,
tableName: string,
index: WorkspaceMigrationIndexAction,
) {
try {
if (isDefined(index.type) && index.type !== IndexType.BTREE) {
const quotedColumns = index.columns.map((column) => `"${column}"`);
await queryRunner.query(`
CREATE INDEX IF NOT EXISTS "${index.name}" ON "${schemaName}"."${tableName}" USING ${index.type} (${quotedColumns.join(', ')})
`);
} else {
const quotedColumns = index.columns.map((column) => `"${column}"`);
const isUnique = index.isUnique ? 'UNIQUE' : '';
const whereClause = index.where ? `WHERE ${index.where}` : '';
await queryRunner.query(`
CREATE ${isUnique} INDEX IF NOT EXISTS "${index.name}" ON "${schemaName}"."${tableName}" (${quotedColumns.join(', ')}) ${whereClause}
`);
}
} catch (error) {
// Ignore error if index already exists
if (error.code === '42P07') {
return;
}
if (error.code === '23505') {
throw new IndexMetadataException(
`Unique index creation failed because of unique constraint violation`,
IndexMetadataExceptionCode.INDEX_CREATION_FAILED,
{
userFriendlyMessage: msg`Cannot enable uniqueness due to existing duplicate values. Please review and fix your data first (including soft deleted records).`,
},
);
}
throw error;
}
}
private async dropIndex(
queryRunner: QueryRunner,
schemaName: string,
tableName: string,
indexName: string,
) {
try {
await queryRunner.dropIndex(`${schemaName}.${tableName}`, indexName);
} catch (error) {
// Ignore error if index does not exist
if (
error.message ===
`Supplied index ${indexName} was not found in table ${schemaName}.${tableName}`
) {
return;
}
throw error;
}
}
private async createTable(
queryRunner: PostgresQueryRunner,
schemaName: string,
tableName: string,
columns?: WorkspaceMigrationColumnAction[],
) {
const tableColumns: TableColumn[] = [];
if (columns && columns.length > 0) {
const createColumns = columns.filter(
(column) => column.action === WorkspaceMigrationColumnActionType.CREATE,
) as WorkspaceMigrationColumnCreate[];
for (const column of createColumns) {
tableColumns.push(
this.workspaceMigrationColumnService.createTableColumnFromMigration(
tableName,
column,
),
);
}
}
await queryRunner.createTable(
new Table({
name: tableName,
schema: schemaName,
columns: tableColumns.length > 0 ? tableColumns : tableDefaultColumns(),
}),
true,
);
if (columns && columns.length > 0) {
const nonCreateColumns = columns.filter(
(column) => column.action !== WorkspaceMigrationColumnActionType.CREATE,
);
if (nonCreateColumns.length > 0) {
await this.workspaceMigrationColumnService.handleColumnChanges(
queryRunner,
schemaName,
tableName,
nonCreateColumns,
);
}
}
}
private async renameTable(
queryRunner: QueryRunner,
schemaName: string,
oldTableName: string,
newTableName: string,
) {
await queryRunner.renameTable(
`${schemaName}.${oldTableName}`,
newTableName,
);
}
private async createForeignTable(
queryRunner: QueryRunner,
schemaName: string,
name: string,
foreignTable: WorkspaceMigrationForeignTable | undefined,
) {
if (!foreignTable) {
return;
}
const foreignTableColumns = foreignTable.columns
.map(
(column) =>
`"${column.columnName}" ${column.columnType} OPTIONS (column_name '${column.distantColumnName}')`,
)
.join(', ');
const serverOptions = Object.entries(foreignTable.referencedTable)
.map(([key, value]) => `${key} '${value}'`)
.join(', ');
await queryRunner.query(
`CREATE FOREIGN TABLE ${schemaName}."${name}" (${foreignTableColumns}) SERVER "${foreignTable.foreignDataWrapperId}" OPTIONS (${serverOptions})`,
);
await queryRunner.query(`
COMMENT ON FOREIGN TABLE "${schemaName}"."${name}" IS '@graphql({"primary_key_columns": ["id"], "totalCount": {"enabled": true}})';
`);
}
private async alterForeignTable(
queryRunner: QueryRunner,
schemaName: string,
name: string,
columns: WorkspaceMigrationColumnAction[] | undefined,
) {
const columnUpdatesQuery = columns
?.map((column) => {
switch (column.action) {
case WorkspaceMigrationColumnActionType.DROP:
return `DROP COLUMN "${column.columnName}"`;
case WorkspaceMigrationColumnActionType.CREATE:
return `ADD COLUMN "${column.columnName}" ${column.columnType}`;
default:
return '';
}
})
.filter(Boolean)
.join(', ');
await queryRunner.query(
`ALTER FOREIGN TABLE ${schemaName}."${name}" ${columnUpdatesQuery};`,
);
}
}
@@ -1,79 +0,0 @@
import { Module } from '@nestjs/common';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { FlatFieldMetadataTypeValidatorService } from 'src/engine/metadata-modules/flat-field-metadata/services/flat-field-metadata-type-validator.service';
import { WorkspaceMigrationV2AgentActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/agent/workspace-migration-v2-agent-actions-builder.service';
import { WorkspaceMigrationV2SkillActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/skill/workspace-migration-v2-skill-actions-builder.service';
import { WorkspaceMigrationV2CronTriggerActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/cron-trigger/workspace-migration-v2-cron-trigger-action-builder.service';
import { WorkspaceMigrationV2DatabaseEventTriggerActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/database-event-trigger/workspace-migration-v2-database-event-trigger-actions-builder.service';
import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/workspace-migration-v2-field-actions-builder.service';
import { WorkspaceMigrationV2IndexActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/index/workspace-migration-v2-index-actions-builder.service';
import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/workspace-migration-v2-object-actions-builder.service';
import { WorkspaceMigrationV2PageLayoutTabActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/page-layout-tab/workspace-migration-v2-page-layout-tab-actions-builder.service';
import { WorkspaceMigrationV2PageLayoutWidgetActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/page-layout-widget/workspace-migration-v2-page-layout-widget-actions-builder.service';
import { WorkspaceMigrationV2PageLayoutActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/page-layout/workspace-migration-v2-page-layout-actions-builder.service';
import { WorkspaceMigrationV2RoleTargetActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/role-target/workspace-migration-v2-role-target-actions-builder.service';
import { WorkspaceMigrationV2RoleActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/role/workspace-migration-v2-role-actions-builder.service';
import { WorkspaceMigrationV2RouteTriggerActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/route-trigger/workspace-migration-v2-route-trigger-actions-builder.service';
import { WorkspaceMigrationV2RowLevelPermissionPredicateGroupActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/row-level-permission-predicate-group/workspace-migration-v2-row-level-permission-predicate-group-actions-builder.service';
import { WorkspaceMigrationV2RowLevelPermissionPredicateActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/row-level-permission-predicate/workspace-migration-v2-row-level-permission-predicate-actions-builder.service';
import { WorkspaceMigrationV2ServerlessFunctionActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/serverless-function/workspace-migration-v2-serverless-function-actions-builder.service';
import { WorkspaceMigrationV2ViewFieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view-field/workspace-migration-v2-view-field-actions-builder.service';
import { WorkspaceMigrationV2ViewFilterActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view-filter/workspace-migration-v2-view-filter-actions-builder.service';
import { WorkspaceMigrationV2ViewFilterGroupActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view-filter-group/workspace-migration-v2-view-filter-group-actions-builder.service';
import { WorkspaceMigrationV2ViewGroupActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view-group/workspace-migration-v2-view-group-actions-builder.service';
import { WorkspaceMigrationV2ViewActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view/workspace-migration-v2-view-actions-builder.service';
import { WorkspaceMigrationBuilderValidatorsModule } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/workspace-migration-builder-validators.module';
@Module({
imports: [FeatureFlagModule, WorkspaceMigrationBuilderValidatorsModule],
providers: [
FlatFieldMetadataTypeValidatorService,
WorkspaceMigrationV2ObjectActionsBuilderService,
WorkspaceMigrationV2ViewActionsBuilderService,
WorkspaceMigrationV2ViewFieldActionsBuilderService,
WorkspaceMigrationV2ViewFilterActionsBuilderService,
WorkspaceMigrationV2ViewFilterGroupActionsBuilderService,
WorkspaceMigrationV2ViewGroupActionsBuilderService,
WorkspaceMigrationV2IndexActionsBuilderService,
WorkspaceMigrationV2ServerlessFunctionActionsBuilderService,
WorkspaceMigrationV2DatabaseEventTriggerActionsBuilderService,
WorkspaceMigrationV2FieldActionsBuilderService,
WorkspaceMigrationV2CronTriggerActionsBuilderService,
WorkspaceMigrationV2RouteTriggerActionsBuilderService,
WorkspaceMigrationV2RoleActionsBuilderService,
WorkspaceMigrationV2RoleTargetActionsBuilderService,
WorkspaceMigrationV2AgentActionsBuilderService,
WorkspaceMigrationV2SkillActionsBuilderService,
WorkspaceMigrationV2PageLayoutActionsBuilderService,
WorkspaceMigrationV2PageLayoutWidgetActionsBuilderService,
WorkspaceMigrationV2PageLayoutTabActionsBuilderService,
WorkspaceMigrationV2RowLevelPermissionPredicateActionsBuilderService,
WorkspaceMigrationV2RowLevelPermissionPredicateGroupActionsBuilderService,
],
exports: [
WorkspaceMigrationV2ViewActionsBuilderService,
WorkspaceMigrationV2IndexActionsBuilderService,
WorkspaceMigrationV2ObjectActionsBuilderService,
WorkspaceMigrationV2ViewFieldActionsBuilderService,
WorkspaceMigrationV2ViewFilterActionsBuilderService,
WorkspaceMigrationV2ViewFilterGroupActionsBuilderService,
WorkspaceMigrationV2ViewGroupActionsBuilderService,
WorkspaceMigrationV2FieldActionsBuilderService,
WorkspaceMigrationV2ServerlessFunctionActionsBuilderService,
WorkspaceMigrationV2DatabaseEventTriggerActionsBuilderService,
WorkspaceMigrationV2CronTriggerActionsBuilderService,
WorkspaceMigrationV2RouteTriggerActionsBuilderService,
WorkspaceMigrationV2RoleActionsBuilderService,
WorkspaceMigrationV2RoleTargetActionsBuilderService,
WorkspaceMigrationV2AgentActionsBuilderService,
WorkspaceMigrationV2SkillActionsBuilderService,
WorkspaceMigrationV2PageLayoutActionsBuilderService,
WorkspaceMigrationV2PageLayoutWidgetActionsBuilderService,
WorkspaceMigrationV2PageLayoutTabActionsBuilderService,
WorkspaceMigrationV2RowLevelPermissionPredicateActionsBuilderService,
WorkspaceMigrationV2RowLevelPermissionPredicateGroupActionsBuilderService,
FlatFieldMetadataTypeValidatorService,
],
})
export class WorkspaceMigrationBuilderV2Module {}
@@ -1,156 +0,0 @@
import { Module } from '@nestjs/common';
import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.module';
import { CreateAgentActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/agent/services/create-agent-action-handler.service';
import { DeleteAgentActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/agent/services/delete-agent-action-handler.service';
import { UpdateAgentActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/agent/services/update-agent-action-handler.service';
import { CreateSkillActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/skill/services/create-skill-action-handler.service';
import { DeleteSkillActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/skill/services/delete-skill-action-handler.service';
import { UpdateSkillActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/skill/services/update-skill-action-handler.service';
import { CreateCronTriggerActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/cron-trigger/services/create-cron-trigger-action-handler.service';
import { DeleteCronTriggerActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/cron-trigger/services/delete-cron-trigger-action-handler.service';
import { UpdateCronTriggerActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/cron-trigger/services/update-cron-trigger-action-handler.service';
import { CreateDatabaseEventTriggerActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/database-event-trigger/services/create-database-event-trigger-action-handler.service';
import { DeleteDatabaseEventTriggerActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/database-event-trigger/services/delete-database-event-trigger-action-handler.service';
import { UpdateDatabaseEventTriggerActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/database-event-trigger/services/update-database-event-trigger-action-handler.service';
import { CreateFieldActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/field/services/create-field-action-handler.service';
import { DeleteFieldActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/field/services/delete-field-action-handler.service';
import { UpdateFieldActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/field/services/update-field-action-handler.service';
import { CreateIndexActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/index/services/create-index-action-handler.service';
import { DeleteIndexActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/index/services/delete-index-action-handler.service';
import { UpdateIndexActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/index/services/update-index-action-handler.service';
import { CreateObjectActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/create-object-action-handler.service';
import { DeleteObjectActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/delete-object-action-handler.service';
import { UpdateObjectActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/update-object-action-handler.service';
import { CreatePageLayoutTabActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/page-layout-tab/services/create-page-layout-tab-action-handler.service';
import { DeletePageLayoutTabActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/page-layout-tab/services/delete-page-layout-tab-action-handler.service';
import { UpdatePageLayoutTabActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/page-layout-tab/services/update-page-layout-tab-action-handler.service';
import { CreatePageLayoutWidgetActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/page-layout-widget/services/create-page-layout-widget-action-handler.service';
import { DeletePageLayoutWidgetActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/page-layout-widget/services/delete-page-layout-widget-action-handler.service';
import { UpdatePageLayoutWidgetActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/page-layout-widget/services/update-page-layout-widget-action-handler.service';
import { CreatePageLayoutActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/page-layout/services/create-page-layout-action-handler.service';
import { DeletePageLayoutActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/page-layout/services/delete-page-layout-action-handler.service';
import { UpdatePageLayoutActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/page-layout/services/update-page-layout-action-handler.service';
import { CreateRoleTargetActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/role-target/services/create-role-target-action-handler.service';
import { DeleteRoleTargetActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/role-target/services/delete-role-target-action-handler.service';
import { UpdateRoleTargetActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/role-target/services/update-role-target-action-handler.service';
import { CreateRoleActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/role/services/create-role-action-handler.service';
import { DeleteRoleActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/role/services/delete-role-action-handler.service';
import { UpdateRoleActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/role/services/update-role-action-handler.service';
import { CreateRouteTriggerActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/route-trigger/services/create-route-trigger-action-handler.service';
import { DeleteRouteTriggerActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/route-trigger/services/delete-route-trigger-action-handler.service';
import { UpdateRouteTriggerActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/route-trigger/services/update-route-trigger-action-handler.service';
import { CreateRowLevelPermissionPredicateGroupActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/row-level-permission-predicate-group/services/create-row-level-permission-predicate-group-action-handler.service';
import { DeleteRowLevelPermissionPredicateGroupActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/row-level-permission-predicate-group/services/delete-row-level-permission-predicate-group-action-handler.service';
import { UpdateRowLevelPermissionPredicateGroupActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/row-level-permission-predicate-group/services/update-row-level-permission-predicate-group-action-handler.service';
import { CreateRowLevelPermissionPredicateActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/row-level-permission-predicate/services/create-row-level-permission-predicate-action-handler.service';
import { DeleteRowLevelPermissionPredicateActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/row-level-permission-predicate/services/delete-row-level-permission-predicate-action-handler.service';
import { UpdateRowLevelPermissionPredicateActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/row-level-permission-predicate/services/update-row-level-permission-predicate-action-handler.service';
import { CreateServerlessFunctionActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/serverless-function/services/create-serverless-function-action-handler.service';
import { DeleteServerlessFunctionActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/serverless-function/services/delete-serverless-function-action-handler.service';
import { UpdateServerlessFunctionActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/serverless-function/services/update-serverless-function-action-handler.service';
import { CreateViewFieldActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-field/services/create-view-field-action-handler.service';
import { DeleteViewFieldActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-field/services/delete-view-field-action-handler.service';
import { UpdateViewFieldActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-field/services/update-view-field-action-handler.service';
import { CreateViewFilterActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-filter/services/create-view-filter-action-handler.service';
import { DeleteViewFilterActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-filter/services/delete-view-filter-action-handler.service';
import { UpdateViewFilterActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-filter/services/update-view-filter-action-handler.service';
import { CreateViewFilterGroupActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-filter-group/services/create-view-filter-group-action-handler.service';
import { DeleteViewFilterGroupActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-filter-group/services/delete-view-filter-group-action-handler.service';
import { UpdateViewFilterGroupActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-filter-group/services/update-view-filter-group-action-handler.service';
import { CreateViewGroupActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-group/services/create-view-group-action-handler.service';
import { DeleteViewGroupActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-group/services/delete-view-group-action-handler.service';
import { UpdateViewGroupActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view-group/services/update-view-group-action-handler.service';
import { CreateViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view/services/create-view-action-handler.service';
import { DeleteViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view/services/delete-view-action-handler.service';
import { UpdateViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view/services/update-view-action-handler.service';
@Module({
imports: [WorkspaceSchemaManagerModule],
providers: [
CreateFieldActionHandlerService,
UpdateFieldActionHandlerService,
DeleteFieldActionHandlerService,
CreateObjectActionHandlerService,
UpdateObjectActionHandlerService,
DeleteObjectActionHandlerService,
CreateIndexActionHandlerService,
UpdateIndexActionHandlerService,
DeleteIndexActionHandlerService,
CreateViewActionHandlerService,
UpdateViewActionHandlerService,
DeleteViewActionHandlerService,
CreateViewFieldActionHandlerService,
UpdateViewFieldActionHandlerService,
DeleteViewFieldActionHandlerService,
CreateViewFilterActionHandlerService,
UpdateViewFilterActionHandlerService,
DeleteViewFilterActionHandlerService,
CreateViewFilterGroupActionHandlerService,
UpdateViewFilterGroupActionHandlerService,
DeleteViewFilterGroupActionHandlerService,
CreateViewGroupActionHandlerService,
UpdateViewGroupActionHandlerService,
DeleteViewGroupActionHandlerService,
CreateServerlessFunctionActionHandlerService,
DeleteServerlessFunctionActionHandlerService,
UpdateServerlessFunctionActionHandlerService,
CreateDatabaseEventTriggerActionHandlerService,
DeleteDatabaseEventTriggerActionHandlerService,
UpdateDatabaseEventTriggerActionHandlerService,
CreateCronTriggerActionHandlerService,
DeleteCronTriggerActionHandlerService,
UpdateCronTriggerActionHandlerService,
CreateRouteTriggerActionHandlerService,
DeleteRouteTriggerActionHandlerService,
UpdateRouteTriggerActionHandlerService,
CreateRoleActionHandlerService,
UpdateRoleActionHandlerService,
DeleteRoleActionHandlerService,
CreateRoleTargetActionHandlerService,
DeleteRoleTargetActionHandlerService,
UpdateRoleTargetActionHandlerService,
CreateAgentActionHandlerService,
UpdateAgentActionHandlerService,
DeleteAgentActionHandlerService,
CreateSkillActionHandlerService,
UpdateSkillActionHandlerService,
DeleteSkillActionHandlerService,
CreatePageLayoutActionHandlerService,
UpdatePageLayoutActionHandlerService,
DeletePageLayoutActionHandlerService,
CreatePageLayoutWidgetActionHandlerService,
UpdatePageLayoutWidgetActionHandlerService,
DeletePageLayoutWidgetActionHandlerService,
CreatePageLayoutTabActionHandlerService,
UpdatePageLayoutTabActionHandlerService,
DeletePageLayoutTabActionHandlerService,
CreateRowLevelPermissionPredicateActionHandlerService,
UpdateRowLevelPermissionPredicateActionHandlerService,
DeleteRowLevelPermissionPredicateActionHandlerService,
CreateRowLevelPermissionPredicateGroupActionHandlerService,
UpdateRowLevelPermissionPredicateGroupActionHandlerService,
DeleteRowLevelPermissionPredicateGroupActionHandlerService,
],
})
export class WorkspaceSchemaMigrationRunnerActionHandlersModule {}
@@ -1,24 +0,0 @@
import { Module } from '@nestjs/common';
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
import { WorkspaceMigrationBuildOrchestratorService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-build-orchestrator.service';
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-validate-build-and-run-service';
import { WorkspaceMigrationBuilderV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.module';
import { WorkspaceMigrationRunnerV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/workspace-migration-runner-v2.module';
@Module({
imports: [
WorkspaceMigrationBuilderV2Module,
WorkspaceMigrationRunnerV2Module,
WorkspaceCacheModule,
],
providers: [
WorkspaceMigrationValidateBuildAndRunService,
WorkspaceMigrationBuildOrchestratorService,
],
exports: [
WorkspaceMigrationValidateBuildAndRunService,
WorkspaceMigrationBuildOrchestratorService,
],
})
export class WorkspaceMigrationV2Module {}
@@ -1,7 +1,7 @@
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { getMetadataEmptyWorkspaceMigrationActionRecord } from 'src/engine/workspace-manager/workspace-migration-v2/utils/get-metadata-empty-workspace-migration-action-record.util';
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
import { getMetadataEmptyWorkspaceMigrationActionRecord } from 'src/engine/workspace-manager/workspace-migration/utils/get-metadata-empty-workspace-migration-action-record.util';
export const createEmptyOrchestratorActionsReport =
(): OrchestratorActionsReport =>
@@ -1,6 +1,6 @@
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { type OrchestratorFailureReport } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { type OrchestratorFailureReport } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
export const EMPTY_ORCHESTRATOR_FAILURE_REPORT =
(): OrchestratorFailureReport =>
@@ -0,0 +1,3 @@
export const HELPER_AGENT = {
standardId: '20202020-0002-0001-0001-000000000004',
} as const;
@@ -1,11 +1,11 @@
import { type WorkspaceMigrationOrchestratorFailedResult } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { type WorkspaceMigrationOrchestratorFailedResult } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
export class WorkspaceMigrationBuilderExceptionV2 extends Error {
export class WorkspaceMigrationBuilderException extends Error {
constructor(
public readonly failedWorkspaceMigrationBuildResult: WorkspaceMigrationOrchestratorFailedResult,
message = 'Workspace migration builder failed',
) {
super(message);
this.name = 'WorkspaceMigrationBuilderExceptionV2';
this.name = 'WorkspaceMigrationBuilderException';
}
}
@@ -1,12 +1,12 @@
import { type I18n } from '@lingui/core';
import { type MetadataValidationErrorResponse } from 'twenty-shared/metadata';
import { type WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2';
import { translateOrchestratorFailureReportErrors } from 'src/engine/workspace-manager/workspace-migration-v2/interceptors/utils/translate-orchestrator-failure-report-errors.util';
import { type WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
import { translateOrchestratorFailureReportErrors } from 'src/engine/workspace-manager/workspace-migration/interceptors/utils/translate-orchestrator-failure-report-errors.util';
export const fromWorkspaceMigrationBuilderExceptionToMetadataValidationResponseError =
(
workspaceMigrationBuilderException: WorkspaceMigrationBuilderExceptionV2,
workspaceMigrationBuilderException: WorkspaceMigrationBuilderException,
i18n: I18n,
): MetadataValidationErrorResponse => {
const translatedReport = translateOrchestratorFailureReportErrors(
@@ -1,8 +1,8 @@
import { type I18n, type MessageDescriptor } from '@lingui/core';
import { isDefined } from 'twenty-shared/utils';
import { type OrchestratorFailureReport } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { type FlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/types/failed-flat-entity-validation.type';
import { type OrchestratorFailureReport } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
import { type FlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/types/failed-flat-entity-validation.type';
const isMessageDescriptor = (obj: unknown): obj is MessageDescriptor =>
isDefined(obj) &&
@@ -1,17 +1,17 @@
import { type I18n } from '@lingui/core';
import { msg } from '@lingui/core/macro';
import { isDefined } from 'twenty-shared/utils';
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { isDefined } from 'twenty-shared/utils';
import {
BaseGraphQLError,
ErrorCode,
} from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
import { type WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2';
import { fromWorkspaceMigrationBuilderExceptionToMetadataValidationResponseError } from 'src/engine/workspace-manager/workspace-migration-v2/interceptors/utils/from-workspace-migration-builder-exception-to-metadata-validation-response-error.util';
import { type WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
import { fromWorkspaceMigrationBuilderExceptionToMetadataValidationResponseError } from 'src/engine/workspace-manager/workspace-migration/interceptors/utils/from-workspace-migration-builder-exception-to-metadata-validation-response-error.util';
export const workspaceMigrationBuilderExceptionV2Formatter = (
error: WorkspaceMigrationBuilderExceptionV2,
export const workspaceMigrationBuilderExceptionFormatter = (
error: WorkspaceMigrationBuilderException,
i18n: I18n,
) => {
const { errors, summary } =
@@ -10,8 +10,8 @@ import { type Observable, catchError } from 'rxjs';
import { SOURCE_LOCALE } from 'twenty-shared/translations';
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
import { WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2';
import { workspaceMigrationBuilderExceptionV2Formatter } from 'src/engine/workspace-manager/workspace-migration-v2/interceptors/workspace-migration-builder-exception-v2-formatter';
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
import { workspaceMigrationBuilderExceptionFormatter } from 'src/engine/workspace-manager/workspace-migration/interceptors/workspace-migration-builder-exception-formatter';
@Injectable()
export class WorkspaceMigrationBuilderGraphqlApiExceptionInterceptor
@@ -27,8 +27,8 @@ export class WorkspaceMigrationBuilderGraphqlApiExceptionInterceptor
return next.handle().pipe(
catchError((error) => {
if (error instanceof WorkspaceMigrationBuilderExceptionV2) {
workspaceMigrationBuilderExceptionV2Formatter(error, i18n);
if (error instanceof WorkspaceMigrationBuilderException) {
workspaceMigrationBuilderExceptionFormatter(error, i18n);
}
throw error;
@@ -6,60 +6,60 @@ import { isDefined } from 'twenty-shared/utils';
import { createEmptyAllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-all-flat-entity-maps.constant';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { type MetadataFlatEntityAndRelatedFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-related-types.type';
import { createEmptyOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/constant/empty-orchestrator-actions-report.constant';
import { EMPTY_ORCHESTRATOR_FAILURE_REPORT } from 'src/engine/workspace-manager/workspace-migration-v2/constant/empty-orchestrator-failure-report.constant';
import { createEmptyOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration/constant/empty-orchestrator-actions-report.constant';
import { EMPTY_ORCHESTRATOR_FAILURE_REPORT } from 'src/engine/workspace-manager/workspace-migration/constant/empty-orchestrator-failure-report.constant';
import {
type WorkspaceMigrationOrchestratorBuildArgs,
type WorkspaceMigrationOrchestratorFailedResult,
type WorkspaceMigrationOrchestratorSuccessfulResult,
} from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { aggregateOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/utils/aggregate-orchestrator-actions-report.util';
import { WorkspaceMigrationV2AgentActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/agent/workspace-migration-v2-agent-actions-builder.service';
import { WorkspaceMigrationV2CronTriggerActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/cron-trigger/workspace-migration-v2-cron-trigger-action-builder.service';
import { WorkspaceMigrationV2DatabaseEventTriggerActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/database-event-trigger/workspace-migration-v2-database-event-trigger-actions-builder.service';
import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/workspace-migration-v2-field-actions-builder.service';
import { WorkspaceMigrationV2IndexActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/index/workspace-migration-v2-index-actions-builder.service';
import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/workspace-migration-v2-object-actions-builder.service';
import { WorkspaceMigrationV2PageLayoutTabActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/page-layout-tab/workspace-migration-v2-page-layout-tab-actions-builder.service';
import { WorkspaceMigrationV2PageLayoutWidgetActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/page-layout-widget/workspace-migration-v2-page-layout-widget-actions-builder.service';
import { WorkspaceMigrationV2PageLayoutActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/page-layout/workspace-migration-v2-page-layout-actions-builder.service';
import { WorkspaceMigrationV2RoleTargetActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/role-target/workspace-migration-v2-role-target-actions-builder.service';
import { WorkspaceMigrationV2RoleActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/role/workspace-migration-v2-role-actions-builder.service';
import { WorkspaceMigrationV2RouteTriggerActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/route-trigger/workspace-migration-v2-route-trigger-actions-builder.service';
import { WorkspaceMigrationV2RowLevelPermissionPredicateGroupActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/row-level-permission-predicate-group/workspace-migration-v2-row-level-permission-predicate-group-actions-builder.service';
import { WorkspaceMigrationV2RowLevelPermissionPredicateActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/row-level-permission-predicate/workspace-migration-v2-row-level-permission-predicate-actions-builder.service';
import { WorkspaceMigrationV2ServerlessFunctionActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/serverless-function/workspace-migration-v2-serverless-function-actions-builder.service';
import { WorkspaceMigrationV2SkillActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/skill/workspace-migration-v2-skill-actions-builder.service';
import { WorkspaceMigrationV2ViewFieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view-field/workspace-migration-v2-view-field-actions-builder.service';
import { WorkspaceMigrationV2ViewFilterGroupActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view-filter-group/workspace-migration-v2-view-filter-group-actions-builder.service';
import { WorkspaceMigrationV2ViewFilterActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view-filter/workspace-migration-v2-view-filter-actions-builder.service';
import { WorkspaceMigrationV2ViewGroupActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view-group/workspace-migration-v2-view-group-actions-builder.service';
import { WorkspaceMigrationV2ViewActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view/workspace-migration-v2-view-actions-builder.service';
} from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
import { aggregateOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration/utils/aggregate-orchestrator-actions-report.util';
import { WorkspaceMigrationAgentActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/agent/workspace-migration-agent-actions-builder.service';
import { WorkspaceMigrationCronTriggerActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/cron-trigger/workspace-migration-cron-trigger-action-builder.service';
import { WorkspaceMigrationDatabaseEventTriggerActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/database-event-trigger/workspace-migration-database-event-trigger-actions-builder.service';
import { WorkspaceMigrationFieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/field/workspace-migration-field-actions-builder.service';
import { WorkspaceMigrationIndexActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/index/workspace-migration-index-actions-builder.service';
import { WorkspaceMigrationObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/object/workspace-migration-object-actions-builder.service';
import { WorkspaceMigrationPageLayoutTabActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/page-layout-tab/workspace-migration-page-layout-tab-actions-builder.service';
import { WorkspaceMigrationPageLayoutWidgetActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/page-layout-widget/workspace-migration-page-layout-widget-actions-builder.service';
import { WorkspaceMigrationPageLayoutActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/page-layout/workspace-migration-page-layout-actions-builder.service';
import { WorkspaceMigrationRoleTargetActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/role-target/workspace-migration-role-target-actions-builder.service';
import { WorkspaceMigrationRoleActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/role/workspace-migration-role-actions-builder.service';
import { WorkspaceMigrationRouteTriggerActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/route-trigger/workspace-migration-route-trigger-actions-builder.service';
import { WorkspaceMigrationRowLevelPermissionPredicateGroupActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/row-level-permission-predicate-group/workspace-migration-row-level-permission-predicate-group-actions-builder.service';
import { WorkspaceMigrationRowLevelPermissionPredicateActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/row-level-permission-predicate/workspace-migration-row-level-permission-predicate-actions-builder.service';
import { WorkspaceMigrationServerlessFunctionActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/serverless-function/workspace-migration-serverless-function-actions-builder.service';
import { WorkspaceMigrationSkillActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/skill/workspace-migration-skill-actions-builder.service';
import { WorkspaceMigrationViewFieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-field/workspace-migration-view-field-actions-builder.service';
import { WorkspaceMigrationViewFilterGroupActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-filter-group/workspace-migration-view-filter-group-actions-builder.service';
import { WorkspaceMigrationViewFilterActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-filter/workspace-migration-view-filter-actions-builder.service';
import { WorkspaceMigrationViewGroupActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-group/workspace-migration-view-group-actions-builder.service';
import { WorkspaceMigrationViewActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view/workspace-migration-view-actions-builder.service';
@Injectable()
export class WorkspaceMigrationBuildOrchestratorService {
constructor(
private readonly workspaceMigrationV2ObjectActionsBuilderService: WorkspaceMigrationV2ObjectActionsBuilderService,
private readonly workspaceMigrationV2IndexActionsBuilderService: WorkspaceMigrationV2IndexActionsBuilderService,
private readonly workspaceMigrationV2ViewActionsBuilderService: WorkspaceMigrationV2ViewActionsBuilderService,
private readonly workspaceMigrationV2ViewFieldActionsBuilderService: WorkspaceMigrationV2ViewFieldActionsBuilderService,
private readonly workspaceMigrationV2ViewFilterActionsBuilderService: WorkspaceMigrationV2ViewFilterActionsBuilderService,
private readonly workspaceMigrationV2ViewFilterGroupActionsBuilderService: WorkspaceMigrationV2ViewFilterGroupActionsBuilderService,
private readonly workspaceMigrationV2ViewGroupActionsBuilderService: WorkspaceMigrationV2ViewGroupActionsBuilderService,
private readonly workspaceMigrationV2ServerlessFunctionActionsBuilderService: WorkspaceMigrationV2ServerlessFunctionActionsBuilderService,
private readonly workspaceMigrationV2DatabaseEventTriggerActionsBuilderService: WorkspaceMigrationV2DatabaseEventTriggerActionsBuilderService,
private readonly workspaceMigrationV2CronTriggerActionsBuilderService: WorkspaceMigrationV2CronTriggerActionsBuilderService,
private readonly workspaceMigrationV2RouteTriggerActionsBuilderService: WorkspaceMigrationV2RouteTriggerActionsBuilderService,
private readonly workspaceMigrationV2RoleTargetActionsBuilderService: WorkspaceMigrationV2RoleTargetActionsBuilderService,
private readonly workspaceMigrationV2FieldActionsBuilderService: WorkspaceMigrationV2FieldActionsBuilderService,
private readonly workspaceMigrationV2RoleActionsBuilderService: WorkspaceMigrationV2RoleActionsBuilderService,
private readonly workspaceMigrationV2AgentActionsBuilderService: WorkspaceMigrationV2AgentActionsBuilderService,
private readonly workspaceMigrationV2SkillActionsBuilderService: WorkspaceMigrationV2SkillActionsBuilderService,
private readonly workspaceMigrationV2PageLayoutActionsBuilderService: WorkspaceMigrationV2PageLayoutActionsBuilderService,
private readonly workspaceMigrationV2PageLayoutWidgetActionsBuilderService: WorkspaceMigrationV2PageLayoutWidgetActionsBuilderService,
private readonly workspaceMigrationV2PageLayoutTabActionsBuilderService: WorkspaceMigrationV2PageLayoutTabActionsBuilderService,
private readonly workspaceMigrationV2RowLevelPermissionPredicateActionsBuilderService: WorkspaceMigrationV2RowLevelPermissionPredicateActionsBuilderService,
private readonly workspaceMigrationV2RowLevelPermissionPredicateGroupActionsBuilderService: WorkspaceMigrationV2RowLevelPermissionPredicateGroupActionsBuilderService,
private readonly workspaceMigrationObjectActionsBuilderService: WorkspaceMigrationObjectActionsBuilderService,
private readonly workspaceMigrationIndexActionsBuilderService: WorkspaceMigrationIndexActionsBuilderService,
private readonly workspaceMigrationViewActionsBuilderService: WorkspaceMigrationViewActionsBuilderService,
private readonly workspaceMigrationViewFieldActionsBuilderService: WorkspaceMigrationViewFieldActionsBuilderService,
private readonly workspaceMigrationViewFilterActionsBuilderService: WorkspaceMigrationViewFilterActionsBuilderService,
private readonly workspaceMigrationViewFilterGroupActionsBuilderService: WorkspaceMigrationViewFilterGroupActionsBuilderService,
private readonly workspaceMigrationViewGroupActionsBuilderService: WorkspaceMigrationViewGroupActionsBuilderService,
private readonly workspaceMigrationServerlessFunctionActionsBuilderService: WorkspaceMigrationServerlessFunctionActionsBuilderService,
private readonly workspaceMigrationDatabaseEventTriggerActionsBuilderService: WorkspaceMigrationDatabaseEventTriggerActionsBuilderService,
private readonly workspaceMigrationCronTriggerActionsBuilderService: WorkspaceMigrationCronTriggerActionsBuilderService,
private readonly workspaceMigrationRouteTriggerActionsBuilderService: WorkspaceMigrationRouteTriggerActionsBuilderService,
private readonly workspaceMigrationRoleTargetActionsBuilderService: WorkspaceMigrationRoleTargetActionsBuilderService,
private readonly workspaceMigrationFieldActionsBuilderService: WorkspaceMigrationFieldActionsBuilderService,
private readonly workspaceMigrationRoleActionsBuilderService: WorkspaceMigrationRoleActionsBuilderService,
private readonly workspaceMigrationAgentActionsBuilderService: WorkspaceMigrationAgentActionsBuilderService,
private readonly workspaceMigrationSkillActionsBuilderService: WorkspaceMigrationSkillActionsBuilderService,
private readonly workspaceMigrationPageLayoutActionsBuilderService: WorkspaceMigrationPageLayoutActionsBuilderService,
private readonly workspaceMigrationPageLayoutWidgetActionsBuilderService: WorkspaceMigrationPageLayoutWidgetActionsBuilderService,
private readonly workspaceMigrationPageLayoutTabActionsBuilderService: WorkspaceMigrationPageLayoutTabActionsBuilderService,
private readonly workspaceMigrationRowLevelPermissionPredicateActionsBuilderService: WorkspaceMigrationRowLevelPermissionPredicateActionsBuilderService,
private readonly workspaceMigrationRowLevelPermissionPredicateGroupActionsBuilderService: WorkspaceMigrationRowLevelPermissionPredicateGroupActionsBuilderService,
) {}
private setupOptimisticCache({
@@ -166,7 +166,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
flatObjectMetadataMaps;
const objectResult =
await this.workspaceMigrationV2ObjectActionsBuilderService.validateAndBuild(
await this.workspaceMigrationObjectActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
buildOptions,
@@ -220,7 +220,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
const { from: fromFlatFieldMetadataMaps, to: toFlatFieldMetadataMaps } =
flatFieldMetadataMaps;
const fieldResult =
await this.workspaceMigrationV2FieldActionsBuilderService.validateAndBuild(
await this.workspaceMigrationFieldActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatFieldMetadataMaps,
@@ -252,7 +252,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
if (isDefined(flatIndexMaps)) {
const { from: fromFlatIndexMaps, to: toFlatIndexMaps } = flatIndexMaps;
const indexResult =
await this.workspaceMigrationV2IndexActionsBuilderService.validateAndBuild(
await this.workspaceMigrationIndexActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatIndexMaps,
@@ -286,7 +286,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
if (isDefined(flatViewMaps)) {
const { from: fromFlatViewMaps, to: toFlatViewMaps } = flatViewMaps;
const viewResult =
await this.workspaceMigrationV2ViewActionsBuilderService.validateAndBuild(
await this.workspaceMigrationViewActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
dependencyOptimisticFlatEntityMaps: {
@@ -321,7 +321,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
const { from: fromFlatViewFieldMaps, to: toFlatViewFieldMaps } =
flatViewFieldMaps;
const viewFieldResult =
await this.workspaceMigrationV2ViewFieldActionsBuilderService.validateAndBuild(
await this.workspaceMigrationViewFieldActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatViewFieldMaps,
@@ -360,7 +360,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
} = flatViewFilterGroupMaps;
const viewFilterGroupResult =
await this.workspaceMigrationV2ViewFilterGroupActionsBuilderService.validateAndBuild(
await this.workspaceMigrationViewFilterGroupActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatViewFilterGroupMaps,
@@ -395,7 +395,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
const { from: fromFlatViewFilterMaps, to: toFlatViewFilterMaps } =
flatViewFilterMaps;
const viewFilterResult =
await this.workspaceMigrationV2ViewFilterActionsBuilderService.validateAndBuild(
await this.workspaceMigrationViewFilterActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatViewFilterMaps,
@@ -431,7 +431,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
const { from: fromFlatViewGroupMaps, to: toFlatViewGroupMaps } =
flatViewGroupMaps;
const viewGroupResult =
await this.workspaceMigrationV2ViewGroupActionsBuilderService.validateAndBuild(
await this.workspaceMigrationViewGroupActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatViewGroupMaps,
@@ -467,7 +467,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
to: toFlatRowLevelPermissionPredicateGroupMaps,
} = flatRowLevelPermissionPredicateGroupMaps;
const rowLevelPermissionPredicateGroupResult =
await this.workspaceMigrationV2RowLevelPermissionPredicateGroupActionsBuilderService.validateAndBuild(
await this.workspaceMigrationRowLevelPermissionPredicateGroupActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatRowLevelPermissionPredicateGroupMaps,
@@ -504,7 +504,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
to: toFlatRowLevelPermissionPredicateMaps,
} = flatRowLevelPermissionPredicateMaps;
const rowLevelPermissionPredicateResult =
await this.workspaceMigrationV2RowLevelPermissionPredicateActionsBuilderService.validateAndBuild(
await this.workspaceMigrationRowLevelPermissionPredicateActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatRowLevelPermissionPredicateMaps,
@@ -548,7 +548,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
} = flatServerlessFunctionMaps;
const serverlessFunctionResult =
await this.workspaceMigrationV2ServerlessFunctionActionsBuilderService.validateAndBuild(
await this.workspaceMigrationServerlessFunctionActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatServerlessFunctionMaps,
@@ -584,7 +584,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
} = flatDatabaseEventTriggerMaps;
const databaseEventTriggerResult =
await this.workspaceMigrationV2DatabaseEventTriggerActionsBuilderService.validateAndBuild(
await this.workspaceMigrationDatabaseEventTriggerActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatDatabaseEventTriggerMaps,
@@ -621,7 +621,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
flatCronTriggerMaps;
const cronTriggerResult =
await this.workspaceMigrationV2CronTriggerActionsBuilderService.validateAndBuild(
await this.workspaceMigrationCronTriggerActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatCronTriggerMaps,
@@ -655,7 +655,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
flatRouteTriggerMaps;
const routeTriggerResult =
await this.workspaceMigrationV2RouteTriggerActionsBuilderService.validateAndBuild(
await this.workspaceMigrationRouteTriggerActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatRouteTriggerMaps,
@@ -690,7 +690,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
const { from: fromFlatRoleMaps, to: toFlatRoleMaps } = flatRoleMaps;
const roleResult =
await this.workspaceMigrationV2RoleActionsBuilderService.validateAndBuild(
await this.workspaceMigrationRoleActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatRoleMaps,
@@ -721,7 +721,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
flatRoleTargetMaps;
const roleTargetResult =
await this.workspaceMigrationV2RoleTargetActionsBuilderService.validateAndBuild(
await this.workspaceMigrationRoleTargetActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatRoleTargetMaps,
@@ -754,7 +754,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
const { from: fromFlatAgentMaps, to: toFlatAgentMaps } = flatAgentMaps;
const agentResult =
await this.workspaceMigrationV2AgentActionsBuilderService.validateAndBuild(
await this.workspaceMigrationAgentActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatAgentMaps,
@@ -786,7 +786,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
const { from: fromFlatSkillMaps, to: toFlatSkillMaps } = flatSkillMaps;
const skillResult =
await this.workspaceMigrationV2SkillActionsBuilderService.validateAndBuild(
await this.workspaceMigrationSkillActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatSkillMaps,
@@ -817,7 +817,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
flatPageLayoutMaps;
const pageLayoutResult =
await this.workspaceMigrationV2PageLayoutActionsBuilderService.validateAndBuild(
await this.workspaceMigrationPageLayoutActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatPageLayoutMaps,
@@ -854,7 +854,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
flatPageLayoutTabMaps;
const pageLayoutTabResult =
await this.workspaceMigrationV2PageLayoutTabActionsBuilderService.validateAndBuild(
await this.workspaceMigrationPageLayoutTabActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatPageLayoutTabMaps,
@@ -892,7 +892,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
} = flatPageLayoutWidgetMaps;
const pageLayoutWidgetResult =
await this.workspaceMigrationV2PageLayoutWidgetActionsBuilderService.validateAndBuild(
await this.workspaceMigrationPageLayoutWidgetActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatPageLayoutWidgetMaps,
@@ -13,17 +13,17 @@ import { FlatEntityToCreateDeleteUpdate } from 'src/engine/metadata-modules/flat
import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
import { WORKSPACE_MIGRATION_ADDITIONAL_CACHE_DATA_MAPS_KEY } from 'src/engine/workspace-manager/workspace-migration-v2/constant/workspace-migration-additional-cache-data-maps-key.constant';
import { WorkspaceMigrationBuildOrchestratorService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-build-orchestrator.service';
import { WorkspaceMigrationBuilderAdditionalCacheDataMaps } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-builder-additional-cache-data-maps.type';
import { WorkspaceMigrationV2Exception } from 'src/engine/workspace-manager/workspace-migration.exception';
import { WORKSPACE_MIGRATION_ADDITIONAL_CACHE_DATA_MAPS_KEY } from 'src/engine/workspace-manager/workspace-migration/constant/workspace-migration-additional-cache-data-maps-key.constant';
import { WorkspaceMigrationBuildOrchestratorService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-build-orchestrator.service';
import { WorkspaceMigrationBuilderAdditionalCacheDataMaps } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-builder-additional-cache-data-maps.type';
import {
FromToAllFlatEntityMaps,
WorkspaceMigrationOrchestratorBuildArgs,
WorkspaceMigrationOrchestratorFailedResult,
} from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { InferDeletionFromMissingEntities } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/infer-deletion-from-missing-entities.type';
import { WorkspaceMigrationRunnerV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/services/workspace-migration-runner-v2.service';
import { WorkspaceMigrationV2Exception } from 'src/engine/workspace-manager/workspace-migration.exception';
} from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
import { InferDeletionFromMissingEntities } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/infer-deletion-from-missing-entities.type';
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/services/workspace-migration-runner.service';
type ValidateBuildAndRunWorkspaceMigrationFromMatriceArgs = {
workspaceId: string;
@@ -40,7 +40,7 @@ export class WorkspaceMigrationValidateBuildAndRunService {
);
constructor(
private readonly workspaceMigrationRunnerV2Service: WorkspaceMigrationRunnerV2Service,
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
private readonly workspaceMigrationBuildOrchestratorService: WorkspaceMigrationBuildOrchestratorService,
private readonly workspaceCacheService: WorkspaceCacheService,
) {}
@@ -196,7 +196,7 @@ export class WorkspaceMigrationValidateBuildAndRunService {
return;
}
await this.workspaceMigrationRunnerV2Service
await this.workspaceMigrationRunnerService
.run(validateAndBuildResult.workspaceMigration)
.catch((error) => {
this.logger.error(error);
@@ -2,4 +2,4 @@
* Wrapper type used to circumvent ESM modules circular dependency issue
* caused by reflection metadata saving the type of the property.
*/
export type Relation<T> = T;
export type EntityRelation<T> = T;
@@ -1,6 +1,6 @@
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
export type AggregateOrchestratorActionsReportArgs = {
orchestratorActionsReport: OrchestratorActionsReport;
@@ -1,5 +1,5 @@
import { type AdditionalCacheDataMaps } from 'src/engine/workspace-cache/types/workspace-cache-key.type';
import { type WORKSPACE_MIGRATION_ADDITIONAL_CACHE_DATA_MAPS_KEY } from 'src/engine/workspace-manager/workspace-migration-v2/constant/workspace-migration-additional-cache-data-maps-key.constant';
import { type WORKSPACE_MIGRATION_ADDITIONAL_CACHE_DATA_MAPS_KEY } from 'src/engine/workspace-manager/workspace-migration/constant/workspace-migration-additional-cache-data-maps-key.constant';
export type WorkspaceMigrationBuilderAdditionalCacheDataMaps = Pick<
AdditionalCacheDataMaps,
@@ -3,13 +3,13 @@ import { type FromTo } from 'twenty-shared/types';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import {
type WorkspaceMigrationActionType,
type MetadataWorkspaceMigrationActionsRecord,
type WorkspaceMigrationActionType,
} from 'src/engine/metadata-modules/flat-entity/types/metadata-workspace-migration-action.type';
import { type WorkspaceMigrationBuilderAdditionalCacheDataMaps } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-builder-additional-cache-data-maps.type';
import { type FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/types/failed-flat-entity-validation.type';
import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-builder-options.type';
import { type WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2';
import { type WorkspaceMigrationBuilderAdditionalCacheDataMaps } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-builder-additional-cache-data-maps.type';
import { type FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/types/failed-flat-entity-validation.type';
import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration-builder-options.type';
import { type WorkspaceMigration } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration';
export type FromToAllFlatEntityMaps = {
[P in keyof AllFlatEntityMaps]?: FromTo<AllFlatEntityMaps[P]>;
@@ -41,5 +41,5 @@ export type WorkspaceMigrationOrchestratorFailedResult = {
export type WorkspaceMigrationOrchestratorSuccessfulResult = {
status: 'success';
workspaceMigration: WorkspaceMigrationV2;
workspaceMigration: WorkspaceMigration;
};
@@ -6,11 +6,11 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock';
import { createEmptyOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/constant/empty-orchestrator-actions-report.constant';
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { aggregateOrchestratorActionsReportCreateObjectAndCreateFieldActions } from 'src/engine/workspace-manager/workspace-migration-v2/utils/aggregate-orchestrator-actions-report-create-object-and-create-field-actions.util';
import { type CreateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/types/workspace-migration-field-action-v2';
import { type CreateObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/types/workspace-migration-object-action-v2';
import { createEmptyOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration/constant/empty-orchestrator-actions-report.constant';
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
import { aggregateOrchestratorActionsReportCreateObjectAndCreateFieldActions } from 'src/engine/workspace-manager/workspace-migration/utils/aggregate-orchestrator-actions-report-create-object-and-create-field-actions.util';
import { type CreateFieldAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/field/types/workspace-migration-field-action';
import { type CreateObjectAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/object/types/workspace-migration-object-action';
type CreateAggregationTestCase = EachTestingContext<{
input: OrchestratorActionsReport;
@@ -3,11 +3,11 @@ import {
type EachTestingContext,
} from 'twenty-shared/testing';
import { createEmptyOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/constant/empty-orchestrator-actions-report.constant';
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { aggregateOrchestratorActionsReportDeleteObjectAndDeleteFieldActions } from 'src/engine/workspace-manager/workspace-migration-v2/utils/aggregate-orchestrator-actions-report-delete-object-and-delete-field.util';
import { type DeleteFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/types/workspace-migration-field-action-v2';
import { type DeleteObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/types/workspace-migration-object-action-v2';
import { createEmptyOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration/constant/empty-orchestrator-actions-report.constant';
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
import { aggregateOrchestratorActionsReportDeleteObjectAndDeleteFieldActions } from 'src/engine/workspace-manager/workspace-migration/utils/aggregate-orchestrator-actions-report-delete-object-and-delete-field.util';
import { type DeleteFieldAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/field/types/workspace-migration-field-action';
import { type DeleteObjectAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/object/types/workspace-migration-object-action';
type DeleteAggregationTestCase = EachTestingContext<{
input: OrchestratorActionsReport;
@@ -6,9 +6,9 @@ import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-module
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { SEARCH_VECTOR_FIELD } from 'src/engine/metadata-modules/search-field-metadata/constants/search-vector-field.constants';
import { createEmptyOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/constant/empty-orchestrator-actions-report.constant';
import { aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldActions } from 'src/engine/workspace-manager/workspace-migration-v2/utils/aggregate-orchestrator-actions-report-deprioritize-search-vector-update-field-actions.util';
import { type UpdateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/types/workspace-migration-field-action-v2';
import { createEmptyOrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration/constant/empty-orchestrator-actions-report.constant';
import { aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldActions } from 'src/engine/workspace-manager/workspace-migration/utils/aggregate-orchestrator-actions-report-deprioritize-search-vector-update-field-actions.util';
import { type UpdateFieldAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/field/types/workspace-migration-field-action';
describe('aggregateOrchestratorActionsReportDeprioritizeSearchVectorUpdateFieldActions', () => {
it('should move searchVector update actions to the end of the update list', () => {
@@ -6,8 +6,8 @@ import { FieldMetadataType, type FromTo } from 'twenty-shared/types';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { flatEntityDeletedCreatedUpdatedMatrixDispatcher } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-entity-deleted-created-updated-matrix-dispatcher.util';
import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-builder-options.type';
import { flatEntityDeletedCreatedUpdatedMatrixDispatcher } from 'src/engine/workspace-manager/workspace-migration/utils/flat-entity-deleted-created-updated-matrix-dispatcher.util';
import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration-builder-options.type';
type TestContext = FromTo<MetadataFlatEntity<'fieldMetadata'>[]> & {
metadataName: 'fieldMetadata';
@@ -5,7 +5,7 @@ import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity
import {
type CircularDependencyValidationResult,
validateFlatEntityCircularDependency,
} from 'src/engine/workspace-manager/workspace-migration-v2/utils/validate-flat-entity-circular-dependency.util';
} from 'src/engine/workspace-manager/workspace-migration/utils/validate-flat-entity-circular-dependency.util';
type TestFlatEntity = SyncableFlatEntity & {
parentId: string | null;
@@ -2,10 +2,10 @@ import { isDefined } from 'twenty-shared/utils';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { type AggregateOrchestratorActionsReportArgs } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-aggregate-orchestrator-actions-report-args.type';
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration-v2/types/workspace-migration-orchestrator.type';
import { type CreateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/types/workspace-migration-field-action-v2';
import { type CreateObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/types/workspace-migration-object-action-v2';
import { type AggregateOrchestratorActionsReportArgs } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-aggregate-orchestrator-actions-report-args.type';
import { type OrchestratorActionsReport } from 'src/engine/workspace-manager/workspace-migration/types/workspace-migration-orchestrator.type';
import { type CreateFieldAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/field/types/workspace-migration-field-action';
import { type CreateObjectAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/object/types/workspace-migration-object-action';
type AggregatedActions = {
createdFieldActionByObjectMetadataId: Record<string, CreateFieldAction>;

Some files were not shown because too many files have changed in this diff Show More