Skip to content

fix(edit-content): refresh History, Comments and Reference Pages after save #36617 - #36901

Open
adrianjm-dotCMS wants to merge 9 commits into
mainfrom
adrianjm-dotCMS/history-comments-side-panel-not-refreshing-when
Open

fix(edit-content): refresh History, Comments and Reference Pages after save #36617#36901
adrianjm-dotCMS wants to merge 9 commits into
mainfrom
adrianjm-dotCMS/history-comments-side-panel-not-refreshing-when

Conversation

@adrianjm-dotCMS

@adrianjm-dotCMS adrianjm-dotCMS commented Aug 5, 2026

Copy link
Copy Markdown
Member

Fixes #36617

Proposed Changes

The sidebar's History, Comments and Reference Pages stayed stale after a save/publish and needed a manual page reload. There were two independent root causes.

  • The refresh effects lived on a component that gets destroyed. They sat on DotEditContentSidebarComponent, which the layout's @if destroys and recreates — taking the effects with it. Moved into store-level withHooks({ onInit }) in withActivities and withInformation, so they live as long as the store does. This matches the existing lock / workflow / history features.

  • withHistory did not recognise a newly minted version. Its memo only invalidated on ${identifier}:${languageId}, but a save mints a new inode under the same identifier and locale, so loadVersions never re-fired. The symptom differed per host, which is why it looked like two separate bugs:

Screen.Recording.2026-08-05.at.3.47.52.PM.mov
Full-screen Dialog
Navigates on save? Yes → runs initializeExistingContent No
Effect on the list Emptied (versions: []) Left untouched
What you saw "it went blank" "it didn't update"

Added two invalidation signals: a cleared list (status === INIT, ignored mid-reload so it cannot fetch the identifier being left behind) and a live-inode baseline that only advances when not viewing a historical version, so browsing versions — and returning from them — does not refetch.

  • Fixed signal granularity in both effects. They read store.uiState(), i.e. the whole slice. Every writer replaces that object wholesale, so the effects refetched on unrelated UI changes — including the view flip loadVersions performs internally, costing 3–4 redundant requests per save. Now they read the store.uiState.isSidebarOpen() leaf.

Checklist

  • Tests
  • Translations
  • Security Implications Contemplated (none — no new endpoints, inputs or permissions; only client-side refresh timing)

Additional Info

Tests: 2180 passing across 111 suites in edit-content; lint and typecheck clean. New coverage includes publish-in-dialog, publish-while-comparing, the mid-reload case, historical/compare round trips, and a regression test for the signal-granularity fix (verified it fails against the previous code).

One existing test changed expectationshould not reload anything when only the version inode changes asserted that moving only the inode does not reload, which was literally the bug. Rewritten as should reload versions but not push publish history when the live inode moves. This is safe because browsing versions always goes through loadVersionContent, which sets isViewingHistoricalVersion; a bare inode move only happens on save/publish. The browsing cases are now covered by dedicated tests that set the realistic state.

Known follow-ups, deliberately out of scope:

  • Push Publish History still does not reload on publish (kept the original per-identifier scoping).
  • clearVersions() / resetVersions() / clearPushPublishHistory() / resetPushPublishHistory() in history.feature.ts have no production call sites — dead code worth removing separately.

🤖 Generated with Claude Code

…r save #36617

The sidebar's History, Comments and Reference Pages stayed stale after a
save/publish, requiring a manual page reload. Two root causes:

- The refresh effects lived on DotEditContentSidebarComponent, which the
  layout's @if destroys and recreates, taking the effects with it. Moved
  them into store-level withHooks({onInit}) in withActivities and
  withInformation, matching the existing lock/workflow/history features.

- withHistory only invalidated its memo on `${identifier}:${languageId}`,
  but a save mints a new inode under the SAME identifier and locale, so
  loadVersions never re-fired. Full-screen rendered an empty list
  (initializeExistingContent had already cleared it); the dialog host,
  which never navigates, rendered a stale one. Added two invalidation
  signals: a cleared list (status INIT, ignored mid-reload so it cannot
  fetch the identifier being left behind) and a live-inode baseline that
  only advances when not viewing a historical version, so browsing
  versions and returning from them does not refetch.

Both effects now read the isSidebarOpen leaf instead of uiState(): every
writer replaces that slice wholesale, so depending on the object refetched
on unrelated UI changes, including the view flip loadVersions performs.

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

claude Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

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


Code Review

Reviewed the diff against origin/main, focusing on the store-feature refactor (withHistory/withActivities/withInformation), the invalidation logic, and the two prior Copilot findings.

