Skip to content

updated style of panel#118

Merged
AviPeltz merged 4 commits intomainfrom
slight-style-updates
Nov 24, 2025
Merged

updated style of panel#118
AviPeltz merged 4 commits intomainfrom
slight-style-updates

Conversation

@AviPeltz
Copy link
Copy Markdown
Collaborator

@AviPeltz AviPeltz commented Nov 21, 2025

Description

Related Issues

Type of Change

  • Bug fix
  • New feature
  • Documentation
  • Refactor
  • Other (please describe):

Testing

Screenshots (if applicable)

Additional Notes

Summary by CodeRabbit

  • New Features

    • Animated spinner for running agents
    • Status legend showing Running, Idle, Error, Stopped
  • Improvements

    • Status indicators updated with color/emoji for clarity
    • More responsive dashboard and panel layouts for varied terminal sizes
    • Improved agent row visuals and spacing for easier scanning
  • Chores

    • Minimum Node requirement raised to v20

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 21, 2025

Walkthrough

Adds a Spinner component and useSpinner hook, introduces animated status indicators and a status legend in CLI dashboard/panels, adds responsive width/padding calculations using string-width, updates package engine and dependency, and applies formatting/reflow across several CLI and orchestrator files; no public API signature changes.

Changes

Cohort / File(s) Summary
Dependency & Manifest
apps/cli/package.json
Node engine bumped to ">=20"; added dependency string-width "^8.1.0".
Spinner Component
apps/cli/src/components/Spinner.tsx
New useSpinner hook and Spinner component with defaults; exports SpinnerProps, useSpinner, and Spinner.
Dashboard UI
apps/cli/src/commands/dashboard.tsx
Replaced textual status badges with Spinner/emoji-based indicators, added status legend, adjusted selection/label emphasis and status rendering.
Panels UI & Layout
apps/cli/src/commands/panels.tsx
Added string-width usage, responsive width calculations, spinnerFrame integration, dynamic padding/target widths, adjusted agent row rendering and responsive footer/legend; Details pane hidden on small terminals.
Agent Command
apps/cli/src/commands/agent.tsx
Minor whitespace/formatting adjustment in start-complete view; no behavior changes.
Init / Launch / Orchestrator formatting
apps/cli/src/commands/init.tsx, apps/cli/src/lib/launch/run.ts, apps/cli/src/lib/orchestrators/process-orchestrator.ts
Code reflow and multi-line formatting changes only; no logic alterations.
Orchestrator Tests
apps/cli/src/lib/orchestrators/__tests__/process-orchestrator.test.ts
Reformatted orchestrator.create call across multiple lines; test logic unchanged.
Desktop router cleanup
apps/desktop/src/lib/trpc/routers/projects/projects.ts, apps/desktop/src/lib/trpc/routers/terminal/terminal.ts, apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
Reordered imports and removed a duplicate db import; no runtime behavior changes.

Sequence Diagram(s)

sequenceDiagram
    participant UI as Panels/Dashboard
    participant Effect as useEffect
    participant SpinnerHook as useSpinner
    participant Renderer as InkRenderer

    UI->>Effect: mount or agents state change
    alt any agent RUNNING
        Effect->>SpinnerHook: start interval (e.g. 80ms)
        loop every interval
            SpinnerHook->>Renderer: emit next frame
            Renderer->>Renderer: render spinner (green) + status legend
        end
    else no running agents
        Effect->>SpinnerHook: clear interval
        Renderer->>Renderer: render static emoji (idle/error/stopped)
    end
    Renderer->>Renderer: compute layout using string-width and apply padding
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review Spinner hook: interval lifecycle and edge-case handling for empty frames.
  • Verify spinner integration and cleanup in dashboard.tsx and panels.tsx.
  • Validate string-width usage and padding/width math to avoid truncation and layout regressions.
  • Spot-check reflowed orchestrator code to ensure no unintended formatting-induced logic changes.

Possibly related PRs

Poem

