fix(server): skip standard page layout widgets referencing missing field metadatas during 1.23 backfill (#19825)
Some checks are pending
CD deploy main / deploy-main (push) Waiting to run
CI Create App E2E minimal / changed-files-check (push) Waiting to run
CI Create App E2E minimal / create-app-e2e-minimal (push) Blocked by required conditions
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Blocked by required conditions
CI Create App / changed-files-check (push) Waiting to run
CI Create App / create-app-test (lint) (push) Blocked by required conditions
CI Create App / create-app-test (test) (push) Blocked by required conditions
CI Create App / create-app-test (typecheck) (push) Blocked by required conditions
CI Create App / ci-create-app-status-check (push) Blocked by required conditions
CI Docs / changed-files-check (push) Waiting to run
CI Docs / docs-lint (push) Blocked by required conditions
CI Emails / ci-emails-status-check (push) Blocked by required conditions
CI Emails / changed-files-check (push) Waiting to run
CI Emails / emails-test (push) Blocked by required conditions
CI Example App Hello World / changed-files-check (push) Waiting to run
CI Example App Hello World / example-app-hello-world (push) Blocked by required conditions
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Blocked by required conditions
CI Example App Postcard / changed-files-check (push) Waiting to run
CI Example App Postcard / example-app-postcard (push) Blocked by required conditions
CI Example App Postcard / ci-example-app-postcard-status-check (push) Blocked by required conditions
Push translations to Crowdin / Extract and upload translations (push) Waiting to run

## Summary

The 1.23 backfill command (`upgrade:1-23:backfill-record-page-layouts`)
creates standard page layout widgets from `STANDARD_PAGE_LAYOUTS`. Some
widgets reference field metadatas via `universalConfiguration` (e.g. the
`opportunity.owner` FIELD widget pointing at universal identifier
`20202020-be7e-4d1e-8e19-3d5c7c4b9f2a`).

If a workspace's matching field metadata does not exist or has a
different universal identifier (e.g. older workspaces created before
standard universal identifiers were backfilled), the runner throws

```
Field metadata not found for universal identifier: 20202020-be7e-4d1e-8e19-3d5c7c4b9f2a
```

and the entire migration for that workspace aborts. This was the
underlying cause behind the `Migration action 'create' for
'pageLayoutWidget' failed` error surfaced by #19823.
This commit is contained in:
Charles Bochet 2026-04-17 23:59:13 +02:00 committed by GitHub
parent e878d646ed
commit 4fa2c400c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -15,6 +15,7 @@ import { type FlatPageLayout } from 'src/engine/metadata-modules/flat-page-layou
import { computeFlatDefaultRecordPageLayoutToCreate } from 'src/engine/metadata-modules/object-metadata/utils/compute-flat-default-record-page-layout-to-create.util';
import { computeFlatRecordPageFieldsViewToCreate } from 'src/engine/metadata-modules/object-metadata/utils/compute-flat-record-page-fields-view-to-create.util';
import { computeFlatViewFieldsToCreate } from 'src/engine/metadata-modules/object-metadata/utils/compute-flat-view-fields-to-create.util';
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant';
@ -245,9 +246,10 @@ export class BackfillRecordPageLayoutsCommand extends ActiveOrSuspendedWorkspace
twentyStandardApplicationId: twentyStandardFlatApplication.id,
});
const { flatObjectMetadataMaps } =
const { flatObjectMetadataMaps, flatFieldMetadataMaps } =
await this.workspaceCacheService.getOrRecompute(workspaceId, [
'flatObjectMetadataMaps',
'flatFieldMetadataMaps',
]);
const existingObjectMetadataUniversalIdentifiers = new Set(
@ -311,9 +313,37 @@ export class BackfillRecordPageLayoutsCommand extends ActiveOrSuspendedWorkspace
standardMaps.flatPageLayoutWidgetMaps.byUniversalIdentifier,
)
.filter(isDefined)
.filter((widget) =>
tabUniversalIdentifiers.has(widget.pageLayoutTabUniversalIdentifier),
);
.filter((widget) => {
if (
!tabUniversalIdentifiers.has(widget.pageLayoutTabUniversalIdentifier)
) {
return false;
}
if (
widget.universalConfiguration.configurationType ===
WidgetConfigurationType.FIELD
) {
const fieldMetadataUniversalIdentifier =
widget.universalConfiguration.fieldMetadataId;
if (
!isDefined(
flatFieldMetadataMaps.byUniversalIdentifier[
fieldMetadataUniversalIdentifier
],
)
) {
this.logger.log(
`Skipping standard widget ${widget.universalIdentifier} for workspace ${workspaceId}: field metadata ${fieldMetadataUniversalIdentifier} not found`,
);
return false;
}
}
return true;
});
const fieldsWidgetViewUniversalIdentifiers = new Set<string>();
@ -338,11 +368,6 @@ export class BackfillRecordPageLayoutsCommand extends ActiveOrSuspendedWorkspace
return true;
});
const { flatFieldMetadataMaps } =
await this.workspaceCacheService.getOrRecompute(workspaceId, [
'flatFieldMetadataMaps',
]);
const viewFields = Object.values(
standardMaps.flatViewFieldMaps.byUniversalIdentifier,
)