dotCMS / dotCMS/core

Rules portlet keeps showing the previous site's rules after switching sites

Open
#37,556 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

dotCMS : Rules-Engine OKR : Customer Support Team : Maintenance Type : Defect
Dominant language
Java
Stars
970
Forks
486
Avg merge
3d 33m
Merged PRs (30d)
170

Description

Problem Statement

On the Rules portlet (Site → Rules), switching sites with the header site selector can leave the rules list showing the previously selected site's rules under the newly selected site's name. Nothing in the UI indicates the list is stale, so an administrator can believe a rule belongs to the site currently shown in the selector, and can create, edit, toggle, or delete rules while looking at another site's data. Reloading the page corrects the list.

Reported by a customer configuring Set Response Header rules across several sites: the header rules appeared to be shared across every site, and toggling a rule appeared to take effect on one site but not another. Both symptoms are explained by the stale list.

The behaviour is intermittent, which is consistent with the ordering dependency described under Root cause.

Expected: switching sites in the selector reloads the Rules list for the newly selected site.

Actual: the list can keep showing the previous site's rules until the page is reloaded.

Root cause (code analysis)

core-web/libs/dot-rules/src/lib/services/api/rule/Rule.ts:316-321

this.siteService.currentSite$.subscribe((site) => {
    const siteId = this.loadRulesSiteId();
    if (siteId === site.identifier) {
        this.sendLoadRulesRequest(site.identifier);
    }
});

loadRulesSiteId() (Rule.ts:615-626) returns the pageId from the URL when one is present, and otherwise falls back to this.siteService.currentSite.identifier. On the Rules portlet there is no pageId in the URL, so it returns the cached current site id.

The guard therefore reloads the rules only when the cached site id already equals the site being emitted — that is, only when the site has effectively not changed from the cache's point of view. Whether a real switch reloads at all depends on whether SiteService.currentSite has been updated before the currentSite$ subscriber runs:

  • cache already updated → ids match → the reload happens (correct, but incidentally so)
  • cache not yet updated → old id vs new identifier → the guard fails → no reload, and the list stays on the previous site

SiteService is the deprecated service from @dotcms/dotcms-js. Per #35909, its site-change propagation in legacy portlets depends on the WebSocket connection, so this emission ordering is not deterministic — which matches the intermittency reported.

Related
  • #37232 — the same class of defect in the Containers list, where DotContainerListStore sources the host from the deprecated SiteService rather than GlobalStore. Different portlet, same underlying pattern; a Containers-scoped fix will not cover Rules.
  • #35909 — legacy portlets not updating on site switch when the WebSocket drops. Closed and shipped in 26.07.04-01; that fix does not remove the reload guard above.
Steps to Reproduce
  1. Log in as an administrator on an instance with at least two sites (site A and site B).
  2. With site A selected in the header site selector, go to Site → Rules and note the rules listed.
  3. Create a rule on site A (for example a Set Response Header rule) so that the two sites have different rule sets.
  4. Switch the header site selector to site B, staying on the Rules screen.
  5. Observe the rules list: it can continue to show site A's rules while the selector reads site B.
  6. Reload the page — the list now shows site B's rules.

Repeat steps 4–6 several times, or after the session has been open long enough for WebSocket reconnect messages to appear in the browser console (see #35909). The stale list does not occur on every switch.

Acceptance Criteria
  • Switching sites in the header site selector reloads the Rules list for the newly selected site, with no page reload required.
  • The reload does not depend on the order in which SiteService.currentSite is updated relative to currentSite$ emissions.
  • Rule create, edit, toggle, and delete operations act on the site shown in the selector.
  • The behaviour holds when the WebSocket connection has dropped and reconnected during the session.
  • Deep-linking into a page's rules (pageId present in the URL) continues to load that page's rules.
dotCMS Version

Current Release (dotEvergreen). Reported September 2026.

Severity

High - Major functionality broken

Links

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in core-web/libs/dot-rules/src/lib/services/api/rule/Rule.ts, especially the currentSite$ subscription at lines 316-321 and loadRulesSiteId() at lines 615-626. Trace site-switch handling and verify it remains correct when SiteService updates in either order, including deep links with a pageId. Done means switching sites reloads the correct Rules list without a page reload, including after WebSocket reconnects, and rule operations target the selected site.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
70/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.