[DASHBOARDS] Allow dashboards to be restored (#17042)
This PR introduces a few changes: - Add three actions: see deleted dashboards, destroy dashboard and restore dashboard - Remove the soft delete and restore on all the page layout entities - Cascade the destruction of a dashboard to a page layout Video QA: https://github.com/user-attachments/assets/ab993b11-dd9c-4e88-880c-92691a521cc2
This commit is contained in:
-44
@@ -1,44 +0,0 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatPageLayoutTabMaps } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab-maps.type';
|
||||
import { type FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type';
|
||||
import {
|
||||
PageLayoutTabException,
|
||||
PageLayoutTabExceptionCode,
|
||||
} from 'src/engine/metadata-modules/page-layout-tab/exceptions/page-layout-tab.exception';
|
||||
|
||||
export type DeletePageLayoutTabInput = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const fromDeletePageLayoutTabInputToFlatPageLayoutTabOrThrow = ({
|
||||
deletePageLayoutTabInput: rawDeletePageLayoutTabInput,
|
||||
flatPageLayoutTabMaps,
|
||||
}: {
|
||||
deletePageLayoutTabInput: DeletePageLayoutTabInput;
|
||||
flatPageLayoutTabMaps: FlatPageLayoutTabMaps;
|
||||
}): FlatPageLayoutTab => {
|
||||
const { id: pageLayoutTabId } = extractAndSanitizeObjectStringFields(
|
||||
rawDeletePageLayoutTabInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatPageLayoutTabToDelete =
|
||||
flatPageLayoutTabMaps.byId[pageLayoutTabId];
|
||||
|
||||
if (!isDefined(existingFlatPageLayoutTabToDelete)) {
|
||||
throw new PageLayoutTabException(
|
||||
t`Page layout tab to delete not found`,
|
||||
PageLayoutTabExceptionCode.PAGE_LAYOUT_TAB_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...existingFlatPageLayoutTabToDelete,
|
||||
deletedAt: new Date().toISOString(),
|
||||
};
|
||||
};
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatPageLayoutTabMaps } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab-maps.type';
|
||||
import { type FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type';
|
||||
import {
|
||||
PageLayoutTabException,
|
||||
PageLayoutTabExceptionCode,
|
||||
} from 'src/engine/metadata-modules/page-layout-tab/exceptions/page-layout-tab.exception';
|
||||
|
||||
export type RestorePageLayoutTabInput = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const fromRestorePageLayoutTabInputToFlatPageLayoutTabOrThrow = ({
|
||||
restorePageLayoutTabInput,
|
||||
flatPageLayoutTabMaps,
|
||||
}: {
|
||||
restorePageLayoutTabInput: RestorePageLayoutTabInput;
|
||||
flatPageLayoutTabMaps: FlatPageLayoutTabMaps;
|
||||
}): FlatPageLayoutTab => {
|
||||
const { id: pageLayoutTabId } = extractAndSanitizeObjectStringFields(
|
||||
restorePageLayoutTabInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatPageLayoutTabToRestore =
|
||||
flatPageLayoutTabMaps.byId[pageLayoutTabId];
|
||||
|
||||
if (!isDefined(existingFlatPageLayoutTabToRestore)) {
|
||||
throw new PageLayoutTabException(
|
||||
t`Page layout tab to restore not found`,
|
||||
PageLayoutTabExceptionCode.PAGE_LAYOUT_TAB_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
if (!isDefined(existingFlatPageLayoutTabToRestore.deletedAt)) {
|
||||
throw new PageLayoutTabException(
|
||||
t`Page layout tab is not deleted and cannot be restored`,
|
||||
PageLayoutTabExceptionCode.INVALID_PAGE_LAYOUT_TAB_DATA,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...existingFlatPageLayoutTabToRestore,
|
||||
deletedAt: null,
|
||||
};
|
||||
};
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatPageLayoutWidgetMaps } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-maps.type';
|
||||
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
|
||||
import { type DeletePageLayoutWidgetInput } from 'src/engine/metadata-modules/page-layout-widget/dtos/inputs/delete-page-layout-widget.input';
|
||||
import {
|
||||
PageLayoutWidgetException,
|
||||
PageLayoutWidgetExceptionCode,
|
||||
} from 'src/engine/metadata-modules/page-layout-widget/exceptions/page-layout-widget.exception';
|
||||
|
||||
export const fromDeletePageLayoutWidgetInputToFlatPageLayoutWidgetOrThrow = ({
|
||||
deletePageLayoutWidgetInput: rawDeletePageLayoutWidgetInput,
|
||||
flatPageLayoutWidgetMaps,
|
||||
}: {
|
||||
deletePageLayoutWidgetInput: DeletePageLayoutWidgetInput;
|
||||
flatPageLayoutWidgetMaps: FlatPageLayoutWidgetMaps;
|
||||
}): FlatPageLayoutWidget => {
|
||||
const { id: pageLayoutWidgetId } = extractAndSanitizeObjectStringFields(
|
||||
rawDeletePageLayoutWidgetInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatPageLayoutWidgetToDelete =
|
||||
flatPageLayoutWidgetMaps.byId[pageLayoutWidgetId];
|
||||
|
||||
if (!isDefined(existingFlatPageLayoutWidgetToDelete)) {
|
||||
throw new PageLayoutWidgetException(
|
||||
t`Page layout widget to delete not found`,
|
||||
PageLayoutWidgetExceptionCode.PAGE_LAYOUT_WIDGET_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...existingFlatPageLayoutWidgetToDelete,
|
||||
deletedAt: new Date().toISOString(),
|
||||
};
|
||||
};
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatPageLayoutWidgetMaps } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-maps.type';
|
||||
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
|
||||
import {
|
||||
PageLayoutWidgetException,
|
||||
PageLayoutWidgetExceptionCode,
|
||||
} from 'src/engine/metadata-modules/page-layout-widget/exceptions/page-layout-widget.exception';
|
||||
|
||||
export type RestorePageLayoutWidgetInput = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const fromRestorePageLayoutWidgetInputToFlatPageLayoutWidgetOrThrow = ({
|
||||
restorePageLayoutWidgetInput,
|
||||
flatPageLayoutWidgetMaps,
|
||||
}: {
|
||||
restorePageLayoutWidgetInput: RestorePageLayoutWidgetInput;
|
||||
flatPageLayoutWidgetMaps: FlatPageLayoutWidgetMaps;
|
||||
}): FlatPageLayoutWidget => {
|
||||
const { id: pageLayoutWidgetId } = extractAndSanitizeObjectStringFields(
|
||||
restorePageLayoutWidgetInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatPageLayoutWidgetToRestore =
|
||||
flatPageLayoutWidgetMaps.byId[pageLayoutWidgetId];
|
||||
|
||||
if (!isDefined(existingFlatPageLayoutWidgetToRestore)) {
|
||||
throw new PageLayoutWidgetException(
|
||||
t`Page layout widget to restore not found`,
|
||||
PageLayoutWidgetExceptionCode.PAGE_LAYOUT_WIDGET_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
if (!isDefined(existingFlatPageLayoutWidgetToRestore.deletedAt)) {
|
||||
throw new PageLayoutWidgetException(
|
||||
t`Page layout widget is not deleted and cannot be restored`,
|
||||
PageLayoutWidgetExceptionCode.INVALID_PAGE_LAYOUT_WIDGET_DATA,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...existingFlatPageLayoutWidgetToRestore,
|
||||
deletedAt: null,
|
||||
};
|
||||
};
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatPageLayoutMaps } from 'src/engine/metadata-modules/flat-page-layout/types/flat-page-layout-maps.type';
|
||||
import { type FlatPageLayout } from 'src/engine/metadata-modules/flat-page-layout/types/flat-page-layout.type';
|
||||
import {
|
||||
PageLayoutException,
|
||||
PageLayoutExceptionCode,
|
||||
} from 'src/engine/metadata-modules/page-layout/exceptions/page-layout.exception';
|
||||
|
||||
export type DeletePageLayoutInput = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const fromDeletePageLayoutInputToFlatPageLayoutOrThrow = ({
|
||||
deletePageLayoutInput: rawDeletePageLayoutInput,
|
||||
flatPageLayoutMaps,
|
||||
}: {
|
||||
deletePageLayoutInput: DeletePageLayoutInput;
|
||||
flatPageLayoutMaps: FlatPageLayoutMaps;
|
||||
}): FlatPageLayout => {
|
||||
const { id: pageLayoutId } = extractAndSanitizeObjectStringFields(
|
||||
rawDeletePageLayoutInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatPageLayoutToDelete = flatPageLayoutMaps.byId[pageLayoutId];
|
||||
|
||||
if (!isDefined(existingFlatPageLayoutToDelete)) {
|
||||
throw new PageLayoutException(
|
||||
t`Page layout to delete not found`,
|
||||
PageLayoutExceptionCode.PAGE_LAYOUT_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...existingFlatPageLayoutToDelete,
|
||||
deletedAt: new Date().toISOString(),
|
||||
};
|
||||
};
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatPageLayoutMaps } from 'src/engine/metadata-modules/flat-page-layout/types/flat-page-layout-maps.type';
|
||||
import { type FlatPageLayout } from 'src/engine/metadata-modules/flat-page-layout/types/flat-page-layout.type';
|
||||
import {
|
||||
PageLayoutException,
|
||||
PageLayoutExceptionCode,
|
||||
} from 'src/engine/metadata-modules/page-layout/exceptions/page-layout.exception';
|
||||
|
||||
export type RestorePageLayoutInput = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const fromRestorePageLayoutInputToFlatPageLayoutOrThrow = ({
|
||||
restorePageLayoutInput,
|
||||
flatPageLayoutMaps,
|
||||
}: {
|
||||
restorePageLayoutInput: RestorePageLayoutInput;
|
||||
flatPageLayoutMaps: FlatPageLayoutMaps;
|
||||
}): FlatPageLayout => {
|
||||
const { id: pageLayoutId } = extractAndSanitizeObjectStringFields(
|
||||
restorePageLayoutInput,
|
||||
['id'],
|
||||
);
|
||||
|
||||
const existingFlatPageLayoutToRestore = flatPageLayoutMaps.byId[pageLayoutId];
|
||||
|
||||
if (!isDefined(existingFlatPageLayoutToRestore)) {
|
||||
throw new PageLayoutException(
|
||||
t`Page layout to restore not found`,
|
||||
PageLayoutExceptionCode.PAGE_LAYOUT_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
if (!isDefined(existingFlatPageLayoutToRestore.deletedAt)) {
|
||||
throw new PageLayoutException(
|
||||
t`Page layout is not deleted and cannot be restored`,
|
||||
PageLayoutExceptionCode.INVALID_PAGE_LAYOUT_DATA,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...existingFlatPageLayoutToRestore,
|
||||
deletedAt: null,
|
||||
};
|
||||
};
|
||||
+21
-8
@@ -52,10 +52,10 @@ export class PageLayoutTabController {
|
||||
);
|
||||
}
|
||||
|
||||
return this.pageLayoutTabService.findByPageLayoutId(
|
||||
workspace.id,
|
||||
return this.pageLayoutTabService.findByPageLayoutId({
|
||||
workspaceId: workspace.id,
|
||||
pageLayoutId,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@@ -64,7 +64,10 @@ export class PageLayoutTabController {
|
||||
@Param('id') id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutTabDTO | null> {
|
||||
return this.pageLayoutTabService.findByIdOrThrow(id, workspace.id);
|
||||
return this.pageLayoutTabService.findByIdOrThrow({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Post()
|
||||
@@ -73,7 +76,10 @@ export class PageLayoutTabController {
|
||||
@Body() input: CreatePageLayoutTabInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutTabDTO> {
|
||||
return this.pageLayoutTabService.create(input, workspace.id);
|
||||
return this.pageLayoutTabService.create({
|
||||
createPageLayoutTabInput: input,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@@ -83,7 +89,11 @@ export class PageLayoutTabController {
|
||||
@Body() input: UpdatePageLayoutTabInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutTabDTO> {
|
||||
return this.pageLayoutTabService.update(id, workspace.id, input);
|
||||
return this.pageLayoutTabService.update({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
updateData: input,
|
||||
});
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@@ -91,7 +101,10 @@ export class PageLayoutTabController {
|
||||
async delete(
|
||||
@Param('id') id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutTabDTO> {
|
||||
return this.pageLayoutTabService.delete(id, workspace.id);
|
||||
): Promise<boolean> {
|
||||
return this.pageLayoutTabService.destroy({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+19
-30
@@ -7,7 +7,6 @@ import {
|
||||
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
|
||||
import { type WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
@@ -36,10 +35,10 @@ export class PageLayoutTabResolver {
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
@Args('pageLayoutId', { type: () => String }) pageLayoutId: string,
|
||||
): Promise<PageLayoutTabDTO[]> {
|
||||
return this.pageLayoutTabService.findByPageLayoutId(
|
||||
workspace.id,
|
||||
return this.pageLayoutTabService.findByPageLayoutId({
|
||||
workspaceId: workspace.id,
|
||||
pageLayoutId,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Query(() => PageLayoutTabDTO)
|
||||
@@ -48,7 +47,10 @@ export class PageLayoutTabResolver {
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutTabDTO> {
|
||||
return this.pageLayoutTabService.findByIdOrThrow(id, workspace.id);
|
||||
return this.pageLayoutTabService.findByIdOrThrow({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutTabDTO)
|
||||
@@ -57,7 +59,10 @@ export class PageLayoutTabResolver {
|
||||
@Args('input') input: CreatePageLayoutTabInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutTabDTO> {
|
||||
return this.pageLayoutTabService.create(input, workspace.id);
|
||||
return this.pageLayoutTabService.create({
|
||||
createPageLayoutTabInput: input,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutTabDTO)
|
||||
@@ -67,21 +72,11 @@ export class PageLayoutTabResolver {
|
||||
@Args('input') input: UpdatePageLayoutTabInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutTabDTO> {
|
||||
return this.pageLayoutTabService.update(id, workspace.id, input);
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.LAYOUTS))
|
||||
async deletePageLayoutTab(
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<boolean> {
|
||||
const deletedPageLayoutTab = await this.pageLayoutTabService.delete(
|
||||
return this.pageLayoutTabService.update({
|
||||
id,
|
||||
workspace.id,
|
||||
);
|
||||
|
||||
return isDefined(deletedPageLayoutTab);
|
||||
workspaceId: workspace.id,
|
||||
updateData: input,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean)
|
||||
@@ -90,15 +85,9 @@ export class PageLayoutTabResolver {
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<boolean> {
|
||||
return this.pageLayoutTabService.destroy(id, workspace.id);
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutTabDTO)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.LAYOUTS))
|
||||
async restorePageLayoutTab(
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutTabDTO> {
|
||||
return this.pageLayoutTabService.restore(id, workspace.id);
|
||||
return this.pageLayoutTabService.destroy({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+37
-144
@@ -7,9 +7,7 @@ import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadat
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { FlatPageLayoutTabMaps } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab-maps.type';
|
||||
import { fromCreatePageLayoutTabInputToFlatPageLayoutTabToCreate } from 'src/engine/metadata-modules/flat-page-layout-tab/utils/from-create-page-layout-tab-input-to-flat-page-layout-tab-to-create.util';
|
||||
import { fromDeletePageLayoutTabInputToFlatPageLayoutTabOrThrow } from 'src/engine/metadata-modules/flat-page-layout-tab/utils/from-delete-page-layout-tab-input-to-flat-page-layout-tab-or-throw.util';
|
||||
import { fromDestroyPageLayoutTabInputToFlatPageLayoutTabOrThrow } from 'src/engine/metadata-modules/flat-page-layout-tab/utils/from-destroy-page-layout-tab-input-to-flat-page-layout-tab-or-throw.util';
|
||||
import { fromRestorePageLayoutTabInputToFlatPageLayoutTabOrThrow } from 'src/engine/metadata-modules/flat-page-layout-tab/utils/from-restore-page-layout-tab-input-to-flat-page-layout-tab-or-throw.util';
|
||||
import {
|
||||
fromUpdatePageLayoutTabInputToFlatPageLayoutTabToUpdateOrThrow,
|
||||
type UpdatePageLayoutTabInputWithId,
|
||||
@@ -40,10 +38,13 @@ export class PageLayoutTabService {
|
||||
private readonly dashboardSyncService: DashboardSyncService,
|
||||
) {}
|
||||
|
||||
async findByPageLayoutId(
|
||||
workspaceId: string,
|
||||
pageLayoutId: string,
|
||||
): Promise<PageLayoutTabDTO[]> {
|
||||
async findByPageLayoutId({
|
||||
workspaceId,
|
||||
pageLayoutId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
pageLayoutId: string;
|
||||
}): Promise<PageLayoutTabDTO[]> {
|
||||
const { flatPageLayoutTabMaps, flatPageLayoutWidgetMaps } =
|
||||
await this.getPageLayoutTabFlatEntityMaps(workspaceId);
|
||||
|
||||
@@ -63,10 +64,13 @@ export class PageLayoutTabService {
|
||||
);
|
||||
}
|
||||
|
||||
async findByIdOrThrow(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
): Promise<PageLayoutTabDTO> {
|
||||
async findByIdOrThrow({
|
||||
id,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}): Promise<PageLayoutTabDTO> {
|
||||
const { flatPageLayoutTabMaps, flatPageLayoutWidgetMaps } =
|
||||
await this.getPageLayoutTabFlatEntityMaps(workspaceId);
|
||||
|
||||
@@ -102,10 +106,13 @@ export class PageLayoutTabService {
|
||||
);
|
||||
}
|
||||
|
||||
async create(
|
||||
createPageLayoutTabInput: CreatePageLayoutTabInput,
|
||||
workspaceId: string,
|
||||
): Promise<Omit<PageLayoutTabDTO, 'widgets'>> {
|
||||
async create({
|
||||
createPageLayoutTabInput,
|
||||
workspaceId,
|
||||
}: {
|
||||
createPageLayoutTabInput: CreatePageLayoutTabInput;
|
||||
workspaceId: string;
|
||||
}): Promise<Omit<PageLayoutTabDTO, 'widgets'>> {
|
||||
if (!isDefined(createPageLayoutTabInput.title)) {
|
||||
throw new PageLayoutTabException(
|
||||
generatePageLayoutTabExceptionMessage(
|
||||
@@ -180,11 +187,15 @@ export class PageLayoutTabService {
|
||||
return fromFlatPageLayoutTabToPageLayoutTabDto(createdTab);
|
||||
}
|
||||
|
||||
async update(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
updateData: UpdatePageLayoutTabInput,
|
||||
): Promise<Omit<PageLayoutTabDTO, 'widgets'>> {
|
||||
async update({
|
||||
id,
|
||||
workspaceId,
|
||||
updateData,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
updateData: UpdatePageLayoutTabInput;
|
||||
}): Promise<Omit<PageLayoutTabDTO, 'widgets'>> {
|
||||
const { flatPageLayoutTabMaps: existingFlatPageLayoutTabMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
@@ -248,69 +259,13 @@ export class PageLayoutTabService {
|
||||
return fromFlatPageLayoutTabToPageLayoutTabDto(updatedTab);
|
||||
}
|
||||
|
||||
async delete(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
): Promise<Omit<PageLayoutTabDTO, 'widgets'>> {
|
||||
const { flatPageLayoutTabMaps: existingFlatPageLayoutTabMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatPageLayoutTabMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const flatPageLayoutTabToDelete =
|
||||
fromDeletePageLayoutTabInputToFlatPageLayoutTabOrThrow({
|
||||
deletePageLayoutTabInput: { id },
|
||||
flatPageLayoutTabMaps: existingFlatPageLayoutTabMaps,
|
||||
});
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayoutTab: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [flatPageLayoutTabToDelete],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild: false,
|
||||
},
|
||||
);
|
||||
|
||||
if (isDefined(validateAndBuildResult)) {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
validateAndBuildResult,
|
||||
'Multiple validation errors occurred while deleting page layout tab',
|
||||
);
|
||||
}
|
||||
|
||||
const { flatPageLayoutTabMaps: recomputedFlatPageLayoutTabMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatPageLayoutTabMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const deletedTab = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: recomputedFlatPageLayoutTabMaps,
|
||||
});
|
||||
|
||||
await this.dashboardSyncService.updateLinkedDashboardsUpdatedAtByTabId({
|
||||
tabId: id,
|
||||
workspaceId,
|
||||
updatedAt: new Date(deletedTab.updatedAt),
|
||||
});
|
||||
|
||||
return fromFlatPageLayoutTabToPageLayoutTabDto(deletedTab);
|
||||
}
|
||||
|
||||
async destroy(id: string, workspaceId: string): Promise<boolean> {
|
||||
async destroy({
|
||||
id,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}): Promise<boolean> {
|
||||
const { flatPageLayoutTabMaps: existingFlatPageLayoutTabMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
@@ -355,66 +310,4 @@ export class PageLayoutTabService {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async restore(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
): Promise<Omit<PageLayoutTabDTO, 'widgets'>> {
|
||||
const { flatPageLayoutTabMaps: existingFlatPageLayoutTabMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatPageLayoutTabMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const flatPageLayoutTabToRestore =
|
||||
fromRestorePageLayoutTabInputToFlatPageLayoutTabOrThrow({
|
||||
restorePageLayoutTabInput: { id },
|
||||
flatPageLayoutTabMaps: existingFlatPageLayoutTabMaps,
|
||||
});
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayoutTab: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [flatPageLayoutTabToRestore],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild: false,
|
||||
},
|
||||
);
|
||||
|
||||
if (isDefined(validateAndBuildResult)) {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
validateAndBuildResult,
|
||||
'Multiple validation errors occurred while restoring page layout tab',
|
||||
);
|
||||
}
|
||||
|
||||
const { flatPageLayoutTabMaps: recomputedFlatPageLayoutTabMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatPageLayoutTabMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const restoredTab = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: recomputedFlatPageLayoutTabMaps,
|
||||
});
|
||||
|
||||
await this.dashboardSyncService.updateLinkedDashboardsUpdatedAtByTabId({
|
||||
tabId: id,
|
||||
workspaceId,
|
||||
updatedAt: new Date(restoredTab.updatedAt),
|
||||
});
|
||||
|
||||
return fromFlatPageLayoutTabToPageLayoutTabDto(restoredTab);
|
||||
}
|
||||
}
|
||||
|
||||
+21
-8
@@ -54,10 +54,10 @@ export class PageLayoutWidgetController {
|
||||
);
|
||||
}
|
||||
|
||||
return this.pageLayoutWidgetService.findByPageLayoutTabId(
|
||||
workspace.id,
|
||||
return this.pageLayoutWidgetService.findByPageLayoutTabId({
|
||||
workspaceId: workspace.id,
|
||||
pageLayoutTabId,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@@ -66,7 +66,10 @@ export class PageLayoutWidgetController {
|
||||
@Param('id') id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutWidgetDTO | null> {
|
||||
return this.pageLayoutWidgetService.findByIdOrThrow(id, workspace.id);
|
||||
return this.pageLayoutWidgetService.findByIdOrThrow({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Post()
|
||||
@@ -75,7 +78,10 @@ export class PageLayoutWidgetController {
|
||||
@Body() input: CreatePageLayoutWidgetInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutWidgetDTO> {
|
||||
return this.pageLayoutWidgetService.create(input, workspace.id);
|
||||
return this.pageLayoutWidgetService.create({
|
||||
input,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@@ -85,7 +91,11 @@ export class PageLayoutWidgetController {
|
||||
@Body() input: UpdatePageLayoutWidgetInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutWidgetDTO> {
|
||||
return this.pageLayoutWidgetService.update(id, workspace.id, input);
|
||||
return this.pageLayoutWidgetService.update({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
updateData: input,
|
||||
});
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@@ -93,7 +103,10 @@ export class PageLayoutWidgetController {
|
||||
async delete(
|
||||
@Param('id') id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutWidgetDTO> {
|
||||
return this.pageLayoutWidgetService.delete(id, workspace.id);
|
||||
): Promise<boolean> {
|
||||
return this.pageLayoutWidgetService.destroy({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+20
-25
@@ -45,10 +45,10 @@ export class PageLayoutWidgetResolver {
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
@Args('pageLayoutTabId', { type: () => String }) pageLayoutTabId: string,
|
||||
): Promise<PageLayoutWidgetDTO[]> {
|
||||
return this.pageLayoutWidgetService.findByPageLayoutTabId(
|
||||
workspace.id,
|
||||
return this.pageLayoutWidgetService.findByPageLayoutTabId({
|
||||
workspaceId: workspace.id,
|
||||
pageLayoutTabId,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Query(() => PageLayoutWidgetDTO)
|
||||
@@ -57,7 +57,10 @@ export class PageLayoutWidgetResolver {
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutWidgetDTO> {
|
||||
return this.pageLayoutWidgetService.findByIdOrThrow(id, workspace.id);
|
||||
return this.pageLayoutWidgetService.findByIdOrThrow({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutWidgetDTO)
|
||||
@@ -66,7 +69,10 @@ export class PageLayoutWidgetResolver {
|
||||
@Args('input') input: CreatePageLayoutWidgetInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutWidgetDTO> {
|
||||
return this.pageLayoutWidgetService.create(input, workspace.id);
|
||||
return this.pageLayoutWidgetService.create({
|
||||
input,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutWidgetDTO)
|
||||
@@ -76,16 +82,11 @@ export class PageLayoutWidgetResolver {
|
||||
@Args('input') input: UpdatePageLayoutWidgetInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutWidgetDTO> {
|
||||
return this.pageLayoutWidgetService.update(id, workspace.id, input);
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutWidgetDTO)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.LAYOUTS))
|
||||
async deletePageLayoutWidget(
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutWidgetDTO> {
|
||||
return this.pageLayoutWidgetService.delete(id, workspace.id);
|
||||
return this.pageLayoutWidgetService.update({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
updateData: input,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean)
|
||||
@@ -94,16 +95,10 @@ export class PageLayoutWidgetResolver {
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<boolean> {
|
||||
return this.pageLayoutWidgetService.destroy(id, workspace.id);
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutWidgetDTO)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.LAYOUTS))
|
||||
async restorePageLayoutWidget(
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutWidgetDTO> {
|
||||
return this.pageLayoutWidgetService.restore(id, workspace.id);
|
||||
return this.pageLayoutWidgetService.destroy({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@ResolveField(() => WidgetConfiguration, { nullable: true })
|
||||
|
||||
+38
-95
@@ -8,9 +8,7 @@ import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-m
|
||||
import { FlatPageLayoutWidgetMaps } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-maps.type';
|
||||
import { FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
|
||||
import { fromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreate } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/from-create-page-layout-widget-input-to-flat-page-layout-widget-to-create.util';
|
||||
import { fromDeletePageLayoutWidgetInputToFlatPageLayoutWidgetOrThrow } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/from-delete-page-layout-widget-input-to-flat-page-layout-widget-or-throw.util';
|
||||
import { fromDestroyPageLayoutWidgetInputToFlatPageLayoutWidgetOrThrow } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/from-destroy-page-layout-widget-input-to-flat-page-layout-widget-or-throw.util';
|
||||
import { fromRestorePageLayoutWidgetInputToFlatPageLayoutWidgetOrThrow } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/from-restore-page-layout-widget-input-to-flat-page-layout-widget-or-throw.util';
|
||||
import {
|
||||
fromUpdatePageLayoutWidgetInputToFlatPageLayoutWidgetToUpdateOrThrow,
|
||||
type UpdatePageLayoutWidgetInputWithId,
|
||||
@@ -87,10 +85,13 @@ export class PageLayoutWidgetService {
|
||||
}
|
||||
}
|
||||
|
||||
async findByPageLayoutTabId(
|
||||
workspaceId: string,
|
||||
pageLayoutTabId: string,
|
||||
): Promise<PageLayoutWidgetDTO[]> {
|
||||
async findByPageLayoutTabId({
|
||||
workspaceId,
|
||||
pageLayoutTabId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
pageLayoutTabId: string;
|
||||
}): Promise<PageLayoutWidgetDTO[]> {
|
||||
const flatPageLayoutWidgetMaps =
|
||||
await this.getFlatPageLayoutWidgetMaps(workspaceId);
|
||||
|
||||
@@ -109,10 +110,13 @@ export class PageLayoutWidgetService {
|
||||
.map(fromFlatPageLayoutWidgetToPageLayoutWidgetDto);
|
||||
}
|
||||
|
||||
async findByIdOrThrow(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
): Promise<PageLayoutWidgetDTO> {
|
||||
async findByIdOrThrow({
|
||||
id,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}): Promise<PageLayoutWidgetDTO> {
|
||||
const flatPageLayoutWidgetMaps =
|
||||
await this.getFlatPageLayoutWidgetMaps(workspaceId);
|
||||
|
||||
@@ -131,10 +135,13 @@ export class PageLayoutWidgetService {
|
||||
return fromFlatPageLayoutWidgetToPageLayoutWidgetDto(flatWidget);
|
||||
}
|
||||
|
||||
async create(
|
||||
createPageLayoutWidgetInput: CreatePageLayoutWidgetInput,
|
||||
workspaceId: string,
|
||||
): Promise<PageLayoutWidgetDTO> {
|
||||
async create({
|
||||
input,
|
||||
workspaceId,
|
||||
}: {
|
||||
input: CreatePageLayoutWidgetInput;
|
||||
workspaceId: string;
|
||||
}): Promise<PageLayoutWidgetDTO> {
|
||||
const { workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
@@ -142,7 +149,7 @@ export class PageLayoutWidgetService {
|
||||
|
||||
const flatPageLayoutWidgetToCreate =
|
||||
fromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreate({
|
||||
createPageLayoutWidgetInput,
|
||||
createPageLayoutWidgetInput: input,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId: workspaceCustomFlatApplication.id,
|
||||
});
|
||||
@@ -174,11 +181,15 @@ export class PageLayoutWidgetService {
|
||||
return fromFlatPageLayoutWidgetToPageLayoutWidgetDto(createdWidget);
|
||||
}
|
||||
|
||||
async update(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
updateData: UpdatePageLayoutWidgetInput,
|
||||
): Promise<PageLayoutWidgetDTO> {
|
||||
async update({
|
||||
id,
|
||||
workspaceId,
|
||||
updateData,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
updateData: UpdatePageLayoutWidgetInput;
|
||||
}): Promise<PageLayoutWidgetDTO> {
|
||||
const existingFlatPageLayoutWidgetMaps =
|
||||
await this.getFlatPageLayoutWidgetMaps(workspaceId);
|
||||
|
||||
@@ -252,44 +263,13 @@ export class PageLayoutWidgetService {
|
||||
return existingWidget;
|
||||
}
|
||||
|
||||
async delete(id: string, workspaceId: string): Promise<PageLayoutWidgetDTO> {
|
||||
const existingFlatPageLayoutWidgetMaps =
|
||||
await this.getFlatPageLayoutWidgetMaps(workspaceId);
|
||||
|
||||
const flatPageLayoutWidgetToDelete =
|
||||
fromDeletePageLayoutWidgetInputToFlatPageLayoutWidgetOrThrow({
|
||||
deletePageLayoutWidgetInput: { id },
|
||||
flatPageLayoutWidgetMaps: existingFlatPageLayoutWidgetMaps,
|
||||
});
|
||||
|
||||
await this.validateAndRunWidgetMigration({
|
||||
workspaceId,
|
||||
operations: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToUpdate: [flatPageLayoutWidgetToDelete],
|
||||
flatEntityToDelete: [],
|
||||
},
|
||||
errorMessage:
|
||||
'Multiple validation errors occurred while deleting page layout widget',
|
||||
});
|
||||
|
||||
const recomputedMaps = await this.getFlatPageLayoutWidgetMaps(workspaceId);
|
||||
|
||||
const deletedWidget = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: recomputedMaps,
|
||||
});
|
||||
|
||||
await this.dashboardSyncService.updateLinkedDashboardsUpdatedAtByWidgetId({
|
||||
widgetId: id,
|
||||
workspaceId,
|
||||
updatedAt: new Date(deletedWidget.updatedAt),
|
||||
});
|
||||
|
||||
return fromFlatPageLayoutWidgetToPageLayoutWidgetDto(deletedWidget);
|
||||
}
|
||||
|
||||
async destroy(id: string, workspaceId: string): Promise<boolean> {
|
||||
async destroy({
|
||||
id,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}): Promise<boolean> {
|
||||
const existingFlatPageLayoutWidgetMaps =
|
||||
await this.getFlatPageLayoutWidgetMaps(workspaceId);
|
||||
|
||||
@@ -318,41 +298,4 @@ export class PageLayoutWidgetService {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async restore(id: string, workspaceId: string): Promise<PageLayoutWidgetDTO> {
|
||||
const existingFlatPageLayoutWidgetMaps =
|
||||
await this.getFlatPageLayoutWidgetMaps(workspaceId);
|
||||
|
||||
const flatPageLayoutWidgetToRestore =
|
||||
fromRestorePageLayoutWidgetInputToFlatPageLayoutWidgetOrThrow({
|
||||
restorePageLayoutWidgetInput: { id },
|
||||
flatPageLayoutWidgetMaps: existingFlatPageLayoutWidgetMaps,
|
||||
});
|
||||
|
||||
await this.validateAndRunWidgetMigration({
|
||||
workspaceId,
|
||||
operations: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToUpdate: [flatPageLayoutWidgetToRestore],
|
||||
flatEntityToDelete: [],
|
||||
},
|
||||
errorMessage:
|
||||
'Multiple validation errors occurred while restoring page layout widget',
|
||||
});
|
||||
|
||||
const recomputedMaps = await this.getFlatPageLayoutWidgetMaps(workspaceId);
|
||||
|
||||
const restoredWidget = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: recomputedMaps,
|
||||
});
|
||||
|
||||
await this.dashboardSyncService.updateLinkedDashboardsUpdatedAtByWidgetId({
|
||||
widgetId: id,
|
||||
workspaceId,
|
||||
updatedAt: new Date(restoredWidget.updatedAt),
|
||||
});
|
||||
|
||||
return fromFlatPageLayoutWidgetToPageLayoutWidgetDto(restoredWidget);
|
||||
}
|
||||
}
|
||||
|
||||
+20
-16
@@ -38,10 +38,10 @@ export class PageLayoutController {
|
||||
@Query('objectMetadataId') objectMetadataId?: string,
|
||||
): Promise<PageLayoutDTO[]> {
|
||||
if (isDefined(objectMetadataId)) {
|
||||
return this.pageLayoutService.findByObjectMetadataId(
|
||||
workspace.id,
|
||||
return this.pageLayoutService.findByObjectMetadataId({
|
||||
workspaceId: workspace.id,
|
||||
objectMetadataId,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return this.pageLayoutService.findByWorkspaceId(workspace.id);
|
||||
@@ -53,7 +53,10 @@ export class PageLayoutController {
|
||||
@Param('id') id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutDTO | null> {
|
||||
return this.pageLayoutService.findByIdOrThrow(id, workspace.id);
|
||||
return this.pageLayoutService.findByIdOrThrow({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Post()
|
||||
@@ -62,7 +65,10 @@ export class PageLayoutController {
|
||||
@Body() input: CreatePageLayoutInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutDTO> {
|
||||
return this.pageLayoutService.create(input, workspace.id);
|
||||
return this.pageLayoutService.create({
|
||||
createPageLayoutInput: input,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@@ -72,26 +78,24 @@ export class PageLayoutController {
|
||||
@Body() input: UpdatePageLayoutInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutDTO> {
|
||||
const updatedPageLayout = await this.pageLayoutService.update(
|
||||
const updatedPageLayout = await this.pageLayoutService.update({
|
||||
id,
|
||||
workspace.id,
|
||||
input,
|
||||
);
|
||||
workspaceId: workspace.id,
|
||||
updateData: input,
|
||||
});
|
||||
|
||||
return updatedPageLayout;
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.LAYOUTS))
|
||||
async delete(
|
||||
async destroy(
|
||||
@Param('id') id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutDTO> {
|
||||
const deletedPageLayout = await this.pageLayoutService.delete(
|
||||
): Promise<boolean> {
|
||||
return this.pageLayoutService.destroy({
|
||||
id,
|
||||
workspace.id,
|
||||
);
|
||||
|
||||
return deletedPageLayout;
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata
|
||||
import { FlatPageLayoutTabModule } from 'src/engine/metadata-modules/flat-page-layout-tab/flat-page-layout-tab.module';
|
||||
import { FlatPageLayoutWidgetModule } from 'src/engine/metadata-modules/flat-page-layout-widget/flat-page-layout-widget.module';
|
||||
import { FlatPageLayoutModule } from 'src/engine/metadata-modules/flat-page-layout/flat-page-layout.module';
|
||||
import { PageLayoutTabModule } from 'src/engine/metadata-modules/page-layout-tab/page-layout-tab.module';
|
||||
import { PageLayoutWidgetModule } from 'src/engine/metadata-modules/page-layout-widget/page-layout-widget.module';
|
||||
import { PageLayoutController } from 'src/engine/metadata-modules/page-layout/controllers/page-layout.controller';
|
||||
import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity';
|
||||
import { PageLayoutResolver } from 'src/engine/metadata-modules/page-layout/resolvers/page-layout.resolver';
|
||||
@@ -38,8 +36,6 @@ import { DashboardSyncModule } from 'src/modules/dashboard-sync/dashboard-sync.m
|
||||
FlatPageLayoutTabModule,
|
||||
FlatPageLayoutWidgetModule,
|
||||
ApplicationModule,
|
||||
PageLayoutTabModule,
|
||||
PageLayoutWidgetModule,
|
||||
DashboardSyncModule,
|
||||
],
|
||||
controllers: [PageLayoutController],
|
||||
|
||||
+18
-34
@@ -7,7 +7,6 @@ import {
|
||||
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
@@ -43,10 +42,10 @@ export class PageLayoutResolver {
|
||||
objectMetadataId?: string,
|
||||
): Promise<PageLayoutDTO[]> {
|
||||
if (objectMetadataId) {
|
||||
return this.pageLayoutService.findByObjectMetadataId(
|
||||
workspace.id,
|
||||
return this.pageLayoutService.findByObjectMetadataId({
|
||||
workspaceId: workspace.id,
|
||||
objectMetadataId,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return this.pageLayoutService.findByWorkspaceId(workspace.id);
|
||||
@@ -58,7 +57,10 @@ export class PageLayoutResolver {
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutDTO | null> {
|
||||
return this.pageLayoutService.findByIdOrThrow(id, workspace.id);
|
||||
return this.pageLayoutService.findByIdOrThrow({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutDTO)
|
||||
@@ -67,7 +69,10 @@ export class PageLayoutResolver {
|
||||
@Args('input') input: CreatePageLayoutInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutDTO> {
|
||||
return this.pageLayoutService.create(input, workspace.id);
|
||||
return this.pageLayoutService.create({
|
||||
createPageLayoutInput: input,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutDTO)
|
||||
@@ -77,21 +82,11 @@ export class PageLayoutResolver {
|
||||
@Args('input') input: UpdatePageLayoutInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutDTO> {
|
||||
return this.pageLayoutService.update(id, workspace.id, input);
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutDTO)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.LAYOUTS))
|
||||
async deletePageLayout(
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutDTO> {
|
||||
const deletedPageLayout = await this.pageLayoutService.delete(
|
||||
return this.pageLayoutService.update({
|
||||
id,
|
||||
workspace.id,
|
||||
);
|
||||
|
||||
return deletedPageLayout;
|
||||
workspaceId: workspace.id,
|
||||
updateData: input,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean)
|
||||
@@ -100,21 +95,10 @@ export class PageLayoutResolver {
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<boolean> {
|
||||
const deletedPageLayout = await this.pageLayoutService.destroy(
|
||||
return this.pageLayoutService.destroy({
|
||||
id,
|
||||
workspace.id,
|
||||
);
|
||||
|
||||
return isDefined(deletedPageLayout);
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutDTO)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.LAYOUTS))
|
||||
async restorePageLayout(
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<PageLayoutDTO> {
|
||||
return this.pageLayoutService.restore(id, workspace.id);
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutDTO)
|
||||
|
||||
+78
-183
@@ -1,4 +1,4 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -10,9 +10,7 @@ import { type FlatPageLayoutTabMaps } from 'src/engine/metadata-modules/flat-pag
|
||||
import { type FlatPageLayoutWidgetMaps } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-maps.type';
|
||||
import { type FlatPageLayoutMaps } from 'src/engine/metadata-modules/flat-page-layout/types/flat-page-layout-maps.type';
|
||||
import { fromCreatePageLayoutInputToFlatPageLayoutToCreate } from 'src/engine/metadata-modules/flat-page-layout/utils/from-create-page-layout-input-to-flat-page-layout-to-create.util';
|
||||
import { fromDeletePageLayoutInputToFlatPageLayoutOrThrow } from 'src/engine/metadata-modules/flat-page-layout/utils/from-delete-page-layout-input-to-flat-page-layout-or-throw.util';
|
||||
import { fromDestroyPageLayoutInputToFlatPageLayoutOrThrow } from 'src/engine/metadata-modules/flat-page-layout/utils/from-destroy-page-layout-input-to-flat-page-layout-or-throw.util';
|
||||
import { fromRestorePageLayoutInputToFlatPageLayoutOrThrow } from 'src/engine/metadata-modules/flat-page-layout/utils/from-restore-page-layout-input-to-flat-page-layout-or-throw.util';
|
||||
import {
|
||||
fromUpdatePageLayoutInputToFlatPageLayoutToUpdateOrThrow,
|
||||
type UpdatePageLayoutInputWithId,
|
||||
@@ -38,8 +36,6 @@ import { DashboardSyncService } from 'src/modules/dashboard-sync/services/dashbo
|
||||
|
||||
@Injectable()
|
||||
export class PageLayoutService {
|
||||
private readonly logger = new Logger(PageLayoutService.name);
|
||||
|
||||
constructor(
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
@@ -70,10 +66,13 @@ export class PageLayoutService {
|
||||
);
|
||||
}
|
||||
|
||||
async findByObjectMetadataId(
|
||||
workspaceId: string,
|
||||
objectMetadataId: string,
|
||||
): Promise<PageLayoutDTO[]> {
|
||||
async findByObjectMetadataId({
|
||||
workspaceId,
|
||||
objectMetadataId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
objectMetadataId: string;
|
||||
}): Promise<PageLayoutDTO[]> {
|
||||
const {
|
||||
flatPageLayoutMaps,
|
||||
flatPageLayoutTabMaps,
|
||||
@@ -99,10 +98,13 @@ export class PageLayoutService {
|
||||
);
|
||||
}
|
||||
|
||||
async findByIdOrThrow(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
): Promise<PageLayoutDTO> {
|
||||
async findByIdOrThrow({
|
||||
id,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}): Promise<PageLayoutDTO> {
|
||||
const {
|
||||
flatPageLayoutMaps,
|
||||
flatPageLayoutTabMaps,
|
||||
@@ -111,7 +113,10 @@ export class PageLayoutService {
|
||||
|
||||
const flatLayout = flatPageLayoutMaps.byId[id];
|
||||
|
||||
if (!isDefined(flatLayout) || isDefined(flatLayout.deletedAt)) {
|
||||
const isLayoutNotFound =
|
||||
!isDefined(flatLayout) || isDefined(flatLayout.deletedAt);
|
||||
|
||||
if (isLayoutNotFound) {
|
||||
throw new PageLayoutException(
|
||||
generatePageLayoutExceptionMessage(
|
||||
PageLayoutExceptionMessageKey.PAGE_LAYOUT_NOT_FOUND,
|
||||
@@ -147,10 +152,13 @@ export class PageLayoutService {
|
||||
);
|
||||
}
|
||||
|
||||
async create(
|
||||
createPageLayoutInput: CreatePageLayoutInput,
|
||||
workspaceId: string,
|
||||
): Promise<Omit<PageLayoutDTO, 'tabs'>> {
|
||||
async create({
|
||||
createPageLayoutInput,
|
||||
workspaceId,
|
||||
}: {
|
||||
createPageLayoutInput: CreatePageLayoutInput;
|
||||
workspaceId: string;
|
||||
}): Promise<Omit<PageLayoutDTO, 'tabs'>> {
|
||||
if (!isNonEmptyString(createPageLayoutInput.name)) {
|
||||
throw new PageLayoutException(
|
||||
generatePageLayoutExceptionMessage(
|
||||
@@ -210,11 +218,15 @@ export class PageLayoutService {
|
||||
);
|
||||
}
|
||||
|
||||
async update(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
updateData: UpdatePageLayoutInput,
|
||||
): Promise<Omit<PageLayoutDTO, 'tabs'>> {
|
||||
async update({
|
||||
id,
|
||||
workspaceId,
|
||||
updateData,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
updateData: UpdatePageLayoutInput;
|
||||
}): Promise<Omit<PageLayoutDTO, 'tabs'>> {
|
||||
const { flatPageLayoutMaps: existingFlatPageLayoutMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
@@ -280,74 +292,15 @@ export class PageLayoutService {
|
||||
return fromFlatPageLayoutToPageLayoutDto(updatedLayout);
|
||||
}
|
||||
|
||||
async delete(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
): Promise<Omit<PageLayoutDTO, 'tabs'>> {
|
||||
const { flatPageLayoutMaps: existingFlatPageLayoutMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatPageLayoutMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const flatPageLayoutToDelete =
|
||||
fromDeletePageLayoutInputToFlatPageLayoutOrThrow({
|
||||
deletePageLayoutInput: { id },
|
||||
flatPageLayoutMaps: existingFlatPageLayoutMaps,
|
||||
});
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayout: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [flatPageLayoutToDelete],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild: false,
|
||||
},
|
||||
);
|
||||
|
||||
if (isDefined(validateAndBuildResult)) {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
validateAndBuildResult,
|
||||
'Multiple validation errors occurred while deleting page layout',
|
||||
);
|
||||
}
|
||||
|
||||
const { flatPageLayoutMaps: recomputedFlatPageLayoutMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatPageLayoutMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const deletedLayout = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: recomputedFlatPageLayoutMaps,
|
||||
});
|
||||
|
||||
await this.dashboardSyncService.softDeleteLinkedDashboardsByPageLayoutId({
|
||||
pageLayoutId: id,
|
||||
workspaceId,
|
||||
deletedAt: isDefined(deletedLayout.deletedAt)
|
||||
? new Date(deletedLayout.deletedAt)
|
||||
: new Date(),
|
||||
});
|
||||
|
||||
return fromFlatPageLayoutToPageLayoutDto(deletedLayout);
|
||||
}
|
||||
|
||||
async destroy(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
): Promise<Omit<PageLayoutDTO, 'tabs'>> {
|
||||
async destroy({
|
||||
id,
|
||||
workspaceId,
|
||||
isLinkedDashboardAlreadyDestroyed = false,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
isLinkedDashboardAlreadyDestroyed?: boolean;
|
||||
}): Promise<boolean> {
|
||||
const { flatPageLayoutMaps: existingFlatPageLayoutMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
@@ -384,106 +337,48 @@ export class PageLayoutService {
|
||||
);
|
||||
}
|
||||
|
||||
if (flatPageLayoutToDestroy.type === PageLayoutType.DASHBOARD) {
|
||||
await this.destroyAssociatedDashboards(id, workspaceId);
|
||||
if (
|
||||
flatPageLayoutToDestroy.type === PageLayoutType.DASHBOARD &&
|
||||
!isLinkedDashboardAlreadyDestroyed
|
||||
) {
|
||||
await this.destroyAssociatedDashboards({
|
||||
pageLayoutId: id,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
return fromFlatPageLayoutToPageLayoutDto(flatPageLayoutToDestroy);
|
||||
return true;
|
||||
}
|
||||
|
||||
private async destroyAssociatedDashboards(
|
||||
pageLayoutId: string,
|
||||
workspaceId: string,
|
||||
): Promise<void> {
|
||||
private async destroyAssociatedDashboards({
|
||||
pageLayoutId,
|
||||
workspaceId,
|
||||
}: {
|
||||
pageLayoutId: string;
|
||||
workspaceId: string;
|
||||
}): Promise<void> {
|
||||
const authContext = buildSystemAuthContext(workspaceId);
|
||||
|
||||
try {
|
||||
await this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
authContext,
|
||||
async () => {
|
||||
const dashboardRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository(
|
||||
workspaceId,
|
||||
'dashboard',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
await this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
authContext,
|
||||
async () => {
|
||||
const dashboardRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository(
|
||||
workspaceId,
|
||||
'dashboard',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
const dashboards = await dashboardRepository.find({
|
||||
where: {
|
||||
pageLayoutId,
|
||||
},
|
||||
});
|
||||
|
||||
for (const dashboard of dashboards) {
|
||||
await dashboardRepository.delete(dashboard.id);
|
||||
}
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to destroy associated dashboards for page layout ${pageLayoutId}: ${error}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async restore(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
): Promise<Omit<PageLayoutDTO, 'tabs'>> {
|
||||
const { flatPageLayoutMaps: existingFlatPageLayoutMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatPageLayoutMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const flatPageLayoutToRestore =
|
||||
fromRestorePageLayoutInputToFlatPageLayoutOrThrow({
|
||||
restorePageLayoutInput: { id },
|
||||
flatPageLayoutMaps: existingFlatPageLayoutMaps,
|
||||
});
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayout: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [flatPageLayoutToRestore],
|
||||
},
|
||||
const dashboards = await dashboardRepository.find({
|
||||
where: {
|
||||
pageLayoutId,
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild: false,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
if (isDefined(validateAndBuildResult)) {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
validateAndBuildResult,
|
||||
'Multiple validation errors occurred while restoring page layout',
|
||||
);
|
||||
}
|
||||
|
||||
const { flatPageLayoutMaps: recomputedFlatPageLayoutMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatPageLayoutMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const restoredLayout = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: recomputedFlatPageLayoutMaps,
|
||||
});
|
||||
|
||||
await this.dashboardSyncService.restoreLinkedDashboardsByPageLayoutId({
|
||||
pageLayoutId: id,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
return fromFlatPageLayoutToPageLayoutDto(restoredLayout);
|
||||
for (const dashboard of dashboards) {
|
||||
await dashboardRepository.delete(dashboard.id);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user