Skip to content

feat(ui): a cohesive redesign around the admin's core flows - #123

Merged
Gkrumbach07 merged 20 commits into
mainfrom
feat/ui-cohesive-redesign
Oct 22, 2026
Merged

Gkrumbach07 merged 20 commits into
mainfrom
feat/ui-cohesive-redesign

Conversation

@Gkrumbach07

@Gkrumbach07 Gkrumbach07 commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Hold: do not merge before 2026-10-23.

The UI redesign @Daniel-Warner-X prototyped on his fork (Daniel-Warner-X/dw-openshell-dashboard, feat/ui-cohesive-redesign at 5979b03), brought onto current main with a review's fixes. The design and the first commit are his. The branch is rebased on main 61e2590 (server-side pagination #122, live logs #124, OpenShell 0.1.5).

The idea. The dashboard is for admins managing sandboxes, and three of their flows were buried: acting on policy proposals, finding out why a sandbox failed, and getting a provider onto a sandbox. Each is now one click from the landing page.

What changes

  • Gateway becomes a dashboard. A Needs attention card leads. It lists pending proposals (with the newest chunk's rationale) and sandboxes in ERROR (with the gateway's condition message, newest first), filterable by kind. A proposal row opens the sandbox's Proposals tab; an error row opens its Logs tab. The gateway's own status, its version, the line this build is for and the compatibility verdict sit under the title. Compute drivers and extensions stay below.
  • Two pages across every workspace.
    • Sandboxes: the paged list from feat(pagination): add server-side pagination and label filters (RHOAIENG-98858) #122 (AllSandboxList), with its label and type filters. The name now leads and the name and workspace are links. It was the first tab of All workspaces, which is now Resources (providers, templates and services).
    • Proposals: every sandbox with rules waiting for a decision. A platform admin reads it in one request. Anyone else reads it one workspace at a time, for the workspaces they are a member of.
  • A calmer Proposals tab. The count banner is info rather than a warning, the bulk actions are outline buttons, the status filter is a dropdown, and the security flag keeps its warning colour on the collapsed row.
  • Nav counts. The nav shows counts for workspaces, sandboxes and pending proposals. The shell reads them every two minutes (NAV_COUNT_POLL_MS), and a decision on a proposal refreshes them at once.
  • BFF. GET /api/v1/draft-summary?allWorkspaces=true answers the summary for every workspace. The gateway refuses the all-workspaces sandbox list to anyone but a platform admin, and that refusal is relayed as it is. Each sandbox's summary carries latestRationale. The route without a scope still answers empty, and a sandbox's drafts are never read with an empty workspace.
  • A mock API for UI work with no gateway: make dev-mock, and make dev-mock-empty for a gateway nobody has used yet (docs/mock-api.md). It answers the paged lists a page at a time, as the BFF does.

Changed from the prototype

  • Polling sized for a landing page. The prototype read the cross-workspace proposal summary every 15 s on every page: one request to the BFF, but one GetDraftPolicy per sandbox on the gateway. It also read every sandbox every 5 s on the Gateway page. Now:
    • The shell's counts refresh every 2 min.
    • The Gateway page reads sandboxes and the summary every 30 s, and providers every 60 s.
    • The Sandboxes and Proposals pages keep their own pace.
    • Against a real gateway, the Gateway page dropped from 28 requests a minute to 13.
  • Bugs fixed in review.
    • The Gateway page said "Nothing needs attention" while its lists were still loading or had failed.
    • The gateway's own status (for example DEGRADED) was shown nowhere.
    • Proposal counts stayed stale after an approve or a reject.
    • The Proposals page showed its empty state before every workspace had answered.
    • Flagged proposals had lost their warning colour.
    • The shell polled workspaces for users with no role.
    • Error rows were unsorted, and timed by creation instead of by the error.
  • The repo's rules.
    • About 100 inline strings moved to the gateway, crossWorkspace and sandboxes i18n namespaces.
    • "Agent" wording removed (ADR 0003).
    • A style override of private PatternFly variables dropped (ADR 0004).
    • Links instead of useNavigate for navigation.
    • Shared helpers, one copy each.
    • The mock is typed, linted and loaded only with MOCK_API.
  • Kept from main.
    • Provider profiles keeps its name. The prototype renamed it Providers, which clashed with the Providers tab of Resources.
    • The About dialog stays. It reads /gateway/compatibility, so the shell never calls GET /gateway, which the gateway refuses to non-admins.
    • The Logs tab streams (Add live logs streaming #124) and its viewer follows the app's theme.
  • Left out: the prototype's toolchain (skill submodules and links, .mcp.json).

For reviewers

  • Dan Reed: AllSandboxList from feat(pagination): add server-side pagination and label filters (RHOAIENG-98858) #122 has one user now, the Sandboxes page. It lost its navigation callbacks: the name column leads and both cells are links. The type-label tests moved with it, from the All workspaces spec to the Sandboxes page's.
  • Daniel: whether the built pages still match the design.
  • Regular members: the Proposals page and the Proposals tab show regular members the rules, but on main only a workspace admin gets Approve, Edit and Reject. The page's description ("review, edit, approve or reject") reads as though anyone can. Either the copy or the gating should change; that is a product call, left out of this PR.

Not in this PR

  • Prompting to attach a provider to a sandbox once the provider is created.
  • A Needs attention view for users who are not platform admins.

Checked

  • CI is green on 22bbd92: build, check-frontend, check-backend, compat, e2e and helm.
  • Locally:
    • Jest, 2176 tests
    • Cypress, 47 tests
    • tsc (including the mock), ESLint, the Prettier check and the build
    • go test -race and golangci-lint v2.12.2, 0 issues
  • make dev-full against gateway 0.1.5, behind Keycloak sign-in:
    • As admin1 (platform admin).
      • A sandbox created from the dashboard, then run with curl to npm and GitHub from its Terminal tab, drafted two rules.
      • Both appeared in Needs attention with the gateway's rationale, and the row opened the Proposals tab.
      • Approving one moved the nav badge from 3 to 2 at once and the sandbox to policy v2.
      • The Logs tab streamed the deny and approve lines, and its viewer followed the theme toggle.
      • The Sandboxes page paged through the gateway (pageSize=10), and a label selector came back filtered by the gateway.
      • The Workspaces page paged, and Resources, Provider profiles and About (built for 0.1.x, gateway 0.1.5) showed as expected.
    • As user1 (member of one workspace).
      • The nav showed only Workspaces and Proposals.
      • /gateway, /sandboxes, /all-workspaces, /provider-profiles and /settings each sent the user to Workspaces.
      • The Proposals page read only that workspace's summary, and no request was refused.
      • The Proposals tab was read-only, as main gates it.
      • Log out returned to the sign-in page.
  • One aside from that run: a sandbox created on gateway 0.1.4 does not start after the gateway moves to 0.1.5 (unknown field outer_fence in its bootstrap). That is the gateway's upgrade, not this PR; Needs attention shows it as a sandbox error.

🤖 Generated with Claude Code

Daniel-Warner-X and others added 20 commits October 22, 2026 17:38
Daniel Warner's prototype (Daniel-Warner-X/dw-openshell-dashboard,
feat/ui-cohesive-redesign at 5979b03), carried onto main as one commit:

