feat(webui): one shell, a system dashboard, organization pages as drill-ins (#1873) #1965

Merged
jason.woltje merged 3 commits from sp1-shell into refactor 2026-11-15 05:56:38 +00:00
Owner

One shell, a system dashboard, organization pages as drill-ins (#1873, lane sp1). First slice of Jason's 11-14 single-pane direction.

What changes for a person:

  • #/dashboard is the system page: totals across the organizations that answered, an Organizations table, Needs you, Active agents, recent project activity.
  • Clicking an organization no longer reloads the page or swaps the app. #/orgs/<id>/... stays the address of an organization page, but it is a route inside the one shell. The sidebar, top bar and Projects list stay put.
  • An organization page carries a Dashboard > <org> crumb. A stopped bus shows a banner and says what could not be read, on the dashboard row and on the page.

How: WebUI only, packages/webui/src/public/. display.js holds the organization as a variable and announces a switch with a mosaic-org-switch event. bus.js, agents.js, projects.js, requests.js, app.js drop per-organization state on a switch, and a read or save in flight at a switch keeps nothing. No server, role, contract or schema change.

Tests: new tests/single-pane-browser.test.mjs (11 tests); six browser tests updated for no-reload switching. Lane gate 126 files, 1031/0. Lead check at c7aecbffa: 11 WebUI files run one at a time, 128/0.

Reviews (fresh Opus 5.5 delegates): two rounds, nine findings, all fixed in bb2f79f3d and c7aecbffa. The fix for reads in flight at a switch has no test of its own.

Follow-ups:

  • The dashboard theme follows the last organization opened.
  • A stopped organization page shows two banners, and the dashboard row repeats the reason.
  • Inbox, Tasks and Agents are still per organization. Side by side is still in the sidebar.
  • The #doc-source draft guard predates this lane.
One shell, a system dashboard, organization pages as drill-ins (#1873, lane sp1). First slice of Jason's 11-14 single-pane direction. What changes for a person: - `#/dashboard` is the system page: totals across the organizations that answered, an Organizations table, Needs you, Active agents, recent project activity. - Clicking an organization no longer reloads the page or swaps the app. `#/orgs/<id>/...` stays the address of an organization page, but it is a route inside the one shell. The sidebar, top bar and Projects list stay put. - An organization page carries a `Dashboard > <org>` crumb. A stopped bus shows a banner and says what could not be read, on the dashboard row and on the page. How: WebUI only, `packages/webui/src/public/`. `display.js` holds the organization as a variable and announces a switch with a `mosaic-org-switch` event. `bus.js`, `agents.js`, `projects.js`, `requests.js`, `app.js` drop per-organization state on a switch, and a read or save in flight at a switch keeps nothing. No server, role, contract or schema change. Tests: new `tests/single-pane-browser.test.mjs` (11 tests); six browser tests updated for no-reload switching. Lane gate 126 files, 1031/0. Lead check at c7aecbffa: 11 WebUI files run one at a time, 128/0. Reviews (fresh Opus 5.5 delegates): two rounds, nine findings, all fixed in bb2f79f3d and c7aecbffa. The fix for reads in flight at a switch has no test of its own. Follow-ups: - The dashboard theme follows the last organization opened. - A stopped organization page shows two banners, and the dashboard row repeats the reason. - Inbox, Tasks and Agents are still per organization. Side by side is still in the sidebar. - The `#doc-source` draft guard predates this lane.
jason.woltje added 3 commits 2026-11-15 05:56:29 +00:00
#/dashboard is the system landing route: one row per organization with its bus
state, agent count (organization files), project count and needs-you count,
each only when a read gave it, and active agents. Opening an organization from
the sidebar or a dashboard row is a route inside the same page: no reload, a
Dashboard / <organization> breadcrumb, and later /api reads scoped to it through
the existing fetch wrapper, whose organization is now a variable the router sets
(mosaic-org-switch event). #/orgs/<id>/... stays the address. An organization
whose bus is down says so on the dashboard and on its page, with the reason the
workspace read gives.
- First run (no organization yet) keeps #/ as its board; the router no longer rewrites it to
  #/dashboard, which first run cannot draw.
- An organization switch stops the agents section's request poll and clears what it held. A
  route-change restart chain finishes on the organization it started in.
- A write in flight at a switch drops its answer: an org epoch in bus.js, checked after each
  await. The switch clears every busy flag, receipt and reply, and the doc drafts.
- The bus banner reads org state again only when the route crosses /dashboard, not on every
  hashchange inside one organization.
- The down banner does not repeat its heading as the reason.
- Tests: first run wordmark, poll stop on switch, restart pinned to its organization, settings
  save in flight at a switch, banner without a repeated reason. The org-switch test comment and
  wait match the in-place switch.
The second review found two paths the first fix round left open.

- The project-file save captures orgEpoch before its POST. When a switch
  happened meanwhile, it neither paints nor announces the old file's
  outcome on the new organization's page. An opaqueredirect still signs out.
- A live read (reader, get.api), the palette's inbox and tasks reads and
  the board poll keep their answer in `last` only while the organization
  they were sent for is still open. A later cached render on the new
  organization no longer draws the old one's rows.

single-pane test 11 holds acme's file save across a switch to beta and
asserts nothing is announced: red on the previous bus.js ("Saved as commit
cccccccccccc."), green now. The kept-read guard has no browser test.
jason.woltje merged commit c7aecbffa9 into refactor 2026-11-15 05:56:38 +00:00
Sign in to join this conversation.