Fix moving a widget to another tab (#19450)
https://github.com/user-attachments/assets/aac81e79-7f2f-4a34-bf68-c76061086821 --------- Co-authored-by: Weiko <corentin@twenty.com>
This commit is contained in:
committed by
GitHub
parent
1e908e5f0f
commit
16e145b036
+2
-6
@@ -116,6 +116,7 @@ export class PageLayoutResetService {
|
||||
const widgetToUpdate: FlatPageLayoutWidget = {
|
||||
...widget,
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
updatedAt: now,
|
||||
};
|
||||
|
||||
@@ -547,15 +548,10 @@ export class PageLayoutResetService {
|
||||
now,
|
||||
});
|
||||
|
||||
const viewFieldsToReset = fieldsToReset.map((field) => ({
|
||||
...field,
|
||||
universalOverrides: null,
|
||||
}));
|
||||
|
||||
return {
|
||||
viewFieldGroupsToUpdate: groupsToReset,
|
||||
viewFieldGroupsToDelete: groupsToDelete,
|
||||
viewFieldsToUpdate: viewFieldsToReset,
|
||||
viewFieldsToUpdate: fieldsToReset,
|
||||
viewFieldsToDelete: fieldsToDelete,
|
||||
};
|
||||
}
|
||||
|
||||
+202
-107
@@ -10,6 +10,7 @@ import { AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types
|
||||
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { resolveEntityRelationUniversalIdentifiers } from 'src/engine/metadata-modules/flat-entity/utils/resolve-entity-relation-universal-identifiers.util';
|
||||
import { splitEntitiesByRemovalStrategy } from 'src/engine/metadata-modules/flat-entity/utils/split-entities-by-removal-strategy.util';
|
||||
import { FLAT_PAGE_LAYOUT_TAB_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-page-layout-tab/constants/flat-page-layout-tab-editable-properties.constant';
|
||||
import { type FlatPageLayoutTabMaps } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab-maps.type';
|
||||
@@ -18,6 +19,7 @@ import { FLAT_PAGE_LAYOUT_WIDGET_EDITABLE_PROPERTIES } from 'src/engine/metadata
|
||||
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
|
||||
import { buildFlatPageLayoutWidgetCommonProperties } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/build-flat-page-layout-widget-common-properties.util';
|
||||
import { fromPageLayoutWidgetConfigurationToUniversalConfiguration } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/from-page-layout-widget-configuration-to-universal-configuration.util';
|
||||
import { fromPageLayoutWidgetOverridesToUniversalOverrides } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/from-page-layout-widget-overrides-to-universal-overrides.util';
|
||||
import { type FlatPageLayout } from 'src/engine/metadata-modules/flat-page-layout/types/flat-page-layout.type';
|
||||
import { reconstructFlatPageLayoutWithTabsAndWidgets } from 'src/engine/metadata-modules/flat-page-layout/utils/reconstruct-flat-page-layout-with-tabs-and-widgets.util';
|
||||
import { UpdatePageLayoutTabWithWidgetsInput } from 'src/engine/metadata-modules/page-layout-tab/dtos/inputs/update-page-layout-tab-with-widgets.input';
|
||||
@@ -468,11 +470,16 @@ export class PageLayoutUpdateService {
|
||||
const allWidgetsToUpdate: FlatPageLayoutWidget[] = [];
|
||||
const allWidgetsToDelete: FlatPageLayoutWidget[] = [];
|
||||
|
||||
const widgetIdsAcrossAllTabs = new Set(
|
||||
tabs.flatMap((tab) => tab.widgets.map((widget) => widget.id)),
|
||||
);
|
||||
|
||||
for (const tabInput of tabs) {
|
||||
const { widgetsToCreate, widgetsToUpdate, widgetsToDelete } =
|
||||
this.computeWidgetOperationsForTab({
|
||||
tabId: tabInput.id,
|
||||
widgets: tabInput.widgets,
|
||||
widgetIdsAcrossAllTabs,
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
@@ -500,6 +507,7 @@ export class PageLayoutUpdateService {
|
||||
private computeWidgetOperationsForTab({
|
||||
tabId,
|
||||
widgets,
|
||||
widgetIdsAcrossAllTabs,
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
@@ -513,6 +521,7 @@ export class PageLayoutUpdateService {
|
||||
}: {
|
||||
tabId: string;
|
||||
widgets: UpdatePageLayoutWidgetWithIdInput[];
|
||||
widgetIdsAcrossAllTabs: Set<string>;
|
||||
workspaceId: string;
|
||||
workspaceCustomApplicationId: string;
|
||||
workspaceCustomApplicationUniversalIdentifier: string;
|
||||
@@ -538,11 +547,15 @@ export class PageLayoutUpdateService {
|
||||
});
|
||||
}
|
||||
|
||||
const existingWidgets = Object.values(
|
||||
flatPageLayoutWidgetMaps.byUniversalIdentifier,
|
||||
)
|
||||
.filter(isDefined)
|
||||
.filter((widget) => widget.pageLayoutTabId === tabId);
|
||||
const widgetIdsInCurrentTabInput = new Set(
|
||||
widgets.map((widget) => widget.id),
|
||||
);
|
||||
|
||||
const existingWidgets = this.findWidgetsInTabOrMovingToTab({
|
||||
tabId,
|
||||
widgetIdsInCurrentTabInput,
|
||||
flatPageLayoutWidgetMaps,
|
||||
});
|
||||
|
||||
const resolvedExistingWidgets = existingWidgets.map(
|
||||
resolveFlatEntityOverridableProperties,
|
||||
@@ -587,6 +600,7 @@ export class PageLayoutUpdateService {
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
conditionalDisplay: null,
|
||||
overrides: null,
|
||||
universalOverrides: null,
|
||||
isActive: true,
|
||||
universalConfiguration:
|
||||
fromPageLayoutWidgetConfigurationToUniversalConfiguration({
|
||||
@@ -604,120 +618,45 @@ export class PageLayoutUpdateService {
|
||||
);
|
||||
|
||||
const widgetsToUpdate: FlatPageLayoutWidget[] = entitiesToUpdate.map(
|
||||
(widgetInput) => {
|
||||
const existingWidget = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: widgetInput.id,
|
||||
flatEntityMaps: flatPageLayoutWidgetMaps,
|
||||
});
|
||||
|
||||
const shouldOverride = isCallerOverridingEntity({
|
||||
callerApplicationUniversalIdentifier:
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingWidget.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
const commonProperties = buildFlatPageLayoutWidgetCommonProperties({
|
||||
(widgetInput) =>
|
||||
this.buildUpdatedFlatPageLayoutWidget({
|
||||
widgetInput,
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
const updatedConfiguration = widgetInput.configuration ?? null;
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
sanitizeOverridableEntityInput({
|
||||
metadataName: 'pageLayoutWidget',
|
||||
existingFlatEntity: existingWidget,
|
||||
updatedEditableProperties: {
|
||||
...commonProperties,
|
||||
configuration: updatedConfiguration,
|
||||
},
|
||||
shouldOverride,
|
||||
});
|
||||
|
||||
return {
|
||||
...existingWidget,
|
||||
...updatedEditableProperties,
|
||||
overrides,
|
||||
updatedAt: now.toISOString(),
|
||||
...(isDefined(updatedConfiguration) && {
|
||||
universalConfiguration:
|
||||
fromPageLayoutWidgetConfigurationToUniversalConfiguration({
|
||||
configuration: updatedConfiguration,
|
||||
fieldMetadataUniversalIdentifierById:
|
||||
flatFieldMetadataMaps.universalIdentifierById,
|
||||
frontComponentUniversalIdentifierById:
|
||||
flatFrontComponentMaps.universalIdentifierById,
|
||||
viewFieldGroupUniversalIdentifierById:
|
||||
flatViewFieldGroupMaps.universalIdentifierById,
|
||||
viewUniversalIdentifierById:
|
||||
flatViewMaps.universalIdentifierById,
|
||||
}),
|
||||
}),
|
||||
};
|
||||
},
|
||||
flatFieldMetadataMaps,
|
||||
flatFrontComponentMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
flatViewMaps,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
now,
|
||||
}),
|
||||
);
|
||||
|
||||
const widgetsToRestoreAndUpdate: FlatPageLayoutWidget[] =
|
||||
entitiesToRestoreAndUpdate.map((widgetInput) => {
|
||||
const existingWidget = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: widgetInput.id,
|
||||
flatEntityMaps: flatPageLayoutWidgetMaps,
|
||||
});
|
||||
|
||||
const shouldOverride = isCallerOverridingEntity({
|
||||
callerApplicationUniversalIdentifier:
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingWidget.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
const commonProperties = buildFlatPageLayoutWidgetCommonProperties({
|
||||
entitiesToRestoreAndUpdate.map((widgetInput) => ({
|
||||
...this.buildUpdatedFlatPageLayoutWidget({
|
||||
widgetInput,
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
flatFieldMetadataMaps,
|
||||
flatFrontComponentMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
flatViewMaps,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
now,
|
||||
}),
|
||||
isActive: true,
|
||||
}));
|
||||
|
||||
const restoredConfiguration = widgetInput.configuration ?? null;
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
sanitizeOverridableEntityInput({
|
||||
metadataName: 'pageLayoutWidget',
|
||||
existingFlatEntity: existingWidget,
|
||||
updatedEditableProperties: {
|
||||
...commonProperties,
|
||||
configuration: restoredConfiguration,
|
||||
},
|
||||
shouldOverride,
|
||||
});
|
||||
|
||||
return {
|
||||
...existingWidget,
|
||||
...updatedEditableProperties,
|
||||
overrides,
|
||||
isActive: true,
|
||||
updatedAt: now.toISOString(),
|
||||
...(isDefined(restoredConfiguration) && {
|
||||
universalConfiguration:
|
||||
fromPageLayoutWidgetConfigurationToUniversalConfiguration({
|
||||
configuration: restoredConfiguration,
|
||||
fieldMetadataUniversalIdentifierById:
|
||||
flatFieldMetadataMaps.universalIdentifierById,
|
||||
frontComponentUniversalIdentifierById:
|
||||
flatFrontComponentMaps.universalIdentifierById,
|
||||
viewFieldGroupUniversalIdentifierById:
|
||||
flatViewFieldGroupMaps.universalIdentifierById,
|
||||
viewUniversalIdentifierById:
|
||||
flatViewMaps.universalIdentifierById,
|
||||
}),
|
||||
}),
|
||||
};
|
||||
const widgetIdsToRemoveExcludingMovedToOtherTabs =
|
||||
this.excludeWidgetsMovedToOtherTabs({
|
||||
idsToRemove,
|
||||
widgetIdsAcrossAllTabs,
|
||||
});
|
||||
|
||||
const widgetsToRemove = idsToRemove
|
||||
const widgetsToRemove = widgetIdsToRemoveExcludingMovedToOtherTabs
|
||||
.map((widgetId) =>
|
||||
findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: widgetId,
|
||||
@@ -743,6 +682,162 @@ export class PageLayoutUpdateService {
|
||||
};
|
||||
}
|
||||
|
||||
private buildUpdatedFlatPageLayoutWidget({
|
||||
widgetInput,
|
||||
flatPageLayoutWidgetMaps,
|
||||
flatPageLayoutTabMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
flatFrontComponentMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
flatViewMaps,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
now,
|
||||
}: {
|
||||
widgetInput: UpdatePageLayoutWidgetWithIdInput;
|
||||
workspaceCustomApplicationUniversalIdentifier: string;
|
||||
now: Date;
|
||||
} & Pick<
|
||||
AllFlatEntityMaps,
|
||||
| 'flatObjectMetadataMaps'
|
||||
| 'flatFieldMetadataMaps'
|
||||
| 'flatFrontComponentMaps'
|
||||
| 'flatViewFieldGroupMaps'
|
||||
| 'flatViewMaps'
|
||||
| 'flatPageLayoutTabMaps'
|
||||
| 'flatPageLayoutWidgetMaps'
|
||||
>): FlatPageLayoutWidget {
|
||||
const existingWidget = findFlatEntityByIdInFlatEntityMapsOrThrow({
|
||||
flatEntityId: widgetInput.id,
|
||||
flatEntityMaps: flatPageLayoutWidgetMaps,
|
||||
});
|
||||
|
||||
const shouldOverride = isCallerOverridingEntity({
|
||||
callerApplicationUniversalIdentifier:
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
entityApplicationUniversalIdentifier:
|
||||
existingWidget.applicationUniversalIdentifier,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
const configuration = widgetInput.configuration ?? null;
|
||||
|
||||
const editableProperties: Partial<FlatPageLayoutWidget> = {
|
||||
title: widgetInput.title,
|
||||
type: widgetInput.type,
|
||||
objectMetadataId: widgetInput.objectMetadataId ?? null,
|
||||
gridPosition: widgetInput.gridPosition,
|
||||
position: widgetInput.position ?? null,
|
||||
configuration,
|
||||
pageLayoutTabId: widgetInput.pageLayoutTabId,
|
||||
};
|
||||
|
||||
if (widgetInput.conditionalDisplay !== undefined) {
|
||||
editableProperties.conditionalDisplay =
|
||||
widgetInput.conditionalDisplay ?? null;
|
||||
}
|
||||
|
||||
const { overrides, updatedEditableProperties } =
|
||||
sanitizeOverridableEntityInput({
|
||||
metadataName: 'pageLayoutWidget',
|
||||
existingFlatEntity: existingWidget,
|
||||
updatedEditableProperties: editableProperties,
|
||||
shouldOverride,
|
||||
});
|
||||
|
||||
const updatedWidget: FlatPageLayoutWidget = {
|
||||
...existingWidget,
|
||||
...updatedEditableProperties,
|
||||
overrides,
|
||||
updatedAt: now.toISOString(),
|
||||
};
|
||||
|
||||
if (updatedEditableProperties.pageLayoutTabId !== undefined) {
|
||||
const { pageLayoutTabUniversalIdentifier } =
|
||||
resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'pageLayoutWidget',
|
||||
foreignKeyValues: {
|
||||
pageLayoutTabId: updatedWidget.pageLayoutTabId,
|
||||
},
|
||||
flatEntityMaps: { flatPageLayoutTabMaps },
|
||||
});
|
||||
|
||||
updatedWidget.pageLayoutTabUniversalIdentifier =
|
||||
pageLayoutTabUniversalIdentifier;
|
||||
}
|
||||
|
||||
if (updatedEditableProperties.objectMetadataId !== undefined) {
|
||||
const { objectMetadataUniversalIdentifier } =
|
||||
resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'pageLayoutWidget',
|
||||
foreignKeyValues: {
|
||||
objectMetadataId: updatedWidget.objectMetadataId,
|
||||
},
|
||||
flatEntityMaps: { flatObjectMetadataMaps },
|
||||
});
|
||||
|
||||
updatedWidget.objectMetadataUniversalIdentifier =
|
||||
objectMetadataUniversalIdentifier;
|
||||
}
|
||||
|
||||
if (isDefined(overrides)) {
|
||||
updatedWidget.universalOverrides =
|
||||
fromPageLayoutWidgetOverridesToUniversalOverrides({
|
||||
overrides,
|
||||
pageLayoutTabUniversalIdentifierById:
|
||||
flatPageLayoutTabMaps.universalIdentifierById,
|
||||
});
|
||||
} else {
|
||||
updatedWidget.universalOverrides = null;
|
||||
}
|
||||
|
||||
if (isDefined(configuration)) {
|
||||
updatedWidget.universalConfiguration =
|
||||
fromPageLayoutWidgetConfigurationToUniversalConfiguration({
|
||||
configuration,
|
||||
fieldMetadataUniversalIdentifierById:
|
||||
flatFieldMetadataMaps.universalIdentifierById,
|
||||
frontComponentUniversalIdentifierById:
|
||||
flatFrontComponentMaps.universalIdentifierById,
|
||||
viewFieldGroupUniversalIdentifierById:
|
||||
flatViewFieldGroupMaps.universalIdentifierById,
|
||||
viewUniversalIdentifierById: flatViewMaps.universalIdentifierById,
|
||||
});
|
||||
}
|
||||
|
||||
return updatedWidget;
|
||||
}
|
||||
|
||||
private findWidgetsInTabOrMovingToTab({
|
||||
tabId,
|
||||
widgetIdsInCurrentTabInput,
|
||||
flatPageLayoutWidgetMaps,
|
||||
}: {
|
||||
tabId: string;
|
||||
widgetIdsInCurrentTabInput: Set<string>;
|
||||
flatPageLayoutWidgetMaps: AllFlatEntityMaps['flatPageLayoutWidgetMaps'];
|
||||
}): FlatPageLayoutWidget[] {
|
||||
return Object.values(flatPageLayoutWidgetMaps.byUniversalIdentifier)
|
||||
.filter(isDefined)
|
||||
.filter(
|
||||
(widget) =>
|
||||
widget.pageLayoutTabId === tabId ||
|
||||
widgetIdsInCurrentTabInput.has(widget.id),
|
||||
);
|
||||
}
|
||||
|
||||
private excludeWidgetsMovedToOtherTabs({
|
||||
idsToRemove,
|
||||
widgetIdsAcrossAllTabs,
|
||||
}: {
|
||||
idsToRemove: string[];
|
||||
widgetIdsAcrossAllTabs: Set<string>;
|
||||
}): string[] {
|
||||
return idsToRemove.filter(
|
||||
(widgetId) => !widgetIdsAcrossAllTabs.has(widgetId),
|
||||
);
|
||||
}
|
||||
|
||||
private validateChartFieldReferences({
|
||||
widgetInput,
|
||||
flatFieldMetadataMaps,
|
||||
|
||||
Reference in New Issue
Block a user