- Gateway becomes a dashboard: a Needs attention card (pending proposals
  and errored sandboxes, filterable by kind) leads, the gateway's facts sit
  in one line under the title, drivers and extensions below.
- A Proposals page and a Sandboxes page across every workspace.
- The sandbox Proposals tab is calmer: info banner, outline bulk actions,
  a status dropdown, the security flag kept on the collapsed row.
- GET /draft-summary?allWorkspaces=true and the newest chunk's rationale
  in each sandbox's summary, for the Needs attention rows.
- A mock API (make dev-mock) for UI work without a gateway.

Left out: the prototyping toolchain (skill submodules and links, .mcp.json).
Brought up to main: the build line and commit replace the old app version
on the Gateway page, and the About dialog stays, read from the
compatibility route so the shell still never asks for gateway info.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The shell counts proposals and sandboxes on every page for a platform
admin. The proposal count is one request to the BFF but one draft read
per sandbox on the gateway, and the shell asked for it every 15 s on
every page. It now reads both counts every two minutes; the Gateway,
Proposals and Sandboxes pages keep their own pace while they are open,
and the counts ride on those reads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The redesign renamed the Provider profiles entry and page to Providers,
while Resources keeps a Providers tab for the providers made from them:
two different things under one name. Profiles keep their name, and the
page says what they are for and how a sandbox gets one (a workspace
creates a provider from the profile and attaches it), without calling a
sandbox an agent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fixtures still gave compatibility the supportedMin/supportedMax shape
main has since replaced with supportedLine, and summarized one pending
proposal for training-run-42 where its drafts list has two.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Gateway page is where a platform admin lands and often leaves the tab
open. Needs attention read every sandbox on the gateway every 5 s to find
the ones in error, the cross-workspace proposal summary (one draft read per
sandbox on the gateway) every 15 s, and every provider every 15 s only to
say whether any exists. It now reads the sandboxes and the summary every
30 s and the providers every minute; the Sandboxes and Proposals pages keep
their own pace. Measured against gateway 0.1.4: 28 requests a minute on the
page before, 13 after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Gateway page no longer repeats the health the masthead shows, and
states the gateway's version in one line rather than a card; the masthead's
status reads `healthy` from the compatibility answer, which the stub now
gives as the BFF does. The create sandbox form keeps the name behind its
generated-by-default section. The cross-workspace reads the Gateway page and
the shell make (sandboxes, providers, the all-workspaces proposal summary)
are stubbed, so they no longer fall through to a BFF that is not there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Gateway page, the pages across workspaces and the sandbox views the
redesign added text to had it inline. CLAUDE.md and ADR 0004 put new UI
text through useI18n, so each gets a namespace: gateway, crossWorkspace and
sandbox.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ered

Needs attention was built from whatever each list held, so while a list
was loading, or after it failed, the card said nothing needs attention.
It now waits for every read, and a list that could not be read is a row of
its own.

