Rules portlet keeps showing the previous site's rules after switching sites
Nobody has claimed this yet.
- 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
DotContainerListStoresources the host from the deprecatedSiteServicerather thanGlobalStore. 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
- Log in as an administrator on an instance with at least two sites (site A and site B).
- With site A selected in the header site selector, go to Site → Rules and note the rules listed.
- Create a rule on site A (for example a Set Response Header rule) so that the two sites have different rule sets.
- Switch the header site selector to site B, staying on the Rules screen.
- Observe the rules list: it can continue to show site A's rules while the selector reads site B.
- 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.currentSiteis updated relative tocurrentSite$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 (
pageIdpresent 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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