Skip to content

Conversation

@saddlepaddle
Copy link
Collaborator

@saddlepaddle saddlepaddle commented Dec 2, 2025

Summary

  • Add hover cards to workspace tabs that display worktree info and GitHub PR status
  • Fetch PR data via gh CLI with graceful fallback when unavailable
  • Show worktree name, age, rebase warning, PR details (number, status, title, diff stats)
  • Add expandable checks list showing individual CI job statuses with clickable links
  • Display review status and "View on GitHub" button with GitHub logo

Test plan

  • Hover over a workspace tab to see the hover card
  • Verify worktree name and age display correctly
  • Verify PR info shows for branches with open PRs
  • Verify "No PR for this branch" shows for branches without PRs
  • Click "Show checks" to expand the checks list
  • Click individual checks to open them in GitHub
  • Click "View on GitHub" button to open the PR

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added GitHub PR info in workspace hover: PR badge, title, numbers, review status, checks summary, and additions/deletions.
    • Real-time GitHub PR status fetching with caching and new endpoints to retrieve workspace & PR details.
    • New UI components: hover card content, PR status badge, checks summary/list, per-check rows, and review status display.
  • Documentation

    • Project structure documentation reorganized for dashboard components.

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

- Add hover card to workspace tabs showing worktree info and GitHub PR status
- Fetch PR data via `gh` CLI with graceful fallback if unavailable
- Display worktree name, age, rebase warning, PR number/status/title
- Show diff stats (+additions/-deletions) with GitHub-style colors
- Add expandable checks list showing individual CI job statuses with links
- Show review status (approved/changes requested/pending)
- Include "View on GitHub" button with GitHub logo

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

Co-Authored-By: Claude <[email protected]>
@vercel
Copy link

vercel bot commented Dec 2, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
website Ready Ready Preview Comment Dec 2, 2025 2:29am

@coderabbitai
Copy link

coderabbitai bot commented Dec 2, 2025

Walkthrough

Adds GitHub PR status plumbing: a CLI-based GitHub utility, two TRPC endpoints to expose worktree and PR info, extended DB schemas for checks, and a React hover-card UI showing PR details and checks for workspace tabs.

Changes