Also from review of the prototype:
- The gateway's own status (HEALTHY, DEGRADED, UNHEALTHY) is back beside its
  version; the masthead only shows the health check's yes or no.
- Errored sandboxes are listed newest first before the cap, timed by their
  condition's transition, never by when the sandbox was created; the error
  is the Ready condition that is False.
- A filter whose kind is gone is reset rather than kept to come back later.
- Get started starts at the provider step: default exists already.
- No agent in the copy (ADR 0003), and no claims the API does not back.
- Text through the gateway catalog; test ids on the links and filter items.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Approving, rejecting or editing a proposal refreshed the sandbox's inbox
but no summary, so the nav count, the Gateway page and the Proposals page
went on showing it until their next poll. Decisions now invalidate every
workspace's summary and the one across workspaces.

Also from review of the prototype:
- The Proposals page waits for every workspace's read before it says
  nothing is waiting, and counts the sandboxes it could not read in one
  alert after the ones it could.
- The Sandboxes page links with Link and encoded paths instead of buttons
  that navigate, and shares the workspace-name helpers and ImageReference
  with All workspaces instead of copying them.
- No agent in the copy; text through the crossWorkspace catalog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Across workspaces there is no workspace to fall back on, so a sandbox the
gateway lists without one was read with an empty selector, which the
gateway refuses (hard fact 12), and reported under an empty workspace. It
is now reported unavailable without a read, and logged once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The prototype showed a sandbox's pending proposals as info even when the
prover flagged them. Flagged ones are warning again: they are the ones
approve-all skips unless asked (hard fact 25).

Also from review of the prototype:
- The Review link is back in the alert's action links, not its close slot.
- Approve is a secondary button; the private PatternFly variables that
  coloured it green through style are gone (ADR 0004).
- The create forms' optional section no longer says it is generated, says
  which field is, and stays open while it holds a value.
- The terminal's light theme has an ANSI palette, so white text shows.
- The status filter has an accessible name; new text through the sandbox
  catalog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The shell counted workspaces every 15 s on every page, for a user with
  no role too; it now reads at the navigation's pace and not for them.
- The status in the masthead is in sentence case; capitals are spelled
  letter by letter by some screen readers in a live region.
- The theme survives storage that throws.
- A user who is not a platform admin is told to ask for a workspace rather
  than to create one.
- Applying a global policy is a danger action again: it replaces every
  sandbox's own (hard fact 23).
- Unused catalog keys and comments that no longer held are gone; the
  Provider profiles page text is in the catalog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fixtures were untyped and had drifted from what the BFF answers:
network enums in spellings the gateway never sends, draft chunks with no
review token, a user field that does not exist. They are typed against
src/types now, and lint, format and typecheck cover frontend/mock. The
drafts route honours ?status=, the CORS header is gone (same origin), and
vite.config.ts loads the plugin only when MOCK_API is set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main added a sandboxes namespace (the cause of a failed tool server exchange
or token grant) while this branch added a sandbox namespace for the create
forms and the Proposals tab. Their keys do not overlap, so they are one
namespace now, main's: the four components that read sandbox read
sandboxes, and the i18n README lists every namespace.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main put workspaceOf, scopedName and ImageReference in AllWorkspaceCells
while this branch put the same helpers in utils/workspaceNames and
components/sandbox/ImageReference. AllWorkspaceCells now re-exports those,
so the lists keep their import and there is one definition of each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main paged the sandboxes of every workspace through the gateway
(AllSandboxList: a cursor, a page size, label and type filters) on the
All workspaces page's Sandboxes tab, while this branch had moved that list
to a page of its own that read every sandbox at once. The Sandboxes page
now renders AllSandboxList, which keeps the page's layout: the name leads,
and the name and workspace are links rather than buttons. Its only user is
this page, so the navigation callbacks are gone.

main's tests of the type label, the empty type match and a conflicting type
key moved with the list, from the All workspaces spec to the Sandboxes
page's; the page's own text filter is "current page" as main's is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main pages the workspaces, a workspace's sandboxes and the sandboxes of
every workspace through the gateway (pageSize, pageToken). The mock API
answered those with the whole array, which the paged hooks cannot read, so
the lists were empty under make dev-mock. A list asked for with pageSize is
now answered as the BFF answers it, { items, nextPageToken }; without it,
as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main's list fixtures are one page, { items, nextPageToken }, and its stubs
served that page to every request for the workspaces and for the sandboxes
of every workspace. The BFF answers a page only when it is asked for
pageSize; the shell's counts and the Gateway page ask without it and read an
array, so the Gateway page failed on the page object. The two stubs now
answer as the BFF would: the page with pageSize, the items without.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Gkrumbach07
Gkrumbach07 force-pushed the feat/ui-cohesive-redesign branch from 0870eab to 22bbd92 Compare October 22, 2026 22:47
@Gkrumbach07
Gkrumbach07 merged commit 70afb39 into main Oct 22, 2026
14 checks passed
@Gkrumbach07
Gkrumbach07 deleted the feat/ui-cohesive-redesign branch November 6, 2026 17:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants