Redesign the Command dashboard and application chrome - #106
Conversation
The Command page was a stack of bordered lists: nine flat counts, an attention queue, and two link lists. It answered "what exists" but not "what is moving", and the chrome around it gave the product no shape. Chrome: - Sidebar keeps its group vocabulary but reads as navigation — brand block, spaced groups, an accent indicator on the active row, and the collapse control moved to the footer where it is out of the way. - Top bar carries organisation context, a real search affordance with its shortcut, an approvals bell with its pending count, theme, and the signed-in actor with initials. - Page background drops to the darkest paper so cards sit above it. Card now uses the card token, which fixes the flat-on-flat surfaces everywhere, not only here. Dashboard: - Stat tiles gain a measured 24h delta and the seven-day series behind the number, and the two tiles whose value disagreed with their series are now scoped to the window they chart. - New panels: hourly agent run activity (toggleable series), work-item status donut counted in SQL over the whole backlog, a work queue split between items you own and items nobody owns, per-agent run volume and success rate over 7 days, and control-plane integration health. - Attention queue, risk radar, and the audit feed stay, restyled. Every number comes from the database. Where the rate cannot be measured — an agent with no settled runs, a session without administration.manage — the panel says so instead of inventing a figure. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MT2TCg43f2npxaN3HzQg7g
|
Warning Review limit reached
Next review available in: 20 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughThe Command dashboard now supplies time-windowed activity, task, integration, and trend data, renders reusable charts and panels, refreshes the application shell, and reorganizes the Command page into operational dashboard sections. ChangesCommand dashboard
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (6)
apps/web/types/os.ts (2)
81-110: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
successRatedoc drifts from the producer's denominator.The comment says null when there are "no completed runs", but the domain code nulls it when there are no settled runs (completed + failed). Worth aligning the wording so consumers don't misread the rate.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/types/os.ts` around lines 81 - 110, Update the JSDoc for AgentActivityRow.successRate to state that it is null when the agent has no settled runs in the window, meaning completed or failed runs, matching the producer’s denominator. Leave the type and surrounding fields unchanged.
69-79: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
labelis documented as local time but is produced in UTC.
getCommandSummaryfillslabelwithgetUTCHours()(apps/web/lib/command-summary-domain.tsLine 503), andRunActivityChartignoreslabelentirely, deriving its own axis label frombucket. Either droplabelfrom the contract or fix the doc to say UTC.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/types/os.ts` around lines 69 - 79, Resolve the RunActivityPoint contract mismatch by removing the unused label field, since getCommandSummary produces it in UTC and RunActivityChart derives labels from bucket. Update the type and all associated producers or consumers to stop requiring label, while preserving the existing bucket-based chart labeling.apps/web/components/os/panel.tsx (1)
26-26: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winDerive
headingIdwithuseId()instead of slugging the title.Two panels sharing a title (or titles differing only in punctuation) collide on one DOM id, breaking
aria-labelledby.useIdis collision-free and keeps this a server-renderable component.♻️ Proposed change
-import type { ReactNode } from "react"; +import { useId, type ReactNode } from "react";- const headingId = `panel-${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`; + const headingId = useId();🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/components/os/panel.tsx` at line 26, Update the panel component’s headingId derivation to use React’s useId() hook instead of normalizing and slugging title. Keep the generated id stable, collision-free, and compatible with server rendering, and retain its use for aria-labelledby.apps/web/components/os/charts.tsx (1)
150-191: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winNo text equivalent for the line chart.
The donut ships an adjacent slice list, but hourly run activity is SVG-only — screen readers get nothing. Consider a visually hidden summary or table of the buckets.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/components/os/charts.tsx` around lines 150 - 191, Add an accessible, visually hidden text equivalent to RunActivityChart using the existing points data, including each bucket’s time and corresponding activity values for the visible series. Keep the SVG chart unchanged visually, and ensure screen readers can access the summary or table without duplicating visible content.apps/web/lib/command-summary-domain.ts (2)
947-951: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftConsider splitting
getCommandSummary.The function now spans ~850 lines covering queries, aggregation, and view-model shaping for eight panels. Extracting per-panel builders (
buildRunActivity,buildAgentActivity,buildMyTasks,buildIntegrations) would make each testable in isolation. As per coding guidelines, "Prefer small domain services over giant route handlers".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/lib/command-summary-domain.ts` around lines 947 - 951, Refactor getCommandSummary into focused per-panel builders, extracting at least buildRunActivity, buildAgentActivity, buildMyTasks, and buildIntegrations for their respective queries, aggregation, and view-model shaping. Have getCommandSummary orchestrate these builders while preserving the existing outputs and behavior for all eight panels.Source: Coding guidelines
238-320: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winThese five new reads run sequentially on the request path.
taskStatusCounts→recentTasks→recentApprovals→recentMissionRuns→recentAgentRunsare independent, but eachawaitblocks the next, adding five round trips to an endpoint that already issues ~8 queries and refetches every 30s per client. Batch the independent ones withPromise.all.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/lib/command-summary-domain.ts` around lines 238 - 320, Batch the independent database reads for taskStatusCounts, recentTasks, recentApprovals, recentMissionRuns, and recentAgentRuns with Promise.all so they execute concurrently on the request path. Preserve each existing permission guard, query filters, limits, ordering, and result assignment while removing the sequential await chain.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/components/os/company-os-shell.tsx`:
- Around line 425-443: Update the pendingApprovals badge rendering in the topbar
Link to match the sidebar’s truncation behavior: display the exact count through
99 and show "99+" only when pendingApprovals exceeds 99. Keep the existing
aria-label and zero-count behavior unchanged.
In `@apps/web/features/command/command-view.tsx`:
- Around line 339-388: Replace the incomplete tab semantics in the work queue
filter around taskTab with accessible filter toggles: remove role="tablist" and
role="tab" (and the associated aria-selected usage), while preserving the
existing selected styling, click behavior, and task filtering. Do not add
partial tabpanel wiring or keyboard navigation.
In `@apps/web/lib/command-summary-domain.ts`:
- Around line 496-509: Remove the unused UTC-formatted label from the
RunActivityPoint objects created in command-summary-domain.ts around lines
496-509, and remove the corresponding label field from the RunActivityPoint type
in apps/web/types/os.ts around lines 69-79. Keep bucket as the source for
viewer-local axis formatting in RunActivityChart.
- Around line 580-606: The myTasks construction currently filters the
already-capped openTasks list, which can omit eligible assigned or unassigned
tasks. Update the surrounding command-summary data-loading logic to use a
dedicated query or uncapped source containing the actor’s tasks and all
unassigned open tasks, then retain the existing priority sorting, 20-item limit,
and mapping in myTasks.
- Around line 256-300: Make the capped recent-history queries deterministic by
adding ascending timestamp ordering before the 2,000-row limit in both
recentTasks and recentApprovals, so truncation removes the oldest rows rather
than an arbitrary subset. Preserve the existing filters and
dailySeries/dayOverDayTrend processing.
---
Nitpick comments:
In `@apps/web/components/os/charts.tsx`:
- Around line 150-191: Add an accessible, visually hidden text equivalent to
RunActivityChart using the existing points data, including each bucket’s time
and corresponding activity values for the visible series. Keep the SVG chart
unchanged visually, and ensure screen readers can access the summary or table
without duplicating visible content.
In `@apps/web/components/os/panel.tsx`:
- Line 26: Update the panel component’s headingId derivation to use React’s
useId() hook instead of normalizing and slugging title. Keep the generated id
stable, collision-free, and compatible with server rendering, and retain its use
for aria-labelledby.
In `@apps/web/lib/command-summary-domain.ts`:
- Around line 947-951: Refactor getCommandSummary into focused per-panel
builders, extracting at least buildRunActivity, buildAgentActivity,
buildMyTasks, and buildIntegrations for their respective queries, aggregation,
and view-model shaping. Have getCommandSummary orchestrate these builders while
preserving the existing outputs and behavior for all eight panels.
- Around line 238-320: Batch the independent database reads for
taskStatusCounts, recentTasks, recentApprovals, recentMissionRuns, and
recentAgentRuns with Promise.all so they execute concurrently on the request
path. Preserve each existing permission guard, query filters, limits, ordering,
and result assignment while removing the sequential await chain.
In `@apps/web/types/os.ts`:
- Around line 81-110: Update the JSDoc for AgentActivityRow.successRate to state
that it is null when the agent has no settled runs in the window, meaning
completed or failed runs, matching the producer’s denominator. Leave the type
and surrounding fields unchanged.
- Around line 69-79: Resolve the RunActivityPoint contract mismatch by removing
the unused label field, since getCommandSummary produces it in UTC and
RunActivityChart derives labels from bucket. Update the type and all associated
producers or consumers to stop requiring label, while preserving the existing
bucket-based chart labeling.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 39868d1f-c421-4205-8f09-e0a1f579e64f
📒 Files selected for processing (11)
DESIGN.mdapps/web/components/os/charts.tsxapps/web/components/os/company-os-shell.tsxapps/web/components/os/metric-tile.tsxapps/web/components/os/panel.tsxapps/web/components/page-header.tsxapps/web/components/ui/card.tsxapps/web/components/ui/progress.tsxapps/web/features/command/command-view.tsxapps/web/lib/command-summary-domain.tsapps/web/types/os.ts
Match approvals badge truncation to the sidebar (99+), replace incomplete tab semantics on the work-queue filter, drop the unused UTC run-activity label, load myTasks from a dedicated mine/unassigned query, make capped history reads deterministic, and extract panel builders with concurrent reads. Chart and panel accessibility nits included.
The Command page was a stack of bordered lists: nine flat counts, an
attention queue, and two link lists. It answered "what exists" but not
"what is moving", and the chrome around it gave the product no shape.
Chrome:
spaced groups, an accent indicator on the active row, and the collapse
control moved to the footer where it is out of the way.
shortcut, an approvals bell with its pending count, theme, and the
signed-in actor with initials.
now uses the card token, which fixes the flat-on-flat surfaces everywhere,
not only here.
Dashboard:
number, and the two tiles whose value disagreed with their series are now
scoped to the window they chart.
status donut counted in SQL over the whole backlog, a work queue split
between items you own and items nobody owns, per-agent run volume and
success rate over 7 days, and control-plane integration health.
Every number comes from the database. Where the rate cannot be measured —
an agent with no settled runs, a session without administration.manage —
the panel says so instead of inventing a figure.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01MT2TCg43f2npxaN3HzQg7g
Summary by CodeRabbit
New Features
Style
Documentation