Page layout tab v2 (#16319)

# Introduction
Migrating `pageLayoutTab` to the v2 engine
- Types and constants
- Builder and validate
- Runner

Introduced a new `StrictSyncableEntity` that enforces that
`universalIdentifier` and `applicationId` are defined
As these entities are brand new we could enforce this rule already
This still requires a migration command to associate the existing
entities to custom workspace application instance and define
universalIdentifier

Handled retro-comp of the migration through a migration as upgrade
command fallback

---------

Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
This commit is contained in:
Paul Rastoin
2025-12-04 17:37:16 +01:00
committed by GitHub
parent 1981cf0ed6
commit b2d785de4b
56 changed files with 1284 additions and 13 deletions
@@ -0,0 +1,6 @@
import { type FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type';
export const FLAT_PAGE_LAYOUT_TAB_EDITABLE_PROPERTIES = [
'title',
'position',
] as const satisfies (keyof FlatPageLayoutTab)[];
@@ -0,0 +1,16 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PageLayoutTabEntity } from 'src/engine/core-modules/page-layout/entities/page-layout-tab.entity';
import { WorkspaceFlatPageLayoutTabMapCacheService } from 'src/engine/metadata-modules/flat-page-layout-tab/services/workspace-flat-page-layout-tab-map-cache.service';
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
@Module({
imports: [
TypeOrmModule.forFeature([PageLayoutTabEntity]),
WorkspaceManyOrAllFlatEntityMapsCacheModule,
],
providers: [WorkspaceFlatPageLayoutTabMapCacheService],
exports: [WorkspaceFlatPageLayoutTabMapCacheService],
})
export class FlatPageLayoutTabModule {}
@@ -0,0 +1,45 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service';
import { PageLayoutTabEntity } from 'src/engine/core-modules/page-layout/entities/page-layout-tab.entity';
import { type FlatPageLayoutTabMaps } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab-maps.type';
import { transformPageLayoutTabEntityToFlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/utils/transform-page-layout-tab-entity-to-flat-page-layout-tab.util';
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator';
import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration-v2/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util';
@Injectable()
@WorkspaceCache('flatPageLayoutTabMaps')
export class WorkspaceFlatPageLayoutTabMapCacheService extends WorkspaceCacheProvider<FlatPageLayoutTabMaps> {
constructor(
@InjectRepository(PageLayoutTabEntity)
private readonly pageLayoutTabRepository: Repository<PageLayoutTabEntity>,
) {
super();
}
async computeForCache(workspaceId: string): Promise<FlatPageLayoutTabMaps> {
const pageLayoutTabs = await this.pageLayoutTabRepository.find({
where: { workspaceId },
withDeleted: true,
});
const flatPageLayoutTabMaps = createEmptyFlatEntityMaps();
for (const pageLayoutTabEntity of pageLayoutTabs) {
const flatPageLayoutTab =
transformPageLayoutTabEntityToFlatPageLayoutTab(pageLayoutTabEntity);
addFlatEntityToFlatEntityMapsThroughMutationOrThrow({
flatEntity: flatPageLayoutTab,
flatEntityMapsToMutate: flatPageLayoutTabMaps,
});
}
return flatPageLayoutTabMaps;
}
}
@@ -0,0 +1,5 @@
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatPageLayoutTab } from './flat-page-layout-tab.type';
export type FlatPageLayoutTabMaps = FlatEntityMaps<FlatPageLayoutTab>;
@@ -0,0 +1,17 @@
import { type PageLayoutTabEntity } from 'src/engine/core-modules/page-layout/entities/page-layout-tab.entity';
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type';
export const pageLayoutTabEntityRelationProperties = [
'workspace',
'pageLayout',
'widgets',
'application',
] as const;
export type PageLayoutTabEntityRelationProperties =
(typeof pageLayoutTabEntityRelationProperties)[number];
export type FlatPageLayoutTab = FlatEntityFrom<
PageLayoutTabEntity,
PageLayoutTabEntityRelationProperties
>;
@@ -0,0 +1,19 @@
import { type PageLayoutTabEntity } from 'src/engine/core-modules/page-layout/entities/page-layout-tab.entity';
import { type FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type';
export const transformPageLayoutTabEntityToFlatPageLayoutTab = (
pageLayoutTabEntity: PageLayoutTabEntity,
): FlatPageLayoutTab => {
return {
createdAt: pageLayoutTabEntity.createdAt,
deletedAt: pageLayoutTabEntity.deletedAt,
updatedAt: pageLayoutTabEntity.updatedAt,
id: pageLayoutTabEntity.id,
title: pageLayoutTabEntity.title,
position: pageLayoutTabEntity.position,
pageLayoutId: pageLayoutTabEntity.pageLayoutId,
workspaceId: pageLayoutTabEntity.workspaceId,
universalIdentifier: pageLayoutTabEntity.universalIdentifier,
applicationId: pageLayoutTabEntity.applicationId,
};
};