Resolved

  • history-refresh.spec.ts:139-153 — The dialog-scenario content types are now tracked (dialogTargetTypeId, dialogParentTypeId) and deleted in a dedicated afterAll for the dialog host describe block, parent-first to respect the relationship reference. The prior finding (leaked content types after each run) is addressed, including the partial-setup case since each ID is assigned as soon as its create resolves.
  • history.feature.ts:834-838 — The inode-based newLiveVersion invalidation is now gated on !isReloading. During an in-place reload, initializeExistingContent flips state to LOADING and clears isViewingHistoricalVersion in the same patch while keeping the outgoing (possibly historical) contentlet on screen; the !isReloading guard prevents that transient state from firing a fetch for the identifier being left behind, exactly as the prior finding requested. The incoming contentlet still triggers the correct load via identityChanged or the still-INIT versionsCleared once the reload completes.

Notes (non-blocking)

  • The cleared-list / new-live-inode / signal-granularity logic in history.feature.ts:781-887 rests on a stated invariant: nothing writes INIT back to the version/push-publish statuses except the reducer defaults, initializeExistingContent, and clearVersions/clearPushPublishHistory, and the loaders only move LOADING → LOADED/ERROR. I verified this holds across the current diff and content.feature.ts:294-314. This is a genuine coupling that a future change to those loaders could silently break into a fetch loop — the in-code comment already flags it, which is the right mitigation.
  • withInformation/withActivities effects correctly read the store.uiState.isSidebarOpen() leaf rather than the whole uiState() slice, avoiding the redundant refetches described in the PR body. isSidebarOpen defaults to true, so the reference-pages/activities fetch still fires on initial load — consistent with prior behavior.

No new bugs, security issues, or dotCMS-convention violations found in the diff. The two known follow-ups called out in the PR body (Push Publish History not reloading on publish; dead clear*/reset* methods) are reasonable to defer.
· adrianjm-dotCMS/history-comments-side-panel-not-refreshing-when


  • Read changed files
  • Analyze history/activities/information feature changes
  • Recheck the two prior Copilot review findings
  • Post review

…+ e2e #36617

The feature specs verify the store effects against a synthetic store with no
component mounted, so they cannot catch the regression this fix addresses: the
effects used to live on DotEditContentSidebarComponent, which the layout's @if
destroys and recreates. Moving them back would leave every feature spec green.

Two layers close that gap, both parameterized over the full-screen and dialog
hosts since the bug had a different face in each:

- Integration (dot-edit-content.layout.component.spec.ts): real store mounted in
  the real layout with the sidebar as a MockComponent. Asserts the fetches happen
  while the sidebar is not rendered at all, that they survive the sidebar being
  destroyed and recreated, and that a save minting a new inode refreshes without
  any re-initialization (the dialog path). Verified these fail when the store
  hooks are removed.

- E2E (apps/dotcms-ui-e2e/.../sidebar/history-refresh.spec.ts): publishes and
  comments through the UI and asserts History/Comments update with no reload,
  in full-screen and in the dialog (reached via the relationship field's "New
  Content", which needs no page/template fixture). Verified against the pre-fix
  code: full-screen reproduced the empty list (expected 2, got 0) and the dialog
  reproduced the stale list (expected 2, got 1).

Dialog comments are deliberately not covered — the comment form is hidden for
content opened as 'new', which is the only mode that entry point offers. It
needs the UVE pencil flow and a page fixture; documented in the spec.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
adrianjm-dotCMS and others added 2 commits August 5, 2026 23:04
`nx format:check` — the CI's format-test goal — flagged this file. The
lint-staged hook ran `nx format:write` on it at commit time but left it
unformatted, so the check only surfaced in the pipeline.

Formatting only; no test logic changed. 2186 tests still pass.

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

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

Fixes stale sidebar History, Comments, and Reference Pages after saving content across routed and dialog editors.

Changes:

  • Moves sidebar refresh effects into store features.
  • Invalidates History when live inodes or lists change.
  • Adds unit, integration, and E2E regression coverage.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
information.feature.ts Adds store-owned reference-page refresh.
information.feature.spec.ts Tests information loading and refresh.
history.feature.ts Expands History invalidation logic.
history.feature.spec.ts Tests save, reload, compare, and historical flows.
content.feature.ts Updates refresh ownership documentation.
activities.feature.ts Adds store-owned activities refresh.
activities.feature.spec.ts Tests automatic activities refresh.
dot-edit-content-sidebar.component.ts Removes component-owned refresh effect.
dot-edit-content.layout.component.spec.ts Adds host and component-lifecycle integration coverage.
history-refresh.spec.ts Adds full-screen and dialog E2E coverage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area : Frontend PR changes Angular/TypeScript frontend code

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

History & Comments side panel not refreshing when editing via UVE (works via content search)

3 participants