feat(dashboard): apply G2 Barrier Membrane redesign to all routes - #75
Conversation
Redesign Overview, Audit, Policies, and Approvals on top of the existing components, API client, polling hooks, and routing; no new routes. - index.css: oklch design tokens (dark primary, light secondary with reduced depth), Tailwind @theme bridge, double-bezel Panel, mono verdict pills with glyphs (checkmark ALLOWED/APPROVED, pause PAUSED, cross DENIED/REJECTED), cyan primary Approve + red-outline Deny actions, global :focus-visible, reduced-motion-aware reveal - App shell: lowercase mono "honmoon" wordmark + cyan mark, right command capsule (nav, live pending badge, gateway reachability derived from the approvals poll, account area) - Overview: status hero derived from live data, pending-approval strip with shared per-id busy actions, KPI tiles, latest 8 decisions, decision mix; API errors stay explicit and never look like a healthy empty state - Audit: same Time/Decision/Request/Rule columns; loading/error/empty/ populated states; request truncation keeps the full value in title - Policies: keeps Prism + react-simple-code-editor (and the CJS unwrap workaround), adds gutter line numbers and G2 Prism token colours (prism-tomorrow theme dropped), local-only edits, "Reset to active" only when dirty, Phase 5 hot-reload note; no save/deploy actions - Approvals: useApprovalActions hook (Set-based per-id busy) shared with Overview; approve/reject + refresh, empty/error states preserved - Nav label "Audit Log" renamed to "Audit" Verified: typecheck, build, build:demo, and eslint all pass; manual dark/light browser verification of all states.
Merging this PR will improve performance by 50.18%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ⚡ | parse_k8s_path[/api/v1/namespaces/prod/secrets/db-password] |
8.7 µs | 5.8 µs | +50.18% |
Tip
Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.
Comparing feat/dashboard-g2-redesign (9545d0e) with main (3ea2879)
There was a problem hiding this comment.
Code Review
This pull request introduces a major visual redesign of the dashboard using G2 'Barrier Membrane' tokens, OKLCH colors, and custom UI components, alongside refactoring the approval actions into a reusable hook and component. The review feedback highlights a layout-breaking bug in PolicyView due to an invalid padding object format passed to react-simple-code-editor. Additionally, the reviewer points out a significant DRY violation where the approvals endpoint is polled redundantly across multiple components, recommending that the polling state be lifted to the parent App component and shared via props.
- AGENTS.md: list `SectionHead` among the `ui` exports - PolicyView: promote the Posture heading to `h2` so the Policy route no longer skips from h1 to h3 (WCAG 1.3.1) - Record the review's rejected findings in the ledger Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
react-simple-code-editor spreads unknown props onto its wrapper div, so the `aria-label` on `<Editor>` never reached the textarea. Bind a visually hidden `<label>` to `textareaId` instead (WCAG 4.1.2 / 3.3.2) and record the review-fix-loop iteration 2 rejections in the ledger. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Raise dark-mode `--dim` to oklch(60%) so metadata text clears WCAG 4.5:1 against every backdrop it sits on (was 3.1:1 on `--bg`) - Render the posture headline through a Verdict lookup so a `pause` default reads "paused", not "pauseed" - Use `DEFAULT_EGRESS_VERDICT` from @honmoon/policy instead of a `'deny'` literal - Correct the useApprovalActions docstring: refresh runs only after success - Record the iteration 3 rejections in the review ledger Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Track approve/reject failures per approval id (`actionErrors` Map) and render each note on its own card / next to its own row, so one row's failure is never hidden by another row's action. - Derive the header's gateway state from both live polls: approvals plus a one-row audit probe, so an audit-only outage no longer reads as "live". - Overview hero waits for the approvals poll before claiming the queue is empty; audit-only panels key off the audit poll alone and receive only the audit error. - Approve/Deny buttons expose "Resolving…" in their accessible name while busy, matching the visible label. - DecisionBadge renders an unknown verdict as "?" instead of throwing. - Fix the `--*-ink` token comment and the AGENTS.md theming note. - Add `bun test` for the dashboard with a happy-dom + `act` harness and three `useApprovalActions` tests (per-id busy, per-id error, refresh only on success). CI does not run this suite yet. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Every route put `max-w-[1440px]` and `px-10` on the same element, so the page body sat 40px inside the header's content edge at wide viewports. Use the header's pattern instead — padding on the outer element, a `max-w-[1440px]` wrapper inside — on Overview, Audit, Policies and Approvals, and drop the now-redundant max-width from PageHead. Measured header and body edges match on all four routes at 1536px. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…w hero Audit, Policies and Approvals sat 30px below the app header and 24px above their first panel, while the Overview hero uses 32px and 50px. Use `pt-8` on the three sections and `mb-[50px]` on PageHead so every route lands its first panel at the same offset. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Greptile SummaryApplies the Barrier Membrane redesign across all four dashboard routes while adding shared panels, approval controls, live status presentation, policy posture details, and hook tests.
Confidence Score: 4/5The slow-response polling failure should be fixed before merging because it can leave every live dashboard surface permanently loading despite completed API responses. The new latest-run check combines with unconditional fixed-interval requests to discard every response whenever API latency remains above the polling interval, preventing data, errors, and settled state from reaching the UI. Files Needing Attention: apps/dashboard/src/hooks.ts
|
| Filename | Overview |
|---|---|
| apps/dashboard/src/hooks.ts | Adds shared approval actions and stale-run polling protection, but slow responses can be invalidated forever by subsequent interval ticks. |
| apps/dashboard/src/App.tsx | Rebuilds the shell and derives gateway reachability from approvals and audit polling. |
| apps/dashboard/src/components/Overview.tsx | Reworks live KPI, status, decision, and approval presentation while preserving explicit unknown/error states. |
| apps/dashboard/src/components/Approvals.tsx | Redesigns the queue and adopts per-ID action state and error rendering. |
| apps/dashboard/src/components/PolicyView.tsx | Adds line-numbered Prism highlighting and active-policy posture while keeping edits local. |
| apps/dashboard/src/index.css | Introduces the Barrier Membrane token system, themes, shared component styling, focus treatment, and reduced-motion behavior. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
API[Management API] --> Poll[usePolling]
Poll --> Shell[Gateway status]
Poll --> Overview[Overview]
Poll --> Audit[Audit log]
Poll --> Approvals[Approval queue]
Actions[Approve or deny] --> API
Comments Outside Diff (1)
-
apps/dashboard/src/hooks.ts, line 33-36 (link)Polling can discard every response
If management API latency consistently exceeds the 1.5- or 2-second polling interval, each interval increments
latestRunbefore the preceding request settles. Every successful response and error is then rejected as stale, leaving the dashboard permanently on Loading/Connecting instead of displaying data or an API failure.Knowledge Base Used: Operations dashboard
Prompt To Fix With AI
This is a comment left during a code review. Path: apps/dashboard/src/hooks.ts Line: 33-36 Comment: **Polling can discard every response** If management API latency consistently exceeds the 1.5- or 2-second polling interval, each interval increments `latestRun` before the preceding request settles. Every successful response and error is then rejected as stale, leaving the dashboard permanently on Loading/Connecting instead of displaying data or an API failure. **Knowledge Base Used:** [Operations dashboard](https://app.greptile.com/passionfactory/-/custom-context/knowledge-base/pleaseai/honmoon/-/docs/operations-dashboard.md) --- For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Prompt To Fix All With AI
### Issue 1
apps/dashboard/src/hooks.ts:33-36
**Polling can discard every response**
If management API latency consistently exceeds the 1.5- or 2-second polling interval, each interval increments `latestRun` before the preceding request settles. Every successful response and error is then rejected as stale, leaving the dashboard permanently on Loading/Connecting instead of displaying data or an API failure.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "fix(dashboard): match secondary pages' v..." | Re-trigger Greptile
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c12d69e6ed
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- usePolling: commit a run when it is newer than the last *committed* run rather than only when it is the latest *started* run. An API that is consistently slower than the poll interval now shows stale-but-real data instead of discarding every response and sitting on Loading forever. Add an ordering test covering the slow-first, newer-over-older and late-older-dropped cases. - Header: below `md` the nav capsule wraps onto its own full-width row and scrolls horizontally as a last resort, so every route stays reachable at 360-430px instead of overflowing the viewport. - Policy posture: describe the egress fallback as applying when neither the deny nor the allow list matches; the engine checks deny before allow, so "not on the allow list" was wrong for policies with a deny list. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Re Greptile's |
There was a problem hiding this comment.
All reported issues were addressed
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
…fix light-mode focus contrast - ApprovalActions accepts placement classes; the approval card passes `max-md:col-span-full max-md:justify-self-end` so the Deny/Approve pair gets a full-width row below `md` instead of being auto-placed into the 44px icon track. - The shared `:focus-visible` ring uses `--accent-ink`, which equals `--accent` in dark mode and is the darkened variant in light mode (~6:1 against the near-white surfaces instead of ~1.6:1). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9545d0e6a8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| type="button" | ||
| className="action action-deny" | ||
| disabled={busy} | ||
| onClick={onReject} |
There was a problem hiding this comment.
Add interaction coverage for the new dashboard surfaces
The new dashboard behavior is only covered through direct hook tests in hooks.test.tsx; none of the added routes or components is rendered in a test. In particular, this user-facing Deny control has no interaction coverage proving it dispatches the rejection, reflects busy/error state, or remains correctly wired in its card and overview hosts. Add happy-dom component tests for the newly built surfaces rather than relying solely on hook tests.
AGENTS.md reference: apps/dashboard/AGENTS.md:L61-L63
Useful? React with 👍 / 👎.



Summary
Applies the G2 "Barrier Membrane" visual redesign to all four existing dashboard hash routes (Overview
#/, Audit#/audit, Policies#/policies, Approvals#/approvals), on top of the existing components,api.ts,usePolling, and hash routing. No new routes, no new dependencies, and the demo shim is untouched.Changes
index.css(dark primary theme, light secondary theme with reduced shadow depth), Tailwind@themebridge, double-bezelPanel, mono verdict pills with glyphs (✓ ALLOWED,✓ APPROVED,‖ PAUSED,✕ DENIED,✕ REJECTED), cyan primary Approve / red-outline Deny, global:focus-visible, reduced-motion-aware reveal animation.honmoonwordmark, right-side command capsule with nav, live pending badge, gateway reachability derived from the approvals poll.title.react-simple-code-editorkept (including the CJS unwrap workaround), gutter line numbers added, G2 Prism token colours replaceprism-tomorrow; edits remain local only, "Reset to active" only appears when dirty, Phase 5 note kept, no Save/Deploy/Validate.useApprovalActionshook (Set-based per-id busy tracking) shared with Overview; approve/reject + refresh, empty/error states preserved.components/ui.tsx(Panel,PageHead,SectionHead,ErrorNote,PanelState),components/ApprovalActions.tsx.AGENTS.mdstructure table updated. Nav label "Audit Log" → "Audit".Test Plan
bun run --filter '@honmoon/dashboard' typecheckbun run --filter '@honmoon/dashboard' buildbun run --filter '@honmoon/dashboard' build:demobunx eslint apps/dashboard/src✓ APPROVEDinto AuditNotes for Reviewers
--*-inktext variants were added because the prototype's 81%-lightness cyan lacked contrast on white.formatTimewidth, no dashboard component tests yet.Related Issues
No linked issue for this work.
Summary by cubic
Applies the G2 Barrier Membrane redesign to Overview, Audit, Policies, and Approvals on top of the existing API client, polling, hash routing, and demo flow.
Shared shell
mdthe capsule wraps to its own full-width row and scrolls horizontally as a fallback.usePollingcommits a run newer than the last committed response, so a slow API shows stale-but-real data instead of loading forever.Route behavior
react-simple-code-editor, adds G2 token colors and line numbers, labels the YAML editor accessibly, and limits edits to local state.bun testcoversuseApprovalActionsper-id busy, error, and refresh behavior plususePollingcommit ordering.Written for commit 9545d0e. Summary will update on new commits.