From f793faae2bf18f75ec9ab936c2bf038dfaa8aed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Tue, 13 Jan 2026 17:25:30 +0100 Subject: [PATCH] 17042 followups (#17122) Followups after @Weiko review on https://github.com/twentyhq/twenty/pull/17042 --- .../controllers/page-layout-tab.controller.ts | 14 ++--- .../page-layout-widget.controller.ts | 2 +- .../services/page-layout.service.ts | 51 +++++++++++++++++++ .../dashboard-to-page-layout-sync.service.ts | 17 +++---- 4 files changed, 66 insertions(+), 18 deletions(-) diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/controllers/page-layout-tab.controller.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/controllers/page-layout-tab.controller.ts index fed651fd405..d6131f69bfa 100644 --- a/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/controllers/page-layout-tab.controller.ts +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout-tab/controllers/page-layout-tab.controller.ts @@ -11,9 +11,14 @@ import { UseGuards, } from '@nestjs/common'; -import { isDefined } from 'twenty-shared/utils'; import { PermissionFlagType } from 'twenty-shared/constants'; +import { isDefined } from 'twenty-shared/utils'; +import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; +import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator'; +import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard'; +import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard'; +import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard'; import { CreatePageLayoutTabInput } from 'src/engine/metadata-modules/page-layout-tab/dtos/inputs/create-page-layout-tab.input'; import { UpdatePageLayoutTabInput } from 'src/engine/metadata-modules/page-layout-tab/dtos/inputs/update-page-layout-tab.input'; import { type PageLayoutTabDTO } from 'src/engine/metadata-modules/page-layout-tab/dtos/page-layout-tab.dto'; @@ -25,11 +30,6 @@ import { } from 'src/engine/metadata-modules/page-layout-tab/exceptions/page-layout-tab.exception'; import { PageLayoutTabRestApiExceptionFilter } from 'src/engine/metadata-modules/page-layout-tab/filters/page-layout-tab-rest-api-exception.filter'; import { PageLayoutTabService } from 'src/engine/metadata-modules/page-layout-tab/services/page-layout-tab.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator'; -import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard'; -import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard'; -import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard'; @Controller('rest/metadata/pageLayoutTabs') @UseGuards(WorkspaceAuthGuard) @@ -98,7 +98,7 @@ export class PageLayoutTabController { @Delete(':id') @UseGuards(SettingsPermissionGuard(PermissionFlagType.LAYOUTS)) - async delete( + async destroy( @Param('id') id: string, @AuthWorkspace() workspace: WorkspaceEntity, ): Promise { diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/controllers/page-layout-widget.controller.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/controllers/page-layout-widget.controller.ts index 288634ba758..a1e776063b9 100644 --- a/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/controllers/page-layout-widget.controller.ts +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout-widget/controllers/page-layout-widget.controller.ts @@ -100,7 +100,7 @@ export class PageLayoutWidgetController { @Delete(':id') @UseGuards(SettingsPermissionGuard(PermissionFlagType.LAYOUTS)) - async delete( + async destroy( @Param('id') id: string, @AuthWorkspace() workspace: WorkspaceEntity, ): Promise { diff --git a/packages/twenty-server/src/engine/metadata-modules/page-layout/services/page-layout.service.ts b/packages/twenty-server/src/engine/metadata-modules/page-layout/services/page-layout.service.ts index 413b1a06ae7..cb822dc46d8 100644 --- a/packages/twenty-server/src/engine/metadata-modules/page-layout/services/page-layout.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/page-layout/services/page-layout.service.ts @@ -350,6 +350,57 @@ export class PageLayoutService { return true; } + async destroyMany({ + ids, + workspaceId, + }: { + ids: string[]; + workspaceId: string; + }): Promise { + if (ids.length === 0) { + return true; + } + + const { flatPageLayoutMaps: existingFlatPageLayoutMaps } = + await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( + { + workspaceId, + flatMapsKeys: ['flatPageLayoutMaps'], + }, + ); + + const flatPageLayoutsToDestroy = ids.map((id) => + fromDestroyPageLayoutInputToFlatPageLayoutOrThrow({ + destroyPageLayoutInput: { id }, + flatPageLayoutMaps: existingFlatPageLayoutMaps, + }), + ); + + const validateAndBuildResult = + await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( + { + allFlatEntityOperationByMetadataName: { + pageLayout: { + flatEntityToCreate: [], + flatEntityToDelete: flatPageLayoutsToDestroy, + flatEntityToUpdate: [], + }, + }, + workspaceId, + isSystemBuild: false, + }, + ); + + if (isDefined(validateAndBuildResult)) { + throw new WorkspaceMigrationBuilderException( + validateAndBuildResult, + 'Multiple validation errors occurred while destroying page layouts', + ); + } + + return true; + } + private async destroyAssociatedDashboards({ pageLayoutId, workspaceId, diff --git a/packages/twenty-server/src/modules/dashboard/services/dashboard-to-page-layout-sync.service.ts b/packages/twenty-server/src/modules/dashboard/services/dashboard-to-page-layout-sync.service.ts index 3dd4b5ff6f5..aec90766cea 100644 --- a/packages/twenty-server/src/modules/dashboard/services/dashboard-to-page-layout-sync.service.ts +++ b/packages/twenty-server/src/modules/dashboard/services/dashboard-to-page-layout-sync.service.ts @@ -69,17 +69,14 @@ export class DashboardToPageLayoutSyncService { withDeleted: true, }); - for (const dashboard of dashboards) { - if (!isDefined(dashboard.pageLayoutId)) { - continue; - } + const pageLayoutIds = dashboards + .map((dashboard) => dashboard.pageLayoutId) + .filter(isDefined); - await this.pageLayoutService.destroy({ - id: dashboard.pageLayoutId, - workspaceId, - isLinkedDashboardAlreadyDestroyed: true, - }); - } + await this.pageLayoutService.destroyMany({ + ids: pageLayoutIds, + workspaceId, + }); }, ); }