Cohort / File(s) Summary
GitHub CLI utility
apps/desktop/src/lib/trpc/routers/workspaces/utils/github.ts
New module that runs gh (and git) commands to fetch repo URL and PR for the current branch, parses & normalizes PR fields and status checks into GitHubStatus/CheckItem, computes overall checksStatus, and handles expected errors by returning null or rethrowing unexpected errors.
TRPC router endpoints
apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
Adds getGitHubStatus and getWorktreeInfo public procedures that resolve workspace → worktree, call fetchGitHubPRStatus, cache result on the worktree, and return worktree metadata plus (fresh) GitHub PR status or null.
Schema / Types
apps/desktop/src/main/lib/db/schemas.ts
Introduces CheckItem type and extends GitHubStatus.pr with additions, deletions, reviewDecision, checksStatus, and checks: CheckItem[].
Hover card UI & subcomponents
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
New WorkspaceHoverCardContent component that fetches worktree info & GitHub status via TRPC and renders PR header, status badge, diffs, title, checks summary/list (expandable), review status, and a GitHub link; includes internal subcomponents and conditional states.
Hover card exports
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/index.ts
Re-exports WorkspaceHoverCardContent.
Workspace item prop plumbing
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
Passes workspaceId={id} into WorkspaceItemContextMenu so hover-card can identify the workspace.
Context menu → HoverCard integration
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItemContextMenu.tsx
Wraps existing context menu trigger in a HoverCard / HoverCardTrigger and renders WorkspaceHoverCardContent in HoverCardContent; adds workspaceId prop and hover delays.
Checks list & item components
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/*
.../CheckItemRow/*
New ChecksList collapsible component and CheckItemRow item renderer (with status icons, optional links); index barrels added for exports.
Checks summary & badge components
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/*, .../PRStatusBadge/*, .../ReviewStatus/*
New ChecksSummary, PRStatusBadge, and ReviewStatus components with corresponding index re-exports for small UI status bits.
Docs & deps
AGENTS.md, apps/desktop/package.json
Documentation reorganization and addition of dependency "date-fns": "^4.1.0".

Sequence Diagram

sequenceDiagram
    participant User
    participant UI as Workspace Tab
    participant HoverCard
    participant TRPC as Workspaces Router
    participant GHUtil as GitHub Utility
    participant GHCli as GitHub CLI
    participant Display as Hover Card Content

    User->>UI: Hover over workspace tab
    UI->>HoverCard: open trigger
    HoverCard->>TRPC: getWorktreeInfo(workspaceId)
    TRPC->>GHUtil: fetchGitHubPRStatus(worktreePath)
    GHUtil->>GHCli: gh repo view --json url
    GHCli-->>GHUtil: repo url (JSON)
    GHUtil->>GHCli: gh pr view <branch> --json <fields>
    GHCli-->>GHUtil: PR + status checks (JSON)
    GHUtil->>GHUtil: parse checks, map states, compute checksStatus
    GHUtil-->>TRPC: GitHubStatus | null
    TRPC-->>HoverCard: worktreeInfo + githubStatus
    HoverCard->>Display: render PR info, checks, review status
    Display-->>User: visible hover-card UI
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45–60 minutes

  • Pay attention to github.ts for command invocation, JSON parsing, and error classification.
  • Verify schema changes in schemas.ts are compatible with all consumers.
  • Review WorkspaceHoverCard.tsx for edge cases (loading states, missing fields) and accessibility.
  • Confirm WorkspaceItemContextMenu prop propagation and hover-delay behavior.
  • Ensure new dependency (date-fns) is used consistently and bundled.

Possibly related PRs

Poem

🐰 I nibbled at branches, found PR light,
CLI whispers checks in the gentle night.
Hover and behold the status, neat and bright,
Rabbits cheer for badges, checks in flight! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The description addresses key sections but lacks details in several required template areas, particularly Related Issues, Type of Change, Testing, and Screenshots. Complete the PR description by filling out Related Issues (link any related issues), selecting Type of Change, providing detailed testing steps with completion checkmarks, and adding screenshots if applicable.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding workspace hover cards with GitHub PR status display.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch silver-glacier-88

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.

Copy link

@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

🧹 Nitpick comments (8)
apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts (2)

500-531: Consider adding request deduplication or throttling for frequent hovers.

The endpoint always fetches fresh data on every hover. If users rapidly hover over workspace tabs (e.g., moving mouse across many tabs), this could trigger many concurrent gh CLI calls. Consider:

  1. Using tRPC's built-in deduplication via staleTime on the client side
  2. Adding a short cache TTL check before fetching (e.g., skip fetch if last refresh was < 30s ago)

Example server-side throttle:

 		getGitHubStatus: publicProcedure
 			.input(z.object({ workspaceId: z.string() }))
 			.query(async ({ input }) => {
 				const workspace = db.data.workspaces.find(
 					(w) => w.id === input.workspaceId,
 				);
 				if (!workspace) {
 					return null;
 				}

 				const worktree = db.data.worktrees.find(
 					(wt) => wt.id === workspace.worktreeId,
 				);
 				if (!worktree) {
 					return null;
 				}

+				// Return cached data if recently fetched (< 30s ago)
+				const CACHE_TTL_MS = 30_000;
+				if (
+					worktree.githubStatus &&
+					Date.now() - worktree.githubStatus.lastRefreshed < CACHE_TTL_MS
+				) {
+					return worktree.githubStatus;
+				}
+
 				// Always fetch fresh data on hover
 				const freshStatus = await fetchGitHubPRStatus(worktree.path);

550-551: Path extraction could yield empty string for trailing-slash paths.

worktree.path.split("/").pop() returns an empty string if the path ends with / (e.g., /path/to/worktree/). Consider using Node's path.basename which handles this correctly.

+import { basename } from "node:path";
 // ...
-				const worktreeName = worktree.path.split("/").pop() ?? worktree.branch;
+				const worktreeName = basename(worktree.path) || worktree.branch;
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx (2)

11-11: Consider re-exporting types from a shared location.

The renderer imports the CheckItem type directly from main/lib/db/schemas. While this works for TypeScript types (no runtime Node.js dependency), it creates a coupling between renderer and main process code paths. Consider re-exporting shared types from a shared/ or lib/ location to keep the boundary cleaner.


122-281: Multiple helper components in the same file.

The coding guidelines state "One component per file." However, these are tightly-coupled internal subcomponents (PRStatusBadge, ChecksSummary, ChecksList, CheckItemRow, ReviewStatus) that are only used within WorkspaceHoverCardContent. Keeping them co-located is reasonable for maintainability. Consider extracting to a components/ subdirectory if they grow in complexity or are reused elsewhere.

apps/desktop/src/lib/trpc/routers/workspaces/utils/github.ts (4)

94-98: Potential shell injection via branch name.

While branch names from git rev-parse are typically safe, maliciously crafted branch names (e.g., containing backticks or $()) could lead to command injection. Consider using a shell-safe approach.

Use an array-based approach or quote the branch name properly:

-		const { stdout } = await execAsync(
-			`gh pr view ${branch} --json number,title,url,state,isDraft,mergedAt,additions,deletions,reviewDecision,statusCheckRollup`,
-			{ cwd: worktreePath },
-		);
+		const { stdout } = await execAsync(
+			`gh pr view "${branch.replace(/"/g, '\\"')}" --json number,title,url,state,isDraft,mergedAt,additions,deletions,reviewDecision,statusCheckRollup`,
+			{ cwd: worktreePath },
+		);

Alternatively, consider using execFile (which doesn't spawn a shell) with argument arrays for better security.


115-125: Fragile error detection via string matching.

Checking for "no pull requests found" in the error message is brittle—GitHub CLI could change wording or localization could affect it.

Consider checking the exit code or using a more robust pattern:

 	} catch (error) {
-		// "no pull requests found" is not an error - just no PR
-		if (
-			error instanceof Error &&
-			error.message.includes("no pull requests found")
-		) {
+		// gh returns exit code 1 with "no pull requests found" when no PR exists
+		if (error instanceof Error && /no pull requests? found/i.test(error.message)) {
 			return null;
 		}
 		// Re-throw other errors to be caught by parent
 		throw error;
 	}

This at least handles singular/plural variations and case differences.


160-174: ACTION_REQUIRED conclusion is not explicitly handled.

The GHCheckContext type includes ACTION_REQUIRED as a possible conclusion (line 18), but it's not mapped in parseChecks. It falls through to "pending", which may be the intended behavior but is implicit.

Consider explicitly handling ACTION_REQUIRED for clarity:

 		} else if (rawStatus === "CANCELLED") {
 			status = "cancelled";
+		} else if (rawStatus === "ACTION_REQUIRED") {
+			status = "pending"; // Requires manual intervention, treat as pending
 		} else {
 			status = "pending";
 		}

48-70: Silent error handling may hinder debugging.

Both fetchGitHubPRStatus and getRepoUrl catch all errors and return null silently. While graceful degradation is good for UX, this could make debugging harder when issues occur.

Consider adding debug-level logging for unexpected errors:

 	} catch (error) {
-		// Any error (gh not installed, not auth'd, etc.) - return null
+		// Any error (gh not installed, not auth'd, etc.) - log and return null
+		if (process.env.NODE_ENV === "development") {
+			console.debug("[github] fetchGitHubPRStatus failed:", error);
+		}
 		return null;
 	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b0240ba and 838e57e.

📒 Files selected for processing (7)
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/github.ts (1 hunks)
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts (2 hunks)
  • apps/desktop/src/main/lib/db/schemas.ts (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/index.ts (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItemContextMenu.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/github.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItemContextMenu.tsx
  • apps/desktop/src/main/lib/db/schemas.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: Please use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/github.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItemContextMenu.tsx
  • apps/desktop/src/main/lib/db/schemas.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid using any type - use explicit types instead for type safety
Use camelCase for variable and function names following existing codebase patterns
Keep diffs minimal with targeted edits only - avoid unnecessary changes when making modifications
Follow existing patterns and match the codebase style when writing new code

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/github.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItemContextMenu.tsx
  • apps/desktop/src/main/lib/db/schemas.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
apps/desktop/src/renderer/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules (fs, path, os, net, etc.) in renderer process code - browser environment only

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItemContextMenu.tsx
**/components/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/components/**/*.tsx: Create one folder per component with structure: ComponentName/ComponentName.tsx + index.ts for barrel export
Co-locate tests next to the component file they test (e.g., ComponentName.test.tsx)
Co-locate dependencies (utils, hooks, constants, config, stories) next to the file using them
Use nested components/ subdirectory within a parent component only if a sub-component is used 2+ times within that parent; otherwise keep it in the parent's components/ folder
One component per file - avoid multi-component files

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItemContextMenu.tsx
apps/desktop/src/renderer/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Call IPC methods using window.ipcRenderer.invoke() with object parameters - TypeScript will infer the exact response type automatically

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItemContextMenu.tsx
apps/desktop/src/lib/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules in shared code like src/lib/electron-router-dom.ts - this code runs in both main and renderer processes

