Combine and clean upgrade commands for record page layouts (#19004)
- Remove the label identifier field for all standard objects as it's a first-class citizen that is displayed specifically in the app; it doesn't make a lot of sense to display it in the Fields widgets - Disable logic that made the label identifier required and in first position - Add all fields for all standard objects in record page layout view fields - Do not include position and ts vector fields in custom objects > [!IMPORTANT] > The command will create Field widgets for all relations. It is consistent to the way the frontend dynamically generates them as of today. We will have to decide which relations we pin as individual Field widgets before the release. (This will likely land in this command or in another one.)
This commit is contained in:
committed by
GitHub
parent
31718d163c
commit
da1b1f1cbc
-431
@@ -1,431 +0,0 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Command } from 'nest-commander';
|
||||
import {
|
||||
CoreObjectNameSingular,
|
||||
FieldMetadataType,
|
||||
PageLayoutTabLayoutMode,
|
||||
} from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { Repository } from 'typeorm';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
|
||||
import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
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 FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
|
||||
import { FieldDisplayMode } from 'src/engine/metadata-modules/page-layout-widget/enums/field-display-mode.enum';
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
import { WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum';
|
||||
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import {
|
||||
GRID_POSITIONS,
|
||||
VERTICAL_LIST_LAYOUT_POSITIONS,
|
||||
} from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout-tabs.template';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
const HOME_TAB_POSITION = 10;
|
||||
|
||||
const isActivityTargetField = (
|
||||
fieldName: string,
|
||||
objectNameSingular: string,
|
||||
): boolean =>
|
||||
(objectNameSingular === CoreObjectNameSingular.Note &&
|
||||
fieldName === 'noteTargets') ||
|
||||
(objectNameSingular === CoreObjectNameSingular.Task &&
|
||||
fieldName === 'taskTargets');
|
||||
|
||||
const isJunctionRelationField = (field: FlatFieldMetadata): boolean => {
|
||||
const settings = field.settings as
|
||||
| { junctionTargetFieldId?: string }
|
||||
| undefined;
|
||||
|
||||
return (
|
||||
isDefined(settings?.junctionTargetFieldId) &&
|
||||
typeof settings?.junctionTargetFieldId === 'string' &&
|
||||
settings.junctionTargetFieldId.length > 0
|
||||
);
|
||||
};
|
||||
|
||||
const isRelationTargetAvailable = (
|
||||
targetObject: FlatObjectMetadata | undefined,
|
||||
): boolean => {
|
||||
if (!isDefined(targetObject)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (targetObject.isRemote) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
targetObject.isSystem &&
|
||||
targetObject.nameSingular !== CoreObjectNameSingular.WorkspaceMember
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@Command({
|
||||
name: 'upgrade:1-20:backfill-field-widgets',
|
||||
description:
|
||||
'Backfill FIELD widgets for relation fields in existing page layouts',
|
||||
})
|
||||
export class BackfillFieldWidgetsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(WorkspaceEntity)
|
||||
protected readonly workspaceRepository: Repository<WorkspaceEntity>,
|
||||
protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager,
|
||||
protected readonly dataSourceService: DataSourceService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
) {
|
||||
super(workspaceRepository, twentyORMGlobalManager, dataSourceService);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
const isDryRun = options.dryRun ?? false;
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Starting backfill of FIELD widgets for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const { twentyStandardFlatApplication, workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
const {
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatPageLayoutMaps,
|
||||
flatPageLayoutTabMaps,
|
||||
flatPageLayoutWidgetMaps,
|
||||
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
'flatPageLayoutMaps',
|
||||
'flatPageLayoutTabMaps',
|
||||
'flatPageLayoutWidgetMaps',
|
||||
]);
|
||||
|
||||
// Build a set of fieldMetadataIds that already have a FIELD widget
|
||||
const existingFieldWidgetFieldIds = new Set<string>();
|
||||
|
||||
for (const widget of Object.values(
|
||||
flatPageLayoutWidgetMaps.byUniversalIdentifier,
|
||||
)) {
|
||||
if (
|
||||
isDefined(widget) &&
|
||||
widget.configuration?.configurationType ===
|
||||
WidgetConfigurationType.FIELD &&
|
||||
isDefined(widget.configuration.fieldMetadataId)
|
||||
) {
|
||||
existingFieldWidgetFieldIds.add(widget.configuration.fieldMetadataId);
|
||||
}
|
||||
}
|
||||
|
||||
// Build object ID → objectMetadata map
|
||||
const objectById = new Map<string, FlatObjectMetadata>();
|
||||
|
||||
for (const obj of Object.values(
|
||||
flatObjectMetadataMaps.byUniversalIdentifier,
|
||||
)) {
|
||||
if (isDefined(obj)) {
|
||||
objectById.set(obj.id, obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Build object ID → RECORD_PAGE layout map
|
||||
const recordPageLayoutByObjectId = new Map<
|
||||
string,
|
||||
{ id: string; universalIdentifier: string }
|
||||
>();
|
||||
|
||||
for (const layout of Object.values(
|
||||
flatPageLayoutMaps.byUniversalIdentifier,
|
||||
)) {
|
||||
if (
|
||||
isDefined(layout) &&
|
||||
layout.type === PageLayoutType.RECORD_PAGE &&
|
||||
isDefined(layout.objectMetadataId)
|
||||
) {
|
||||
recordPageLayoutByObjectId.set(layout.objectMetadataId, {
|
||||
id: layout.id,
|
||||
universalIdentifier: layout.universalIdentifier,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Build pageLayoutId → home tab map
|
||||
const homeTabByPageLayoutId = new Map<
|
||||
string,
|
||||
{
|
||||
id: string;
|
||||
universalIdentifier: string;
|
||||
widgetCount: number;
|
||||
}
|
||||
>();
|
||||
|
||||
for (const tab of Object.values(
|
||||
flatPageLayoutTabMaps.byUniversalIdentifier,
|
||||
)) {
|
||||
if (
|
||||
isDefined(tab) &&
|
||||
tab.position === HOME_TAB_POSITION &&
|
||||
tab.layoutMode === PageLayoutTabLayoutMode.VERTICAL_LIST
|
||||
) {
|
||||
homeTabByPageLayoutId.set(tab.pageLayoutId, {
|
||||
id: tab.id,
|
||||
universalIdentifier: tab.universalIdentifier,
|
||||
widgetCount: tab.widgetIds?.length ?? 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Group fields by objectMetadataId
|
||||
const fieldsByObjectId = new Map<string, FlatFieldMetadata[]>();
|
||||
|
||||
// Map morphId → all field IDs sharing that morphId (for dedup)
|
||||
const fieldIdsByMorphId = new Map<string, string[]>();
|
||||
|
||||
for (const field of Object.values(
|
||||
flatFieldMetadataMaps.byUniversalIdentifier,
|
||||
)) {
|
||||
if (!isDefined(field) || !isDefined(field.objectMetadataId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const list = fieldsByObjectId.get(field.objectMetadataId) ?? [];
|
||||
|
||||
list.push(field);
|
||||
fieldsByObjectId.set(field.objectMetadataId, list);
|
||||
|
||||
if (
|
||||
field.type === FieldMetadataType.MORPH_RELATION &&
|
||||
isDefined(field.morphId)
|
||||
) {
|
||||
const morphFieldIds = fieldIdsByMorphId.get(field.morphId) ?? [];
|
||||
|
||||
morphFieldIds.push(field.id);
|
||||
fieldIdsByMorphId.set(field.morphId, morphFieldIds);
|
||||
}
|
||||
}
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
const standardWidgetsToCreate: FlatPageLayoutWidget[] = [];
|
||||
const customWidgetsToCreate: FlatPageLayoutWidget[] = [];
|
||||
const processedMorphIds = new Set<string>();
|
||||
|
||||
for (const object of objectById.values()) {
|
||||
const pageLayout = recordPageLayoutByObjectId.get(object.id);
|
||||
|
||||
if (!isDefined(pageLayout)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const homeTab = homeTabByPageLayoutId.get(pageLayout.id);
|
||||
|
||||
if (!isDefined(homeTab)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const flatApplication: FlatApplication = object.isCustom
|
||||
? workspaceCustomFlatApplication
|
||||
: twentyStandardFlatApplication;
|
||||
|
||||
const targetList: FlatPageLayoutWidget[] = object.isCustom
|
||||
? customWidgetsToCreate
|
||||
: standardWidgetsToCreate;
|
||||
|
||||
const fields = fieldsByObjectId.get(object.id) ?? [];
|
||||
let nextWidgetIndex = homeTab.widgetCount;
|
||||
|
||||
for (const field of fields) {
|
||||
if (
|
||||
field.type !== FieldMetadataType.RELATION &&
|
||||
field.type !== FieldMetadataType.MORPH_RELATION
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isActivityTargetField(field.name, object.nameSingular)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isJunctionRelationField(field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (field.type === FieldMetadataType.RELATION) {
|
||||
const targetObject = isDefined(field.relationTargetObjectMetadataId)
|
||||
? objectById.get(field.relationTargetObjectMetadataId)
|
||||
: undefined;
|
||||
|
||||
if (!isRelationTargetAvailable(targetObject)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// For morph relations, skip if any sibling field (same morphId)
|
||||
// already has a widget or was already processed in this run
|
||||
if (
|
||||
field.type === FieldMetadataType.MORPH_RELATION &&
|
||||
isDefined(field.morphId)
|
||||
) {
|
||||
if (processedMorphIds.has(field.morphId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const siblingFieldIds = fieldIdsByMorphId.get(field.morphId) ?? [];
|
||||
const alreadyHasWidget = siblingFieldIds.some((id) =>
|
||||
existingFieldWidgetFieldIds.has(id),
|
||||
);
|
||||
|
||||
if (alreadyHasWidget) {
|
||||
continue;
|
||||
}
|
||||
|
||||
processedMorphIds.add(field.morphId);
|
||||
}
|
||||
|
||||
if (existingFieldWidgetFieldIds.has(field.id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const widget: FlatPageLayoutWidget = {
|
||||
id: v4(),
|
||||
universalIdentifier: v4(),
|
||||
applicationId: flatApplication.id,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
workspaceId,
|
||||
pageLayoutTabId: homeTab.id,
|
||||
pageLayoutTabUniversalIdentifier: homeTab.universalIdentifier,
|
||||
title: field.label,
|
||||
type: WidgetType.FIELD,
|
||||
gridPosition: { ...GRID_POSITIONS.FULL_WIDTH },
|
||||
position: {
|
||||
...VERTICAL_LIST_LAYOUT_POSITIONS.SECOND,
|
||||
index: nextWidgetIndex,
|
||||
},
|
||||
configuration: {
|
||||
configurationType: WidgetConfigurationType.FIELD,
|
||||
fieldMetadataId: field.id,
|
||||
fieldDisplayMode: FieldDisplayMode.CARD,
|
||||
},
|
||||
universalConfiguration: {
|
||||
configurationType: WidgetConfigurationType.FIELD,
|
||||
fieldMetadataId: field.universalIdentifier,
|
||||
fieldDisplayMode: FieldDisplayMode.CARD,
|
||||
},
|
||||
objectMetadataId: object.id,
|
||||
objectMetadataUniversalIdentifier: object.universalIdentifier,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
conditionalDisplay: null,
|
||||
overrides: null,
|
||||
};
|
||||
|
||||
targetList.push(widget);
|
||||
existingFieldWidgetFieldIds.add(field.id);
|
||||
nextWidgetIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
const totalWidgets =
|
||||
standardWidgetsToCreate.length + customWidgetsToCreate.length;
|
||||
|
||||
if (totalWidgets === 0) {
|
||||
this.logger.log(
|
||||
`All FIELD widgets already exist for workspace ${workspaceId}, skipping`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Found ${totalWidgets} FIELD widget(s) to create for workspace ${workspaceId} (${standardWidgetsToCreate.length} standard, ${customWidgetsToCreate.length} custom)`,
|
||||
);
|
||||
|
||||
if (isDryRun) {
|
||||
this.logger.log(
|
||||
`[DRY RUN] Would create ${totalWidgets} FIELD widget(s) for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (standardWidgetsToCreate.length > 0) {
|
||||
const result =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: standardWidgetsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (result.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to create standard FIELD widgets:\n${JSON.stringify(result, null, 2)}`,
|
||||
);
|
||||
throw new Error(
|
||||
`Failed to create standard FIELD widgets for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (customWidgetsToCreate.length > 0) {
|
||||
const result =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: customWidgetsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (result.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to create custom FIELD widgets:\n${JSON.stringify(result, null, 2)}`,
|
||||
);
|
||||
throw new Error(
|
||||
`Failed to create custom FIELD widgets for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Successfully created ${totalWidgets} FIELD widget(s) for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
+868
@@ -0,0 +1,868 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Command } from 'nest-commander';
|
||||
import {
|
||||
CoreObjectNameSingular,
|
||||
FeatureFlagKey,
|
||||
FieldMetadataType,
|
||||
PageLayoutTabLayoutMode,
|
||||
ViewType,
|
||||
} from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { Repository } from 'typeorm';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
|
||||
import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
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 FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type';
|
||||
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
|
||||
import { type FlatPageLayout } from 'src/engine/metadata-modules/flat-page-layout/types/flat-page-layout.type';
|
||||
import { computeFlatDefaultRecordPageLayoutToCreate } from 'src/engine/metadata-modules/object-metadata/utils/compute-flat-default-record-page-layout-to-create.util';
|
||||
import { computeFlatRecordPageFieldsViewToCreate } from 'src/engine/metadata-modules/object-metadata/utils/compute-flat-record-page-fields-view-to-create.util';
|
||||
import { computeFlatViewFieldsToCreate } from 'src/engine/metadata-modules/object-metadata/utils/compute-flat-view-fields-to-create.util';
|
||||
import { FieldDisplayMode } from 'src/engine/metadata-modules/page-layout-widget/enums/field-display-mode.enum';
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
import { WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum';
|
||||
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import {
|
||||
GRID_POSITIONS,
|
||||
VERTICAL_LIST_LAYOUT_POSITIONS,
|
||||
} from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout-tabs.template';
|
||||
import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
import { type UniversalFlatViewField } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-field.type';
|
||||
import { type UniversalFlatView } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view.type';
|
||||
|
||||
const HOME_TAB_POSITION = 10;
|
||||
|
||||
const isActivityTargetField = (
|
||||
fieldName: string,
|
||||
objectNameSingular: string,
|
||||
): boolean =>
|
||||
(objectNameSingular === CoreObjectNameSingular.Note &&
|
||||
fieldName === 'noteTargets') ||
|
||||
(objectNameSingular === CoreObjectNameSingular.Task &&
|
||||
fieldName === 'taskTargets');
|
||||
|
||||
const isJunctionRelationField = (field: FlatFieldMetadata): boolean => {
|
||||
const settings = field.settings as
|
||||
| { junctionTargetFieldId?: string }
|
||||
| undefined;
|
||||
|
||||
return (
|
||||
isDefined(settings?.junctionTargetFieldId) &&
|
||||
typeof settings?.junctionTargetFieldId === 'string' &&
|
||||
settings.junctionTargetFieldId.length > 0
|
||||
);
|
||||
};
|
||||
|
||||
const isRelationTargetAvailable = (
|
||||
targetObject: FlatObjectMetadata | undefined,
|
||||
): boolean => {
|
||||
if (!isDefined(targetObject)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (targetObject.isRemote) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
targetObject.isSystem &&
|
||||
targetObject.nameSingular !== CoreObjectNameSingular.WorkspaceMember
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@Command({
|
||||
name: 'upgrade:1-20:backfill-page-layouts-and-fields-widget-view-fields',
|
||||
description:
|
||||
'Backfill RECORD_PAGE page layouts, sync FIELDS_WIDGET view fields, create FIELD widgets, and enable IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
|
||||
})
|
||||
export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(WorkspaceEntity)
|
||||
protected readonly workspaceRepository: Repository<WorkspaceEntity>,
|
||||
protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager,
|
||||
protected readonly dataSourceService: DataSourceService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
) {
|
||||
super(workspaceRepository, twentyORMGlobalManager, dataSourceService);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
const isDryRun = options.dryRun ?? false;
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Starting backfill of page layouts and field widgets for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const isAlreadyEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
if (isAlreadyEnabled) {
|
||||
this.logger.log(
|
||||
`IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED already enabled for workspace ${workspaceId}, skipping`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDryRun) {
|
||||
this.logger.log(
|
||||
`[DRY RUN] Would create page layouts, sync view fields, create FIELD widgets and enable IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const { twentyStandardFlatApplication, workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
await this.backfillStandardPageLayoutsAndSyncViews({
|
||||
workspaceId,
|
||||
twentyStandardFlatApplication,
|
||||
});
|
||||
|
||||
await this.backfillCustomObjectPageLayouts({
|
||||
workspaceId,
|
||||
workspaceCustomFlatApplication,
|
||||
});
|
||||
|
||||
await this.backfillFieldWidgets({
|
||||
workspaceId,
|
||||
twentyStandardFlatApplication,
|
||||
workspaceCustomFlatApplication,
|
||||
});
|
||||
|
||||
await this.featureFlagService.enableFeatureFlags(
|
||||
[FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED],
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`Successfully backfilled page layouts and field widgets for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
private async backfillStandardPageLayoutsAndSyncViews({
|
||||
workspaceId,
|
||||
twentyStandardFlatApplication,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
twentyStandardFlatApplication: FlatApplication;
|
||||
}): Promise<void> {
|
||||
const { allFlatEntityMaps: standardAllFlatEntityMaps } =
|
||||
computeTwentyStandardApplicationAllFlatEntityMaps({
|
||||
shouldIncludeRecordPageLayouts: true,
|
||||
now: new Date().toISOString(),
|
||||
workspaceId,
|
||||
twentyStandardApplicationId: twentyStandardFlatApplication.id,
|
||||
});
|
||||
|
||||
const recordPageLayoutUniversalIdentifiers = new Set<string>();
|
||||
|
||||
const recordPageLayoutsFromStandard = Object.values(
|
||||
standardAllFlatEntityMaps.flatPageLayoutMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((pageLayout) => {
|
||||
if (pageLayout.type !== PageLayoutType.RECORD_PAGE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
recordPageLayoutUniversalIdentifiers.add(
|
||||
pageLayout.universalIdentifier,
|
||||
);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
const tabUniversalIdentifiers = new Set<string>();
|
||||
|
||||
const tabsFromStandard = Object.values(
|
||||
standardAllFlatEntityMaps.flatPageLayoutTabMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((tab) => {
|
||||
if (
|
||||
!recordPageLayoutUniversalIdentifiers.has(
|
||||
tab.pageLayoutUniversalIdentifier,
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tabUniversalIdentifiers.add(tab.universalIdentifier);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
const widgetsFromStandard = Object.values(
|
||||
standardAllFlatEntityMaps.flatPageLayoutWidgetMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((widget) =>
|
||||
tabUniversalIdentifiers.has(widget.pageLayoutTabUniversalIdentifier),
|
||||
);
|
||||
|
||||
const {
|
||||
flatPageLayoutMaps: existingFlatPageLayoutMaps,
|
||||
flatPageLayoutTabMaps: existingFlatPageLayoutTabMaps,
|
||||
flatPageLayoutWidgetMaps: existingFlatPageLayoutWidgetMaps,
|
||||
flatViewMaps: existingFlatViewMaps,
|
||||
flatViewFieldMaps: existingFlatViewFieldMaps,
|
||||
flatViewFieldGroupMaps: existingFlatViewFieldGroupMaps,
|
||||
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatPageLayoutMaps',
|
||||
'flatPageLayoutTabMaps',
|
||||
'flatPageLayoutWidgetMaps',
|
||||
'flatViewMaps',
|
||||
'flatViewFieldMaps',
|
||||
'flatViewFieldGroupMaps',
|
||||
]);
|
||||
|
||||
// Filter out page layouts, tabs, and widgets that already exist in the workspace
|
||||
const pageLayoutsToCreate = recordPageLayoutsFromStandard.filter(
|
||||
(pageLayout) =>
|
||||
!isDefined(
|
||||
existingFlatPageLayoutMaps.byUniversalIdentifier[
|
||||
pageLayout.universalIdentifier
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
const pageLayoutTabsToCreate = tabsFromStandard.filter(
|
||||
(tab) =>
|
||||
!isDefined(
|
||||
existingFlatPageLayoutTabMaps.byUniversalIdentifier[
|
||||
tab.universalIdentifier
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
const pageLayoutWidgetsToCreate = widgetsFromStandard.filter(
|
||||
(widget) =>
|
||||
!isDefined(
|
||||
existingFlatPageLayoutWidgetMaps.byUniversalIdentifier[
|
||||
widget.universalIdentifier
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
// Collect all standard FIELDS_WIDGET view universal identifiers
|
||||
// This includes both new views to create AND existing views (created by 1-19)
|
||||
const allStandardFieldsWidgetViewUniversalIds = new Set<string>();
|
||||
|
||||
const viewsToCreate = Object.values(
|
||||
standardAllFlatEntityMaps.flatViewMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((view) => {
|
||||
if (view.type !== ViewType.FIELDS_WIDGET) {
|
||||
return false;
|
||||
}
|
||||
|
||||
allStandardFieldsWidgetViewUniversalIds.add(view.universalIdentifier);
|
||||
|
||||
if (
|
||||
isDefined(
|
||||
existingFlatViewMaps.byUniversalIdentifier[
|
||||
view.universalIdentifier
|
||||
],
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Delete all existing viewFields for standard FIELDS_WIDGET views and recreate from current standard.
|
||||
// This ensures positions, visibility, and groups match the current standard definition.
|
||||
const viewFieldsToDelete = Object.values(
|
||||
existingFlatViewFieldMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((viewField) =>
|
||||
allStandardFieldsWidgetViewUniversalIds.has(
|
||||
viewField.viewUniversalIdentifier,
|
||||
),
|
||||
);
|
||||
|
||||
const viewFieldsToCreate = Object.values(
|
||||
standardAllFlatEntityMaps.flatViewFieldMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((viewField) =>
|
||||
allStandardFieldsWidgetViewUniversalIds.has(
|
||||
viewField.viewUniversalIdentifier,
|
||||
),
|
||||
);
|
||||
|
||||
// Same delete-and-recreate approach for viewFieldGroups
|
||||
const viewFieldGroupsToDelete = Object.values(
|
||||
existingFlatViewFieldGroupMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((viewFieldGroup) =>
|
||||
allStandardFieldsWidgetViewUniversalIds.has(
|
||||
viewFieldGroup.viewUniversalIdentifier,
|
||||
),
|
||||
);
|
||||
|
||||
const viewFieldGroupsToCreate = Object.values(
|
||||
standardAllFlatEntityMaps.flatViewFieldGroupMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((viewFieldGroup) =>
|
||||
allStandardFieldsWidgetViewUniversalIds.has(
|
||||
viewFieldGroup.viewUniversalIdentifier,
|
||||
),
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`Creating ${pageLayoutsToCreate.length} page layouts, ${viewsToCreate.length} views, deleting ${viewFieldsToDelete.length} and creating ${viewFieldsToCreate.length} view fields, deleting ${viewFieldGroupsToDelete.length} and creating ${viewFieldGroupsToCreate.length} view field groups for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayout: {
|
||||
flatEntityToCreate: pageLayoutsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutTab: {
|
||||
flatEntityToCreate: pageLayoutTabsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: pageLayoutWidgetsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
view: {
|
||||
flatEntityToCreate: viewsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: viewFieldsToCreate,
|
||||
flatEntityToDelete: viewFieldsToDelete,
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewFieldGroup: {
|
||||
flatEntityToCreate: viewFieldGroupsToCreate,
|
||||
flatEntityToDelete: viewFieldGroupsToDelete,
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (validateAndBuildResult.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to create standard page layouts and sync view fields:\n${JSON.stringify(validateAndBuildResult, null, 2)}`,
|
||||
);
|
||||
throw new Error(
|
||||
`Failed to create standard page layouts and sync view fields for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async backfillCustomObjectPageLayouts({
|
||||
workspaceId,
|
||||
workspaceCustomFlatApplication,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
workspaceCustomFlatApplication: FlatApplication;
|
||||
}): Promise<void> {
|
||||
const {
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatPageLayoutMaps,
|
||||
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
'flatPageLayoutMaps',
|
||||
]);
|
||||
|
||||
const existingPageLayouts = Object.values(
|
||||
flatPageLayoutMaps.byUniversalIdentifier,
|
||||
).filter(isDefined);
|
||||
|
||||
const objectIdsWithRecordPageLayout = new Set(
|
||||
existingPageLayouts
|
||||
.filter(
|
||||
(layout: FlatPageLayout) =>
|
||||
layout.type === PageLayoutType.RECORD_PAGE &&
|
||||
isDefined(layout.objectMetadataId),
|
||||
)
|
||||
.map((layout: FlatPageLayout) => layout.objectMetadataId),
|
||||
);
|
||||
|
||||
const customObjectsWithoutPageLayout = Object.values(
|
||||
flatObjectMetadataMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter(
|
||||
(objectMetadata) =>
|
||||
objectMetadata.isCustom &&
|
||||
!objectMetadata.isRemote &&
|
||||
!objectIdsWithRecordPageLayout.has(objectMetadata.id),
|
||||
);
|
||||
|
||||
if (customObjectsWithoutPageLayout.length === 0) {
|
||||
this.logger.log(
|
||||
`No custom objects without page layouts found for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Creating page layouts for ${customObjectsWithoutPageLayout.length} custom object(s) in workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const allCustomPageLayoutsToCreate: FlatPageLayout[] = [];
|
||||
const allCustomPageLayoutTabsToCreate: FlatPageLayoutTab[] = [];
|
||||
const allCustomPageLayoutWidgetsToCreate: FlatPageLayoutWidget[] = [];
|
||||
const allCustomViewsToCreate: (UniversalFlatView & { id: string })[] = [];
|
||||
const allCustomViewFieldsToCreate: UniversalFlatViewField[] = [];
|
||||
|
||||
for (const customObject of customObjectsWithoutPageLayout) {
|
||||
const flatRecordPageFieldsView = computeFlatRecordPageFieldsViewToCreate({
|
||||
objectMetadata: customObject,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
});
|
||||
|
||||
const objectFieldMetadatas = Object.values(
|
||||
flatFieldMetadataMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((field) => field.objectMetadataId === customObject.id);
|
||||
|
||||
const viewFields = computeFlatViewFieldsToCreate({
|
||||
objectFlatFieldMetadatas: objectFieldMetadatas,
|
||||
viewUniversalIdentifier: flatRecordPageFieldsView.universalIdentifier,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
customObject.labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
excludeLabelIdentifier: true,
|
||||
});
|
||||
|
||||
const { pageLayouts, pageLayoutTabs, pageLayoutWidgets } =
|
||||
computeFlatDefaultRecordPageLayoutToCreate({
|
||||
objectMetadata: customObject,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
recordPageFieldsView: flatRecordPageFieldsView,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
allCustomPageLayoutsToCreate.push(...pageLayouts);
|
||||
allCustomPageLayoutTabsToCreate.push(...pageLayoutTabs);
|
||||
allCustomPageLayoutWidgetsToCreate.push(...pageLayoutWidgets);
|
||||
allCustomViewsToCreate.push(flatRecordPageFieldsView);
|
||||
allCustomViewFieldsToCreate.push(...viewFields);
|
||||
}
|
||||
|
||||
const customValidateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayout: {
|
||||
flatEntityToCreate: allCustomPageLayoutsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutTab: {
|
||||
flatEntityToCreate: allCustomPageLayoutTabsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: allCustomPageLayoutWidgetsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
view: {
|
||||
flatEntityToCreate: allCustomViewsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: allCustomViewFieldsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (customValidateAndBuildResult.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to create custom object page layouts:\n${JSON.stringify(customValidateAndBuildResult, null, 2)}`,
|
||||
);
|
||||
throw new Error(
|
||||
`Failed to create custom object page layouts for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Successfully created page layouts for ${customObjectsWithoutPageLayout.length} custom object(s) in workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
private async backfillFieldWidgets({
|
||||
workspaceId,
|
||||
twentyStandardFlatApplication,
|
||||
workspaceCustomFlatApplication,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
twentyStandardFlatApplication: FlatApplication;
|
||||
workspaceCustomFlatApplication: FlatApplication;
|
||||
}): Promise<void> {
|
||||
const {
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatPageLayoutMaps,
|
||||
flatPageLayoutTabMaps,
|
||||
flatPageLayoutWidgetMaps,
|
||||
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
'flatPageLayoutMaps',
|
||||
'flatPageLayoutTabMaps',
|
||||
'flatPageLayoutWidgetMaps',
|
||||
]);
|
||||
|
||||
// Build a set of fieldMetadataIds that already have a FIELD widget
|
||||
const existingFieldWidgetFieldIds = new Set<string>();
|
||||
|
||||
for (const widget of Object.values(
|
||||
flatPageLayoutWidgetMaps.byUniversalIdentifier,
|
||||
)) {
|
||||
if (
|
||||
isDefined(widget) &&
|
||||
widget.configuration?.configurationType ===
|
||||
WidgetConfigurationType.FIELD &&
|
||||
isDefined(widget.configuration.fieldMetadataId)
|
||||
) {
|
||||
existingFieldWidgetFieldIds.add(widget.configuration.fieldMetadataId);
|
||||
}
|
||||
}
|
||||
|
||||
// Build object ID → objectMetadata map
|
||||
const objectById = new Map<string, FlatObjectMetadata>();
|
||||
|
||||
for (const obj of Object.values(
|
||||
flatObjectMetadataMaps.byUniversalIdentifier,
|
||||
)) {
|
||||
if (isDefined(obj)) {
|
||||
objectById.set(obj.id, obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Build object ID → RECORD_PAGE layout map
|
||||
const recordPageLayoutByObjectId = new Map<
|
||||
string,
|
||||
{ id: string; universalIdentifier: string }
|
||||
>();
|
||||
|
||||
for (const layout of Object.values(
|
||||
flatPageLayoutMaps.byUniversalIdentifier,
|
||||
)) {
|
||||
if (
|
||||
isDefined(layout) &&
|
||||
layout.type === PageLayoutType.RECORD_PAGE &&
|
||||
isDefined(layout.objectMetadataId)
|
||||
) {
|
||||
recordPageLayoutByObjectId.set(layout.objectMetadataId, {
|
||||
id: layout.id,
|
||||
universalIdentifier: layout.universalIdentifier,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Build pageLayoutId → home tab map
|
||||
const homeTabByPageLayoutId = new Map<
|
||||
string,
|
||||
{
|
||||
id: string;
|
||||
universalIdentifier: string;
|
||||
widgetCount: number;
|
||||
}
|
||||
>();
|
||||
|
||||
for (const tab of Object.values(
|
||||
flatPageLayoutTabMaps.byUniversalIdentifier,
|
||||
)) {
|
||||
if (
|
||||
isDefined(tab) &&
|
||||
tab.position === HOME_TAB_POSITION &&
|
||||
tab.layoutMode === PageLayoutTabLayoutMode.VERTICAL_LIST
|
||||
) {
|
||||
homeTabByPageLayoutId.set(tab.pageLayoutId, {
|
||||
id: tab.id,
|
||||
universalIdentifier: tab.universalIdentifier,
|
||||
widgetCount: tab.widgetIds?.length ?? 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Group fields by objectMetadataId
|
||||
const fieldsByObjectId = new Map<string, FlatFieldMetadata[]>();
|
||||
|
||||
// Map morphId → all field IDs sharing that morphId (for dedup)
|
||||
const fieldIdsByMorphId = new Map<string, string[]>();
|
||||
|
||||
for (const field of Object.values(
|
||||
flatFieldMetadataMaps.byUniversalIdentifier,
|
||||
)) {
|
||||
if (!isDefined(field) || !isDefined(field.objectMetadataId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const list = fieldsByObjectId.get(field.objectMetadataId) ?? [];
|
||||
|
||||
list.push(field);
|
||||
fieldsByObjectId.set(field.objectMetadataId, list);
|
||||
|
||||
if (
|
||||
field.type === FieldMetadataType.MORPH_RELATION &&
|
||||
isDefined(field.morphId)
|
||||
) {
|
||||
const morphFieldIds = fieldIdsByMorphId.get(field.morphId) ?? [];
|
||||
|
||||
morphFieldIds.push(field.id);
|
||||
fieldIdsByMorphId.set(field.morphId, morphFieldIds);
|
||||
}
|
||||
}
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
const standardWidgetsToCreate: FlatPageLayoutWidget[] = [];
|
||||
const customWidgetsToCreate: FlatPageLayoutWidget[] = [];
|
||||
const processedMorphIds = new Set<string>();
|
||||
|
||||
for (const object of objectById.values()) {
|
||||
const pageLayout = recordPageLayoutByObjectId.get(object.id);
|
||||
|
||||
if (!isDefined(pageLayout)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const homeTab = homeTabByPageLayoutId.get(pageLayout.id);
|
||||
|
||||
if (!isDefined(homeTab)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const flatApplication: FlatApplication = object.isCustom
|
||||
? workspaceCustomFlatApplication
|
||||
: twentyStandardFlatApplication;
|
||||
|
||||
const targetList: FlatPageLayoutWidget[] = object.isCustom
|
||||
? customWidgetsToCreate
|
||||
: standardWidgetsToCreate;
|
||||
|
||||
const fields = fieldsByObjectId.get(object.id) ?? [];
|
||||
let nextWidgetIndex = homeTab.widgetCount;
|
||||
|
||||
for (const field of fields) {
|
||||
if (
|
||||
field.type !== FieldMetadataType.RELATION &&
|
||||
field.type !== FieldMetadataType.MORPH_RELATION
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isActivityTargetField(field.name, object.nameSingular)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isJunctionRelationField(field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (field.type === FieldMetadataType.RELATION) {
|
||||
const targetObject = isDefined(field.relationTargetObjectMetadataId)
|
||||
? objectById.get(field.relationTargetObjectMetadataId)
|
||||
: undefined;
|
||||
|
||||
if (!isRelationTargetAvailable(targetObject)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// For morph relations, skip if any sibling field (same morphId)
|
||||
// already has a widget or was already processed in this run
|
||||
if (
|
||||
field.type === FieldMetadataType.MORPH_RELATION &&
|
||||
isDefined(field.morphId)
|
||||
) {
|
||||
if (processedMorphIds.has(field.morphId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const siblingFieldIds = fieldIdsByMorphId.get(field.morphId) ?? [];
|
||||
const alreadyHasWidget = siblingFieldIds.some((id) =>
|
||||
existingFieldWidgetFieldIds.has(id),
|
||||
);
|
||||
|
||||
if (alreadyHasWidget) {
|
||||
continue;
|
||||
}
|
||||
|
||||
processedMorphIds.add(field.morphId);
|
||||
}
|
||||
|
||||
if (existingFieldWidgetFieldIds.has(field.id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const widget: FlatPageLayoutWidget = {
|
||||
id: v4(),
|
||||
universalIdentifier: v4(),
|
||||
applicationId: flatApplication.id,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
workspaceId,
|
||||
pageLayoutTabId: homeTab.id,
|
||||
pageLayoutTabUniversalIdentifier: homeTab.universalIdentifier,
|
||||
title: field.label,
|
||||
type: WidgetType.FIELD,
|
||||
gridPosition: { ...GRID_POSITIONS.FULL_WIDTH },
|
||||
position: {
|
||||
...VERTICAL_LIST_LAYOUT_POSITIONS.SECOND,
|
||||
index: nextWidgetIndex,
|
||||
},
|
||||
configuration: {
|
||||
configurationType: WidgetConfigurationType.FIELD,
|
||||
fieldMetadataId: field.id,
|
||||
fieldDisplayMode: FieldDisplayMode.CARD,
|
||||
},
|
||||
universalConfiguration: {
|
||||
configurationType: WidgetConfigurationType.FIELD,
|
||||
fieldMetadataId: field.universalIdentifier,
|
||||
fieldDisplayMode: FieldDisplayMode.CARD,
|
||||
},
|
||||
objectMetadataId: object.id,
|
||||
objectMetadataUniversalIdentifier: object.universalIdentifier,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
deletedAt: null,
|
||||
conditionalDisplay: null,
|
||||
overrides: null,
|
||||
};
|
||||
|
||||
targetList.push(widget);
|
||||
existingFieldWidgetFieldIds.add(field.id);
|
||||
nextWidgetIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
const totalWidgets =
|
||||
standardWidgetsToCreate.length + customWidgetsToCreate.length;
|
||||
|
||||
if (totalWidgets === 0) {
|
||||
this.logger.log(
|
||||
`All FIELD widgets already exist for workspace ${workspaceId}, skipping`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Found ${totalWidgets} FIELD widget(s) to create for workspace ${workspaceId} (${standardWidgetsToCreate.length} standard, ${customWidgetsToCreate.length} custom)`,
|
||||
);
|
||||
|
||||
if (standardWidgetsToCreate.length > 0) {
|
||||
const result =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: standardWidgetsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (result.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to create standard FIELD widgets:\n${JSON.stringify(result, null, 2)}`,
|
||||
);
|
||||
throw new Error(
|
||||
`Failed to create standard FIELD widgets for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (customWidgetsToCreate.length > 0) {
|
||||
const result =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: customWidgetsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (result.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to create custom FIELD widgets:\n${JSON.stringify(result, null, 2)}`,
|
||||
);
|
||||
throw new Error(
|
||||
`Failed to create custom FIELD widgets for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Successfully created ${totalWidgets} FIELD widget(s) for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
-485
@@ -1,485 +0,0 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Command } from 'nest-commander';
|
||||
import { FeatureFlagKey, ViewType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
|
||||
import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
import { type FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type';
|
||||
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
|
||||
import { type FlatPageLayout } from 'src/engine/metadata-modules/flat-page-layout/types/flat-page-layout.type';
|
||||
import { computeFlatDefaultRecordPageLayoutToCreate } from 'src/engine/metadata-modules/object-metadata/utils/compute-flat-default-record-page-layout-to-create.util';
|
||||
import { computeFlatRecordPageFieldsViewToCreate } from 'src/engine/metadata-modules/object-metadata/utils/compute-flat-record-page-fields-view-to-create.util';
|
||||
import { computeFlatViewFieldsToCreate } from 'src/engine/metadata-modules/object-metadata/utils/compute-flat-view-fields-to-create.util';
|
||||
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
import { type UniversalFlatViewField } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-field.type';
|
||||
import { type UniversalFlatView } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view.type';
|
||||
|
||||
@Command({
|
||||
name: 'upgrade:1-20:backfill-page-layouts',
|
||||
description:
|
||||
'Backfill RECORD_PAGE page layouts for legacy workspaces and enable the IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED feature flag',
|
||||
})
|
||||
export class BackfillPageLayoutsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(WorkspaceEntity)
|
||||
protected readonly workspaceRepository: Repository<WorkspaceEntity>,
|
||||
protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager,
|
||||
protected readonly dataSourceService: DataSourceService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
) {
|
||||
super(workspaceRepository, twentyORMGlobalManager, dataSourceService);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
const isDryRun = options.dryRun ?? false;
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Starting backfill of page layouts for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const isAlreadyEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
if (isAlreadyEnabled) {
|
||||
this.logger.log(
|
||||
`IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED already enabled for workspace ${workspaceId}, skipping`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const { twentyStandardFlatApplication, workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
await this.backfillStandardObjectPageLayouts({
|
||||
workspaceId,
|
||||
twentyStandardFlatApplication,
|
||||
isDryRun,
|
||||
});
|
||||
|
||||
await this.backfillCustomObjectPageLayouts({
|
||||
workspaceId,
|
||||
workspaceCustomFlatApplication,
|
||||
isDryRun,
|
||||
});
|
||||
|
||||
if (!isDryRun) {
|
||||
await this.featureFlagService.enableFeatureFlags(
|
||||
[FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED],
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
isDryRun
|
||||
? `[DRY RUN] Would create page layouts and enable IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED for workspace ${workspaceId}`
|
||||
: `Successfully created page layouts and enabled IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
private async backfillStandardObjectPageLayouts({
|
||||
workspaceId,
|
||||
twentyStandardFlatApplication,
|
||||
isDryRun,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
twentyStandardFlatApplication: FlatApplication;
|
||||
isDryRun: boolean;
|
||||
}): Promise<void> {
|
||||
const { allFlatEntityMaps: standardAllFlatEntityMaps } =
|
||||
computeTwentyStandardApplicationAllFlatEntityMaps({
|
||||
shouldIncludeRecordPageLayouts: true,
|
||||
now: new Date().toISOString(),
|
||||
workspaceId,
|
||||
twentyStandardApplicationId: twentyStandardFlatApplication.id,
|
||||
});
|
||||
|
||||
const {
|
||||
flatPageLayoutMaps: existingFlatPageLayoutMaps,
|
||||
flatPageLayoutTabMaps: existingFlatPageLayoutTabMaps,
|
||||
flatPageLayoutWidgetMaps: existingFlatPageLayoutWidgetMaps,
|
||||
flatViewMaps: existingFlatViewMaps,
|
||||
flatViewFieldMaps: existingFlatViewFieldMaps,
|
||||
flatViewFieldGroupMaps: existingFlatViewFieldGroupMaps,
|
||||
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatPageLayoutMaps',
|
||||
'flatPageLayoutTabMaps',
|
||||
'flatPageLayoutWidgetMaps',
|
||||
'flatViewMaps',
|
||||
'flatViewFieldMaps',
|
||||
'flatViewFieldGroupMaps',
|
||||
]);
|
||||
|
||||
const recordPageLayoutUniversalIdentifiers = new Set<string>();
|
||||
|
||||
const pageLayoutsToCreate = Object.values(
|
||||
standardAllFlatEntityMaps.flatPageLayoutMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((pageLayout) => {
|
||||
if (pageLayout.type !== PageLayoutType.RECORD_PAGE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
recordPageLayoutUniversalIdentifiers.add(
|
||||
pageLayout.universalIdentifier,
|
||||
);
|
||||
|
||||
if (
|
||||
isDefined(
|
||||
existingFlatPageLayoutMaps.byUniversalIdentifier[
|
||||
pageLayout.universalIdentifier
|
||||
],
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
const tabUniversalIdentifiers = new Set<string>();
|
||||
|
||||
const pageLayoutTabsToCreate = Object.values(
|
||||
standardAllFlatEntityMaps.flatPageLayoutTabMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((tab) => {
|
||||
if (
|
||||
!recordPageLayoutUniversalIdentifiers.has(
|
||||
tab.pageLayoutUniversalIdentifier,
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tabUniversalIdentifiers.add(tab.universalIdentifier);
|
||||
|
||||
if (
|
||||
isDefined(
|
||||
existingFlatPageLayoutTabMaps.byUniversalIdentifier[
|
||||
tab.universalIdentifier
|
||||
],
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
const pageLayoutWidgetsToCreate = Object.values(
|
||||
standardAllFlatEntityMaps.flatPageLayoutWidgetMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter(
|
||||
(widget) =>
|
||||
tabUniversalIdentifiers.has(
|
||||
widget.pageLayoutTabUniversalIdentifier,
|
||||
) &&
|
||||
!isDefined(
|
||||
existingFlatPageLayoutWidgetMaps.byUniversalIdentifier[
|
||||
widget.universalIdentifier
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
const viewUniversalIdentifiers = new Set<string>();
|
||||
|
||||
const viewsToCreate = Object.values(
|
||||
standardAllFlatEntityMaps.flatViewMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((view) => {
|
||||
if (view.type !== ViewType.FIELDS_WIDGET) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
isDefined(
|
||||
existingFlatViewMaps.byUniversalIdentifier[
|
||||
view.universalIdentifier
|
||||
],
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
viewUniversalIdentifiers.add(view.universalIdentifier);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
const viewFieldsToCreate = Object.values(
|
||||
standardAllFlatEntityMaps.flatViewFieldMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter(
|
||||
(viewField) =>
|
||||
viewUniversalIdentifiers.has(viewField.viewUniversalIdentifier) &&
|
||||
!isDefined(
|
||||
existingFlatViewFieldMaps.byUniversalIdentifier[
|
||||
viewField.universalIdentifier
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
const viewFieldGroupsToCreate = Object.values(
|
||||
standardAllFlatEntityMaps.flatViewFieldGroupMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter(
|
||||
(viewFieldGroup) =>
|
||||
viewUniversalIdentifiers.has(
|
||||
viewFieldGroup.viewUniversalIdentifier,
|
||||
) &&
|
||||
!isDefined(
|
||||
existingFlatViewFieldGroupMaps.byUniversalIdentifier[
|
||||
viewFieldGroup.universalIdentifier
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Found standard entities to create for workspace ${workspaceId}: ` +
|
||||
`${pageLayoutsToCreate.length} page layout(s), ` +
|
||||
`${pageLayoutTabsToCreate.length} tab(s), ` +
|
||||
`${pageLayoutWidgetsToCreate.length} widget(s), ` +
|
||||
`${viewsToCreate.length} view(s), ` +
|
||||
`${viewFieldsToCreate.length} view field(s), ` +
|
||||
`${viewFieldGroupsToCreate.length} view field group(s)`,
|
||||
);
|
||||
|
||||
if (isDryRun) {
|
||||
return;
|
||||
}
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayout: {
|
||||
flatEntityToCreate: pageLayoutsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutTab: {
|
||||
flatEntityToCreate: pageLayoutTabsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: pageLayoutWidgetsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
view: {
|
||||
flatEntityToCreate: viewsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: viewFieldsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewFieldGroup: {
|
||||
flatEntityToCreate: viewFieldGroupsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (validateAndBuildResult.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to create standard page layouts:\n${JSON.stringify(validateAndBuildResult, null, 2)}`,
|
||||
);
|
||||
throw new Error(
|
||||
`Failed to create standard page layouts for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async backfillCustomObjectPageLayouts({
|
||||
workspaceId,
|
||||
workspaceCustomFlatApplication,
|
||||
isDryRun,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
workspaceCustomFlatApplication: FlatApplication;
|
||||
isDryRun: boolean;
|
||||
}): Promise<void> {
|
||||
const {
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatPageLayoutMaps,
|
||||
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
'flatPageLayoutMaps',
|
||||
]);
|
||||
|
||||
const existingPageLayouts = Object.values(
|
||||
flatPageLayoutMaps.byUniversalIdentifier,
|
||||
).filter(isDefined);
|
||||
|
||||
const objectIdsWithRecordPageLayout = new Set(
|
||||
existingPageLayouts
|
||||
.filter(
|
||||
(layout: FlatPageLayout) =>
|
||||
layout.type === PageLayoutType.RECORD_PAGE &&
|
||||
isDefined(layout.objectMetadataId),
|
||||
)
|
||||
.map((layout: FlatPageLayout) => layout.objectMetadataId),
|
||||
);
|
||||
|
||||
const customObjectsWithoutPageLayout = Object.values(
|
||||
flatObjectMetadataMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter(
|
||||
(objectMetadata) =>
|
||||
objectMetadata.isCustom &&
|
||||
!objectMetadata.isRemote &&
|
||||
!objectIdsWithRecordPageLayout.has(objectMetadata.id),
|
||||
);
|
||||
|
||||
if (customObjectsWithoutPageLayout.length === 0) {
|
||||
this.logger.log(
|
||||
`No custom objects without page layouts found for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const allCustomPageLayoutsToCreate: FlatPageLayout[] = [];
|
||||
const allCustomPageLayoutTabsToCreate: FlatPageLayoutTab[] = [];
|
||||
const allCustomPageLayoutWidgetsToCreate: FlatPageLayoutWidget[] = [];
|
||||
const allCustomViewsToCreate: (UniversalFlatView & { id: string })[] = [];
|
||||
const allCustomViewFieldsToCreate: UniversalFlatViewField[] = [];
|
||||
|
||||
for (const customObject of customObjectsWithoutPageLayout) {
|
||||
const flatRecordPageFieldsView = computeFlatRecordPageFieldsViewToCreate({
|
||||
objectMetadata: customObject,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
});
|
||||
|
||||
const objectFieldMetadatas = Object.values(
|
||||
flatFieldMetadataMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((field) => field.objectMetadataId === customObject.id);
|
||||
|
||||
const viewFields = computeFlatViewFieldsToCreate({
|
||||
objectFlatFieldMetadatas: objectFieldMetadatas,
|
||||
viewUniversalIdentifier: flatRecordPageFieldsView.universalIdentifier,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
customObject.labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
});
|
||||
|
||||
const { pageLayouts, pageLayoutTabs, pageLayoutWidgets } =
|
||||
computeFlatDefaultRecordPageLayoutToCreate({
|
||||
objectMetadata: customObject,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
recordPageFieldsView: flatRecordPageFieldsView,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
allCustomPageLayoutsToCreate.push(...pageLayouts);
|
||||
allCustomPageLayoutTabsToCreate.push(...pageLayoutTabs);
|
||||
allCustomPageLayoutWidgetsToCreate.push(...pageLayoutWidgets);
|
||||
allCustomViewsToCreate.push(flatRecordPageFieldsView);
|
||||
allCustomViewFieldsToCreate.push(...viewFields);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Found custom entities to create for ${customObjectsWithoutPageLayout.length} custom object(s) in workspace ${workspaceId}: ` +
|
||||
`${allCustomPageLayoutsToCreate.length} page layout(s), ` +
|
||||
`${allCustomPageLayoutTabsToCreate.length} tab(s), ` +
|
||||
`${allCustomPageLayoutWidgetsToCreate.length} widget(s), ` +
|
||||
`${allCustomViewsToCreate.length} view(s), ` +
|
||||
`${allCustomViewFieldsToCreate.length} view field(s)`,
|
||||
);
|
||||
|
||||
if (isDryRun) {
|
||||
return;
|
||||
}
|
||||
|
||||
const customValidateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayout: {
|
||||
flatEntityToCreate: allCustomPageLayoutsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutTab: {
|
||||
flatEntityToCreate: allCustomPageLayoutTabsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: allCustomPageLayoutWidgetsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
view: {
|
||||
flatEntityToCreate: allCustomViewsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: allCustomViewFieldsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (customValidateAndBuildResult.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to create custom object page layouts:\n${JSON.stringify(customValidateAndBuildResult, null, 2)}`,
|
||||
);
|
||||
throw new Error(
|
||||
`Failed to create custom object page layouts for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Successfully created page layouts for ${customObjectsWithoutPageLayout.length} custom object(s) in workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
+3
-6
@@ -2,9 +2,8 @@ import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { BackfillCommandMenuItemsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-command-menu-items.command';
|
||||
import { BackfillFieldWidgetsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-field-widgets.command';
|
||||
import { BackfillNavigationMenuItemTypeCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-navigation-menu-item-type.command';
|
||||
import { BackfillPageLayoutsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-page-layouts.command';
|
||||
import { BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-page-layouts-and-fields-widget-view-fields.command';
|
||||
import { BackfillSelectFieldOptionIdsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-select-field-option-ids.command';
|
||||
import { DeleteOrphanNavigationMenuItemsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-delete-orphan-navigation-menu-items.command';
|
||||
import { GenerateApplicationSdkClientsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-generate-application-sdk-clients.command';
|
||||
@@ -67,9 +66,8 @@ import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-commo
|
||||
IdentifyObjectPermissionMetadataCommand,
|
||||
MakeObjectPermissionUniversalIdentifierAndApplicationIdNotNullableMigrationCommand,
|
||||
BackfillCommandMenuItemsCommand,
|
||||
BackfillFieldWidgetsCommand,
|
||||
BackfillNavigationMenuItemTypeCommand,
|
||||
BackfillPageLayoutsCommand,
|
||||
BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand,
|
||||
BackfillSelectFieldOptionIdsCommand,
|
||||
DeleteOrphanNavigationMenuItemsCommand,
|
||||
GenerateApplicationSdkClientsCommand,
|
||||
@@ -85,9 +83,8 @@ import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-commo
|
||||
IdentifyObjectPermissionMetadataCommand,
|
||||
MakeObjectPermissionUniversalIdentifierAndApplicationIdNotNullableMigrationCommand,
|
||||
BackfillCommandMenuItemsCommand,
|
||||
BackfillFieldWidgetsCommand,
|
||||
BackfillNavigationMenuItemTypeCommand,
|
||||
BackfillPageLayoutsCommand,
|
||||
BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand,
|
||||
BackfillSelectFieldOptionIdsCommand,
|
||||
DeleteOrphanNavigationMenuItemsCommand,
|
||||
GenerateApplicationSdkClientsCommand,
|
||||
|
||||
+5
-8
@@ -34,11 +34,11 @@ import { BackfillSystemFieldsIsSystemCommand } from 'src/database/commands/upgra
|
||||
import { FixInvalidStandardUniversalIdentifiersCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-fix-invalid-standard-universal-identifiers.command';
|
||||
import { SeedServerIdCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-seed-server-id.command';
|
||||
import { BackfillCommandMenuItemsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-command-menu-items.command';
|
||||
import { BackfillFieldWidgetsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-field-widgets.command';
|
||||
import { BackfillNavigationMenuItemTypeCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-navigation-menu-item-type.command';
|
||||
import { DeleteOrphanNavigationMenuItemsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-delete-orphan-navigation-menu-items.command';
|
||||
import { BackfillPageLayoutsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-page-layouts.command';
|
||||
import { BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-page-layouts-and-fields-widget-view-fields.command';
|
||||
import { BackfillSelectFieldOptionIdsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-select-field-option-ids.command';
|
||||
import { DeleteOrphanNavigationMenuItemsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-delete-orphan-navigation-menu-items.command';
|
||||
import { GenerateApplicationSdkClientsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-generate-application-sdk-clients.command';
|
||||
import { IdentifyObjectPermissionMetadataCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-identify-object-permission-metadata.command';
|
||||
import { IdentifyPermissionFlagMetadataCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-identify-permission-flag-metadata.command';
|
||||
import { MakeObjectPermissionUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-make-object-permission-universal-identifier-and-application-id-not-nullable-migration.command';
|
||||
@@ -46,7 +46,6 @@ import { MakePermissionFlagUniversalIdentifierAndApplicationIdNotNullableMigrati
|
||||
import { MakeWorkflowSearchableCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-make-workflow-searchable.command';
|
||||
import { MigrateMessagingInfrastructureToMetadataCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-migrate-messaging-infrastructure-to-metadata.command';
|
||||
import { MigrateRichTextToTextCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-migrate-rich-text-to-text.command';
|
||||
import { GenerateApplicationSdkClientsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-generate-application-sdk-clients.command';
|
||||
import { SeedCliApplicationRegistrationCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-seed-cli-application-registration.command';
|
||||
import { UpdateStandardIndexViewNamesCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-update-standard-index-view-names.command';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
@@ -106,12 +105,11 @@ export class UpgradeCommand extends UpgradeCommandRunner {
|
||||
protected readonly backfillNavigationMenuItemTypeCommand: BackfillNavigationMenuItemTypeCommand,
|
||||
protected readonly backfillCommandMenuItemsCommand: BackfillCommandMenuItemsCommand,
|
||||
protected readonly deleteOrphanNavigationMenuItemsCommand: DeleteOrphanNavigationMenuItemsCommand,
|
||||
protected readonly backfillPageLayoutsCommand: BackfillPageLayoutsCommand,
|
||||
protected readonly backfillPageLayoutsAndFieldsWidgetViewFieldsCommand: BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand,
|
||||
protected readonly generateApplicationSdkClientsCommand: GenerateApplicationSdkClientsCommand,
|
||||
protected readonly seedCliApplicationRegistrationCommand: SeedCliApplicationRegistrationCommand,
|
||||
protected readonly migrateRichTextToTextCommand: MigrateRichTextToTextCommand,
|
||||
protected readonly migrateMessagingInfrastructureToMetadataCommand: MigrateMessagingInfrastructureToMetadataCommand,
|
||||
protected readonly backfillFieldWidgetsCommand: BackfillFieldWidgetsCommand,
|
||||
protected readonly backfillSelectFieldOptionIdsCommand: BackfillSelectFieldOptionIdsCommand,
|
||||
protected readonly updateStandardIndexViewNamesCommand: UpdateStandardIndexViewNamesCommand,
|
||||
protected readonly makeWorkflowSearchableCommand: MakeWorkflowSearchableCommand,
|
||||
@@ -172,10 +170,9 @@ export class UpgradeCommand extends UpgradeCommandRunner {
|
||||
this.migrateRichTextToTextCommand,
|
||||
this.deleteOrphanNavigationMenuItemsCommand,
|
||||
this.backfillCommandMenuItemsCommand,
|
||||
this.backfillPageLayoutsCommand,
|
||||
this.backfillPageLayoutsAndFieldsWidgetViewFieldsCommand,
|
||||
this.seedCliApplicationRegistrationCommand,
|
||||
this.migrateMessagingInfrastructureToMetadataCommand,
|
||||
this.backfillFieldWidgetsCommand,
|
||||
this.backfillSelectFieldOptionIdsCommand,
|
||||
this.updateStandardIndexViewNamesCommand,
|
||||
this.makeWorkflowSearchableCommand,
|
||||
|
||||
+1
@@ -455,6 +455,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
flatObjectMetadataToCreate.labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
viewUniversalIdentifier:
|
||||
flatRecordPageFieldsViewToCreate.universalIdentifier,
|
||||
excludeLabelIdentifier: true,
|
||||
});
|
||||
|
||||
flatDefaultRecordPageLayoutsToCreate =
|
||||
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
|
||||
|
||||
import { computeFlatViewFieldsToCreate } from '../compute-flat-view-fields-to-create.util';
|
||||
|
||||
const makeFieldMetadata = (
|
||||
overrides: Partial<UniversalFlatFieldMetadata> & {
|
||||
name: string;
|
||||
type: FieldMetadataType;
|
||||
},
|
||||
): UniversalFlatFieldMetadata => {
|
||||
const universalIdentifier = overrides.universalIdentifier ?? v4();
|
||||
|
||||
return {
|
||||
universalIdentifier,
|
||||
objectMetadataUniversalIdentifier: 'object-uid',
|
||||
applicationUniversalIdentifier: 'app-uid',
|
||||
name: overrides.name,
|
||||
label: overrides.label ?? overrides.name,
|
||||
type: overrides.type,
|
||||
isCustom: overrides.isCustom ?? false,
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
isNullable: true,
|
||||
isUnique: false,
|
||||
isLabelSyncedWithName: false,
|
||||
defaultValue: null,
|
||||
description: null,
|
||||
icon: null,
|
||||
options: null,
|
||||
settings: null,
|
||||
standardOverrides: null,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
updatedAt: '2026-01-01T00:00:00.000Z',
|
||||
deletedAt: null,
|
||||
} as unknown as UniversalFlatFieldMetadata;
|
||||
};
|
||||
|
||||
const flatApplication = {
|
||||
universalIdentifier: 'app-uid',
|
||||
id: 'app-id',
|
||||
} as never;
|
||||
|
||||
const viewUniversalIdentifier = 'view-uid';
|
||||
|
||||
describe('computeFlatViewFieldsToCreate', () => {
|
||||
it('should exclude TS_VECTOR fields', () => {
|
||||
const fields = [
|
||||
makeFieldMetadata({
|
||||
name: 'name',
|
||||
type: FieldMetadataType.TEXT,
|
||||
}),
|
||||
makeFieldMetadata({
|
||||
name: 'searchVector',
|
||||
type: FieldMetadataType.TS_VECTOR,
|
||||
}),
|
||||
];
|
||||
|
||||
const result = computeFlatViewFieldsToCreate({
|
||||
objectFlatFieldMetadatas: fields,
|
||||
viewUniversalIdentifier,
|
||||
flatApplication,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier: null,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].fieldMetadataUniversalIdentifier).toBe(
|
||||
fields[0].universalIdentifier,
|
||||
);
|
||||
});
|
||||
|
||||
it('should exclude POSITION fields', () => {
|
||||
const fields = [
|
||||
makeFieldMetadata({
|
||||
name: 'name',
|
||||
type: FieldMetadataType.TEXT,
|
||||
}),
|
||||
makeFieldMetadata({
|
||||
name: 'position',
|
||||
type: FieldMetadataType.POSITION,
|
||||
}),
|
||||
];
|
||||
|
||||
const result = computeFlatViewFieldsToCreate({
|
||||
objectFlatFieldMetadatas: fields,
|
||||
viewUniversalIdentifier,
|
||||
flatApplication,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier: null,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].fieldMetadataUniversalIdentifier).toBe(
|
||||
fields[0].universalIdentifier,
|
||||
);
|
||||
});
|
||||
|
||||
it('should exclude RELATION and MORPH_RELATION fields', () => {
|
||||
const fields = [
|
||||
makeFieldMetadata({
|
||||
name: 'name',
|
||||
type: FieldMetadataType.TEXT,
|
||||
}),
|
||||
makeFieldMetadata({
|
||||
name: 'company',
|
||||
type: FieldMetadataType.RELATION,
|
||||
}),
|
||||
makeFieldMetadata({
|
||||
name: 'target',
|
||||
type: FieldMetadataType.MORPH_RELATION,
|
||||
}),
|
||||
];
|
||||
|
||||
const result = computeFlatViewFieldsToCreate({
|
||||
objectFlatFieldMetadatas: fields,
|
||||
viewUniversalIdentifier,
|
||||
flatApplication,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier: null,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].fieldMetadataUniversalIdentifier).toBe(
|
||||
fields[0].universalIdentifier,
|
||||
);
|
||||
});
|
||||
|
||||
it('should exclude deletedAt field', () => {
|
||||
const fields = [
|
||||
makeFieldMetadata({
|
||||
name: 'name',
|
||||
type: FieldMetadataType.TEXT,
|
||||
}),
|
||||
makeFieldMetadata({
|
||||
name: 'deletedAt',
|
||||
type: FieldMetadataType.DATE_TIME,
|
||||
}),
|
||||
];
|
||||
|
||||
const result = computeFlatViewFieldsToCreate({
|
||||
objectFlatFieldMetadatas: fields,
|
||||
viewUniversalIdentifier,
|
||||
flatApplication,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier: null,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].fieldMetadataUniversalIdentifier).toBe(
|
||||
fields[0].universalIdentifier,
|
||||
);
|
||||
});
|
||||
|
||||
it('should place label identifier field first', () => {
|
||||
const labelField = makeFieldMetadata({
|
||||
name: 'name',
|
||||
type: FieldMetadataType.TEXT,
|
||||
});
|
||||
const otherField = makeFieldMetadata({
|
||||
name: 'createdAt',
|
||||
type: FieldMetadataType.DATE_TIME,
|
||||
});
|
||||
const fields = [otherField, labelField];
|
||||
|
||||
const result = computeFlatViewFieldsToCreate({
|
||||
objectFlatFieldMetadatas: fields,
|
||||
viewUniversalIdentifier,
|
||||
flatApplication,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
labelField.universalIdentifier,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].fieldMetadataUniversalIdentifier).toBe(
|
||||
labelField.universalIdentifier,
|
||||
);
|
||||
expect(result[0].position).toBe(0);
|
||||
expect(result[1].fieldMetadataUniversalIdentifier).toBe(
|
||||
otherField.universalIdentifier,
|
||||
);
|
||||
expect(result[1].position).toBe(1);
|
||||
});
|
||||
|
||||
it('should exclude label identifier when excludeLabelIdentifier is true', () => {
|
||||
const labelField = makeFieldMetadata({
|
||||
name: 'name',
|
||||
type: FieldMetadataType.TEXT,
|
||||
});
|
||||
const otherField = makeFieldMetadata({
|
||||
name: 'createdAt',
|
||||
type: FieldMetadataType.DATE_TIME,
|
||||
});
|
||||
|
||||
const result = computeFlatViewFieldsToCreate({
|
||||
objectFlatFieldMetadatas: [labelField, otherField],
|
||||
viewUniversalIdentifier,
|
||||
flatApplication,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
labelField.universalIdentifier,
|
||||
excludeLabelIdentifier: true,
|
||||
});
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].fieldMetadataUniversalIdentifier).toBe(
|
||||
otherField.universalIdentifier,
|
||||
);
|
||||
});
|
||||
});
|
||||
+8
@@ -11,22 +11,30 @@ export const computeFlatViewFieldsToCreate = ({
|
||||
viewUniversalIdentifier,
|
||||
flatApplication,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
excludeLabelIdentifier = false,
|
||||
}: {
|
||||
flatApplication: FlatApplication;
|
||||
objectFlatFieldMetadatas: UniversalFlatFieldMetadata[];
|
||||
viewUniversalIdentifier: string;
|
||||
labelIdentifierFieldMetadataUniversalIdentifier: string | null;
|
||||
excludeLabelIdentifier?: boolean;
|
||||
}): UniversalFlatViewField[] => {
|
||||
const createdAt = new Date().toISOString();
|
||||
const defaultViewFields = objectFlatFieldMetadatas
|
||||
.filter(
|
||||
(field) =>
|
||||
field.name !== 'deletedAt' &&
|
||||
field.type !== FieldMetadataType.TS_VECTOR &&
|
||||
field.type !== FieldMetadataType.POSITION &&
|
||||
field.type !== FieldMetadataType.MORPH_RELATION &&
|
||||
field.type !== FieldMetadataType.RELATION &&
|
||||
// Include 'id' only if it's the label identifier (e.g., for junction tables)
|
||||
(field.name !== 'id' ||
|
||||
field.universalIdentifier ===
|
||||
labelIdentifierFieldMetadataUniversalIdentifier) &&
|
||||
// Exclude label identifier field when requested (e.g., for FIELDS_WIDGET views)
|
||||
(!excludeLabelIdentifier ||
|
||||
field.universalIdentifier !==
|
||||
labelIdentifierFieldMetadataUniversalIdentifier),
|
||||
)
|
||||
.sort((a, b) => {
|
||||
|
||||
+1678
-1549
File diff suppressed because it is too large
Load Diff
+84
-90
@@ -6,40 +6,37 @@ exports[`getStandardPageLayoutMetadataRelatedEntityIds should return standard pa
|
||||
"id": "00000000-0000-0000-0000-000000000011",
|
||||
"tabs": {
|
||||
"calendar": {
|
||||
"id": "00000000-0000-0000-0000-000000000027",
|
||||
"id": "00000000-0000-0000-0000-000000000026",
|
||||
"widgets": {
|
||||
"calendar": {
|
||||
"id": "00000000-0000-0000-0000-000000000028",
|
||||
"id": "00000000-0000-0000-0000-000000000027",
|
||||
},
|
||||
},
|
||||
},
|
||||
"emails": {
|
||||
"id": "00000000-0000-0000-0000-000000000025",
|
||||
"id": "00000000-0000-0000-0000-000000000024",
|
||||
"widgets": {
|
||||
"emails": {
|
||||
"id": "00000000-0000-0000-0000-000000000026",
|
||||
"id": "00000000-0000-0000-0000-000000000025",
|
||||
},
|
||||
},
|
||||
},
|
||||
"files": {
|
||||
"id": "00000000-0000-0000-0000-000000000023",
|
||||
"id": "00000000-0000-0000-0000-000000000022",
|
||||
"widgets": {
|
||||
"files": {
|
||||
"id": "00000000-0000-0000-0000-000000000024",
|
||||
"id": "00000000-0000-0000-0000-000000000023",
|
||||
},
|
||||
},
|
||||
},
|
||||
"home": {
|
||||
"id": "00000000-0000-0000-0000-000000000012",
|
||||
"widgets": {
|
||||
"accountOwner": {
|
||||
"id": "00000000-0000-0000-0000-000000000015",
|
||||
},
|
||||
"fields": {
|
||||
"id": "00000000-0000-0000-0000-000000000013",
|
||||
},
|
||||
"opportunities": {
|
||||
"id": "00000000-0000-0000-0000-000000000016",
|
||||
"id": "00000000-0000-0000-0000-000000000015",
|
||||
},
|
||||
"people": {
|
||||
"id": "00000000-0000-0000-0000-000000000014",
|
||||
@@ -47,26 +44,26 @@ exports[`getStandardPageLayoutMetadataRelatedEntityIds should return standard pa
|
||||
},
|
||||
},
|
||||
"notes": {
|
||||
"id": "00000000-0000-0000-0000-000000000021",
|
||||
"id": "00000000-0000-0000-0000-000000000020",
|
||||
"widgets": {
|
||||
"notes": {
|
||||
"id": "00000000-0000-0000-0000-000000000022",
|
||||
"id": "00000000-0000-0000-0000-000000000021",
|
||||
},
|
||||
},
|
||||
},
|
||||
"tasks": {
|
||||
"id": "00000000-0000-0000-0000-000000000019",
|
||||
"id": "00000000-0000-0000-0000-000000000018",
|
||||
"widgets": {
|
||||
"tasks": {
|
||||
"id": "00000000-0000-0000-0000-000000000020",
|
||||
"id": "00000000-0000-0000-0000-000000000019",
|
||||
},
|
||||
},
|
||||
},
|
||||
"timeline": {
|
||||
"id": "00000000-0000-0000-0000-000000000017",
|
||||
"id": "00000000-0000-0000-0000-000000000016",
|
||||
"widgets": {
|
||||
"timeline": {
|
||||
"id": "00000000-0000-0000-0000-000000000018",
|
||||
"id": "00000000-0000-0000-0000-000000000017",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -107,281 +104,278 @@ exports[`getStandardPageLayoutMetadataRelatedEntityIds should return standard pa
|
||||
},
|
||||
},
|
||||
"noteRecordPage": {
|
||||
"id": "00000000-0000-0000-0000-000000000064",
|
||||
"id": "00000000-0000-0000-0000-000000000063",
|
||||
"tabs": {
|
||||
"files": {
|
||||
"id": "00000000-0000-0000-0000-000000000072",
|
||||
"id": "00000000-0000-0000-0000-000000000071",
|
||||
"widgets": {
|
||||
"files": {
|
||||
"id": "00000000-0000-0000-0000-000000000073",
|
||||
"id": "00000000-0000-0000-0000-000000000072",
|
||||
},
|
||||
},
|
||||
},
|
||||
"home": {
|
||||
"id": "00000000-0000-0000-0000-000000000065",
|
||||
"id": "00000000-0000-0000-0000-000000000064",
|
||||
"widgets": {
|
||||
"fields": {
|
||||
"id": "00000000-0000-0000-0000-000000000066",
|
||||
"id": "00000000-0000-0000-0000-000000000065",
|
||||
},
|
||||
"noteRichText": {
|
||||
"id": "00000000-0000-0000-0000-000000000067",
|
||||
"id": "00000000-0000-0000-0000-000000000066",
|
||||
},
|
||||
},
|
||||
},
|
||||
"note": {
|
||||
"id": "00000000-0000-0000-0000-000000000068",
|
||||
"id": "00000000-0000-0000-0000-000000000067",
|
||||
"widgets": {
|
||||
"noteRichText": {
|
||||
"id": "00000000-0000-0000-0000-000000000069",
|
||||
"id": "00000000-0000-0000-0000-000000000068",
|
||||
},
|
||||
},
|
||||
},
|
||||
"timeline": {
|
||||
"id": "00000000-0000-0000-0000-000000000070",
|
||||
"id": "00000000-0000-0000-0000-000000000069",
|
||||
"widgets": {
|
||||
"timeline": {
|
||||
"id": "00000000-0000-0000-0000-000000000071",
|
||||
"id": "00000000-0000-0000-0000-000000000070",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"opportunityRecordPage": {
|
||||
"id": "00000000-0000-0000-0000-000000000046",
|
||||
"id": "00000000-0000-0000-0000-000000000045",
|
||||
"tabs": {
|
||||
"calendar": {
|
||||
"id": "00000000-0000-0000-0000-000000000062",
|
||||
"id": "00000000-0000-0000-0000-000000000061",
|
||||
"widgets": {
|
||||
"calendar": {
|
||||
"id": "00000000-0000-0000-0000-000000000063",
|
||||
"id": "00000000-0000-0000-0000-000000000062",
|
||||
},
|
||||
},
|
||||
},
|
||||
"emails": {
|
||||
"id": "00000000-0000-0000-0000-000000000060",
|
||||
"id": "00000000-0000-0000-0000-000000000059",
|
||||
"widgets": {
|
||||
"emails": {
|
||||
"id": "00000000-0000-0000-0000-000000000061",
|
||||
"id": "00000000-0000-0000-0000-000000000060",
|
||||
},
|
||||
},
|
||||
},
|
||||
"files": {
|
||||
"id": "00000000-0000-0000-0000-000000000058",
|
||||
"id": "00000000-0000-0000-0000-000000000057",
|
||||
"widgets": {
|
||||
"files": {
|
||||
"id": "00000000-0000-0000-0000-000000000059",
|
||||
"id": "00000000-0000-0000-0000-000000000058",
|
||||
},
|
||||
},
|
||||
},
|
||||
"home": {
|
||||
"id": "00000000-0000-0000-0000-000000000047",
|
||||
"id": "00000000-0000-0000-0000-000000000046",
|
||||
"widgets": {
|
||||
"company": {
|
||||
"id": "00000000-0000-0000-0000-000000000050",
|
||||
"id": "00000000-0000-0000-0000-000000000049",
|
||||
},
|
||||
"fields": {
|
||||
"id": "00000000-0000-0000-0000-000000000048",
|
||||
"id": "00000000-0000-0000-0000-000000000047",
|
||||
},
|
||||
"owner": {
|
||||
"id": "00000000-0000-0000-0000-000000000051",
|
||||
"id": "00000000-0000-0000-0000-000000000050",
|
||||
},
|
||||
"pointOfContact": {
|
||||
"id": "00000000-0000-0000-0000-000000000049",
|
||||
"id": "00000000-0000-0000-0000-000000000048",
|
||||
},
|
||||
},
|
||||
},
|
||||
"notes": {
|
||||
"id": "00000000-0000-0000-0000-000000000056",
|
||||
"id": "00000000-0000-0000-0000-000000000055",
|
||||
"widgets": {
|
||||
"notes": {
|
||||
"id": "00000000-0000-0000-0000-000000000057",
|
||||
"id": "00000000-0000-0000-0000-000000000056",
|
||||
},
|
||||
},
|
||||
},
|
||||
"tasks": {
|
||||
"id": "00000000-0000-0000-0000-000000000054",
|
||||
"id": "00000000-0000-0000-0000-000000000053",
|
||||
"widgets": {
|
||||
"tasks": {
|
||||
"id": "00000000-0000-0000-0000-000000000055",
|
||||
"id": "00000000-0000-0000-0000-000000000054",
|
||||
},
|
||||
},
|
||||
},
|
||||
"timeline": {
|
||||
"id": "00000000-0000-0000-0000-000000000052",
|
||||
"id": "00000000-0000-0000-0000-000000000051",
|
||||
"widgets": {
|
||||
"timeline": {
|
||||
"id": "00000000-0000-0000-0000-000000000053",
|
||||
"id": "00000000-0000-0000-0000-000000000052",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"personRecordPage": {
|
||||
"id": "00000000-0000-0000-0000-000000000029",
|
||||
"id": "00000000-0000-0000-0000-000000000028",
|
||||
"tabs": {
|
||||
"calendar": {
|
||||
"id": "00000000-0000-0000-0000-000000000044",
|
||||
"id": "00000000-0000-0000-0000-000000000043",
|
||||
"widgets": {
|
||||
"calendar": {
|
||||
"id": "00000000-0000-0000-0000-000000000045",
|
||||
"id": "00000000-0000-0000-0000-000000000044",
|
||||
},
|
||||
},
|
||||
},
|
||||
"emails": {
|
||||
"id": "00000000-0000-0000-0000-000000000042",
|
||||
"id": "00000000-0000-0000-0000-000000000041",
|
||||
"widgets": {
|
||||
"emails": {
|
||||
"id": "00000000-0000-0000-0000-000000000043",
|
||||
"id": "00000000-0000-0000-0000-000000000042",
|
||||
},
|
||||
},
|
||||
},
|
||||
"files": {
|
||||
"id": "00000000-0000-0000-0000-000000000040",
|
||||
"id": "00000000-0000-0000-0000-000000000039",
|
||||
"widgets": {
|
||||
"files": {
|
||||
"id": "00000000-0000-0000-0000-000000000041",
|
||||
"id": "00000000-0000-0000-0000-000000000040",
|
||||
},
|
||||
},
|
||||
},
|
||||
"home": {
|
||||
"id": "00000000-0000-0000-0000-000000000030",
|
||||
"id": "00000000-0000-0000-0000-000000000029",
|
||||
"widgets": {
|
||||
"company": {
|
||||
"id": "00000000-0000-0000-0000-000000000032",
|
||||
},
|
||||
"fields": {
|
||||
"id": "00000000-0000-0000-0000-000000000031",
|
||||
},
|
||||
"fields": {
|
||||
"id": "00000000-0000-0000-0000-000000000030",
|
||||
},
|
||||
"pointOfContactForOpportunities": {
|
||||
"id": "00000000-0000-0000-0000-000000000033",
|
||||
"id": "00000000-0000-0000-0000-000000000032",
|
||||
},
|
||||
},
|
||||
},
|
||||
"notes": {
|
||||
"id": "00000000-0000-0000-0000-000000000038",
|
||||
"id": "00000000-0000-0000-0000-000000000037",
|
||||
"widgets": {
|
||||
"notes": {
|
||||
"id": "00000000-0000-0000-0000-000000000039",
|
||||
"id": "00000000-0000-0000-0000-000000000038",
|
||||
},
|
||||
},
|
||||
},
|
||||
"tasks": {
|
||||
"id": "00000000-0000-0000-0000-000000000036",
|
||||
"id": "00000000-0000-0000-0000-000000000035",
|
||||
"widgets": {
|
||||
"tasks": {
|
||||
"id": "00000000-0000-0000-0000-000000000037",
|
||||
"id": "00000000-0000-0000-0000-000000000036",
|
||||
},
|
||||
},
|
||||
},
|
||||
"timeline": {
|
||||
"id": "00000000-0000-0000-0000-000000000034",
|
||||
"id": "00000000-0000-0000-0000-000000000033",
|
||||
"widgets": {
|
||||
"timeline": {
|
||||
"id": "00000000-0000-0000-0000-000000000035",
|
||||
"id": "00000000-0000-0000-0000-000000000034",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"taskRecordPage": {
|
||||
"id": "00000000-0000-0000-0000-000000000074",
|
||||
"id": "00000000-0000-0000-0000-000000000073",
|
||||
"tabs": {
|
||||
"files": {
|
||||
"id": "00000000-0000-0000-0000-000000000083",
|
||||
"id": "00000000-0000-0000-0000-000000000081",
|
||||
"widgets": {
|
||||
"files": {
|
||||
"id": "00000000-0000-0000-0000-000000000084",
|
||||
"id": "00000000-0000-0000-0000-000000000082",
|
||||
},
|
||||
},
|
||||
},
|
||||
"home": {
|
||||
"id": "00000000-0000-0000-0000-000000000075",
|
||||
"id": "00000000-0000-0000-0000-000000000074",
|
||||
"widgets": {
|
||||
"assignee": {
|
||||
"id": "00000000-0000-0000-0000-000000000078",
|
||||
},
|
||||
"fields": {
|
||||
"id": "00000000-0000-0000-0000-000000000076",
|
||||
"id": "00000000-0000-0000-0000-000000000075",
|
||||
},
|
||||
"taskRichText": {
|
||||
"id": "00000000-0000-0000-0000-000000000077",
|
||||
"id": "00000000-0000-0000-0000-000000000076",
|
||||
},
|
||||
},
|
||||
},
|
||||
"note": {
|
||||
"id": "00000000-0000-0000-0000-000000000079",
|
||||
"id": "00000000-0000-0000-0000-000000000077",
|
||||
"widgets": {
|
||||
"taskRichText": {
|
||||
"id": "00000000-0000-0000-0000-000000000080",
|
||||
"id": "00000000-0000-0000-0000-000000000078",
|
||||
},
|
||||
},
|
||||
},
|
||||
"timeline": {
|
||||
"id": "00000000-0000-0000-0000-000000000081",
|
||||
"id": "00000000-0000-0000-0000-000000000079",
|
||||
"widgets": {
|
||||
"timeline": {
|
||||
"id": "00000000-0000-0000-0000-000000000082",
|
||||
"id": "00000000-0000-0000-0000-000000000080",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"workflowRecordPage": {
|
||||
"id": "00000000-0000-0000-0000-000000000085",
|
||||
"id": "00000000-0000-0000-0000-000000000083",
|
||||
"tabs": {
|
||||
"flow": {
|
||||
"id": "00000000-0000-0000-0000-000000000086",
|
||||
"id": "00000000-0000-0000-0000-000000000084",
|
||||
"widgets": {
|
||||
"workflow": {
|
||||
"id": "00000000-0000-0000-0000-000000000087",
|
||||
"id": "00000000-0000-0000-0000-000000000085",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"workflowRunRecordPage": {
|
||||
"id": "00000000-0000-0000-0000-000000000094",
|
||||
"id": "00000000-0000-0000-0000-000000000092",
|
||||
"tabs": {
|
||||
"flow": {
|
||||
"id": "00000000-0000-0000-0000-000000000098",
|
||||
"id": "00000000-0000-0000-0000-000000000096",
|
||||
"widgets": {
|
||||
"workflowRun": {
|
||||
"id": "00000000-0000-0000-0000-000000000099",
|
||||
"id": "00000000-0000-0000-0000-000000000097",
|
||||
},
|
||||
},
|
||||
},
|
||||
"home": {
|
||||
"id": "00000000-0000-0000-0000-000000000095",
|
||||
"id": "00000000-0000-0000-0000-000000000093",
|
||||
"widgets": {
|
||||
"fields": {
|
||||
"id": "00000000-0000-0000-0000-000000000096",
|
||||
"id": "00000000-0000-0000-0000-000000000094",
|
||||
},
|
||||
"workflow": {
|
||||
"id": "00000000-0000-0000-0000-000000000097",
|
||||
"id": "00000000-0000-0000-0000-000000000095",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"workflowVersionRecordPage": {
|
||||
"id": "00000000-0000-0000-0000-000000000088",
|
||||
"id": "00000000-0000-0000-0000-000000000086",
|
||||
"tabs": {
|
||||
"flow": {
|
||||
"id": "00000000-0000-0000-0000-000000000092",
|
||||
"id": "00000000-0000-0000-0000-000000000090",
|
||||
"widgets": {
|
||||
"workflowVersion": {
|
||||
"id": "00000000-0000-0000-0000-000000000093",
|
||||
"id": "00000000-0000-0000-0000-000000000091",
|
||||
},
|
||||
},
|
||||
},
|
||||
"home": {
|
||||
"id": "00000000-0000-0000-0000-000000000089",
|
||||
"id": "00000000-0000-0000-0000-000000000087",
|
||||
"widgets": {
|
||||
"fields": {
|
||||
"id": "00000000-0000-0000-0000-000000000090",
|
||||
"id": "00000000-0000-0000-0000-000000000088",
|
||||
},
|
||||
"workflow": {
|
||||
"id": "00000000-0000-0000-0000-000000000091",
|
||||
"id": "00000000-0000-0000-0000-000000000089",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
+1
-10
@@ -31,21 +31,12 @@ const COMPANY_PAGE_TABS = {
|
||||
fieldUniversalIdentifier:
|
||||
STANDARD_OBJECTS.company.fields.people.universalIdentifier,
|
||||
},
|
||||
accountOwner: {
|
||||
universalIdentifier: '20202020-ac01-4001-8001-c0aba11c0113',
|
||||
title: 'Account Owner',
|
||||
type: WidgetType.FIELD,
|
||||
gridPosition: GRID_POSITIONS.FULL_WIDTH,
|
||||
position: VERTICAL_LIST_LAYOUT_POSITIONS.THIRD,
|
||||
fieldUniversalIdentifier:
|
||||
STANDARD_OBJECTS.company.fields.accountOwner.universalIdentifier,
|
||||
},
|
||||
opportunities: {
|
||||
universalIdentifier: '20202020-ac01-4001-8001-c0aba11c0114',
|
||||
title: 'Opportunities',
|
||||
type: WidgetType.FIELD,
|
||||
gridPosition: GRID_POSITIONS.FULL_WIDTH,
|
||||
position: VERTICAL_LIST_LAYOUT_POSITIONS.FOURTH,
|
||||
position: VERTICAL_LIST_LAYOUT_POSITIONS.THIRD,
|
||||
fieldUniversalIdentifier:
|
||||
STANDARD_OBJECTS.company.fields.opportunities.universalIdentifier,
|
||||
},
|
||||
|
||||
-12
@@ -1,13 +1,10 @@
|
||||
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
|
||||
import { WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum';
|
||||
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
|
||||
import {
|
||||
CONDITIONAL_DISPLAY_DEVICE_DESKTOP,
|
||||
CONDITIONAL_DISPLAY_DEVICE_MOBILE,
|
||||
GRID_POSITIONS,
|
||||
TAB_PROPS,
|
||||
VERTICAL_LIST_LAYOUT_POSITIONS,
|
||||
WIDGET_PROPS,
|
||||
} from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout-tabs.template';
|
||||
import {
|
||||
@@ -32,15 +29,6 @@ const TASK_PAGE_TABS = {
|
||||
position: { layoutMode: TAB_PROPS.home.layoutMode, index: 1 },
|
||||
conditionalDisplay: CONDITIONAL_DISPLAY_DEVICE_MOBILE,
|
||||
},
|
||||
assignee: {
|
||||
universalIdentifier: '20202020-ac05-4005-8005-ba5ca11a5513',
|
||||
title: 'Assignee',
|
||||
type: WidgetType.FIELD,
|
||||
gridPosition: GRID_POSITIONS.FULL_WIDTH,
|
||||
position: VERTICAL_LIST_LAYOUT_POSITIONS.THIRD,
|
||||
fieldUniversalIdentifier:
|
||||
STANDARD_OBJECTS.task.fields.assignee.universalIdentifier,
|
||||
},
|
||||
},
|
||||
},
|
||||
note: {
|
||||
|
||||
-13
@@ -45,19 +45,6 @@ export const computeStandardBlocklistViewFields = (
|
||||
},
|
||||
}),
|
||||
|
||||
blocklistRecordPageFieldsHandle: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'blocklist',
|
||||
context: {
|
||||
viewName: 'blocklistRecordPageFields',
|
||||
viewFieldName: 'handle',
|
||||
fieldName: 'handle',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
blocklistRecordPageFieldsWorkspaceMember:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
|
||||
-13
@@ -81,19 +81,6 @@ export const computeStandardCalendarChannelViewFields = (
|
||||
},
|
||||
}),
|
||||
|
||||
calendarChannelRecordPageFieldsHandle: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'calendarChannel',
|
||||
context: {
|
||||
viewName: 'calendarChannelRecordPageFields',
|
||||
viewFieldName: 'handle',
|
||||
fieldName: 'handle',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
calendarChannelRecordPageFieldsConnectedAccount:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
|
||||
+118
@@ -245,5 +245,123 @@ export const computeStandardCompanyViewFields = (
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
companyRecordPageFieldsUpdatedAt: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'company',
|
||||
context: {
|
||||
viewName: 'companyRecordPageFields',
|
||||
viewFieldName: 'updatedAt',
|
||||
fieldName: 'updatedAt',
|
||||
position: 6,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
companyRecordPageFieldsUpdatedBy: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'company',
|
||||
context: {
|
||||
viewName: 'companyRecordPageFields',
|
||||
viewFieldName: 'updatedBy',
|
||||
fieldName: 'updatedBy',
|
||||
position: 7,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
companyRecordPageFieldsPeople: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'company',
|
||||
context: {
|
||||
viewName: 'companyRecordPageFields',
|
||||
viewFieldName: 'people',
|
||||
fieldName: 'people',
|
||||
position: 4,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
companyRecordPageFieldsTaskTargets: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'company',
|
||||
context: {
|
||||
viewName: 'companyRecordPageFields',
|
||||
viewFieldName: 'taskTargets',
|
||||
fieldName: 'taskTargets',
|
||||
position: 5,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
companyRecordPageFieldsNoteTargets: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'company',
|
||||
context: {
|
||||
viewName: 'companyRecordPageFields',
|
||||
viewFieldName: 'noteTargets',
|
||||
fieldName: 'noteTargets',
|
||||
position: 6,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
companyRecordPageFieldsOpportunities: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'company',
|
||||
context: {
|
||||
viewName: 'companyRecordPageFields',
|
||||
viewFieldName: 'opportunities',
|
||||
fieldName: 'opportunities',
|
||||
position: 7,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
companyRecordPageFieldsFavorites: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'company',
|
||||
context: {
|
||||
viewName: 'companyRecordPageFields',
|
||||
viewFieldName: 'favorites',
|
||||
fieldName: 'favorites',
|
||||
position: 8,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
companyRecordPageFieldsAttachments: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'company',
|
||||
context: {
|
||||
viewName: 'companyRecordPageFields',
|
||||
viewFieldName: 'attachments',
|
||||
fieldName: 'attachments',
|
||||
position: 9,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
companyRecordPageFieldsTimelineActivities:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'company',
|
||||
context: {
|
||||
viewName: 'companyRecordPageFields',
|
||||
viewFieldName: 'timelineActivities',
|
||||
fieldName: 'timelineActivities',
|
||||
position: 10,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
-15
@@ -69,21 +69,6 @@ export const computeStandardConnectedAccountViewFields = (
|
||||
},
|
||||
}),
|
||||
|
||||
connectedAccountRecordPageFieldsHandle: createStandardViewFieldFlatMetadata(
|
||||
{
|
||||
...args,
|
||||
objectName: 'connectedAccount',
|
||||
context: {
|
||||
viewName: 'connectedAccountRecordPageFields',
|
||||
viewFieldName: 'handle',
|
||||
fieldName: 'handle',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
},
|
||||
),
|
||||
connectedAccountRecordPageFieldsProvider:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
|
||||
-13
@@ -33,19 +33,6 @@ export const computeStandardFavoriteFolderViewFields = (
|
||||
},
|
||||
}),
|
||||
|
||||
favoriteFolderRecordPageFieldsName: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'favoriteFolder',
|
||||
context: {
|
||||
viewName: 'favoriteFolderRecordPageFields',
|
||||
viewFieldName: 'name',
|
||||
fieldName: 'name',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
favoriteFolderRecordPageFieldsCreatedAt:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
|
||||
-13
@@ -93,19 +93,6 @@ export const computeStandardMessageChannelViewFields = (
|
||||
},
|
||||
}),
|
||||
|
||||
messageChannelRecordPageFieldsHandle: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageChannel',
|
||||
context: {
|
||||
viewName: 'messageChannelRecordPageFields',
|
||||
viewFieldName: 'handle',
|
||||
fieldName: 'handle',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
messageChannelRecordPageFieldsConnectedAccount:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
|
||||
-13
@@ -69,19 +69,6 @@ export const computeStandardMessageFolderViewFields = (
|
||||
},
|
||||
}),
|
||||
|
||||
messageFolderRecordPageFieldsName: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageFolder',
|
||||
context: {
|
||||
viewName: 'messageFolderRecordPageFields',
|
||||
viewFieldName: 'name',
|
||||
fieldName: 'name',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
messageFolderRecordPageFieldsMessageChannel:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
|
||||
-14
@@ -93,20 +93,6 @@ export const computeStandardMessageParticipantViewFields = (
|
||||
},
|
||||
}),
|
||||
|
||||
messageParticipantRecordPageFieldsHandle:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'messageParticipant',
|
||||
context: {
|
||||
viewName: 'messageParticipantRecordPageFields',
|
||||
viewFieldName: 'handle',
|
||||
fieldName: 'handle',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
messageParticipantRecordPageFieldsMessage:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
|
||||
+80
-13
@@ -70,19 +70,6 @@ export const computeStandardNoteViewFields = (
|
||||
}),
|
||||
|
||||
// noteRecordPageFields view fields
|
||||
noteRecordPageFieldsTitle: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'note',
|
||||
context: {
|
||||
viewName: 'noteRecordPageFields',
|
||||
viewFieldName: 'title',
|
||||
fieldName: 'title',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
noteRecordPageFieldsNoteTargets: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'note',
|
||||
@@ -122,5 +109,85 @@ export const computeStandardNoteViewFields = (
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
noteRecordPageFieldsBodyV2: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'note',
|
||||
context: {
|
||||
viewName: 'noteRecordPageFields',
|
||||
viewFieldName: 'bodyV2',
|
||||
fieldName: 'bodyV2',
|
||||
position: 0,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'additional',
|
||||
},
|
||||
}),
|
||||
noteRecordPageFieldsUpdatedAt: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'note',
|
||||
context: {
|
||||
viewName: 'noteRecordPageFields',
|
||||
viewFieldName: 'updatedAt',
|
||||
fieldName: 'updatedAt',
|
||||
position: 2,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
noteRecordPageFieldsUpdatedBy: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'note',
|
||||
context: {
|
||||
viewName: 'noteRecordPageFields',
|
||||
viewFieldName: 'updatedBy',
|
||||
fieldName: 'updatedBy',
|
||||
position: 3,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
noteRecordPageFieldsAttachments: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'note',
|
||||
context: {
|
||||
viewName: 'noteRecordPageFields',
|
||||
viewFieldName: 'attachments',
|
||||
fieldName: 'attachments',
|
||||
position: 2,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
noteRecordPageFieldsTimelineActivities: createStandardViewFieldFlatMetadata(
|
||||
{
|
||||
...args,
|
||||
objectName: 'note',
|
||||
context: {
|
||||
viewName: 'noteRecordPageFields',
|
||||
viewFieldName: 'timelineActivities',
|
||||
fieldName: 'timelineActivities',
|
||||
position: 3,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
},
|
||||
),
|
||||
noteRecordPageFieldsFavorites: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'note',
|
||||
context: {
|
||||
viewName: 'noteRecordPageFields',
|
||||
viewFieldName: 'favorites',
|
||||
fieldName: 'favorites',
|
||||
position: 4,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
+98
@@ -266,5 +266,103 @@ export const computeStandardOpportunityViewFields = (
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
opportunityRecordPageFieldsUpdatedAt: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'opportunity',
|
||||
context: {
|
||||
viewName: 'opportunityRecordPageFields',
|
||||
viewFieldName: 'updatedAt',
|
||||
fieldName: 'updatedAt',
|
||||
position: 2,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
opportunityRecordPageFieldsUpdatedBy: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'opportunity',
|
||||
context: {
|
||||
viewName: 'opportunityRecordPageFields',
|
||||
viewFieldName: 'updatedBy',
|
||||
fieldName: 'updatedBy',
|
||||
position: 3,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
opportunityRecordPageFieldsFavorites: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'opportunity',
|
||||
context: {
|
||||
viewName: 'opportunityRecordPageFields',
|
||||
viewFieldName: 'favorites',
|
||||
fieldName: 'favorites',
|
||||
position: 5,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
opportunityRecordPageFieldsTaskTargets: createStandardViewFieldFlatMetadata(
|
||||
{
|
||||
...args,
|
||||
objectName: 'opportunity',
|
||||
context: {
|
||||
viewName: 'opportunityRecordPageFields',
|
||||
viewFieldName: 'taskTargets',
|
||||
fieldName: 'taskTargets',
|
||||
position: 6,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
},
|
||||
),
|
||||
opportunityRecordPageFieldsNoteTargets: createStandardViewFieldFlatMetadata(
|
||||
{
|
||||
...args,
|
||||
objectName: 'opportunity',
|
||||
context: {
|
||||
viewName: 'opportunityRecordPageFields',
|
||||
viewFieldName: 'noteTargets',
|
||||
fieldName: 'noteTargets',
|
||||
position: 7,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
},
|
||||
),
|
||||
opportunityRecordPageFieldsAttachments: createStandardViewFieldFlatMetadata(
|
||||
{
|
||||
...args,
|
||||
objectName: 'opportunity',
|
||||
context: {
|
||||
viewName: 'opportunityRecordPageFields',
|
||||
viewFieldName: 'attachments',
|
||||
fieldName: 'attachments',
|
||||
position: 8,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
},
|
||||
),
|
||||
opportunityRecordPageFieldsTimelineActivities:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'opportunity',
|
||||
context: {
|
||||
viewName: 'opportunityRecordPageFields',
|
||||
viewFieldName: 'timelineActivities',
|
||||
fieldName: 'timelineActivities',
|
||||
position: 9,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
+147
@@ -266,5 +266,152 @@ export const computeStandardPersonViewFields = (
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
personRecordPageFieldsUpdatedAt: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'person',
|
||||
context: {
|
||||
viewName: 'personRecordPageFields',
|
||||
viewFieldName: 'updatedAt',
|
||||
fieldName: 'updatedAt',
|
||||
position: 4,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
personRecordPageFieldsUpdatedBy: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'person',
|
||||
context: {
|
||||
viewName: 'personRecordPageFields',
|
||||
viewFieldName: 'updatedBy',
|
||||
fieldName: 'updatedBy',
|
||||
position: 5,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
personRecordPageFieldsAvatarFile: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'person',
|
||||
context: {
|
||||
viewName: 'personRecordPageFields',
|
||||
viewFieldName: 'avatarFile',
|
||||
fieldName: 'avatarFile',
|
||||
position: 0,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'additional',
|
||||
},
|
||||
}),
|
||||
personRecordPageFieldsPointOfContactForOpportunities:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'person',
|
||||
context: {
|
||||
viewName: 'personRecordPageFields',
|
||||
viewFieldName: 'pointOfContactForOpportunities',
|
||||
fieldName: 'pointOfContactForOpportunities',
|
||||
position: 5,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
personRecordPageFieldsTaskTargets: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'person',
|
||||
context: {
|
||||
viewName: 'personRecordPageFields',
|
||||
viewFieldName: 'taskTargets',
|
||||
fieldName: 'taskTargets',
|
||||
position: 6,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
personRecordPageFieldsNoteTargets: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'person',
|
||||
context: {
|
||||
viewName: 'personRecordPageFields',
|
||||
viewFieldName: 'noteTargets',
|
||||
fieldName: 'noteTargets',
|
||||
position: 7,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
personRecordPageFieldsFavorites: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'person',
|
||||
context: {
|
||||
viewName: 'personRecordPageFields',
|
||||
viewFieldName: 'favorites',
|
||||
fieldName: 'favorites',
|
||||
position: 8,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
personRecordPageFieldsAttachments: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'person',
|
||||
context: {
|
||||
viewName: 'personRecordPageFields',
|
||||
viewFieldName: 'attachments',
|
||||
fieldName: 'attachments',
|
||||
position: 9,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
personRecordPageFieldsMessageParticipants:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'person',
|
||||
context: {
|
||||
viewName: 'personRecordPageFields',
|
||||
viewFieldName: 'messageParticipants',
|
||||
fieldName: 'messageParticipants',
|
||||
position: 10,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
personRecordPageFieldsCalendarEventParticipants:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'person',
|
||||
context: {
|
||||
viewName: 'personRecordPageFields',
|
||||
viewFieldName: 'calendarEventParticipants',
|
||||
fieldName: 'calendarEventParticipants',
|
||||
position: 11,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
personRecordPageFieldsTimelineActivities:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'person',
|
||||
context: {
|
||||
viewName: 'personRecordPageFields',
|
||||
viewFieldName: 'timelineActivities',
|
||||
fieldName: 'timelineActivities',
|
||||
position: 12,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
+80
-13
@@ -255,19 +255,6 @@ export const computeStandardTaskViewFields = (
|
||||
}),
|
||||
|
||||
// taskRecordPageFields view fields
|
||||
taskRecordPageFieldsTitle: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'task',
|
||||
context: {
|
||||
viewName: 'taskRecordPageFields',
|
||||
viewFieldName: 'title',
|
||||
fieldName: 'title',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
taskRecordPageFieldsDueAt: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'task',
|
||||
@@ -346,5 +333,85 @@ export const computeStandardTaskViewFields = (
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
taskRecordPageFieldsBodyV2: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'task',
|
||||
context: {
|
||||
viewName: 'taskRecordPageFields',
|
||||
viewFieldName: 'bodyV2',
|
||||
fieldName: 'bodyV2',
|
||||
position: 0,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'additional',
|
||||
},
|
||||
}),
|
||||
taskRecordPageFieldsUpdatedAt: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'task',
|
||||
context: {
|
||||
viewName: 'taskRecordPageFields',
|
||||
viewFieldName: 'updatedAt',
|
||||
fieldName: 'updatedAt',
|
||||
position: 2,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
taskRecordPageFieldsUpdatedBy: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'task',
|
||||
context: {
|
||||
viewName: 'taskRecordPageFields',
|
||||
viewFieldName: 'updatedBy',
|
||||
fieldName: 'updatedBy',
|
||||
position: 3,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
taskRecordPageFieldsAttachments: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'task',
|
||||
context: {
|
||||
viewName: 'taskRecordPageFields',
|
||||
viewFieldName: 'attachments',
|
||||
fieldName: 'attachments',
|
||||
position: 5,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
taskRecordPageFieldsTimelineActivities: createStandardViewFieldFlatMetadata(
|
||||
{
|
||||
...args,
|
||||
objectName: 'task',
|
||||
context: {
|
||||
viewName: 'taskRecordPageFields',
|
||||
viewFieldName: 'timelineActivities',
|
||||
fieldName: 'timelineActivities',
|
||||
position: 6,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
},
|
||||
),
|
||||
taskRecordPageFieldsFavorites: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'task',
|
||||
context: {
|
||||
viewName: 'taskRecordPageFields',
|
||||
viewFieldName: 'favorites',
|
||||
fieldName: 'favorites',
|
||||
position: 7,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
+105
-13
@@ -46,19 +46,6 @@ export const computeStandardWorkflowRunViewFields = (
|
||||
}),
|
||||
|
||||
// workflowRunRecordPageFields view fields
|
||||
workflowRunRecordPageFieldsName: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowRun',
|
||||
context: {
|
||||
viewName: 'workflowRunRecordPageFields',
|
||||
viewFieldName: 'name',
|
||||
fieldName: 'name',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
workflowRunRecordPageFieldsStatus: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowRun',
|
||||
@@ -151,5 +138,110 @@ export const computeStandardWorkflowRunViewFields = (
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
workflowRunRecordPageFieldsEnqueuedAt: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowRun',
|
||||
context: {
|
||||
viewName: 'workflowRunRecordPageFields',
|
||||
viewFieldName: 'enqueuedAt',
|
||||
fieldName: 'enqueuedAt',
|
||||
position: 0,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'additional',
|
||||
},
|
||||
}),
|
||||
workflowRunRecordPageFieldsOutput: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowRun',
|
||||
context: {
|
||||
viewName: 'workflowRunRecordPageFields',
|
||||
viewFieldName: 'output',
|
||||
fieldName: 'output',
|
||||
position: 6,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
workflowRunRecordPageFieldsContext: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowRun',
|
||||
context: {
|
||||
viewName: 'workflowRunRecordPageFields',
|
||||
viewFieldName: 'context',
|
||||
fieldName: 'context',
|
||||
position: 7,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
workflowRunRecordPageFieldsState: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowRun',
|
||||
context: {
|
||||
viewName: 'workflowRunRecordPageFields',
|
||||
viewFieldName: 'state',
|
||||
fieldName: 'state',
|
||||
position: 8,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
workflowRunRecordPageFieldsUpdatedAt: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowRun',
|
||||
context: {
|
||||
viewName: 'workflowRunRecordPageFields',
|
||||
viewFieldName: 'updatedAt',
|
||||
fieldName: 'updatedAt',
|
||||
position: 2,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
workflowRunRecordPageFieldsUpdatedBy: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowRun',
|
||||
context: {
|
||||
viewName: 'workflowRunRecordPageFields',
|
||||
viewFieldName: 'updatedBy',
|
||||
fieldName: 'updatedBy',
|
||||
position: 3,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
workflowRunRecordPageFieldsFavorites: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowRun',
|
||||
context: {
|
||||
viewName: 'workflowRunRecordPageFields',
|
||||
viewFieldName: 'favorites',
|
||||
fieldName: 'favorites',
|
||||
position: 9,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
workflowRunRecordPageFieldsTimelineActivities:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowRun',
|
||||
context: {
|
||||
viewName: 'workflowRunRecordPageFields',
|
||||
viewFieldName: 'timelineActivities',
|
||||
fieldName: 'timelineActivities',
|
||||
position: 10,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
+96
-13
@@ -70,19 +70,6 @@ export const computeStandardWorkflowVersionViewFields = (
|
||||
}),
|
||||
|
||||
// workflowVersionRecordPageFields view fields
|
||||
workflowVersionRecordPageFieldsName: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowVersion',
|
||||
context: {
|
||||
viewName: 'workflowVersionRecordPageFields',
|
||||
viewFieldName: 'name',
|
||||
fieldName: 'name',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
workflowVersionRecordPageFieldsStatus: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowVersion',
|
||||
@@ -139,5 +126,101 @@ export const computeStandardWorkflowVersionViewFields = (
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
workflowVersionRecordPageFieldsSteps: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowVersion',
|
||||
context: {
|
||||
viewName: 'workflowVersionRecordPageFields',
|
||||
viewFieldName: 'steps',
|
||||
fieldName: 'steps',
|
||||
position: 0,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'additional',
|
||||
},
|
||||
}),
|
||||
workflowVersionRecordPageFieldsCreatedBy:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowVersion',
|
||||
context: {
|
||||
viewName: 'workflowVersionRecordPageFields',
|
||||
viewFieldName: 'createdBy',
|
||||
fieldName: 'createdBy',
|
||||
position: 1,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
workflowVersionRecordPageFieldsUpdatedAt:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowVersion',
|
||||
context: {
|
||||
viewName: 'workflowVersionRecordPageFields',
|
||||
viewFieldName: 'updatedAt',
|
||||
fieldName: 'updatedAt',
|
||||
position: 2,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
workflowVersionRecordPageFieldsUpdatedBy:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowVersion',
|
||||
context: {
|
||||
viewName: 'workflowVersionRecordPageFields',
|
||||
viewFieldName: 'updatedBy',
|
||||
fieldName: 'updatedBy',
|
||||
position: 3,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'other',
|
||||
},
|
||||
}),
|
||||
workflowVersionRecordPageFieldsRuns: createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowVersion',
|
||||
context: {
|
||||
viewName: 'workflowVersionRecordPageFields',
|
||||
viewFieldName: 'runs',
|
||||
fieldName: 'runs',
|
||||
position: 4,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
workflowVersionRecordPageFieldsFavorites:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowVersion',
|
||||
context: {
|
||||
viewName: 'workflowVersionRecordPageFields',
|
||||
viewFieldName: 'favorites',
|
||||
fieldName: 'favorites',
|
||||
position: 5,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
workflowVersionRecordPageFieldsTimelineActivities:
|
||||
createStandardViewFieldFlatMetadata({
|
||||
...args,
|
||||
objectName: 'workflowVersion',
|
||||
context: {
|
||||
viewName: 'workflowVersionRecordPageFields',
|
||||
viewFieldName: 'timelineActivities',
|
||||
fieldName: 'timelineActivities',
|
||||
position: 6,
|
||||
isVisible: false,
|
||||
size: 150,
|
||||
viewFieldGroupName: 'general',
|
||||
},
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
+18
-6
@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { msg, t } from '@lingui/core/macro';
|
||||
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
|
||||
import { ViewType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
|
||||
@@ -95,8 +96,9 @@ export class FlatViewFieldValidatorService {
|
||||
}
|
||||
|
||||
if (
|
||||
flatView.type !== ViewType.FIELDS_WIDGET &&
|
||||
flatObjectMetadata.labelIdentifierFieldMetadataUniversalIdentifier ===
|
||||
updatedFlatViewField.fieldMetadataUniversalIdentifier
|
||||
updatedFlatViewField.fieldMetadataUniversalIdentifier
|
||||
) {
|
||||
const otherFlatViewFields =
|
||||
findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow(
|
||||
@@ -127,6 +129,7 @@ export class FlatViewFieldValidatorService {
|
||||
flatViewFieldMaps: optimisticFlatViewFieldMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatViewMaps,
|
||||
},
|
||||
}: UniversalFlatEntityValidationArgs<
|
||||
typeof ALL_METADATA_NAME.viewField
|
||||
@@ -177,11 +180,18 @@ export class FlatViewFieldValidatorService {
|
||||
flatObjectMetadata.labelIdentifierFieldMetadataUniversalIdentifier ===
|
||||
existingFlatViewField.fieldMetadataUniversalIdentifier
|
||||
) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Label identifier view field cannot be deleted`,
|
||||
userFriendlyMessage: msg`Label identifier view field cannot be deleted`,
|
||||
const flatView = findFlatEntityByUniversalIdentifier({
|
||||
universalIdentifier: existingFlatViewField.viewUniversalIdentifier,
|
||||
flatEntityMaps: flatViewMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(flatView) || flatView.type !== ViewType.FIELDS_WIDGET) {
|
||||
validationResult.errors.push({
|
||||
code: ViewExceptionCode.INVALID_VIEW_DATA,
|
||||
message: t`Label identifier view field cannot be deleted`,
|
||||
userFriendlyMessage: msg`Label identifier view field cannot be deleted`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return validationResult;
|
||||
@@ -289,8 +299,9 @@ export class FlatViewFieldValidatorService {
|
||||
}
|
||||
|
||||
if (
|
||||
flatView.type !== ViewType.FIELDS_WIDGET &&
|
||||
flatObjectMetadata.labelIdentifierFieldMetadataUniversalIdentifier ===
|
||||
flatViewFieldToValidate.fieldMetadataUniversalIdentifier
|
||||
flatViewFieldToValidate.fieldMetadataUniversalIdentifier
|
||||
) {
|
||||
validationResult.errors.push(
|
||||
...validateLabelIdentifierFieldMetadataIdFlatViewField({
|
||||
@@ -299,6 +310,7 @@ export class FlatViewFieldValidatorService {
|
||||
}),
|
||||
);
|
||||
} else if (
|
||||
flatView.type !== ViewType.FIELDS_WIDGET &&
|
||||
otherFlatViewFields.some(
|
||||
(flatViewField) =>
|
||||
flatViewField.fieldMetadataUniversalIdentifier ===
|
||||
|
||||
+45
-1695
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -93,6 +93,6 @@ describe('View side effect on object creation', () => {
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
expect(createdViewFields.length).toBe(7);
|
||||
expect(createdViewFields.length).toBe(5);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -188,9 +188,6 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
viewFields: {
|
||||
handle: {
|
||||
universalIdentifier: 'e22a1d19-c1bb-4265-ae48-2054513c21fe',
|
||||
},
|
||||
workspaceMember: {
|
||||
universalIdentifier: 'f2f5732f-7435-44be-986b-4c4d834fdfeb',
|
||||
},
|
||||
@@ -405,9 +402,6 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
viewFields: {
|
||||
handle: {
|
||||
universalIdentifier: 'cd1f641b-5746-49db-9a7e-82dd9a63593d',
|
||||
},
|
||||
connectedAccount: {
|
||||
universalIdentifier: 'bdb40f41-f9ba-4b59-a8cf-878c23701ab3',
|
||||
},
|
||||
@@ -808,6 +802,33 @@ export const STANDARD_OBJECTS = {
|
||||
createdBy: {
|
||||
universalIdentifier: '20202020-af01-4a01-8a01-c0aba11c1210',
|
||||
},
|
||||
updatedAt: {
|
||||
universalIdentifier: '20202020-af01-4a01-8a01-c0aba11c1212',
|
||||
},
|
||||
updatedBy: {
|
||||
universalIdentifier: '20202020-af01-4a01-8a01-c0aba11c1213',
|
||||
},
|
||||
people: {
|
||||
universalIdentifier: '20202020-af01-4a01-8a01-c0aba11c1214',
|
||||
},
|
||||
taskTargets: {
|
||||
universalIdentifier: '20202020-af01-4a01-8a01-c0aba11c1215',
|
||||
},
|
||||
noteTargets: {
|
||||
universalIdentifier: '20202020-af01-4a01-8a01-c0aba11c1216',
|
||||
},
|
||||
opportunities: {
|
||||
universalIdentifier: '20202020-af01-4a01-8a01-c0aba11c1217',
|
||||
},
|
||||
favorites: {
|
||||
universalIdentifier: '20202020-af01-4a01-8a01-c0aba11c1218',
|
||||
},
|
||||
attachments: {
|
||||
universalIdentifier: '20202020-af01-4a01-8a01-c0aba11c1219',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-af01-4a01-8a01-c0aba11c121a',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -914,9 +935,6 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
viewFields: {
|
||||
handle: {
|
||||
universalIdentifier: '41d86e23-ceb2-41ab-975f-8ec5a1023ece',
|
||||
},
|
||||
provider: {
|
||||
universalIdentifier: '83171d2a-0d11-42b1-991d-8d4346b02cff',
|
||||
},
|
||||
@@ -1213,9 +1231,6 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
viewFields: {
|
||||
name: {
|
||||
universalIdentifier: 'cac4f0f7-3a6a-49b1-b86f-41b20f2455c0',
|
||||
},
|
||||
createdAt: {
|
||||
universalIdentifier: 'a4e42591-844c-47d1-b72e-5ded3d541694',
|
||||
},
|
||||
@@ -1554,9 +1569,6 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
viewFields: {
|
||||
handle: {
|
||||
universalIdentifier: 'a9cbb9a5-a6b4-417e-93ad-a5e578c222db',
|
||||
},
|
||||
connectedAccount: {
|
||||
universalIdentifier: '19079cf6-2a9c-40b9-b6c2-58d63c6e37ad',
|
||||
},
|
||||
@@ -1670,9 +1682,6 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
viewFields: {
|
||||
name: {
|
||||
universalIdentifier: '6fa8c474-ee22-47f1-b830-4f169ff82315',
|
||||
},
|
||||
messageChannel: {
|
||||
universalIdentifier: '2fb6ff09-bed5-4b31-af0f-7fa3df5612da',
|
||||
},
|
||||
@@ -1791,9 +1800,6 @@ export const STANDARD_OBJECTS = {
|
||||
role: {
|
||||
universalIdentifier: '5d1f9a65-85cc-41b2-a8bf-8e2c97aab4b3',
|
||||
},
|
||||
handle: {
|
||||
universalIdentifier: '97295fc0-cdb8-4d84-8c1b-327837255c0d',
|
||||
},
|
||||
displayName: {
|
||||
universalIdentifier: 'c50748fe-9f54-4e09-b572-111f076ec7db',
|
||||
},
|
||||
@@ -2018,9 +2024,6 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
viewFields: {
|
||||
title: {
|
||||
universalIdentifier: '20202020-af05-4a05-8a05-a0be5a115201',
|
||||
},
|
||||
createdAt: {
|
||||
universalIdentifier: '20202020-af05-4a05-8a05-a0be5a115202',
|
||||
},
|
||||
@@ -2030,6 +2033,24 @@ export const STANDARD_OBJECTS = {
|
||||
noteTargets: {
|
||||
universalIdentifier: '20202020-af05-4a05-8a05-a0be5a115204',
|
||||
},
|
||||
bodyV2: {
|
||||
universalIdentifier: '20202020-af05-4a05-8a05-a0be5a115205',
|
||||
},
|
||||
updatedAt: {
|
||||
universalIdentifier: '20202020-af05-4a05-8a05-a0be5a115206',
|
||||
},
|
||||
updatedBy: {
|
||||
universalIdentifier: '20202020-af05-4a05-8a05-a0be5a115207',
|
||||
},
|
||||
attachments: {
|
||||
universalIdentifier: '20202020-af05-4a05-8a05-a0be5a115208',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-af05-4a05-8a05-a0be5a115209',
|
||||
},
|
||||
favorites: {
|
||||
universalIdentifier: '20202020-af05-4a05-8a05-a0be5a11520a',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2278,6 +2299,27 @@ export const STANDARD_OBJECTS = {
|
||||
createdBy: {
|
||||
universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca3208',
|
||||
},
|
||||
updatedAt: {
|
||||
universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca320a',
|
||||
},
|
||||
updatedBy: {
|
||||
universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca320b',
|
||||
},
|
||||
favorites: {
|
||||
universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca320c',
|
||||
},
|
||||
taskTargets: {
|
||||
universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca320d',
|
||||
},
|
||||
noteTargets: {
|
||||
universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca320e',
|
||||
},
|
||||
attachments: {
|
||||
universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca320f',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca3210',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2437,6 +2479,39 @@ export const STANDARD_OBJECTS = {
|
||||
createdBy: {
|
||||
universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea12210',
|
||||
},
|
||||
updatedAt: {
|
||||
universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea12212',
|
||||
},
|
||||
updatedBy: {
|
||||
universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea12213',
|
||||
},
|
||||
avatarFile: {
|
||||
universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea12214',
|
||||
},
|
||||
pointOfContactForOpportunities: {
|
||||
universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea12215',
|
||||
},
|
||||
taskTargets: {
|
||||
universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea12216',
|
||||
},
|
||||
noteTargets: {
|
||||
universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea12217',
|
||||
},
|
||||
favorites: {
|
||||
universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea12218',
|
||||
},
|
||||
attachments: {
|
||||
universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea12219',
|
||||
},
|
||||
messageParticipants: {
|
||||
universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea1221a',
|
||||
},
|
||||
calendarEventParticipants: {
|
||||
universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea1221b',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea1221c',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2610,9 +2685,6 @@ export const STANDARD_OBJECTS = {
|
||||
},
|
||||
},
|
||||
viewFields: {
|
||||
title: {
|
||||
universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a6201',
|
||||
},
|
||||
dueAt: {
|
||||
universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a6202',
|
||||
},
|
||||
@@ -2631,6 +2703,24 @@ export const STANDARD_OBJECTS = {
|
||||
taskTargets: {
|
||||
universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a6207',
|
||||
},
|
||||
bodyV2: {
|
||||
universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a6208',
|
||||
},
|
||||
updatedAt: {
|
||||
universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a6209',
|
||||
},
|
||||
updatedBy: {
|
||||
universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a620a',
|
||||
},
|
||||
attachments: {
|
||||
universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a620b',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a620c',
|
||||
},
|
||||
favorites: {
|
||||
universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a620d',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -3114,9 +3204,6 @@ export const STANDARD_OBJECTS = {
|
||||
workflowRunRecordPageFields: {
|
||||
universalIdentifier: '20202020-a011-4a11-8a11-a0bcf10abcf1',
|
||||
viewFields: {
|
||||
name: {
|
||||
universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abcf5',
|
||||
},
|
||||
status: {
|
||||
universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abcf6',
|
||||
},
|
||||
@@ -3138,6 +3225,30 @@ export const STANDARD_OBJECTS = {
|
||||
createdBy: {
|
||||
universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abcfc',
|
||||
},
|
||||
enqueuedAt: {
|
||||
universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abcfd',
|
||||
},
|
||||
output: {
|
||||
universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abcfe',
|
||||
},
|
||||
context: {
|
||||
universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abcff',
|
||||
},
|
||||
state: {
|
||||
universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abd01',
|
||||
},
|
||||
updatedAt: {
|
||||
universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abd02',
|
||||
},
|
||||
updatedBy: {
|
||||
universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abd03',
|
||||
},
|
||||
favorites: {
|
||||
universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abd04',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abd05',
|
||||
},
|
||||
},
|
||||
viewFieldGroups: {
|
||||
general: {
|
||||
@@ -3229,9 +3340,6 @@ export const STANDARD_OBJECTS = {
|
||||
workflowVersionRecordPageFields: {
|
||||
universalIdentifier: '20202020-a010-4a10-8a10-a0bcf10aaef1',
|
||||
viewFields: {
|
||||
name: {
|
||||
universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaef5',
|
||||
},
|
||||
status: {
|
||||
universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaef6',
|
||||
},
|
||||
@@ -3244,6 +3352,27 @@ export const STANDARD_OBJECTS = {
|
||||
createdAt: {
|
||||
universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaef9',
|
||||
},
|
||||
steps: {
|
||||
universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaefa',
|
||||
},
|
||||
createdBy: {
|
||||
universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaefb',
|
||||
},
|
||||
updatedAt: {
|
||||
universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaefc',
|
||||
},
|
||||
updatedBy: {
|
||||
universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaefd',
|
||||
},
|
||||
runs: {
|
||||
universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaefe',
|
||||
},
|
||||
favorites: {
|
||||
universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaeff',
|
||||
},
|
||||
timelineActivities: {
|
||||
universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaf01',
|
||||
},
|
||||
},
|
||||
viewFieldGroups: {
|
||||
general: {
|
||||
|
||||
Reference in New Issue
Block a user