Pagelayout backfill command standard app (#19380)
## Context Due to the chosen strategy for "Reset to default" feature for page layouts. Those overridable entities need to be associated to the Standard app to work properly (there is no "Default" state for custom entities). Until we find a better implementation, I'm changing the backfill command to reflect that
This commit is contained in:
+36
-79
@@ -128,7 +128,7 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
return;
|
||||
}
|
||||
|
||||
const { twentyStandardFlatApplication, workspaceCustomFlatApplication } =
|
||||
const { twentyStandardFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
);
|
||||
@@ -140,13 +140,12 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
|
||||
await this.backfillCustomObjectPageLayouts({
|
||||
workspaceId,
|
||||
workspaceCustomFlatApplication,
|
||||
twentyStandardFlatApplication,
|
||||
});
|
||||
|
||||
await this.backfillFieldWidgets({
|
||||
workspaceId,
|
||||
twentyStandardFlatApplication,
|
||||
workspaceCustomFlatApplication,
|
||||
});
|
||||
|
||||
await this.featureFlagService.enableFeatureFlags(
|
||||
@@ -403,10 +402,10 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
|
||||
private async backfillCustomObjectPageLayouts({
|
||||
workspaceId,
|
||||
workspaceCustomFlatApplication,
|
||||
twentyStandardFlatApplication,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
workspaceCustomFlatApplication: FlatApplication;
|
||||
twentyStandardFlatApplication: FlatApplication;
|
||||
}): Promise<void> {
|
||||
const {
|
||||
flatObjectMetadataMaps,
|
||||
@@ -464,7 +463,7 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
for (const customObject of customObjectsWithoutPageLayout) {
|
||||
const flatRecordPageFieldsView = computeFlatRecordPageFieldsViewToCreate({
|
||||
objectMetadata: customObject,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
flatApplication: twentyStandardFlatApplication,
|
||||
});
|
||||
|
||||
const objectFieldMetadatas = Object.values(
|
||||
@@ -476,7 +475,7 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
const viewFields = computeFlatViewFieldsToCreate({
|
||||
objectFlatFieldMetadatas: objectFieldMetadatas,
|
||||
viewUniversalIdentifier: flatRecordPageFieldsView.universalIdentifier,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
flatApplication: twentyStandardFlatApplication,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
customObject.labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
excludeLabelIdentifier: true,
|
||||
@@ -485,7 +484,7 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
const { pageLayouts, pageLayoutTabs, pageLayoutWidgets } =
|
||||
computeFlatDefaultRecordPageLayoutToCreate({
|
||||
objectMetadata: customObject,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
flatApplication: twentyStandardFlatApplication,
|
||||
recordPageFieldsView: flatRecordPageFieldsView,
|
||||
workspaceId,
|
||||
});
|
||||
@@ -529,7 +528,7 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -550,11 +549,9 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
private async backfillFieldWidgets({
|
||||
workspaceId,
|
||||
twentyStandardFlatApplication,
|
||||
workspaceCustomFlatApplication,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
twentyStandardFlatApplication: FlatApplication;
|
||||
workspaceCustomFlatApplication: FlatApplication;
|
||||
}): Promise<void> {
|
||||
const {
|
||||
flatObjectMetadataMaps,
|
||||
@@ -675,8 +672,7 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
const standardWidgetsToCreate: FlatPageLayoutWidget[] = [];
|
||||
const customWidgetsToCreate: FlatPageLayoutWidget[] = [];
|
||||
const widgetsToCreate: FlatPageLayoutWidget[] = [];
|
||||
const processedMorphIds = new Set<string>();
|
||||
|
||||
for (const object of objectById.values()) {
|
||||
@@ -692,14 +688,6 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
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;
|
||||
|
||||
@@ -758,8 +746,9 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
const widget: FlatPageLayoutWidget = {
|
||||
id: v4(),
|
||||
universalIdentifier: v4(),
|
||||
applicationId: flatApplication.id,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
applicationId: twentyStandardFlatApplication.id,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
workspaceId,
|
||||
pageLayoutTabId: homeTab.id,
|
||||
pageLayoutTabUniversalIdentifier: homeTab.universalIdentifier,
|
||||
@@ -790,16 +779,13 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
overrides: null,
|
||||
};
|
||||
|
||||
targetList.push(widget);
|
||||
widgetsToCreate.push(widget);
|
||||
existingFieldWidgetFieldIds.add(field.id);
|
||||
nextWidgetIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
const totalWidgets =
|
||||
standardWidgetsToCreate.length + customWidgetsToCreate.length;
|
||||
|
||||
if (totalWidgets === 0) {
|
||||
if (widgetsToCreate.length === 0) {
|
||||
this.logger.log(
|
||||
`All FIELD widgets already exist for workspace ${workspaceId}, skipping`,
|
||||
);
|
||||
@@ -808,65 +794,36 @@ export class BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand extends ActiveO
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Found ${totalWidgets} FIELD widget(s) to create for workspace ${workspaceId} (${standardWidgetsToCreate.length} standard, ${customWidgetsToCreate.length} custom)`,
|
||||
`Found ${widgetsToCreate.length} FIELD widget(s) to create for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
if (standardWidgetsToCreate.length > 0) {
|
||||
const result =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: standardWidgetsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
const result =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: widgetsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
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}`,
|
||||
);
|
||||
}
|
||||
if (result.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to create FIELD widgets:\n${JSON.stringify(result, null, 2)}`,
|
||||
);
|
||||
throw new Error(
|
||||
`Failed to create FIELD widgets for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Successfully created ${totalWidgets} FIELD widget(s) for workspace ${workspaceId}`,
|
||||
`Successfully created ${widgetsToCreate.length} FIELD widget(s) for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+78
-75
@@ -49,7 +49,6 @@ import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
|
||||
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
|
||||
import { 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';
|
||||
|
||||
@Injectable()
|
||||
@@ -386,7 +385,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
workspaceId: string;
|
||||
ownerFlatApplication?: FlatApplication;
|
||||
}): Promise<FlatObjectMetadata> {
|
||||
const { workspaceCustomFlatApplication } =
|
||||
const { workspaceCustomFlatApplication, twentyStandardFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{
|
||||
workspaceId,
|
||||
@@ -428,50 +427,10 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
viewUniversalIdentifier: flatDefaultViewToCreate.universalIdentifier,
|
||||
});
|
||||
|
||||
let flatRecordPageFieldsViewToCreate:
|
||||
| (UniversalFlatView & { id: string })
|
||||
| null = null;
|
||||
let flatRecordPageFieldsViewFieldsToCreate: UniversalFlatViewField[] = [];
|
||||
let flatDefaultRecordPageLayoutsToCreate: {
|
||||
pageLayouts: FlatPageLayout[];
|
||||
pageLayoutTabs: FlatPageLayoutTab[];
|
||||
pageLayoutWidgets: FlatPageLayoutWidget[];
|
||||
} = {
|
||||
pageLayouts: [],
|
||||
pageLayoutTabs: [],
|
||||
pageLayoutWidgets: [],
|
||||
};
|
||||
|
||||
if (
|
||||
const isRecordPageLayoutEditingEnabled =
|
||||
existingFeatureFlagsMap[
|
||||
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED
|
||||
] ??
|
||||
false
|
||||
) {
|
||||
flatRecordPageFieldsViewToCreate =
|
||||
this.computeFlatRecordPageFieldsViewToCreate({
|
||||
objectMetadata: flatObjectMetadataToCreate,
|
||||
flatApplication: resolvedOwnerFlatApplication,
|
||||
});
|
||||
|
||||
flatRecordPageFieldsViewFieldsToCreate = computeFlatViewFieldsToCreate({
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
objectFlatFieldMetadatas: flatFieldMetadataToCreateOnObject,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
flatObjectMetadataToCreate.labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
viewUniversalIdentifier:
|
||||
flatRecordPageFieldsViewToCreate.universalIdentifier,
|
||||
excludeLabelIdentifier: true,
|
||||
});
|
||||
|
||||
flatDefaultRecordPageLayoutsToCreate =
|
||||
this.computeFlatDefaultRecordPageLayoutToCreate({
|
||||
objectMetadata: flatObjectMetadataToCreate,
|
||||
flatApplication: resolvedOwnerFlatApplication,
|
||||
recordPageFieldsView: flatRecordPageFieldsViewToCreate,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
] ?? false;
|
||||
|
||||
const flatNavigationMenuItemToCreate =
|
||||
await this.computeFlatNavigationMenuItemToCreate({
|
||||
@@ -492,20 +451,12 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
view: {
|
||||
flatEntityToCreate: [
|
||||
flatDefaultViewToCreate,
|
||||
...(isDefined(flatRecordPageFieldsViewToCreate)
|
||||
? [flatRecordPageFieldsViewToCreate]
|
||||
: []),
|
||||
],
|
||||
flatEntityToCreate: [flatDefaultViewToCreate],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: [
|
||||
...flatDefaultViewFieldsToCreate,
|
||||
...flatRecordPageFieldsViewFieldsToCreate,
|
||||
],
|
||||
flatEntityToCreate: flatDefaultViewFieldsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
@@ -522,27 +473,6 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayout: {
|
||||
flatEntityToCreate: [
|
||||
...flatDefaultRecordPageLayoutsToCreate.pageLayouts,
|
||||
],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutTab: {
|
||||
flatEntityToCreate: [
|
||||
...flatDefaultRecordPageLayoutsToCreate.pageLayoutTabs,
|
||||
],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: [
|
||||
...flatDefaultRecordPageLayoutsToCreate.pageLayoutWidgets,
|
||||
],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
...(isDefined(flatNavigationMenuItemToCreate)
|
||||
? {
|
||||
navigationMenuItem: {
|
||||
@@ -567,6 +497,79 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
);
|
||||
}
|
||||
|
||||
if (isRecordPageLayoutEditingEnabled) {
|
||||
const flatRecordPageFieldsViewToCreate =
|
||||
this.computeFlatRecordPageFieldsViewToCreate({
|
||||
objectMetadata: flatObjectMetadataToCreate,
|
||||
flatApplication: twentyStandardFlatApplication,
|
||||
});
|
||||
|
||||
const flatRecordPageFieldsViewFieldsToCreate =
|
||||
computeFlatViewFieldsToCreate({
|
||||
flatApplication: twentyStandardFlatApplication,
|
||||
objectFlatFieldMetadatas: flatFieldMetadataToCreateOnObject,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
flatObjectMetadataToCreate.labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
viewUniversalIdentifier:
|
||||
flatRecordPageFieldsViewToCreate.universalIdentifier,
|
||||
excludeLabelIdentifier: true,
|
||||
});
|
||||
|
||||
const flatDefaultRecordPageLayoutsToCreate =
|
||||
this.computeFlatDefaultRecordPageLayoutToCreate({
|
||||
objectMetadata: flatObjectMetadataToCreate,
|
||||
flatApplication: twentyStandardFlatApplication,
|
||||
recordPageFieldsView: flatRecordPageFieldsViewToCreate,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const pageLayoutMigrationResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
view: {
|
||||
flatEntityToCreate: [flatRecordPageFieldsViewToCreate],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: flatRecordPageFieldsViewFieldsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayout: {
|
||||
flatEntityToCreate:
|
||||
flatDefaultRecordPageLayoutsToCreate.pageLayouts,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutTab: {
|
||||
flatEntityToCreate:
|
||||
flatDefaultRecordPageLayoutsToCreate.pageLayoutTabs,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate:
|
||||
flatDefaultRecordPageLayoutsToCreate.pageLayoutWidgets,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (pageLayoutMigrationResult.status === 'fail') {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
pageLayoutMigrationResult,
|
||||
'Multiple validation errors occurred while creating page layouts for object',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const { flatObjectMetadataMaps: recomputedFlatObjectMetadataMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
|
||||
+3
-3
@@ -11,13 +11,13 @@ export const seedPageLayoutWidgets = async ({
|
||||
schemaName,
|
||||
workspaceId,
|
||||
objectMetadataItems,
|
||||
workspaceCustomApplicationId,
|
||||
applicationId,
|
||||
}: {
|
||||
dataSource: DataSource;
|
||||
schemaName: string;
|
||||
workspaceId: string;
|
||||
objectMetadataItems: ObjectMetadataEntity[];
|
||||
workspaceCustomApplicationId: string;
|
||||
applicationId: string;
|
||||
}) => {
|
||||
const widgetSeeds = getPageLayoutWidgetDataSeeds(
|
||||
workspaceId,
|
||||
@@ -38,7 +38,7 @@ export const seedPageLayoutWidgets = async ({
|
||||
position: widget.position,
|
||||
configuration: widget.configuration,
|
||||
universalIdentifier: v4(),
|
||||
applicationId: workspaceCustomApplicationId,
|
||||
applicationId,
|
||||
overrides: widget.overrides ?? null,
|
||||
};
|
||||
});
|
||||
|
||||
+3
-3
@@ -129,10 +129,10 @@ export class DevSeederService {
|
||||
this.coreDataSource,
|
||||
'core',
|
||||
workspaceId,
|
||||
workspaceCustomFlatApplication.id,
|
||||
twentyStandardFlatApplication.id,
|
||||
);
|
||||
await seedPageLayoutTabs({
|
||||
applicationId: workspaceCustomFlatApplication.id,
|
||||
applicationId: twentyStandardFlatApplication.id,
|
||||
workspaceId,
|
||||
dataSource: this.coreDataSource,
|
||||
schemaName: 'core',
|
||||
@@ -150,7 +150,7 @@ export class DevSeederService {
|
||||
schemaName: 'core',
|
||||
workspaceId,
|
||||
objectMetadataItems,
|
||||
workspaceCustomApplicationId: workspaceCustomFlatApplication.id,
|
||||
applicationId: twentyStandardFlatApplication.id,
|
||||
});
|
||||
|
||||
const relatedPageLayoutCacheKeysToInvalidate = [
|
||||
|
||||
+60
-1605
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user