Files:

  • apps/desktop/src/lib/trpc/routers/workspaces/utils/github.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
apps/desktop/src/main/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Node.js modules (fs, path, os, net, etc.) can be used in main process code only

Files:

  • apps/desktop/src/main/lib/db/schemas.ts
🧬 Code graph analysis (3)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx (1)
apps/desktop/src/main/lib/db/schemas.ts (1)
  • CheckItem (17-21)
apps/desktop/src/lib/trpc/routers/workspaces/utils/github.ts (1)
apps/desktop/src/main/lib/db/schemas.ts (2)
  • GitHubStatus (23-38)
  • CheckItem (17-21)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItemContextMenu.tsx (1)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx (1)
  • WorkspaceHoverCardContent (20-120)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (10)
apps/desktop/src/main/lib/db/schemas.ts (2)

17-21: LGTM!

The CheckItem interface is well-defined with appropriate status union types covering GitHub CI states. The optional url field correctly handles checks that may not have associated links.


30-34: LGTM!

The extended GitHubStatus.pr fields are comprehensive and align well with GitHub's PR data model. The distinction between checksStatus (aggregate) and checks (individual items) provides flexibility for both summary and detailed views.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/index.ts (1)

1-1: LGTM!

Clean barrel export following the component folder structure guideline.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItem.tsx (1)

