Skip to content

feat(edit-content): related-content navigation via agnostic EditContentHost (#36349)#36491

Open
adrianjm-dotCMS wants to merge 18 commits into
mainfrom
issue-36349-related-content-breadcrumb-navigation
Open

feat(edit-content): related-content navigation via agnostic EditContentHost (#36349)#36491
adrianjm-dotCMS wants to merge 18 commits into
mainfrom
issue-36349-related-content-breadcrumb-navigation

Conversation

@adrianjm-dotCMS

@adrianjm-dotCMS adrianjm-dotCMS commented Jul 9, 2026

Copy link
Copy Markdown
Member

Proposed Changes

Restores navigating between related content in the new Edit Contentlet and, to enable it cleanly, makes the editor presentation-agnostic.

Fixes #36349

Related-content navigation (the feature)

  • Clicking a related content's title opens it; a "Relating content" breadcrumb banner tracks the trail (grows/trims, click an earlier crumb to go back).
  • The existing unsaved-changes prompt still fires when navigating with a dirty form.
  • Works full-screen (URL-driven trail via the rc query param) and inside a dialog (in-place reload, in-memory trail).

Agnostic editor via EditContentHost (the mechanism)

The editor and its store no longer branch on isDialogMode — that conditional is removed entirely. Everything presentation-specific goes through an injected EditContentHost port:

Concern RouterEditContentHost (full-screen) DialogEditContentHost (dialog)
Identity route params dialog config
Navigation (related/crumb/locale/post-save/restore) router in-place reload
Title / breadcrumb document title + shell trail no-op
Save result URL is source of truth reported to opener via saved$

The shell provides the router host; the dialog component provides the dialog host. Adding a new presentation (e.g. side panel) is then just a new adapter + a thin host wrapper — no editor changes.

How to test

Full-screen (/content/:id): open a content with a relationship field → click a related content's title → it opens with the "Relating content" banner → click a crumb to go back. Verify locale switch, version restore, and post-save navigation still work; and that unsaved changes prompt.

Dialog (UVE or "create new related content"): edit/create content in the dialog → click a related content in a relationship field → the editor reloads in place within the dialog with the breadcrumb → go back via a crumb → save reports back to the opener.

Checklist

  • Tests: pnpm nx test edit-content — 107 suites green
  • Lint + typecheck clean
  • Manual QA (full-screen + dialog)

…ntHost (#36349)

Restore navigating between related content in the new Edit Contentlet: clicking
a related content's title opens it and a "Relating content" breadcrumb tracks
the trail (grows/trims, click to go back, unsaved-changes prompt preserved).

Makes the editor presentation-agnostic via an `EditContentHost` port so the same
editor works full-screen and inside a dialog (and, later, a side panel) with no
`isDialogMode` conditionals:

- `RouterEditContentHost` (full-screen): identity from the route, router
  navigation, document title + shell breadcrumb, URL-driven trail (`rc` param).
- `DialogEditContentHost` (dialog): identity from the dialog config, in-place
  reloads, in-memory trail, save result reported to the opener via `saved$`.

Identity (`resolveIdentity`), navigation (related content, crumbs, locale switch,
post-save/restore), the save result (`reportSaved`) and title/breadcrumb all go
through the host; `isDialogMode` is removed entirely.

Related-content navigation now also works from within a dialog (in-place reload).

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

claude Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @adrianjm-dotCMS's task in 11m 29s —— View job


Code Review

Reviewed the full diff against origin/main, focusing on the EditContentHost port, the two adapters, the route-reuse change, the navigation store, and the relationship-field dirty-state handling. Also rechecked the open Copilot findings.

New Issues

  • 🟠 High: core-web/libs/edit-content/src/lib/edit-content.routes.ts:28 (+ core-web/apps/dotcms-ui/src/app/app.routes.ts:132) — Browser back/forward (and manual URL edits) between two content inodes with a dirty form now silently discard unsaved changes. Removing reuseRoute: false means canDeactivate no longer fires on :id → :id. In-app moves are re-guarded via host.setNavigationGuard(), but that guard is only ever invoked from the host's own navigation methods (goToCrumb/reloadContent/goToRelatedContent/goToRestoredVersion/goToSavedContent). A popstate navigation (browser Back/Forward) or a direct URL change bypasses all of them: it fires NavigationEnd, which identityChanges$ picks up in dot-edit-content.layout.component.ts:227 to call this.$store.initialize() without any dirty check, reloading the new content over the dirty form. The route comment claims identityChanges$ "covers browser back/forward" — it covers the reload, not the prompt. Before this PR, reuseRoute: false made canDeactivate fire on these navigations, so this is a regression against the unsaved-changes AC. Consider guarding the identityChanges$ subscription with the same hasUnsavedChanges() / #confirmIfDirty check the in-place path uses (and reverting the URL if the user keeps editing), or a NavigationStart-level guard. Fix this →

Existing (Copilot findings still worth a look)

  • 🟡 Medium: dotCMS/src/main/webapp/WEB-INF/messages/Language.properties:6484 — Label reads Relating content, while the linked issue/AC text is "Related content". Non-blocking, but worth confirming the intended copy with the issue owner before merge.

Resolved / Not applicable (rechecked against current code)

  • dot-relationship-field.component.ts:310 — Copilot's concern that a new-translation crumb overwrites the source inode's cached title does not hold: originTitle is set to '' whenever the origin is not the current content, and registerTitle ignores empty titles, so the source's cached title stands and the target crumb correctly uses item.title.
  • router-edit-content-host.ts / overlay-edit-content-host.ts — Copilot flagged setTrail/reportSaved/setContentTitle/addBreadcrumb as "implemented with no parameter." They in fact keep the parameter with a _-prefix (_inodes, _contentlet, _label, _crumb), matching the port signature. No change needed.
  • dot-related-content-navigation.store.ts — The inMemoryTrail doc comment Copilot referenced is not present in the current file; the doc now correctly describes the trail living in the URL (router host) or in the overlay host.
  • overlay-edit-content-host.ts:goToRestoredVersion / router-edit-content-host.ts:#navigateRepointingCurrentCrumb — the earlier reviewer findings on restore-in-dialog and AC-B4 crumb repointing appear addressed in the current diff.

Everything else in the host abstraction reads cleanly — the port is well documented, error paths in the store features preserve the existing dotHttpErrorManagerService.handle + navigate-away behavior, and the lastChangeSource 'load' vs 'user' split is a sound fix for the async-load-re-dirties-the-form problem.

issue-36349-related-content-breadcrumb-navigation

…36349)

Update stale JSDoc/comments that still described the old "dialog mode vs route
mode" branching: the nav store now holds a URL-or-in-memory trail and does not
navigate (the host does), and workflow/layout comments reflect host delegation.
Comment-only; no behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ath (#36349)

Resolve the two behavioral findings from the PR review plus the smaller ones:

- Dialog "Keep editing" no longer leaves a stale breadcrumb: the in-place trail
  is now emitted with the reload request and committed by the layout (host.setTrail)
  ONLY after the unsaved-changes check passes, instead of being written up-front.
- The dialog no longer blanks a full-screen editor's breadcrumb behind it: the
  in-memory trail moved off the root nav store onto a per-instance signal on
  DialogEditContentHost. The nav store is URL-only again; the host owns its trail
  (host.trail) and the layout reads that.
- Guard the `rc` query param against a repeated-param string[] before .split.
- Rename layout `relatedNavItems` → `$relatedNavItems` (signal convention).
- Explicit `: void` on relationship-field `openRelated`.

Tests: cover the in-place reload dirty-guard (clean/keep-editing/discard/locale),
the breadcrumb `command` branch, RouterEditContentHost.resolveIdentity route walk,
and DialogEditContentHost identity/saved$/deferred-trail. edit-content suite green
(107 suites), lint + typecheck clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tent dialog

- Adjusted CSS classes for error and loading states in the edit content dialog to enhance layout consistency.
- Updated test specifications for `DotEditContentLayoutComponent` to improve readability and maintainability.
- Enhanced `DotRelatedContentNavigationStore` to persist title cache in sessionStorage, ensuring titles are retained across page refreshes.
- Added tests for title cache persistence and hydration to ensure reliability in various scenarios.

These changes collectively improve the user experience and maintainability of the edit content features.
…tentHost (#36349)

The overlay host backs any overlay presentation (dialog or side panel), not just
the dialog, so the name now reflects that. Pure rename — class, file, and
references; no behavior change. edit-content suite green, lint + typecheck clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…dge cases (#36349)

Two related-content breadcrumb fixes:

- Locale switch to an untranslated locale left the content without an inode, so
  clicking a related content did nothing. Now navigation seeds the trail origin
  with the version we came from (new `translationSourceInode` state), falling back
  to a fresh trail when there is none.
- In an overlay (dialog/side panel), saving mints a new inode but the overlay host
  did not repoint its in-memory trail, so a title change never showed in the
  breadcrumb. OverlayEditContentHost.goToSavedContent now repoints the current
  crumb to the saved inode — mirroring RouterEditContentHost's `rc` update.

edit-content suite green (107 suites), lint + typecheck clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@adrianjm-dotCMS
adrianjm-dotCMS marked this pull request as ready for review July 13, 2026 01:10
Comment thread core-web/libs/edit-content/src/lib/services/host/overlay-edit-content-host.ts Outdated
Comment thread core-web/libs/edit-content/src/lib/store/edit-content.store.spec.ts
Comment thread core-web/libs/edit-content/src/lib/store/features/workflow/workflow.feature.ts Outdated
…ence

- Removed `reuseRoute: false` from the content route to allow component reuse during same-route navigations, improving user experience by retaining previous content until new data loads.
- Updated the layout component to display a loading overlay during in-place reloads, ensuring users are aware of ongoing content updates.
- Adjusted breadcrumb navigation to utilize command-based navigation for better handling of unsaved changes during in-editor moves.
- Enhanced the store to maintain previous content while new content is fetched, preventing blank screens during transitions.
- Improved styling for the relating content section to ensure consistent visual feedback during navigation.
…umb component

- Refactored the HTML structure of the dot-collapse-breadcrumb component to enhance readability and maintainability.
- Adjusted the formatting of the span elements containing the Material Symbols icons for better alignment and consistency.
… reloads

- Updated the layout component to ensure the loading overlay remains visible until both the new content and the sidebar's data have finished loading, preventing premature content display.
- Adjusted the CSS for the reloading overlay to span both the body and sidebar, providing a unified loading experience.
- Introduced a new signal to manage the visibility of the loading overlay based on the loading states of the content and sidebar.
- Enhanced the HTML structure of the relating content section in the layout component for better readability.
- Updated CSS classes to ensure consistent styling, including adjustments to the text color for improved visibility.
- Added a class to the message component for better theme integration and maintainability.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restores navigation into related content from relationship fields in the new Edit Content experience, and refactors the editor to be presentation-agnostic via an EditContentHost abstraction (router/full-screen vs dialog/overlay), removing the prior isDialogMode branching.

Changes:

  • Introduces EditContentHost (router + overlay adapters) and updates store features (content/workflow/history/locales) to delegate navigation, title, breadcrumb, and save/restore behaviors to the host.
  • Adds related-content trail state (rc query param in full-screen, in-memory in overlay) plus breadcrumb/banner UI and session-scoped title caching for crumb labels.
  • Improves in-place reload UX (stale-while-revalidate overlay) and prevents relationship-field load syncs from falsely dirtying the form.

Reviewed changes

Copilot reviewed 39 out of 39 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
dotCMS/src/main/webapp/WEB-INF/messages/Language.properties Adds i18n label for the related-content breadcrumb banner.
core-web/libs/ui/src/lib/components/dot-collapse-breadcrumb/dot-collapse-breadcrumb.component.html Updates breadcrumb separator icon rendering.
core-web/libs/edit-content/src/lib/store/features/workflow/workflow.feature.ts Delegates post-save navigation to EditContentHost.
core-web/libs/edit-content/src/lib/store/features/workflow/workflow.feature.spec.ts Updates workflow feature tests to assert host delegation.
core-web/libs/edit-content/src/lib/store/features/ui/ui.feature.ts Removes dialog-mode toggles from UI feature.
core-web/libs/edit-content/src/lib/store/features/locales/locales.feature.ts Delegates locale reload/navigation to host; introduces translationSourceInode.
core-web/libs/edit-content/src/lib/store/features/locales/locales.feature.spec.ts Updates locale feature tests for host-based reload behavior.
core-web/libs/edit-content/src/lib/store/features/history/history.feature.ts Delegates restore-version navigation to host.
core-web/libs/edit-content/src/lib/store/features/history/history.feature.spec.ts Updates history feature tests to assert host delegation.
core-web/libs/edit-content/src/lib/store/features/content/content.feature.ts Delegates title/breadcrumb to host; adds reloading/fully-loaded computed; resets volatile slices on re-init.
core-web/libs/edit-content/src/lib/store/features/content/content.feature.spec.ts Updates content feature tests to assert host title/breadcrumb intents.
core-web/libs/edit-content/src/lib/store/edit-content.store.ts Removes isDialogMode; single initialize() entrypoint via host.resolveIdentity().
core-web/libs/edit-content/src/lib/store/edit-content.store.spec.ts Updates store tests for host-driven initialization.
core-web/libs/edit-content/src/lib/store/dot-related-content-navigation.store.ts Adds URL-driven related-content trail + title cache persistence and helper APIs.
core-web/libs/edit-content/src/lib/store/dot-related-content-navigation.store.spec.ts Adds unit tests for trail parsing, append behavior, and sessionStorage persistence.
core-web/libs/edit-content/src/lib/services/host/edit-content-host.model.ts Introduces the host port contract and DI token.
core-web/libs/edit-content/src/lib/services/host/router-edit-content-host.ts Implements full-screen host: router navigation, title/breadcrumb updates, rc reconciliation.
core-web/libs/edit-content/src/lib/services/host/router-edit-content-host.spec.ts Adds unit tests for router host behaviors.
core-web/libs/edit-content/src/lib/services/host/overlay-edit-content-host.ts Implements overlay host: in-place reload requests, per-instance trail, saved$ reporting.
core-web/libs/edit-content/src/lib/services/host/overlay-edit-content-host.spec.ts Adds unit tests for overlay host behaviors.
core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/store/relationship-field.store.ts Tracks lastChangeSource to control dirty/touched handling.
core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/dot-edit-content-relationship-field.component.spec.ts Updates relationship field tests with host provision.
core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/components/dot-relationship-field/dot-relationship-field.component.ts Adds openRelated() navigation via host and load-vs-user dirty-state handling.
core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/components/dot-relationship-field/dot-relationship-field.component.spec.ts Adds unit tests for touched-state logic and openRelated() behavior.
core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/components/dot-relationship-field/dot-relationship-field.component.html Makes related titles clickable (button) when navigable.
core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/components/dot-file-field-preview/dot-file-field-preview.component.scss Adjusts z-index of file preview actions.
core-web/libs/edit-content/src/lib/edit-content.shell.component.ts Provides EDIT_CONTENT_HOST with RouterEditContentHost for full-screen.
core-web/libs/edit-content/src/lib/edit-content.routes.ts Enables route reuse for content/:id and documents guard behavior changes.
core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/dot-edit-content-sidebar.component.spec.ts Updates sidebar tests with host provision.
core-web/libs/edit-content/src/lib/components/dot-edit-content-layout/dot-edit-content.layout.component.ts Refactors layout to be host-driven; adds relating breadcrumb model; handles in-place reload requests and navigation guard wiring.
core-web/libs/edit-content/src/lib/components/dot-edit-content-layout/dot-edit-content.layout.component.spec.ts Adds/updates tests for host-driven initialization, save reporting, breadcrumb commands, and in-place navigation behavior.
core-web/libs/edit-content/src/lib/components/dot-edit-content-layout/dot-edit-content.layout.component.scss Adds stale-while-revalidate reload overlay styling.
core-web/libs/edit-content/src/lib/components/dot-edit-content-layout/dot-edit-content.layout.component.html Renders “Relating content” banner + breadcrumb; shows reload overlay during in-place reloads.
core-web/libs/edit-content/src/lib/components/dot-edit-content-form/dot-edit-content-form.component.spec.ts Updates form tests with host provision.
core-web/libs/edit-content/src/lib/components/dot-edit-content-field/dot-edit-content-field.component.spec.ts Updates field tests with host provision.
core-web/libs/edit-content/src/lib/components/dot-create-content-dialog/dot-edit-content-dialog.component.html Removes old dialog inputs/outputs wiring; minor layout class tweaks.
core-web/libs/edit-content/src/lib/components/dot-create-content-dialog/dot-create-content-dialog.component.ts Provides overlay host in dialog and switches saved reporting to host’s saved$.
core-web/libs/edit-content/src/lib/components/dot-create-content-dialog/dot-create-content-dialog.component.spec.ts Updates dialog tests to assert save reporting via overlay host.
core-web/apps/dotcms-ui/src/app/app.routes.ts Removes reuseRoute: false from /content parent to allow subtree reuse.

Comment thread core-web/libs/edit-content/src/lib/services/host/router-edit-content-host.ts Outdated
Comment thread core-web/libs/edit-content/src/lib/services/host/router-edit-content-host.ts Outdated
Comment thread core-web/libs/edit-content/src/lib/services/host/overlay-edit-content-host.ts Outdated
Comment thread core-web/libs/edit-content/src/lib/services/host/overlay-edit-content-host.ts Outdated
Comment thread dotCMS/src/main/webapp/WEB-INF/messages/Language.properties
Comment thread core-web/libs/edit-content/src/lib/store/dot-related-content-navigation.store.ts Outdated
…d behavior

- Updated the DotEditContentSidebarComponent to depend on the entire contentlet, ensuring it refreshes correctly after saves or publishes, preventing loading states from hanging.
- Adjusted the DotRelationshipFieldComponent to correctly handle breadcrumb titles for translations, ensuring the origin crumb reflects the appropriate title based on the current content.
- Modified OverlayEditContentHost and RouterEditContentHost to prevent overwriting titles and breadcrumbs in dialog modes, maintaining a clean navigation experience.
- Improved documentation in the DotRelatedContentNavigationStore to clarify trail ownership and behavior across different presentation modes.
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.

Navigate between related content via breadcrumb banner (Edit Contentlet)

3 participants