🐇 I spin with frames in rows so neat,
Green for run and yellow beat.
Widths aligned, the legend sings,
CLI hops bright on tiny springs.
A rabbit cheers these polished things!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description follows the template structure but is mostly empty; required sections like Description, Related Issues, Testing, and Additional Notes lack substantive content. Fill in the Description section with details of changes made, link related issues, describe testing steps performed, and add any relevant context or notes.
Title check ❓ Inconclusive The title 'updated style of panel' is vague and overly broad; it lacks specificity about which panels were updated or what style changes were made. Provide a more specific and descriptive title that clearly indicates the main change, such as 'Add responsive status indicators and legend to CLI panels' or 'Refactor dashboard panel styling with spinner animations'.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch slight-style-updates

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 49d0cce and fbc63bc.

📒 Files selected for processing (1)
  • apps/cli/package.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/cli/package.json

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/cli/src/commands/agent.tsx (2)

434-434: Fix TypeScript any type for workspace state.

The workspace state is typed as any, which bypasses type safety. This should be properly typed as Workspace | null.

Apply this diff to fix the type:

-	const [workspace, setWorkspace] = React.useState<any>(null);
+	const [workspace, setWorkspace] = React.useState<Workspace | null>(null);

479-479: Fix TypeScript any type for startAgents parameter.

The ws parameter in startAgents is implicitly typed as any. This should be explicitly typed as Workspace.

Apply this diff to fix the type:

