[DASHBOARDS] Dashboard duplication (#16291)

## Description

- Created a Dashboard duplication action
- Created a new duplication custom resolver
- Created the service using the v2 of the API
- Created the integration tests following the v2 methodology

## Video QA


https://github.com/user-attachments/assets/e409951a-5946-4da0-91a0-1f7d2ecadb08
This commit is contained in:
Raphaël Bosi
2025-12-11 12:15:15 +01:00
committed by GitHub
parent 6c728fff78
commit 5af2d37253
39 changed files with 1542 additions and 79 deletions
@@ -650,6 +650,44 @@ export class WorkspaceMigrationBuildOrchestratorService {
}
}
// Page layout tabs must be processed before page layout widgets because
// widgets reference tabs, and the optimistic cache needs to contain the
// newly created tabs before widget validation runs
if (isDefined(flatPageLayoutTabMaps)) {
const { from: fromFlatPageLayoutTabMaps, to: toFlatPageLayoutTabMaps } =
flatPageLayoutTabMaps;
const pageLayoutTabResult =
this.workspaceMigrationV2PageLayoutTabActionsBuilderService.validateAndBuild(
{
from: fromFlatPageLayoutTabMaps,
to: toFlatPageLayoutTabMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatPageLayoutMaps:
optimisticAllFlatEntityMaps.flatPageLayoutMaps,
},
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
pageLayoutTabResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (pageLayoutTabResult.status === 'fail') {
orchestratorFailureReport.pageLayoutTab.push(
...pageLayoutTabResult.errors,
);
} else {
orchestratorActionsReport.pageLayoutTab = pageLayoutTabResult.actions;
}
}
if (isDefined(flatPageLayoutWidgetMaps)) {
const {
from: fromFlatPageLayoutWidgetMaps,
@@ -688,41 +726,6 @@ export class WorkspaceMigrationBuildOrchestratorService {
}
}
if (isDefined(flatPageLayoutTabMaps)) {
const { from: fromFlatPageLayoutTabMaps, to: toFlatPageLayoutTabMaps } =
flatPageLayoutTabMaps;
const pageLayoutTabResult =
this.workspaceMigrationV2PageLayoutTabActionsBuilderService.validateAndBuild(
{
from: fromFlatPageLayoutTabMaps,
to: toFlatPageLayoutTabMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: {
flatPageLayoutMaps:
optimisticAllFlatEntityMaps.flatPageLayoutMaps,
},
workspaceId,
},
);
this.mergeFlatEntityMapsAndRelatedFlatEntityMapsInAllFlatEntityMapsThroughMutation(
{
allFlatEntityMaps: optimisticAllFlatEntityMaps,
flatEntityMapsAndRelatedFlatEntityMaps:
pageLayoutTabResult.optimisticFlatEntityMapsAndRelatedFlatEntityMaps,
},
);
if (pageLayoutTabResult.status === 'fail') {
orchestratorFailureReport.pageLayoutTab.push(
...pageLayoutTabResult.errors,
);
} else {
orchestratorActionsReport.pageLayoutTab = pageLayoutTabResult.actions;
}
}
const allErrors = Object.values(orchestratorFailureReport);
if (allErrors.some((report) => report.length > 0)) {
@@ -824,17 +827,17 @@ export class WorkspaceMigrationBuildOrchestratorService {
...aggregatedOrchestratorActionsReport.pageLayout.updated,
///
// Page layout widgets
...aggregatedOrchestratorActionsReport.pageLayoutWidget.deleted,
...aggregatedOrchestratorActionsReport.pageLayoutWidget.created,
...aggregatedOrchestratorActionsReport.pageLayoutWidget.updated,
///
// Page layout tabs
...aggregatedOrchestratorActionsReport.pageLayoutTab.deleted,
...aggregatedOrchestratorActionsReport.pageLayoutTab.created,
...aggregatedOrchestratorActionsReport.pageLayoutTab.updated,
///
// Page layout widgets
...aggregatedOrchestratorActionsReport.pageLayoutWidget.deleted,
...aggregatedOrchestratorActionsReport.pageLayoutWidget.created,
...aggregatedOrchestratorActionsReport.pageLayoutWidget.updated,
///
],
workspaceId,
},