80-84: LGTM!

Clean prop addition enabling the context menu to access workspace-specific data for the hover card feature.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx (2)

20-120: LGTM!

The WorkspaceHoverCardContent component is well-structured with clear conditional rendering for loading, PR present, and no-PR states. Good use of TRPC queries with proper enabled guards.


283-302: LGTM!

The formatRelativeTime helper is simple and effective. It avoids external dependencies for a straightforward use case.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceItemContextMenu.tsx (2)

8-15: LGTM on imports and module structure.

The imports are properly organized, using the UI library's hover-card primitives and the local WorkspaceHoverCardContent component. This follows the existing codebase patterns.


38-55: Clean composition of HoverCard with ContextMenu.

The nested trigger pattern (HoverCardTrigger wrapping ContextMenuTrigger) with asChild is the correct approach for combining these Radix-based primitives. The delay values (400ms open, 100ms close) provide a good balance between responsiveness and avoiding accidental triggers.

apps/desktop/src/lib/trpc/routers/workspaces/utils/github.ts (2)

1-5: LGTM on imports.

Using Node.js built-in modules is appropriate here since this file is in the tRPC routers directory which runs in the main process.


180-208: LGTM on computeChecksStatus logic.

The function correctly prioritizes failure over pending, and treats empty/missing rollups as "none". The handling of null/undefined status as pending is appropriate for in-progress checks.

Break down the monolithic WorkspaceHoverCard.tsx into separate components
following the repo's co-location pattern:

- PRStatusBadge: Badge showing PR state (open/draft/merged/closed)
- ReviewStatus: Shows review decision status
- ChecksSummary: Summary of CI checks (X/Y passing)
- ChecksList: Expandable list of individual checks with CheckItemRow
- utils.ts: Shared formatRelativeTime utility

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

Co-Authored-By: Claude <[email protected]>
- Update AGENTS.md with expanded project structure guidelines
- Add shadcn/ui exception section for kebab-case files
- Move CheckItemRow to proper nested folder structure
- Replace custom formatRelativeTime with date-fns formatDistanceToNow
- Delete unnecessary utils.ts wrapper file

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

Co-Authored-By: Claude <[email protected]>
Copy link

@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

🧹 Nitpick comments (4)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ReviewStatus/ReviewStatus.tsx (1)

1-18: Tighten config typing to keep status mapping in sync

Implementation is clear. To make this future-proof if you extend the status union, you can tie the config type directly to ReviewStatusProps["status"] so missing mappings become a TS error:

