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:
Weiko
2026-04-07 14:49:35 +02:00
committed by GitHub
parent 96a242eb7d
commit 6e23ca35e6
5 changed files with 180 additions and 1765 deletions
@@ -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(
{
@@ -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,
};
});
@@ -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 = [