[FRONT COMPONENTS] Serialize relation between widget and front component (#18228)

This allows us to define page layout widgets of type front component in
an app with the front component universal identifier.
This commit is contained in:
Raphaël Bosi
2026-02-25 15:01:50 +01:00
committed by GitHub
parent 448241540d
commit 435e21d23f
15 changed files with 118 additions and 5 deletions
@@ -5,6 +5,7 @@ import { ApplicationEntity } from 'src/engine/core-modules/application/applicati
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { FlatPageLayoutWidgetTypeValidatorService } from 'src/engine/metadata-modules/flat-page-layout-widget/services/flat-page-layout-widget-type-validator.service';
import { WorkspaceFlatPageLayoutWidgetMapCacheService } from 'src/engine/metadata-modules/flat-page-layout-widget/services/workspace-flat-page-layout-widget-map-cache.service';
import { FrontComponentEntity } from 'src/engine/metadata-modules/front-component/entities/front-component.entity';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity';
import { PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity';
@@ -18,6 +19,7 @@ import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entit
PageLayoutTabEntity,
ObjectMetadataEntity,
FieldMetadataEntity,
FrontComponentEntity,
ViewEntity,
]),
],
@@ -10,6 +10,7 @@ import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
import { FlatPageLayoutWidgetMaps } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-maps.type';
import { fromPageLayoutWidgetEntityToFlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/from-page-layout-widget-entity-to-flat-page-layout-widget.util';
import { FrontComponentEntity } from 'src/engine/metadata-modules/front-component/entities/front-component.entity';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity';
import { PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity';
@@ -32,6 +33,8 @@ export class WorkspaceFlatPageLayoutWidgetMapCacheService extends WorkspaceCache
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
@InjectRepository(FieldMetadataEntity)
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
@InjectRepository(FrontComponentEntity)
private readonly frontComponentRepository: Repository<FrontComponentEntity>,
@InjectRepository(ViewEntity)
private readonly viewRepository: Repository<ViewEntity>,
) {
@@ -47,6 +50,7 @@ export class WorkspaceFlatPageLayoutWidgetMapCacheService extends WorkspaceCache
pageLayoutTabs,
objectMetadatas,
fieldMetadatas,
frontComponents,
views,
] = await Promise.all([
this.pageLayoutWidgetRepository.find({
@@ -73,6 +77,11 @@ export class WorkspaceFlatPageLayoutWidgetMapCacheService extends WorkspaceCache
select: ['id', 'universalIdentifier'],
withDeleted: true,
}),
this.frontComponentRepository.find({
where: { workspaceId },
select: ['id', 'universalIdentifier'],
withDeleted: true,
}),
this.viewRepository.find({
where: { workspaceId },
select: ['id', 'universalIdentifier'],
@@ -89,6 +98,9 @@ export class WorkspaceFlatPageLayoutWidgetMapCacheService extends WorkspaceCache
const fieldMetadataUniversalIdentifierById = Object.fromEntries(
createIdToUniversalIdentifierMap(fieldMetadatas),
);
const frontComponentUniversalIdentifierById = Object.fromEntries(
createIdToUniversalIdentifierMap(frontComponents),
);
const viewUniversalIdentifierById = Object.fromEntries(
createIdToUniversalIdentifierMap(views),
);
@@ -103,6 +115,7 @@ export class WorkspaceFlatPageLayoutWidgetMapCacheService extends WorkspaceCache
pageLayoutTabIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
fieldMetadataUniversalIdentifierById,
frontComponentUniversalIdentifierById,
viewUniversalIdentifierById,
});
@@ -19,6 +19,7 @@ export type FromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreateArgs =
| 'flatPageLayoutTabMaps'
| 'flatObjectMetadataMaps'
| 'flatFieldMetadataMaps'
| 'flatFrontComponentMaps'
| 'flatViewFieldGroupMaps'
| 'flatViewMaps'
>;
@@ -30,6 +31,7 @@ export const fromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreate = ({
flatPageLayoutTabMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatFrontComponentMaps,
flatViewFieldGroupMaps,
flatViewMaps,
}: FromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreateArgs): FlatPageLayoutWidget => {
@@ -82,6 +84,8 @@ export const fromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreate = ({
configuration: createPageLayoutWidgetInput.configuration,
fieldMetadataUniversalIdentifierById:
flatFieldMetadataMaps.universalIdentifierById,
frontComponentUniversalIdentifierById:
flatFrontComponentMaps.universalIdentifierById,
viewFieldGroupUniversalIdentifierById:
flatViewFieldGroupMaps.universalIdentifierById,
viewUniversalIdentifierById: flatViewMaps.universalIdentifierById,
@@ -73,12 +73,14 @@ const convertChartFilterToUniversalFilter = ({
export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
configuration,
fieldMetadataUniversalIdentifierById,
frontComponentUniversalIdentifierById = {},
viewFieldGroupUniversalIdentifierById = {},
viewUniversalIdentifierById = {},
shouldThrowOnMissingIdentifier = false,
}: {
configuration: PageLayoutWidgetConfiguration;
fieldMetadataUniversalIdentifierById: Partial<Record<string, string>>;
frontComponentUniversalIdentifierById?: Partial<Record<string, string>>;
viewFieldGroupUniversalIdentifierById?: Partial<Record<string, string>>;
viewUniversalIdentifierById?: Partial<Record<string, string>>;
shouldThrowOnMissingIdentifier?: boolean;
@@ -326,6 +328,28 @@ export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
};
}
case WidgetConfigurationType.FRONT_COMPONENT: {
const { frontComponentId, ...rest } = configuration;
const frontComponentUniversalIdentifier: string | null =
frontComponentUniversalIdentifierById[frontComponentId] ?? null;
if (
!isDefined(frontComponentUniversalIdentifier) &&
shouldThrowOnMissingIdentifier
) {
throw new FlatEntityMapsException(
`Front component universal identifier not found for id: ${frontComponentId}`,
FlatEntityMapsExceptionCode.RELATION_UNIVERSAL_IDENTIFIER_NOT_FOUND,
);
}
return {
...rest,
frontComponentUniversalIdentifier,
};
}
case WidgetConfigurationType.VIEW:
case WidgetConfigurationType.FIELD:
case WidgetConfigurationType.TIMELINE:
@@ -338,7 +362,6 @@ export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
case WidgetConfigurationType.WORKFLOW:
case WidgetConfigurationType.WORKFLOW_VERSION:
case WidgetConfigurationType.WORKFLOW_RUN:
case WidgetConfigurationType.FRONT_COMPONENT:
case WidgetConfigurationType.IFRAME:
case WidgetConfigurationType.STANDALONE_RICH_TEXT:
return configuration;
@@ -12,6 +12,7 @@ import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/type
type FromPageLayoutWidgetEntityToFlatPageLayoutWidgetArgs =
FromEntityToFlatEntityArgs<'pageLayoutWidget'> & {
fieldMetadataUniversalIdentifierById: Partial<Record<string, string>>;
frontComponentUniversalIdentifierById?: Partial<Record<string, string>>;
viewFieldGroupUniversalIdentifierById?: Partial<Record<string, string>>;
viewUniversalIdentifierById?: Partial<Record<string, string>>;
};
@@ -22,6 +23,7 @@ export const fromPageLayoutWidgetEntityToFlatPageLayoutWidget = ({
pageLayoutTabIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
fieldMetadataUniversalIdentifierById,
frontComponentUniversalIdentifierById,
viewFieldGroupUniversalIdentifierById,
viewUniversalIdentifierById,
}: FromPageLayoutWidgetEntityToFlatPageLayoutWidgetArgs): FlatPageLayoutWidget => {
@@ -74,6 +76,7 @@ export const fromPageLayoutWidgetEntityToFlatPageLayoutWidget = ({
fromPageLayoutWidgetConfigurationToUniversalConfiguration({
configuration: pageLayoutWidgetEntityWithoutRelations.configuration,
fieldMetadataUniversalIdentifierById,
frontComponentUniversalIdentifierById,
viewFieldGroupUniversalIdentifierById,
viewUniversalIdentifierById,
});
@@ -30,6 +30,7 @@ export const fromUpdatePageLayoutWidgetInputToFlatPageLayoutWidgetToUpdateOrThro
flatPageLayoutWidgetMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
flatFrontComponentMaps,
flatViewFieldGroupMaps,
flatViewMaps,
}: {
@@ -39,6 +40,7 @@ export const fromUpdatePageLayoutWidgetInputToFlatPageLayoutWidgetToUpdateOrThro
AllFlatEntityMaps,
| 'flatObjectMetadataMaps'
| 'flatFieldMetadataMaps'
| 'flatFrontComponentMaps'
| 'flatViewFieldGroupMaps'
| 'flatViewMaps'
>): FlatPageLayoutWidget => {
@@ -102,6 +104,8 @@ export const fromUpdatePageLayoutWidgetInputToFlatPageLayoutWidgetToUpdateOrThro
configuration: flatPageLayoutWidgetToUpdate.configuration,
fieldMetadataUniversalIdentifierById:
flatFieldMetadataMaps.universalIdentifierById,
frontComponentUniversalIdentifierById:
flatFrontComponentMaps.universalIdentifierById,
viewFieldGroupUniversalIdentifierById:
flatViewFieldGroupMaps.universalIdentifierById,
viewUniversalIdentifierById: flatViewMaps.universalIdentifierById,