-export function ReviewStatus({ status }: ReviewStatusProps) {
-	const config = {
+export function ReviewStatus({ status }: ReviewStatusProps) {
+	const config: Record<
+		ReviewStatusProps["status"],
+		{ label: string; className: string }
+	> = {
 		approved: { label: "Approved", className: "text-emerald-500" },
@@
 	const { label, className } = config[status];

Purely a type-safety nicety; the current runtime behavior is fine.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/CheckItemRow.tsx (1)

1-42: Status-to-icon mapping is solid; consider stronger typing for future changes

The visual mapping and link handling look good, and covering all CheckItem statuses makes this easy to scan.

For extra type safety if CheckItem["status"] ever grows, you can tie statusConfig to that union so missing mappings fail at compile time:

-export function CheckItemRow({ check }: CheckItemRowProps) {
-	const statusConfig = {
+export function CheckItemRow({ check }: CheckItemRowProps) {
+	const statusConfig: Record<
+		CheckItem["status"],
+		{ icon: typeof Check; className: string }
+	> = {
 		success: { icon: Check, className: "text-emerald-500" },
		failure: { icon: X, className: "text-destructive-foreground" },
		pending: { icon: LoaderCircle, className: "text-amber-500" },
		skipped: { icon: Minus, className: "text-muted-foreground" },
		cancelled: { icon: Minus, className: "text-muted-foreground" },
	};

Optional, but helps keep things in sync if backend statuses evolve.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/PRStatusBadge.tsx (1)

1-27: PRStatusBadge mapping is clear; small type-safety improvement possible

The badge styling/labels are straightforward and match the state union. Similar to ReviewStatus, you can bind the maps to the prop union so adding a new state forces you to update both:

 export function PRStatusBadge({ state }: PRStatusBadgeProps) {
-	const styles = {
+	const styles: Record<PRStatusBadgeProps["state"], string> = {
 		open: "bg-emerald-500/15 text-emerald-500",
 		draft: "bg-muted text-muted-foreground",
 		merged: "bg-violet-500/15 text-violet-500",
 		closed: "bg-destructive/15 text-destructive-foreground",
 	};
 
-	const labels = {
+	const labels: Record<PRStatusBadgeProps["state"], string> = {
 		open: "Open",
 		draft: "Draft",
 		merged: "Merged",
 		closed: "Closed",
 	};

Not required, but makes the component safer to extend later.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx (1)

18-27: Consider handling query error states.

Both tRPC queries handle loading state but silently fail on errors. If getGitHubStatus errors (e.g., gh CLI unavailable), the component falls through to the "No PR" state, which may be acceptable as a graceful fallback. However, getWorktreeInfo errors would leave the header section empty without feedback.

If this graceful degradation is intentional, consider adding a brief inline comment for future maintainers.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 838e57e and e47e42c.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (13)
  • AGENTS.md (2 hunks)
  • apps/desktop/package.json (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/ChecksList.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/CheckItemRow.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/index.ts (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/index.ts (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/ChecksSummary.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/index.ts (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/PRStatusBadge.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/index.ts (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ReviewStatus/ReviewStatus.tsx (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ReviewStatus/index.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ReviewStatus/index.ts
🧰 Additional context used
📓 Path-based instructions (7)
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ReviewStatus/ReviewStatus.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/ChecksSummary.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/CheckItemRow.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/PRStatusBadge.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/ChecksList.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: Please use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ReviewStatus/ReviewStatus.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/ChecksSummary.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/CheckItemRow.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/PRStatusBadge.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/ChecksList.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid using any type - use explicit types instead for type safety
Use camelCase for variable and function names following existing codebase patterns
Keep diffs minimal with targeted edits only - avoid unnecessary changes when making modifications
Follow existing patterns and match the codebase style when writing new code

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ReviewStatus/ReviewStatus.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/ChecksSummary.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/CheckItemRow.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/PRStatusBadge.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/ChecksList.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
**/components/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/components/**/*.tsx: Create one folder per component with structure: ComponentName/ComponentName.tsx + index.ts for barrel export
Co-locate tests next to the component file they test (e.g., ComponentName.test.tsx)
Co-locate dependencies (utils, hooks, constants, config, stories) next to the file using them
Use nested components/ subdirectory within a parent component only if a sub-component is used 2+ times within that parent; otherwise keep it in the parent's components/ folder
One component per file - avoid multi-component files

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ReviewStatus/ReviewStatus.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/ChecksSummary.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/CheckItemRow.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/PRStatusBadge.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/ChecksList.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
apps/desktop/src/renderer/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules (fs, path, os, net, etc.) in renderer process code - browser environment only

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ReviewStatus/ReviewStatus.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/ChecksSummary.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/CheckItemRow.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/PRStatusBadge.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/ChecksList.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
apps/desktop/src/renderer/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Call IPC methods using window.ipcRenderer.invoke() with object parameters - TypeScript will infer the exact response type automatically

Files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ReviewStatus/ReviewStatus.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/ChecksSummary.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/CheckItemRow.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/PRStatusBadge.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/ChecksList.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
AGENTS.md

📄 CodeRabbit inference engine (CLAUDE.md)

Document agent responsibilities and interactions in AGENTS.md

Files:

  • AGENTS.md
🧠 Learnings (13)
📚 Learning: 2025-11-24T21:32:21.725Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/CLAUDE.md:0-0
Timestamp: 2025-11-24T21:32:21.725Z
Learning: Applies to apps/desktop/**/AGENTS.md : Document agent responsibilities, capabilities, and interaction patterns in AGENTS.md

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-24T21:32:17.800Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T21:32:17.800Z
Learning: Applies to AGENTS.md : Document agent responsibilities and interactions in AGENTS.md

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-28T01:03:47.963Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.963Z
Learning: Applies to **/components/**/*.tsx : Co-locate dependencies (utils, hooks, constants, config, stories) next to the file using them

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-28T01:03:47.963Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.963Z
Learning: Applies to **/components/**/*.tsx : Create one folder per component with structure: `ComponentName/ComponentName.tsx` + `index.ts` for barrel export

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-28T01:03:47.963Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.963Z
Learning: Applies to **/components/**/*.tsx : Co-locate tests next to the component file they test (e.g., `ComponentName.test.tsx`)

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-28T01:03:47.963Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.963Z
Learning: Applies to **/components/**/*.tsx : Use nested `components/` subdirectory within a parent component only if a sub-component is used 2+ times within that parent; otherwise keep it in the parent's `components/` folder

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-28T01:03:47.963Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.963Z
Learning: Applies to **/components/**/*.tsx : One component per file - avoid multi-component files

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-28T01:03:47.963Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.963Z
Learning: Applies to packages/ui/src/**/*.tsx : Use shadcn/ui components and TailwindCSS v4 for all UI component styling in the shared UI package

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-28T01:03:47.963Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.963Z
Learning: Applies to packages/db/src/**/*.ts : Define all database schema in `packages/db/src/` using Drizzle ORM

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-28T01:03:47.963Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.963Z
Learning: Applies to **/*.{ts,tsx} : Follow existing patterns and match the codebase style when writing new code

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-28T01:03:47.963Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.963Z
Learning: Applies to **/*.{ts,tsx} : Use camelCase for variable and function names following existing codebase patterns

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-24T21:33:13.267Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-11-24T21:33:13.267Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-24T21:33:13.267Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-11-24T21:33:13.267Z
Learning: Applies to apps/desktop/**/*.test.{ts,tsx,js,jsx} : Tests should be repeatable

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx
🧬 Code graph analysis (5)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ReviewStatus/ReviewStatus.tsx (1)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ReviewStatus/index.ts (1)
  • ReviewStatus (1-1)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/ChecksSummary.tsx (2)
apps/desktop/src/main/lib/db/schemas.ts (1)
  • CheckItem (17-21)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/index.ts (1)
  • ChecksSummary (1-1)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/CheckItemRow.tsx (2)
apps/desktop/src/main/lib/db/schemas.ts (1)
  • CheckItem (17-21)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/index.ts (1)
  • CheckItemRow (1-1)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/PRStatusBadge.tsx (1)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/index.ts (1)
  • PRStatusBadge (1-1)
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/ChecksList.tsx (1)
apps/desktop/src/main/lib/db/schemas.ts (1)
  • CheckItem (17-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (9)
apps/desktop/package.json (1)

55-55: New date utility dependency looks appropriate for hover-card time formatting

Adding a date utility here makes sense for the worktree age/relative time display in the hover card; no issues from a package-layout perspective. Please just confirm that your Electron/Vite setup is happy with the current major version of this library (ESM expectations, tree-shaking, etc.).

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/index.ts (1)

1-1: Barrel export is consistent with component structure

Re-exporting ChecksList from an index.ts matches the component-folder guideline and keeps imports clean.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/PRStatusBadge/index.ts (1)

1-1: PRStatusBadge barrel export matches existing patterns

This keeps consumer imports tidy and matches how other hover-card subcomponents are exposed.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/WorkspaceHoverCard.tsx (1)

32-113: LGTM!

The component structure is well-organized with clear state handling for loading, PR present, and no-PR scenarios. The conditional rendering logic is clean and the sub-components are properly composed.

AGENTS.md (2)

80-103: LGTM!

The expanded project structure documentation provides clear guidance on organizing hooks, utils, stores, and providers alongside components. This aligns well with the co-location principles in the coding guidelines.


141-143: LGTM!

Good addition documenting the shadcn/ui exception for kebab-case files. This prevents confusion when developers encounter the different naming convention in UI component directories.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksSummary/ChecksSummary.tsx (2)

9-42: LGTM!

The component logic is clean with proper handling of all status states. The passing/total calculation correctly excludes skipped and cancelled checks, and the config-driven icon mapping is a nice pattern.


2-2: The import of CheckItem from main/lib/db/schemas in renderer code is acceptable—it's a type-only import (erased at runtime) and uses the alias correctly per AGENTS.md guidelines. While moving this type to src/shared/types.ts would be a reasonable refactoring since shared types are co-located there, AGENTS.md contains no architectural rule requiring this change. The current pattern is consistent with how other database schemas are structured.

apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceHoverCard/components/ChecksList/components/CheckItemRow/index.ts (1)

1-1: LGTM! Standard barrel export pattern.

The re-export follows common TypeScript/React conventions, allowing cleaner imports of the CheckItemRow component.

Comment on lines +6 to +43
interface ChecksListProps {
checks: CheckItem[];
}

export function ChecksList({ checks }: ChecksListProps) {
const [expanded, setExpanded] = useState(false);

// Filter out skipped/cancelled for display count, but show all when expanded
const relevantChecks = checks.filter(
(c) => c.status !== "skipped" && c.status !== "cancelled",
);

if (relevantChecks.length === 0) return null;

return (
<div className="text-xs">
<button
type="button"
onClick={() => setExpanded(!expanded)}
className="flex items-center gap-1 text-muted-foreground hover:text-foreground transition-colors"
>
{expanded ? (
<ChevronDown className="size-3" />
) : (
<ChevronRight className="size-3" />
)}
<span>{expanded ? "Hide checks" : "Show checks"}</span>
</button>

{expanded && (
<div className="mt-1.5 space-y-1 pl-1">
{relevantChecks.map((check) => (
<CheckItemRow key={check.name} check={check} />
))}
</div>
)}
</div>
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Checks filtering contradicts the comment and likely intended UX

Right now:

  • You filter out skipped/cancelled into relevantChecks.
  • You return null when relevantChecks.length === 0.
  • You also render the expanded list from relevantChecks.

So skipped/cancelled checks are never shown, even when expanded, and a list containing only those statuses disappears entirely. That conflicts with the comment “show all when expanded” and can hide real CI jobs.

If you want the expanded list to show every check while still bailing out only when there are literally no checks, a minimal adjustment would be:

-	// Filter out skipped/cancelled for display count, but show all when expanded
-	const relevantChecks = checks.filter(
-		(c) => c.status !== "skipped" && c.status !== "cancelled",
-	);
-
-	if (relevantChecks.length === 0) return null;
+	if (checks.length === 0) return null;
@@
-			{expanded && (
-				<div className="mt-1.5 space-y-1 pl-1">
-					{relevantChecks.map((check) => (
-						<CheckItemRow key={check.name} check={check} />
-					))}
-				</div>
-			)}
+			{expanded && (
+				<div className="mt-1.5 space-y-1 pl-1">
+					{checks.map((check) => (
+						<CheckItemRow key={check.name} check={check} />
+					))}
+				</div>
+			)}

If the intent is instead to always hide skipped/cancelled, I’d at least update the comment to avoid misleading future readers.

Also, if there’s any chance of duplicate check.name values within a PR, consider using a more stable key (e.g. a backend-provided id) when/if it becomes available.

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