5dc9d7ab36
## Summary Uniformizes the workspace migration engine so **every** view child entity — `viewField`, `viewFieldGroup`, `viewGroup`, `viewFilter`, `viewSort`, `viewFilterGroup` — can be reparented from one view to another within a single manifest sync, including when the previous parent view is deleted in the same sync. ### Context When an app manifest deletes a view and reparents its children onto another view in the same sync (e.g. replacing a custom `FIELDS_WIDGET` view with a standard one), the sync failed with a builder validation error `View field to update parent view not found`. Root causes: 1. `viewField`, `viewFieldGroup` and `viewGroup` had `viewId.toCompare: false`, so the diff never detected the parent-view change and never emitted a reparent update (the already-reparentable siblings `viewFilter`/`viewSort`/`viewFilterGroup` had `toCompare: true`). 2. `validateFlatViewFieldGroupUpdate` resolved the *old* parent view (it ignored the update patch), inconsistent with the other view-child validators. 3. Once the builder no longer errors, the runner would fail silently: `view.delete` ran **before** the child reparent updates, and `viewId` is `onDelete: CASCADE`, so the old view's deletion cascade-deleted the children before they could be reparented (silent data loss, since `repository.update` on a missing row is a no-op). ### Changes - **`all-entity-properties-configuration-by-metadata-name.constant.ts`**: set `viewId.toCompare: true` for `viewField`, `viewFieldGroup`, `viewGroup`. Because `viewId` maps to `universalProperty: 'viewUniversalIdentifier'`, the diff compares **only** `viewUniversalIdentifier` (never the raw FK). Snapshot updated accordingly. - **`flat-view-field-group-validator.service.ts`**: merge `flatEntityUpdate` and resolve the **new** parent view, matching the `viewField`/`viewGroup`/`viewSort` validators. - **`compute-ordered-migration-actions.util.ts`**: move `view.delete` to run **after** all view-child create/update actions so a child can be reparented off a view that is being deleted in the same sync. Child `delete → create → update` order is preserved (needed for `viewField`'s partial-unique `(fieldMetadataId, viewId)`). - **New integration test** `successful-manifest-reparent-view-children.integration-spec.ts` covering reparenting of every view child (a) between two persisting views and (b) when the source view is deleted in the same sync. ## Test plan - [x] `nx typecheck twenty-server` - [x] oxlint + oxfmt on changed files - [x] Unit snapshot regenerated: `all-universal-flat-entity-properties-to-compare-and-stringify.constant.spec` - [x] New integration test passes (both scenarios) - [x] Verified the delete-source scenario **fails** on the old action ordering (children cascade-deleted, `Received length: 0`) and **passes** after the reorder — confirming it's a genuine regression guard Made with [Cursor](https://cursor.com) <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22600?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->