Skip to content

fix(edit-content): open related content in a side panel from the full-screen editor - #37415

Merged
adrianjm-dotCMS merged 2 commits into
mainfrom
37385-relationship-nav-unsaved
Sep 4, 2026
Merged

fix(edit-content): open related content in a side panel from the full-screen editor#37415
adrianjm-dotCMS merged 2 commits into
mainfrom
37385-relationship-nav-unsaved

Conversation

@adrianjm-dotCMS

@adrianjm-dotCMS adrianjm-dotCMS commented Sep 4, 2026

Copy link
Copy Markdown
Member

Fixes #37385.

The problem

Creating content from a Relationship field and then clicking it raised the "unsaved changes" dialog. Navigating away unmounts the editor, and the relation to the content you just created lives only in that unsaved form — so the guard was right to warn, and the user was left choosing between losing the relation and not opening the content.

The fix

From the full-screen editor, related content now opens in a side panel instead of navigating. The editor stays mounted, so nothing is lost and there is nothing to warn about; closing the panel returns to it untouched.

From inside a panel, nothing changes — it navigates in place and keeps its crumb trail, so no second panel is stacked.

The rule is positional, not based on form or item state, so the same click always behaves the same way in the same place.

Editing a related content in the panel also refreshes its row (title, status), keeping the current page and without dirtying the form.

Small extra, found while testing

A contentlet returned by a workflow action carries only languageId, not the language object the Locales column formats — so a row for content just created from the field showed a blank locale until the parent was saved. Both paths that add a just-saved contentlet to the table now resolve the language from the editor's already-loaded locales, by id, with no extra request.

Testing

edit-content (full library)   114 suites, 2294 tests   ✅
lint edit-content             0 errors                 ✅

Known gaps: no automated test proves the editor's form survives the panel round-trip (the spec proves no navigation is requested, which is indirect) — covered by the manual steps below. The hop that opens the panel leaves no crumb; a panel-header trail was scoped and deferred. Inside a panel the original prompt still appears, since that context does not stack.

How to test

  1. Open a content item whose type has a Relationship field (side panel flag on).
  2. Edit another field (e.g. the title) so there are pending changes.
  3. Relationship field → Create new content → fill and save. It appears as a row, with its Locales cell already filled.
  4. Click that row → opens in a side panel, no dialog.
  5. Close the panel (✕ or ESC) → the editor still shows your pending title change and lists the new item.
  6. From inside the panel, click one of its related contents → navigates in place with the crumb trail, no second panel.
  7. Regression: with pending changes, close the editor or navigate away → the unsaved-changes prompt still appears.

This PR fixes: #37385

…-screen editor

Clicking a related content in a Relationship field navigated away from the
editor, discarding its unsaved form — the only place a relation created from
that field exists, since nothing persists it at creation time. The
unsaved-changes guard correctly intervened, which left the user choosing
between losing that relation and not opening the content at all. A flow users
are directed into ("create the related content here, then go look at it") could
not be completed.

From the full-screen editor, related content now opens in a side panel over it:
the editor stays mounted, nothing is discarded, and closing the panel returns to
it untouched. From inside a panel, navigation is unchanged — it reloads in place
and keeps its crumb trail, so no second panel is stacked. The decision is
positional (`#opensInSidePanel`), not based on form or item state: two stateful
rules were built and rejected in review because the same click behaved
differently for invisible reasons, losing the trail and breadcrumb.

Editing a related content in the panel now refreshes its row, matched by
identifier so the field's value is unchanged and the refresh cannot dirty the
form by itself.

Also fixes a second, pre-existing defect found while verifying: a contentlet
returned by a workflow action carries only `languageId`, not the language object
the Locales column formats, so a row for content just created from the field
showed a blank locale until the parent was saved. Both paths that put a
just-saved contentlet in the table now resolve the language from the editor's
already-loaded locales, by id, with no extra request.

Test-first was NOT followed here (Constitution Principle V): the implementation
preceded the tests. Each behavioral assertion was afterwards confirmed to fail
against unfixed code by neutering the production helpers, which shows the
assertions are load-bearing but is not Red-before-Green. Disclosed rather than
presented as compliance.

Spec, plan and tasks live in specs/37385-relationship-nav-unsaved/; only spec.md
is tracked, per the repo's Spec-Kit gitignore rules. Implementation ships in this
same PR by developer decision, instead of the usual spec-PR-first flow.

Refs #37385

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Claude finished @adrianjm-dotCMS's task in 2m 16s —— View job


SDK Compatibility Check

  • Read docs/core/SDK_BREAKING_CHANGE_CATEGORIES.md
  • Get the full PR diff for the 2 changed source files (dot-relationship-field.component.ts, relationship-field.store.ts)
  • Analyze against every category (G-1/G-2/G-3, R-1, U-1/U-2, H-1)
  • Conclusion posted below

Result: No SDK breaking change detected.

This PR only touches core-web/libs/edit-content/... (the dotcms-ui full-screen/panel content editor):

  • dot-relationship-field.component.ts — changes openRelated() to open related content in a side panel instead of navigating, adds #opensInSidePanel(), #refreshRelatedItem(), #withResolvedLanguage().
  • relationship-field.store.ts — adds a refreshItem() store method that replaces one row in place (marked lastChangeSource: 'load'), plus corresponding specs.

None of these touch a surface any @dotcms/* SDK relies on:

  • No GraphQL schema/query changes (page-api.ts, buildPageQuery, resolvers) — not touched.
  • No REST response shape changes to /api/v1/nav, /api/v1/content, or /api/v1/page/* — the "language resolution" logic (#withResolvedLanguage) resolves the language client-side from locales the editor already has in memory (this.#editContentStore.locales()); it makes no new request and changes no server response shape.
  • No UVE/editor postMessage protocol changes (DotCMSUVEAction, __DOTCMS_UVE_EVENT__) — not touched.
  • No SdkVersionWebInterceptor / header / compareVersions() changes — not touched.

This falls squarely under the doc's non-breaking calibration example: an admin-UI (dotcms-ui) internal-refactor change with no wire-format impact. Per instructions, no comment/label is being added for this outcome.

`#refreshRelatedItem` went through the store's `setData`, which resets
pagination to page 1 and flags the change as a user edit. Editing a related
content that sits on page 2 or later and saving it therefore snapped the table
back to page 1, losing the user's place — with a page size of 6, that starts at
seven related items.

Replace it with a dedicated `refreshItem` on the store, mirroring `reorderData`,
which exists for the same reason: it replaces one item in place, matched by
identifier (stable across saves, unlike the inode), keeps the current page, and
marks the change as `'load'` so it can never dirty the form. The relationship
itself did not change — only the version of one entry.

The old path did not dirty the form either, but only incidentally: the field's
value is a list of identifiers, which the refresh leaves untouched, so the
computed never emitted. That would have broken silently the moment the value
included anything else.

Refs #37385

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@adrianjm-dotCMS
adrianjm-dotCMS marked this pull request as ready for review September 4, 2026 20:42
@adrianjm-dotCMS
adrianjm-dotCMS added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit e34836f Sep 4, 2026
51 checks passed
@adrianjm-dotCMS
adrianjm-dotCMS deleted the 37385-relationship-nav-unsaved branch September 4, 2026 22:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Safe To Rollback Area : Frontend PR changes Angular/TypeScript frontend code

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Relationship field: navigating to content just created from the field triggers the unsaved-changes prompt

2 participants