[Frontend] Explain gated and blocked states instead of silently hiding or redirecting #382
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Impact: MEDIUM
Found in the August 2026 session lifecycle review (#319).
What the user experiences
Almost every gated or blocked state in the product is handled by hiding the control or silently redirecting, rather than explaining why. A player who follows a shared workbench link gets silently teleported back to the campaign page with no message. A GM sees a "Draft — not yet visible to players" badge on a highlight with no control to approve it and no explanation that approving is a side effect of a completely different button on a different panel. A GM who archives a campaign sees a banner with no restore button and no mention of who (an instance admin, not the GM) can restore it. "Add to shelf" simply vanishes with no explanation when there are no upcoming sessions to add to. A user without edit rights who opens a wiki article's edit URL silently gets the read view rendered at the edit URL, with nothing explaining why their edit didn't take effect.
Evidence
webapp/frontend/src/pages/CampaignPlanning.jsx:836-853—navigate(..., { replace: true })on a non-GM with no message shown.webapp/frontend/src/components/SessionHighlights.jsx:265-269— "Draft — not yet visible to players" badge with no control; only Edit and Delete buttons exist (:281-289), and the state only clears as a side effect of "Approve summary" onSessionDetail.webapp/frontend/src/pages/CampaignDetail.jsx:1268-1292— the archived-campaign banner names no restore path;canRestoreArchivedCampaign(:1235) requiresuser?.is_admin, while archiving itself is a GM action (:1365-1373) — a one-way door with no signage of who holds the other key.webapp/frontend/src/components/AddToShelf.jsx:40—if (options.length === 0) return null;; the only "keep this" control on every generator vanishes with no explanation.webapp/frontend/src/pages/WikiArticle.jsx:1361—isEditMode = mode === "edit" && article?.entry?.can_edit; a user without edit rights opens/wiki/:entryId/editand silently gets the read view with no message.webapp/frontend/src/pages/CampaignNotes.jsx:50-59andwebapp/frontend/src/pages/CampaignHighlights.jsx:74-83already include a "Back to dashboard" link on their error/blocked states — the pattern for handling this well already exists in the codebase; several wiki pages (WikiProposals.jsx:278-284,WikiNewEntry.jsx:183-189,WikiArticle.jsx:1681-1687,WikiDraftReview.jsx:413-419) just don't follow it, rendering a bare "GM access only." or similar with no navigation at all.Why it matters for a hosted product
A silent bounce or an unexplained blocked state reads as "the product is broken" rather than "you don't have permission" or "this isn't ready yet" — and a player who can't tell why cannot even ask their GM the right question.
Proposed fix
Replace the silent redirect at
CampaignPlanning.jsx:840with an inline "Prep is GM-only" message. GiveSessionHighlightsan explicit approve control, or at minimum change the badge text to "Draft — publishes when you approve the session summary". Add a restore hint naming who can restore to the archived-campaign banner. Explain (rather than hide) the empty "Add to shelf" state. Apply the existing "Back to dashboard" pattern fromCampaignNotes.jsx/CampaignHighlights.jsxto the four wiki hard-block pages listed above. This is the audit's P13.Acceptance criteria
SessionHighlights' draft badge either has an approve control or explains what publishes it.AddToShelfshows an explanatory empty state instead of disappearing entirely.WikiArticle's edit URL for a non-editor shows a message explaining why the edit view isn't available, instead of silently rendering the read view.WikiProposals,WikiNewEntry,WikiArticle, andWikiDraftReview's hard-block states include navigation back to the dashboard, matchingCampaignNotes.jsx/CampaignHighlights.jsx.Picking this up as v4.3.0 phase 7 (#514), last on the lane. The Prep page explains itself to a non-GM instead of redirecting; the highlights draft badge gets an approve control if a per-highlight endpoint exists and otherwise says what publishes it; the archived banner names that an instance admin restores and, where the count is available, how many scheduled sessions go quiet (#479); "Add to shelf" explains its empty state; the article edit URL tells a reader they cannot edit; and the four wiki hard-block pages get the "Back to dashboard" pattern
CampaignHighlightsalready uses.Done in the phase 7b PR (auto-merging on green); ships with v4.3.0. All six.
The four wiki hard-blocks share a new
components/BlockedState.jsxrather than four copies (theCampaignHighlightspattern, extracted): what the restriction is, what to do instead, and links back to the article, wiki, campaign or dashboard.WikiArticle's full-page error state gets the same links, since it was the one that could strand a reader with a bare red line.CampaignPlanningno longer redirects; it says Prep is the GM's workspace and offers the way back (the nav bar already hides Prep from players, so anyone here followed a shared link).WikiArticle's/editfor a non-editor still renders the read view, which is the useful thing to show, with a line saying why.AddToShelfsays there is no upcoming session and links to where you schedule one.Two that needed a decision:
POST /sessions/{id}/approvepublishes every highlight on the session in a single update. So the badge now reads "Draft — publishes when the session summary is approved", with a count line pointing at that control, which is on the same page, so a link elsewhere would have pointed at the page you are on.silenced_future_sessions(#479) is on the archive response only, not on the campaign, so the count stays with the post-archive confirmation. The banner names the instance admin as the restore path (only to viewers who are not one) and says scheduled sessions stay on the calendar but stop sending reminders.Tests for each. One collateral fix:
GeneratorPanel.test.jsxrendered without a router, which the new link inAddToShelf's empty state needs; its renders are now wrapped. Frontend 787 passed, eslint clean apart from the pre-existing warning,vite buildclean; backend 2504 passed / 13 skipped, ruff clean. No migration.