Reset Tab Page Layout (#19453)
## Context - Add "Reset to default" for page layout tabs and widgets — backend mutation resets overrides, reactivates deactivated children, and deletes custom children - Fix override write bug where mutating an overridable property (e.g. widget title) on a standard-app entity incorrectly overwrote the base column instead of writing to the overrides JSONB — PageLayoutUpdateService now uses resolveFlatEntityOverridableProperties for accurate diffing and routes properties through sanitizeOverridableEntityInput - Deprecate isOverridden - We need more time to think about this feature. Currently this adds too much complexity for a very small benefit https://github.com/user-attachments/assets/a84546c8-1e15-4d9e-a489-0825cf8b8ed2
This commit is contained in:
+13
@@ -15,6 +15,7 @@ import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorato
|
||||
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 { PageLayoutTabDTO } from 'src/engine/metadata-modules/page-layout-tab/dtos/page-layout-tab.dto';
|
||||
import { PageLayoutWidgetDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/page-layout-widget.dto';
|
||||
import { CreatePageLayoutInput } from 'src/engine/metadata-modules/page-layout/dtos/inputs/create-page-layout.input';
|
||||
import { UpdatePageLayoutWithTabsInput } from 'src/engine/metadata-modules/page-layout/dtos/inputs/update-page-layout-with-tabs.input';
|
||||
@@ -136,4 +137,16 @@ export class PageLayoutResolver {
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => PageLayoutTabDTO)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.LAYOUTS))
|
||||
async resetPageLayoutTabToDefault(
|
||||
@Args('id', { type: () => String }) id: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<Omit<PageLayoutTabDTO, 'widgets'>> {
|
||||
return this.pageLayoutResetService.resetPageLayoutTabToDefault({
|
||||
id,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+308
@@ -7,10 +7,19 @@ import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadat
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { splitEntitiesByResetStrategy } from 'src/engine/metadata-modules/flat-entity/utils/split-entities-by-reset-strategy.util';
|
||||
import { type FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type';
|
||||
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
|
||||
import { isFlatPageLayoutWidgetConfigurationOfType } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/is-flat-page-layout-widget-configuration-of-type.util';
|
||||
import { type FlatViewFieldGroup } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group.type';
|
||||
import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
|
||||
import { type PageLayoutTabDTO } from 'src/engine/metadata-modules/page-layout-tab/dtos/page-layout-tab.dto';
|
||||
import {
|
||||
PageLayoutTabException,
|
||||
PageLayoutTabExceptionCode,
|
||||
PageLayoutTabExceptionMessageKey,
|
||||
generatePageLayoutTabExceptionMessage,
|
||||
} from 'src/engine/metadata-modules/page-layout-tab/exceptions/page-layout-tab.exception';
|
||||
import { fromFlatPageLayoutTabToPageLayoutTabDto } from 'src/engine/metadata-modules/page-layout-tab/utils/from-flat-page-layout-tab-to-page-layout-tab-dto.util';
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
import {
|
||||
PageLayoutWidgetException,
|
||||
@@ -20,6 +29,7 @@ import {
|
||||
} from 'src/engine/metadata-modules/page-layout-widget/exceptions/page-layout-widget.exception';
|
||||
import { type PageLayoutWidgetDTO } from 'src/engine/metadata-modules/page-layout-widget/dtos/page-layout-widget.dto';
|
||||
import { fromFlatPageLayoutWidgetToPageLayoutWidgetDto } from 'src/engine/metadata-modules/page-layout-widget/utils/from-flat-page-layout-widget-to-page-layout-widget-dto.util';
|
||||
import { ViewService } from 'src/engine/metadata-modules/view/services/view.service';
|
||||
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
import { DashboardSyncService } from 'src/modules/dashboard-sync/services/dashboard-sync.service';
|
||||
@@ -33,6 +43,7 @@ export class PageLayoutResetService {
|
||||
private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly dashboardSyncService: DashboardSyncService,
|
||||
private readonly viewService: ViewService,
|
||||
) {}
|
||||
|
||||
async resetPageLayoutWidgetToDefault({
|
||||
@@ -187,6 +198,303 @@ export class PageLayoutResetService {
|
||||
return fromFlatPageLayoutWidgetToPageLayoutWidgetDto(updatedWidget);
|
||||
}
|
||||
|
||||
async resetPageLayoutTabToDefault({
|
||||
id,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}): Promise<Omit<PageLayoutTabDTO, 'widgets'>> {
|
||||
const {
|
||||
flatPageLayoutTabMaps,
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
flatViewFieldMaps,
|
||||
} =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: [
|
||||
'flatPageLayoutTabMaps',
|
||||
'flatPageLayoutWidgetMaps',
|
||||
'flatViewFieldGroupMaps',
|
||||
'flatViewFieldMaps',
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
const tab = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: flatPageLayoutTabMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(tab) || isDefined(tab.deletedAt)) {
|
||||
throw new PageLayoutTabException(
|
||||
generatePageLayoutTabExceptionMessage(
|
||||
PageLayoutTabExceptionMessageKey.PAGE_LAYOUT_TAB_NOT_FOUND,
|
||||
id,
|
||||
),
|
||||
PageLayoutTabExceptionCode.PAGE_LAYOUT_TAB_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const { workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
if (
|
||||
tab.applicationUniversalIdentifier ===
|
||||
workspaceCustomFlatApplication.universalIdentifier
|
||||
) {
|
||||
throw new PageLayoutTabException(
|
||||
`Custom tab "${id}" cannot be reset to default`,
|
||||
PageLayoutTabExceptionCode.INVALID_PAGE_LAYOUT_TAB_DATA,
|
||||
);
|
||||
}
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
const tabToUpdate: FlatPageLayoutTab = {
|
||||
...tab,
|
||||
overrides: null,
|
||||
updatedAt: now,
|
||||
};
|
||||
|
||||
const {
|
||||
widgetsToUpdate,
|
||||
widgetsToDelete,
|
||||
viewFieldGroupsToUpdate,
|
||||
viewFieldGroupsToDelete,
|
||||
viewFieldsToUpdate,
|
||||
viewFieldsToDelete,
|
||||
orphanedViewIds,
|
||||
} = this.computeTabChildResetOperations({
|
||||
tabId: id,
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
flatViewFieldMaps,
|
||||
workspaceCustomApplicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
now,
|
||||
});
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
pageLayoutTab: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToUpdate: [tabToUpdate],
|
||||
flatEntityToDelete: [],
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToUpdate: widgetsToUpdate,
|
||||
flatEntityToDelete: widgetsToDelete,
|
||||
},
|
||||
viewFieldGroup: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToUpdate: viewFieldGroupsToUpdate,
|
||||
flatEntityToDelete: viewFieldGroupsToDelete,
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToUpdate: viewFieldsToUpdate,
|
||||
flatEntityToDelete: viewFieldsToDelete,
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
isSystemBuild: false,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (validateAndBuildResult.status === 'fail') {
|
||||
throw new WorkspaceMigrationBuilderException(
|
||||
validateAndBuildResult,
|
||||
'Multiple validation errors occurred while resetting page layout tab to default',
|
||||
);
|
||||
}
|
||||
|
||||
await this.destroyOrphanedFieldsWidgetViews({
|
||||
viewIds: orphanedViewIds,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const { flatPageLayoutTabMaps: recomputedTabMaps } =
|
||||
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatPageLayoutTabMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const updatedTab = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: recomputedTabMaps,
|
||||
});
|
||||
|
||||
await this.dashboardSyncService.updateLinkedDashboardsUpdatedAtByTabId({
|
||||
tabId: id,
|
||||
workspaceId,
|
||||
updatedAt: new Date(updatedTab.updatedAt),
|
||||
});
|
||||
|
||||
return fromFlatPageLayoutTabToPageLayoutTabDto(updatedTab);
|
||||
}
|
||||
|
||||
private computeTabChildResetOperations({
|
||||
tabId,
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
flatViewFieldMaps,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
now,
|
||||
}: {
|
||||
tabId: string;
|
||||
flatPageLayoutWidgetMaps: {
|
||||
byUniversalIdentifier: Record<string, FlatPageLayoutWidget | undefined>;
|
||||
};
|
||||
flatViewFieldGroupMaps: {
|
||||
byUniversalIdentifier: Record<string, FlatViewFieldGroup | undefined>;
|
||||
};
|
||||
flatViewFieldMaps: {
|
||||
byUniversalIdentifier: Record<string, FlatViewField | undefined>;
|
||||
};
|
||||
workspaceCustomApplicationUniversalIdentifier: string;
|
||||
now: string;
|
||||
}): {
|
||||
widgetsToUpdate: FlatPageLayoutWidget[];
|
||||
widgetsToDelete: FlatPageLayoutWidget[];
|
||||
viewFieldGroupsToUpdate: FlatViewFieldGroup[];
|
||||
viewFieldGroupsToDelete: FlatViewFieldGroup[];
|
||||
viewFieldsToUpdate: FlatViewField[];
|
||||
viewFieldsToDelete: FlatViewField[];
|
||||
orphanedViewIds: string[];
|
||||
} {
|
||||
const existingWidgets = Object.values(
|
||||
flatPageLayoutWidgetMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter(
|
||||
(widget) =>
|
||||
widget.pageLayoutTabId === tabId && !isDefined(widget.deletedAt),
|
||||
);
|
||||
|
||||
const { toHardDelete: widgetsToDelete, toReset: widgetsToReset } =
|
||||
splitEntitiesByResetStrategy({
|
||||
entities: existingWidgets,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
now,
|
||||
});
|
||||
|
||||
let allViewFieldGroupsToUpdate: FlatViewFieldGroup[] = [];
|
||||
let allViewFieldGroupsToDelete: FlatViewFieldGroup[] = [];
|
||||
let allViewFieldsToUpdate: FlatViewField[] = [];
|
||||
let allViewFieldsToDelete: FlatViewField[] = [];
|
||||
|
||||
for (const widget of widgetsToReset) {
|
||||
if (
|
||||
!isFlatPageLayoutWidgetConfigurationOfType(
|
||||
widget,
|
||||
WidgetConfigurationType.FIELDS,
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const viewId = widget.configuration.viewId;
|
||||
|
||||
if (!isDefined(viewId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const {
|
||||
viewFieldGroupsToUpdate,
|
||||
viewFieldGroupsToDelete,
|
||||
viewFieldsToUpdate,
|
||||
viewFieldsToDelete,
|
||||
} = this.computeFieldsWidgetChildResetOperations({
|
||||
viewId,
|
||||
flatViewFieldGroupMaps,
|
||||
flatViewFieldMaps,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
now,
|
||||
});
|
||||
|
||||
allViewFieldGroupsToUpdate = [
|
||||
...allViewFieldGroupsToUpdate,
|
||||
...viewFieldGroupsToUpdate,
|
||||
];
|
||||
allViewFieldGroupsToDelete = [
|
||||
...allViewFieldGroupsToDelete,
|
||||
...viewFieldGroupsToDelete,
|
||||
];
|
||||
allViewFieldsToUpdate = [...allViewFieldsToUpdate, ...viewFieldsToUpdate];
|
||||
allViewFieldsToDelete = [...allViewFieldsToDelete, ...viewFieldsToDelete];
|
||||
}
|
||||
|
||||
const orphanedViewIds =
|
||||
this.collectOrphanedViewIdsFromDeletedWidgets(widgetsToDelete);
|
||||
|
||||
return {
|
||||
widgetsToUpdate: widgetsToReset,
|
||||
widgetsToDelete,
|
||||
viewFieldGroupsToUpdate: allViewFieldGroupsToUpdate,
|
||||
viewFieldGroupsToDelete: allViewFieldGroupsToDelete,
|
||||
viewFieldsToUpdate: allViewFieldsToUpdate,
|
||||
viewFieldsToDelete: allViewFieldsToDelete,
|
||||
orphanedViewIds,
|
||||
};
|
||||
}
|
||||
|
||||
private collectOrphanedViewIdsFromDeletedWidgets(
|
||||
widgets: FlatPageLayoutWidget[],
|
||||
): string[] {
|
||||
const viewIds: string[] = [];
|
||||
|
||||
for (const widget of widgets) {
|
||||
if (
|
||||
widget.configuration.configurationType !==
|
||||
WidgetConfigurationType.FIELDS
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const viewId = (widget.configuration as { viewId?: string | null })
|
||||
.viewId;
|
||||
|
||||
if (typeof viewId === 'string') {
|
||||
viewIds.push(viewId);
|
||||
}
|
||||
}
|
||||
|
||||
return viewIds;
|
||||
}
|
||||
|
||||
private async destroyOrphanedFieldsWidgetViews({
|
||||
viewIds,
|
||||
workspaceId,
|
||||
}: {
|
||||
viewIds: string[];
|
||||
workspaceId: string;
|
||||
}): Promise<void> {
|
||||
for (const viewId of viewIds) {
|
||||
try {
|
||||
await this.viewService.destroyOne({
|
||||
destroyViewInput: { id: viewId },
|
||||
workspaceId,
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.warn(
|
||||
`Failed to destroy orphaned view ${viewId} during tab reset: ${error}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private computeFieldsWidgetChildResetOperations({
|
||||
viewId,
|
||||
flatViewFieldGroupMaps,
|
||||
|
||||
+115
-18
@@ -33,6 +33,9 @@ import {
|
||||
generatePageLayoutExceptionMessage,
|
||||
} from 'src/engine/metadata-modules/page-layout/exceptions/page-layout.exception';
|
||||
import { fromFlatPageLayoutWithTabsAndWidgetsToPageLayoutDto } from 'src/engine/metadata-modules/page-layout/utils/from-flat-page-layout-with-tabs-and-widgets-to-page-layout-dto.util';
|
||||
import { isCallerOverridingEntity } from 'src/engine/metadata-modules/utils/is-caller-overriding-entity.util';
|
||||
import { resolveFlatEntityOverridableProperties } from 'src/engine/metadata-modules/utils/resolve-flat-entity-overridable-properties.util';
|
||||
import { sanitizeOverridableEntityInput } from 'src/engine/metadata-modules/utils/sanitize-overridable-entity-input.util';
|
||||
import { ViewService } from 'src/engine/metadata-modules/view/services/view.service';
|
||||
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
@@ -277,6 +280,10 @@ export class PageLayoutUpdateService {
|
||||
.filter(isDefined)
|
||||
.filter((tab) => tab.pageLayoutId === existingPageLayout.id);
|
||||
|
||||
const resolvedExistingTabs = existingTabs.map(
|
||||
resolveFlatEntityOverridableProperties,
|
||||
);
|
||||
|
||||
const {
|
||||
toCreate: entitiesToCreate,
|
||||
toUpdate: entitiesToUpdate,
|
||||
@@ -286,7 +293,7 @@ export class PageLayoutUpdateService {
|
||||
FlatPageLayoutTab,
|
||||
UpdatePageLayoutTabWithWidgetsInput
|
||||
>({
|
||||
existingObjects: existingTabs,
|
||||
existingObjects: resolvedExistingTabs,
|
||||
receivedObjects: tabs,
|
||||
propertiesToCompare: FLAT_PAGE_LAYOUT_TAB_EDITABLE_PROPERTIES,
|
||||
isEntityIncluded: (entity) => entity.isActive,
|
||||
@@ -329,11 +336,33 @@ export class PageLayoutUpdateService {
|
||||
flatEntityMaps: flatPageLayoutTabMaps,
|
||||
});
|
||||
|
||||
return {
|
||||
...existingTab,
|
||||
const shouldOverride = isCallerOverridingEntity({
|
||||
callerApplicationUniversalIdentifier:
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingTab.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
const editableProperties = {
|
||||
title: tabInput.title,
|
||||
position: tabInput.position,
|
||||
...(tabInput.icon !== undefined && { icon: tabInput.icon }),
|
||||
layoutMode: tabInput.layoutMode ?? existingTab.layoutMode,
|
||||
};
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
sanitizeOverridableEntityInput({
|
||||
metadataName: 'pageLayoutTab',
|
||||
existingFlatEntity: existingTab,
|
||||
updatedEditableProperties: editableProperties,
|
||||
shouldOverride,
|
||||
});
|
||||
|
||||
return {
|
||||
...existingTab,
|
||||
...updatedEditableProperties,
|
||||
overrides,
|
||||
updatedAt: now.toISOString(),
|
||||
};
|
||||
},
|
||||
@@ -346,11 +375,33 @@ export class PageLayoutUpdateService {
|
||||
flatEntityMaps: flatPageLayoutTabMaps,
|
||||
});
|
||||
|
||||
return {
|
||||
...existingTab,
|
||||
const shouldOverride = isCallerOverridingEntity({
|
||||
callerApplicationUniversalIdentifier:
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingTab.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
const editableProperties = {
|
||||
title: tabInput.title,
|
||||
position: tabInput.position,
|
||||
...(tabInput.icon !== undefined && { icon: tabInput.icon }),
|
||||
layoutMode: tabInput.layoutMode ?? existingTab.layoutMode,
|
||||
};
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
sanitizeOverridableEntityInput({
|
||||
metadataName: 'pageLayoutTab',
|
||||
existingFlatEntity: existingTab,
|
||||
updatedEditableProperties: editableProperties,
|
||||
shouldOverride,
|
||||
});
|
||||
|
||||
return {
|
||||
...existingTab,
|
||||
...updatedEditableProperties,
|
||||
overrides,
|
||||
isActive: true,
|
||||
updatedAt: now.toISOString(),
|
||||
};
|
||||
@@ -493,6 +544,10 @@ export class PageLayoutUpdateService {
|
||||
.filter(isDefined)
|
||||
.filter((widget) => widget.pageLayoutTabId === tabId);
|
||||
|
||||
const resolvedExistingWidgets = existingWidgets.map(
|
||||
resolveFlatEntityOverridableProperties,
|
||||
);
|
||||
|
||||
const {
|
||||
toCreate: entitiesToCreate,
|
||||
toUpdate: entitiesToUpdate,
|
||||
@@ -502,7 +557,7 @@ export class PageLayoutUpdateService {
|
||||
FlatPageLayoutWidget,
|
||||
UpdatePageLayoutWidgetWithIdInput
|
||||
>({
|
||||
existingObjects: existingWidgets,
|
||||
existingObjects: resolvedExistingWidgets,
|
||||
receivedObjects: widgets,
|
||||
propertiesToCompare: FLAT_PAGE_LAYOUT_WIDGET_EDITABLE_PROPERTIES,
|
||||
isEntityIncluded: (entity) => entity.isActive,
|
||||
@@ -555,16 +610,37 @@ export class PageLayoutUpdateService {
|
||||
flatEntityMaps: flatPageLayoutWidgetMaps,
|
||||
});
|
||||
|
||||
const shouldOverride = isCallerOverridingEntity({
|
||||
callerApplicationUniversalIdentifier:
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingWidget.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
const commonProperties = buildFlatPageLayoutWidgetCommonProperties({
|
||||
widgetInput,
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
const updatedConfiguration = widgetInput.configuration ?? null;
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
sanitizeOverridableEntityInput({
|
||||
metadataName: 'pageLayoutWidget',
|
||||
existingFlatEntity: existingWidget,
|
||||
updatedEditableProperties: {
|
||||
...commonProperties,
|
||||
configuration: updatedConfiguration,
|
||||
},
|
||||
shouldOverride,
|
||||
});
|
||||
|
||||
return {
|
||||
...existingWidget,
|
||||
...buildFlatPageLayoutWidgetCommonProperties({
|
||||
widgetInput,
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
}),
|
||||
configuration: updatedConfiguration,
|
||||
...updatedEditableProperties,
|
||||
overrides,
|
||||
updatedAt: now.toISOString(),
|
||||
...(isDefined(updatedConfiguration) && {
|
||||
universalConfiguration:
|
||||
@@ -591,16 +667,37 @@ export class PageLayoutUpdateService {
|
||||
flatEntityMaps: flatPageLayoutWidgetMaps,
|
||||
});
|
||||
|
||||
const shouldOverride = isCallerOverridingEntity({
|
||||
callerApplicationUniversalIdentifier:
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingWidget.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
const commonProperties = buildFlatPageLayoutWidgetCommonProperties({
|
||||
widgetInput,
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
const restoredConfiguration = widgetInput.configuration ?? null;
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
sanitizeOverridableEntityInput({
|
||||
metadataName: 'pageLayoutWidget',
|
||||
existingFlatEntity: existingWidget,
|
||||
updatedEditableProperties: {
|
||||
...commonProperties,
|
||||
configuration: restoredConfiguration,
|
||||
},
|
||||
shouldOverride,
|
||||
});
|
||||
|
||||
return {
|
||||
...existingWidget,
|
||||
...buildFlatPageLayoutWidgetCommonProperties({
|
||||
widgetInput,
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
}),
|
||||
configuration: restoredConfiguration,
|
||||
...updatedEditableProperties,
|
||||
overrides,
|
||||
isActive: true,
|
||||
updatedAt: now.toISOString(),
|
||||
...(isDefined(restoredConfiguration) && {
|
||||
|
||||
Reference in New Issue
Block a user