Skip to content

refactor: extract shared UI components (Phase 08)#822

Draft
jSydorowicz21 wants to merge 1 commit intoRunMaestro:rcfrom
jSydorowicz21:dedup/phase-08-shared-ui-components
Draft

refactor: extract shared UI components (Phase 08)#822
jSydorowicz21 wants to merge 1 commit intoRunMaestro:rcfrom
jSydorowicz21:dedup/phase-08-shared-ui-components

Conversation

@jSydorowicz21
Copy link
Copy Markdown
Contributor

Summary

Extracts three shared UI primitives and migrates existing call sites. Net effect: one canonical pattern per primitive instead of 140+ hand-rolled variants.

Net: +223 lines overall (new components + tests), but -178 lines in migrated call sites (3 new component files + tests account for the delta)

08A - GhostIconButton

New: src/renderer/components/ui/GhostIconButton.tsx + test.

The standard "icon-only button with hover bg and optional tooltip" pattern used 100+ times across the renderer.

  • Migrated: 54 call sites across 43 files (AST-aware codemod handled className drop, aria-label -> ariaLabel, style={{color:X}} -> color={X})
  • Skipped: sites with extra layout classes (flex variants, padding variants, focus rings), non-icon children with custom styles - would require adding 3-4 edge-case props for 1-2 callers each

08B - Spinner

New: src/renderer/components/ui/Spinner.tsx + test.

The standard animated loading indicator wrapping Loader2 from lucide-react.

  • Migrated: 84 call sites across 55 files (44 simple + 40 color-styled variants)
  • Loader2 imports removed: 42 files
  • Skipped: 3 files had local components named Spinner that did something different (CSS-driven circular progress) - renamed those to CircularSpinner to resolve the name collision

08C - EmptyStatePlaceholder

New: src/renderer/components/ui/EmptyStatePlaceholder.tsx + test.

A generic placeholder for "No X" / "No results" / "Select something" states. Intentionally distinct from the existing EmptyStateView.tsx, which is the specialized welcome-screen component - different purpose, would have needed a confusing mode prop.

  • Adopted: 2 sites (AgentSessionsBrowser, AgentSessionsModal)
  • Skipped: most other empty-state occurrences had custom headings/actions/layouts that would bloat the component's prop surface for 1-2 callers

Test plan

  • npm run lint passes (all 3 tsconfigs)
  • npx prettier --check . passes
  • 109 UI component tests pass (13 new + existing)
  • 268 migrated-component tests pass (AboutModal, AgentSessionsModal, AgentSessionsBrowser, UpdateCheckModal)
  • Visual regression: hover any ghost icon button - bg should still appear
  • Visual regression: trigger a loading state - spinner should still animate
  • Visual regression: open Agent Sessions Browser with no sessions - placeholder should render

Risk

Low. Behavior-preserving migration: each call site produces identical DOM/styling. Three new components with dedicated tests. One intentional name-rename (Spinner -> CircularSpinner in 3 files) for the collision case.

Cross-PR interaction

This PR modifies AgentSessionsModal.tsx, which is deleted by #791 (Phase 01A). Whichever merges second will need a trivial conflict resolution (this PR's edits to that file will be dropped if 01A is already in).

- 08A: Extract GhostIconButton (src/renderer/components/ui/GhostIconButton.tsx)
  encapsulating the "p-N rounded hover:bg-white/10 transition-colors" icon-button
  pattern. Migrated 54 call sites across 43 files via AST-aware codemod.
- 08B: Extract Spinner (src/renderer/components/ui/Spinner.tsx) for the
  Loader2 + animate-spin loading indicator pattern. Migrated 84 call sites
  across 55 files and removed 42 now-unused Loader2 imports.
- 08C: Add EmptyStatePlaceholder (src/renderer/components/ui/EmptyStatePlaceholder.tsx)
  for the generic "No X" icon + title + description pattern. Adopted at 2 call
  sites (AgentSessionsBrowser, AgentSessionsModal). Distinct from the
  top-level EmptyStateView welcome screen.

Added minimal vitest coverage for each new primitive (13 tests total).
All three components exported from src/renderer/components/ui/index.ts.

Net impact: 70 files changed, 404 insertions(+), 582 deletions(-).
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 13, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 832930f8-0c93-46cf-a52d-ddd196fd46a7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

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

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