-	const startAgents = async (ws: any, agents: AgentType[]) => {
+	const startAgents = async (ws: Workspace, agents: AgentType[]) => {
🧹 Nitpick comments (1)
apps/cli/src/commands/panels.tsx (1)

347-354: Consider edge case: empty agent list.

The width calculation logic at lines 347-354 assumes filteredAgents has items. While the parent conditional at line 316 handles the empty case, the complex padding calculation could benefit from a defensive check to ensure agentsPanelInnerWidth is always positive.

Consider adding a guard:

 const targetWidth = Math.max(agentsPanelInnerWidth, contentWidth);
+const safeTargetWidth = Math.max(0, targetWidth);
-const paddingNeeded = Math.max(0, targetWidth - contentWidth);
+const paddingNeeded = Math.max(0, safeTargetWidth - contentWidth);

This is defensive coding to handle potential edge cases where panel width calculations might produce unexpected values on extremely narrow terminals.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30ffd5b and 181e609.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • apps/cli/package.json (1 hunks)
  • apps/cli/src/commands/agent.tsx (1 hunks)
  • apps/cli/src/commands/dashboard.tsx (6 hunks)
  • apps/cli/src/commands/init.tsx (1 hunks)
  • apps/cli/src/commands/panels.tsx (10 hunks)
  • apps/cli/src/lib/launch/run.ts (6 hunks)
  • apps/cli/src/lib/orchestrators/__tests__/process-orchestrator.test.ts (1 hunks)
  • apps/cli/src/lib/orchestrators/process-orchestrator.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/cli/src/commands/dashboard.tsx (1)
apps/cli/src/types/process.ts (1)
  • Process (15-29)
🪛 GitHub Actions: CI
apps/cli/src/commands/agent.tsx

[error] 434-434: lint/suspicious/noExplicitAny: Unexpected any. Specify a different type for 'workspace'.


[error] 479-479: lint/suspicious/noExplicitAny: Unexpected any. Type of 'ws' parameter for startAgents should be specified.

🔇 Additional comments (11)
apps/cli/src/lib/orchestrators/__tests__/process-orchestrator.test.ts (1)

250-253: LGTM - Formatting improvement.

The multi-line formatting improves readability and aligns with the broader formatting refactors in this PR.

apps/cli/src/commands/agent.tsx (1)

646-647: LGTM - Minor formatting improvement.

The added space after "Success:" improves readability.

apps/cli/src/lib/launch/run.ts (1)

109-111: LGTM - Formatting improvements throughout.

All changes are formatting-only refactors that improve readability by breaking complex expressions across multiple lines. No functional changes.

Also applies to: 156-160, 218-220, 244-247, 311-315, 323-325, 380-384

apps/cli/src/lib/orchestrators/process-orchestrator.ts (1)

39-41: LGTM - Formatting improvements throughout.

All changes are formatting-only refactors that improve readability by breaking complex expressions across multiple lines. No functional changes.

Also applies to: 86-89, 256-258, 297-299

apps/cli/src/commands/init.tsx (1)

187-192: LGTM - Formatting improvement.

The multi-line formatting improves readability and aligns with the broader formatting refactors in this PR.

apps/cli/src/commands/dashboard.tsx (3)

37-37: Well-implemented spinner animation.

The spinner animation is properly implemented with good performance considerations:

  • Only runs when there are running agents
  • 80ms interval provides smooth animation
  • Proper cleanup in useEffect return
  • Dependency on spinnerFrames.length is safe since it's a constant array

Also applies to: 44-110


275-290: Excellent status indicator improvements.

The replacement of text badges with emoji/color indicators plus the status legend significantly improves the UI:

  • More visual and intuitive status display
  • Animated spinner for running agents provides dynamic feedback
  • Legend helps users understand the indicators
  • Color coding (green/yellow/red/gray) follows common UX patterns

Also applies to: 357-374


496-513: LGTM - Improved agent row rendering.

The updated rendering logic properly handles visual emphasis for both selected and running agents, with appropriate color coding. The sessionName truncation prevents layout issues on narrow terminals.

Also applies to: 520-520

apps/cli/src/commands/panels.tsx (3)

3-3: LGTM - Proper dependencies and spinner implementation.

The string-width import enables precise width calculations for terminal rendering. The spinner animation follows the same well-implemented pattern as in dashboard.tsx - only runs when agents are running, with proper cleanup.

Also applies to: 45-56, 96-110


319-384: Complex but correct width calculation logic.

The agent entry rendering with dynamic width calculations is well-implemented:

  • stringWidth properly measures content width including Unicode characters
  • targetWidth uses Math.max to prevent truncation by taking the larger of panel inner width or actual content width
  • Padding is only applied when needed
  • Background color for selected items improves UX

The logic correctly handles responsive layouts and prevents text overflow.


436-481: LGTM - Improved controls footer.

The refactored controls section is more compact and includes a helpful status legend that aligns with the dashboard UI. The responsive behavior for small terminals (hiding the Details panel shortcut) is appropriate.

Comment thread apps/cli/package.json
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (6)
apps/cli/src/commands/panels.tsx (5)

45-56: Responsive widths and shared spinner frame are reasonable; consider extreme‑small terminal behavior

The responsive calculations for workspacePanelWidth / agentsPanelWidth and agentsPanelInnerWidth, combined with a single spinnerFrame via useSpinner(), are a nice improvement.

One edge case worth noting: on very narrow terminals (e.g. widths in the low 30s), the hard minimums (Math.max(20, …) for both panels) can exceed the available contentWidth, causing horizontal overflow. This will mostly just truncate/wrap, but if you care about extremely small environments, you might want to enforce:

  • workspacePanelWidth + agentsPanelWidth + gap <= contentWidth and clamp one or both widths accordingly.

Otherwise this looks solid.


238-256: Workspace status spinner logic is consistent; check semantics of “running”

Using hasRunning to drive a green spinner per workspace and falling back to a gray circle is clear and visually consistent with the agents panel.

Just double‑check that treating !a.endedAt as “running” for workspaces (even when status isn’t RUNNING) matches your domain semantics; if an IDLE-but-not-yet-ended process should count as non‑running, you may want to tighten the predicate to status === RUNNING only.


343-368: Selected-row highlighting and padding behavior look correct

Wrapping the entire row in a <Text backgroundColor={backgroundColor}> and nesting the individual <Text> spans (arrow, spinner, agent type, time, padding) is a good way to get a contiguous highlight for the selected row. The computed paddingNeeded is applied as literal spaces, so the rendered width matches the earlier targetWidth computation.

Only minor stylistic note: color={textColor ?? "yellow"} for the arrow means the (invisible) unselected arrow still uses yellow, which is harmless but slightly surprising. If you want to be precise, you could use color={textColor} and rely on default color when not selected.

Functionally this is fine as‑is.


424-467: Controls footer and status legend are clearer; consider matching legend icon to spinner

The multi‑row footer with explicit key hints and a status legend improves discoverability a lot, and the responsiveness around showing the [3] Details hint only on wider terminals is thoughtful.

One micro‑consistency point: running agents/workspaces show a spinner glyph, but the legend uses a solid green for “Running”. That’s still understandable, but if you want perfect visual alignment you could either:

  • Show the spinner glyph in the legend as well, or
  • Switch the running indicator in the lists to a green (or prepend +spinner) so legend and rows match.

Not a correctness issue, just a UX polish opportunity.


301-341: Consider renaming contentWidth to rowContentWidth for clarity, and test spinner glyph alignment across target terminals

The naming suggestion is valid: renaming the per-row contentWidth variable (e.g., to rowContentWidth) will eliminate confusion with the module-level contentWidth and improve readability.

On string-width caveats: combining marks have zero advance width, certain character sequences may render differently than measured, and Braille spinner glyphs can misalign due to font/terminal variation despite being single-cell Unicode. Your code uses spinnerFrame and other Unicode glyphs (circles, arrows, X marks) that could be affected. Recommended: normalize text (NFC) before measuring and test on target terminals to verify glyph alignment. If users report misalignment across different terminal environments, consider adding guards for combining/enclosing sequences or measuring directly with the actual terminal renderer.

apps/cli/src/components/Spinner.tsx (1)

4-36: Strengthen hook robustness by including full frames array in dependency list

The hook works fine with static frames, but React's exhaustive-deps rule recommends depending on the actual values your effect uses. If you only depend on frames.length but the frame content changes, the effect will not rerun and will use the old frames.

The suggested refactor is sound:

  • Depend on the full frames array (or a stable memoized version if frames is recreated frequently)
  • Reset index to 0 when frames changes to avoid temporary out-of-range access
- React.useEffect(() => {
+ React.useEffect(() => {
+   setIndex(0);
    if (frames.length === 0) {
      return;
    }

    const timer = setInterval(() => {
      setIndex((i) => (i + 1) % frames.length);
    }, interval);

    return () => clearInterval(timer);
- }, [frames.length, interval]);
+ }, [frames, interval]);

This keeps behavior identical for current usage while making the hook robust to dynamic frames changes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 181e609 and 49d0cce.

📒 Files selected for processing (6)
  • apps/cli/src/commands/dashboard.tsx (5 hunks)
  • apps/cli/src/commands/panels.tsx (9 hunks)
  • apps/cli/src/components/Spinner.tsx (1 hunks)
  • apps/desktop/src/lib/trpc/routers/projects/projects.ts (1 hunks)
  • apps/desktop/src/lib/trpc/routers/terminal/terminal.ts (1 hunks)
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
  • apps/desktop/src/lib/trpc/routers/terminal/terminal.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/cli/src/commands/dashboard.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
apps/cli/src/commands/panels.tsx (1)
apps/cli/src/components/Spinner.tsx (1)
  • useSpinner (17-36)
🔇 Additional comments (5)
apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts (1)

2-2: LGTM! Clean import deduplication.

Removing the duplicate import improves code clarity without any functional changes.

apps/cli/src/components/Spinner.tsx (1)

44-56: Spinner component usage looks good and is Ink-friendly

The Spinner wrapper around useSpinner is straightforward and integrates nicely with Ink’s <Text> (color pass-through, null-render on empty frames, sensible defaults). No issues from a correctness standpoint.

apps/cli/src/commands/panels.tsx (3)

292-294: Agents panel width and flex behavior make sense for small vs large terminals

Binding width={agentsPanelWidth} and flexGrow={isSmallTerminal ? 1 : 0} gives agents more room on narrow terminals while keeping a fixed-ish layout when there’s space. That’s a good trade‑off for readability. No changes needed.


395-409: Details panel formatting is clear and compact

Inlining the “Agent:” label with a bolded agent type and formatting endedAt via toLocaleString() reads well and uses space efficiently. This also plays nicely with hiding the whole panel on small terminals.

No issues; behavior matches the rest of the UI.


3-14: Imports and type usage are clean and tree-shake friendly

Switching to string-width and useSpinner, plus using type-only imports for Agent/Process, keeps module boundaries clear and aids tree shaking. The string-width package correctly handles full-width characters, emoji sequences, combining marks, and ANSI codes—all essential for robust terminal column width calculations in CLI applications. No issues.

Resolved conflict in workspaces.ts by keeping the simpleGit import
needed for the canDelete procedure.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@AviPeltz AviPeltz merged commit 2beb8f3 into main Nov 24, 2025
1 of 5 checks passed
@Kitenite Kitenite deleted the slight-style-updates branch November 29, 2025 06:30
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.

1 participant