Skip to content

feature (desktop): Add a workspaces page and add close project ability #599

Merged
AviPeltz merged 10 commits intomainfrom
add-a-worksapces-page
Jan 6, 2026
Merged

feature (desktop): Add a workspaces page and add close project ability #599
AviPeltz merged 10 commits intomainfrom
add-a-worksapces-page

Conversation

@AviPeltz
Copy link
Copy Markdown
Collaborator

@AviPeltz AviPeltz commented Jan 5, 2026

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
    • Added a searchable, filterable workspaces list view with grouped project headers and per-workspace rows
    • New workspace row UI showing status, diffs, timestamps, and reopen/opening states
    • Project headers now offer a context menu: Open in Finder, Project Settings, Close Project (uses project path)
    • Workspace sidebar header is now a clickable toggle and the workspaces list auto-closes on selection

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

AviPeltz and others added 5 commits January 5, 2026 13:55
- Add WorkspacesListView component with time-grouped workspaces
- Make WorkspaceSidebarHeader clickable to navigate to workspaces list
- Show both open and closed workspaces in the list
- Allow opening closed worktrees from the list view
- Add context menu to project headers with Close Project option
- Add Open in Finder and Project Settings to project context menu

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resolve conflict in WorkspaceSidebarHeader by adapting clickable
header functionality to new folder structure with NewWorkspaceButton.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When viewing the workspaces list page, clicking a workspace in the
sidebar now properly navigates to that workspace's terminal view.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 5, 2026

📝 Walkthrough

Walkthrough

Adds a new Workspaces list view and UI flows: extends TRPC workspaces data with mainRepoPath, threads that through sidebar components, introduces a searchable/filterable WorkspacesListView with WorkspaceRow, adds project context-menu actions (open in Finder, settings, close), and new app state for toggling the list view.

Changes

Cohort / File(s) Summary
TRPC Workspaces Router
apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
getAllGrouped now includes mainRepoPath: string on returned project objects and populates it from project.mainRepoPath.
Project header & context menu
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
Replaced header button with a ContextMenu; added props projectId, mainRepoPath; wired TRPC mutations for closeProject and openInFinder; added handlers for settings and close flow (pending state, toasts, cache invalidation).
Prop threading
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx, apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
Added and threaded mainRepoPath prop from WorkspaceSidebar → ProjectSection → ProjectHeader.
Sidebar interactions
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx, apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
Made sidebar header a clickable toggle for workspace list; WorkspaceListItem now calls closeWorkspacesList() when activating a workspace.
Workspaces list UI components
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx, .../WorkspaceRow/WorkspaceRow.tsx, .../WorkspaceRow/index.ts, .../index.ts
New WorkspacesListView component with search/filter/grouping; new WorkspaceRow component handling switch/reopen, hover GitHub status fetch, and opening state; index barrels added.
Types & utils for list view
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/types.ts, .../utils.ts
Added WorkspaceItem, ProjectGroup, FilterMode types and getRelativeTime() utility for timestamps.
Main screen routing
apps/desktop/src/renderer/screens/main/index.tsx
Renders <WorkspacesListView /> when currentView === "workspaces-list".
App state
apps/desktop/src/renderer/stores/app-state.ts
Added "workspaces-list" to AppView, isWorkspacesListOpen flag, openWorkspacesList / closeWorkspacesList actions and hooks.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as WorkspacesListView
    participant Store as App State
    participant TRPC as TRPC Client
    participant Server

    User->>UI: Open workspaces list
    UI->>Store: read isWorkspacesListOpen
    UI->>TRPC: query getAllGrouped
    TRPC->>Server: getAllGrouped
    Server-->>TRPC: grouped workspaces + mainRepoPath
    TRPC-->>UI: workspaces data

    UI->>TRPC: lazy getWorktreesByProject (per project)
    TRPC->>Server: getWorktreesByProject
    Server-->>TRPC: worktrees
    TRPC-->>UI: worktrees data

    UI->>UI: build WorkspaceItem[], group, filter, sort
    UI-->>User: render grouped list

    User->>UI: Click workspace row
    alt isOpen
        UI->>TRPC: setActiveWorkspace
        TRPC->>Server: setActiveWorkspace
        Server-->>TRPC: success
    else closed
        UI->>TRPC: openWorktree
        TRPC->>Server: openWorktree
        Server-->>TRPC: success
    end
    UI->>Store: closeWorkspacesList()
    Store-->>UI: isWorkspacesListOpen = false
    UI-->>User: list closes, workspace active
Loading
sequenceDiagram
    participant User
    participant Header as ProjectHeader
    participant Menu as ContextMenu
    participant TRPC as TRPC Client
    participant Store as App State

    User->>Header: Click header trigger
    Header->>Menu: open
    User->>Menu: Select "Open in Finder"
    Menu->>TRPC: openInFinder(mainRepoPath)
    TRPC->>Server: openInFinder
    Server-->>TRPC: success/error
    TRPC-->>Menu: result (show toast on error)

    User->>Menu: Select "Project Settings"
    Menu->>Store: open settings for projectId

    User->>Menu: Select "Close Project"
    Menu->>TRPC: closeProject(projectId)
    TRPC->>Server: closeProject
    Server-->>TRPC: success + terminalWarning
    TRPC-->>Menu: success (invalidate cache, show toast)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • CharlieHelps
  • saddlepaddle

"I'm a rabbit with a list so bright,
Projects grouped from left to right,
Context menus hop and buttons sing,
Close, open, search—what joy they bring!" 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description uses the template structure but provides almost no actual content—all sections are empty or contain only template placeholders, offering no meaningful information about the changes. Fill in the description with details about the changes, explain the motivation, link related issues, provide testing steps, and add screenshots if applicable.
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly and concisely summarizes the two main changes: adding a workspaces page and adding the ability to close projects.
✨ Finishing touches
  • 📝 Generate docstrings

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.

@AviPeltz AviPeltz marked this pull request as ready for review January 6, 2026 00:44
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

Fix all issues with AI Agents 🤖
In
@apps/desktop/src/renderer/screens/main/components/WorkspacesListView/utils.ts:
- Around line 5-23: The getRelativeTime function uses multiple hardcoded time
thresholds; extract those magic numbers into named constants defined at the top
of the module (e.g., MS_PER_SECOND, MS_PER_MINUTE, MS_PER_HOUR, MS_PER_DAY and
human thresholds like MINUTES_IN_HOUR, HOURS_IN_DAY, DAYS_IN_WEEK,
DAYS_IN_MONTH, DAYS_IN_YEAR or named threshold constants such as
JUST_NOW_MINUTES, WEEK_DAYS_THRESHOLD, MONTH_DAYS_THRESHOLD,
YEAR_DAYS_THRESHOLD) and then replace the literal numbers in getRelativeTime
with these constants to improve readability and maintainability; ensure the
constants are exported or file-scoped at module top and used in calculations for
minutes/hours/days and in the conditional comparisons inside getRelativeTime.
🧹 Nitpick comments (5)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx (1)

27-41: Add accessibility attributes to the toggle button.

The button is missing aria-expanded to indicate whether the workspaces list is open or closed, which helps screen reader users understand the current state. Consider adding:

🔎 Proposed accessibility enhancement
 			<button
 				type="button"
 				onClick={handleClick}
+				aria-expanded={isWorkspacesListOpen}
+				aria-label="Toggle workspaces list"
 				className={cn(
 					"flex items-center gap-2 px-2 py-1.5 w-full rounded-md transition-colors",
 					isWorkspacesListOpen
 						? "text-foreground bg-accent"
 						: "text-muted-foreground hover:text-foreground hover:bg-accent/50",
 				)}
 			>
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/types.ts (1)

1-18: Consider a discriminated union for open vs. closed workspaces.

The current design uses nullable workspaceId and worktreeId fields, which requires consumers to perform null checks and understand which field is valid based on the isOpen flag. A discriminated union would provide better type safety:

type OpenWorkspace = {
  status: "open";
  workspaceId: string;
  worktreeId: null;
  // ... other common fields
};

type ClosedWorkspace = {
  status: "closed";
  workspaceId: null;
  worktreeId: string;
  // ... other common fields
};

export type WorkspaceItem = (OpenWorkspace | ClosedWorkspace) & {
  uniqueId: string;
  projectId: string;
  // ... other common fields
};

This approach eliminates the need for runtime null checks and makes the relationship between isOpen, workspaceId, and worktreeId explicit at the type level.

apps/desktop/src/renderer/screens/main/components/WorkspacesListView/utils.ts (1)

21-21: Document approximate month calculation.

The month calculation using days / 30 is an approximation and may be slightly inaccurate. Consider adding a comment to document this intentional approximation, or use a more precise calendar-based calculation if accuracy is important.

📝 Example with documentation
+	// Note: Month calculation is approximate (30 days) for simplicity
 	if (days < 365) return `${Math.floor(days / 30)} months ago`;
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx (1)

34-41: Effective lazy-loading pattern to avoid N+1 queries.

Using hover state to trigger data fetching is a smart optimization. The enabled flag properly guards against unnecessary queries.

💡 Minor refinement: avoid empty string fallback

Consider passing undefined directly instead of defaulting to an empty string, which better communicates the absence of a value:

-	{ workspaceId: workspace.workspaceId ?? "" },
+	{ workspaceId: workspace.workspaceId ?? undefined },

This is safe because the query is disabled when workspaceId is falsy.

apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx (1)

30-34: Consider backend optimization for worktree fetching.

The current implementation fetches worktrees for each project independently using useQueries, which results in N parallel requests. While this works for typical desktop usage with a moderate number of projects, a single backend endpoint that returns all worktrees across projects would reduce network overhead and improve performance.

This isn't critical for initial release but worth considering for future optimization, especially if users typically have many projects open.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e9443d and c0d1130.

📒 Files selected for processing (14)
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/types.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/utils.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/stores/app-state.ts
🧰 Additional context used
📓 Path-based instructions (6)
apps/desktop/**/*.{ts,tsx}

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

apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc
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.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from @trpc/server/observable instead of async generators, as the library explicitly checks isObservable(result) and throws an error otherwise

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/utils.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/types.ts
  • apps/desktop/src/renderer/stores/app-state.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use object parameters for functions with 2+ parameters instead of positional arguments
Functions with 2+ parameters should accept a single params object with named properties for self-documentation and extensibility
Use prefixed console logging with context pattern: [domain/operation] message
Extract magic numbers and hardcoded values to named constants at module top
Use lookup objects/maps instead of repeated if (type === ...) conditionals
Avoid using any type - maintain type safety in TypeScript code
Never swallow errors silently - at minimum log them with context
Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies
Avoid deep nesting (4+ levels) - use early returns, extract functions, and invert conditions
Use named properties in options objects instead of boolean parameters to avoid boolean blindness

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/utils.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/types.ts
  • apps/desktop/src/renderer/stores/app-state.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
apps/desktop/src/renderer/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules (fs, path, os, net) in renderer process or shared code - they are externalized for browser compatibility

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/utils.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/types.ts
  • apps/desktop/src/renderer/stores/app-state.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
apps/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Drizzle ORM for all database operations - never use raw SQL

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/utils.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/types.ts
  • apps/desktop/src/renderer/stores/app-state.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Biome for formatting and linting - run at root level with bun run lint:fix or biome check --write

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/utils.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/types.ts
  • apps/desktop/src/renderer/stores/app-state.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

One component per file - do not create multi-component files

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
🧠 Learnings (4)
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/desktop/src/renderer/**/*.{ts,tsx} : Never import Node.js modules (fs, path, os, net) in renderer process or shared code - they are externalized for browser compatibility

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/index.ts
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/desktop/src/lib/*.ts : Never import Node.js modules in shared code like electron-router-dom.ts - it runs in both main and renderer processes

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/index.ts
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
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:

  • apps/desktop/src/renderer/stores/app-state.ts
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/*/src/components/{ui,ai-elements,react-flow}/*.tsx : Use kebab-case single files for shadcn/ui components (e.g., button.tsx, base-node.tsx) in src/components/ui/, src/components/ai-elements, and src/components/react-flow/

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
🧬 Code graph analysis (3)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx (1)
apps/desktop/src/renderer/stores/app-state.ts (1)
  • useCloseWorkspacesList (104-105)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx (4)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/types.ts (2)
  • WorkspaceItem (1-18)
  • ProjectGroup (20-24)
apps/desktop/src/renderer/stores/app-state.ts (1)
  • useCloseWorkspacesList (104-105)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx (1)
  • WorkspaceRow (23-144)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx (2)
apps/desktop/src/renderer/stores/app-state.ts (3)
  • useCurrentView (86-86)
  • useOpenWorkspacesList (102-103)
  • useCloseWorkspacesList (104-105)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
⏰ 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 (20)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/index.ts (1)

1-1: LGTM!

Standard barrel export pattern for component organization.

apps/desktop/src/renderer/screens/main/components/WorkspacesListView/index.ts (1)

1-1: LGTM!

Standard barrel export pattern for component organization.

apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx (1)

76-76: LGTM!

The integration of closeWorkspacesList() on workspace activation provides good UX—when a user clicks a workspace, the list closes and reveals the terminal view. The inline comment clearly explains the intent.

Also applies to: 125-126

apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts (1)

829-829: No changes needed—mainRepoPath is guaranteed non-null by database schema.

The mainRepoPath field is constrained with .notNull() in the projects table schema (packages/local-db/src/schema/schema.ts), ensuring it is always defined. The return type correctly declares it as required string. No null handling is necessary.

apps/desktop/src/renderer/screens/main/index.tsx (1)

33-33: LGTM! Clean integration of the new workspaces list view.

The WorkspacesListView import and conditional rendering follow the existing pattern for settings and tasks views. The routing logic is consistent and straightforward.

Also applies to: 299-301

apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx (1)

34-34: LGTM! Correct prop threading.

The mainRepoPath prop is properly threaded from the groups data to ProjectSection, enabling project-specific actions in the UI.

apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx (1)

31-31: LGTM! Proper prop threading to ProjectHeader.

The mainRepoPath prop is correctly added to the interface, destructured, and passed to ProjectHeader along with projectId, enabling the context menu actions mentioned in the PR objectives.

Also applies to: 41-41, 72-74

apps/desktop/src/renderer/screens/main/components/WorkspacesListView/types.ts (2)

20-24: LGTM! Clean project grouping type.

The ProjectGroup interface properly models the hierarchical structure of projects containing workspaces.


26-26: LGTM! Simple and clear filter mode type.

apps/desktop/src/renderer/screens/main/components/WorkspacesListView/utils.ts (2)

17-17: Fix singular/plural inconsistency.

Line 17 uses ${days} days ago which produces grammatically incorrect output for 1 day (e.g., "1 days ago" instead of "1 day ago"). However, the special case at line 16 handles days === 1 with "yesterday", so this is actually not an issue.


28-31: LGTM! Simple date formatting utility.

The formatDate function provides a clean, concise date format. The hardcoded "en-US" locale is acceptable for this use case.

apps/desktop/src/renderer/stores/app-state.ts (1)

4-4: LGTM! Clean zustand state management implementation.

The workspaces-list view state is properly integrated following the established patterns for settings and tasks. The implementation is consistent with zustand best practices and avoids unnecessary effects.

Also applies to: 19-19, 28-29, 38-38, 73-79, 102-105

apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx (2)

13-13: Good practice: magic number extracted to named constant.

The GITHUB_STATUS_STALE_TIME constant improves readability and makes the cache duration easy to adjust.


59-69: Good accessibility and UX handling.

The button properly uses semantic HTML, handles disabled state during loading, and provides appropriate ARIA attributes.

apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx (2)

34-46: Well-structured mutation with comprehensive cache invalidation.

The closeProject mutation properly invalidates all related queries and provides user feedback for both success (terminal warnings) and errors.


65-102: Clean context menu implementation with proper UX.

The menu provides clear actions with appropriate icons, disables items during pending operations, and uses semantic destructive styling for the close action.

apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx (4)

51-105: Well-structured data aggregation with proper memoization.

The useMemo correctly combines open workspaces and closed worktrees into a unified list, with appropriate dependency tracking and defensive coding (optional chaining, null checks).


108-130: Clean filtering logic with good separation of concerns.

Filter mode and search query are applied in a separate memoized computation, making the logic easy to understand and maintain.


133-163: Efficient grouping and sorting implementation.

The project grouping logic properly sorts both within groups (active first, then by recency) and across groups (by most recent activity). Using Map ensures efficient lookups during construction.


268-278: Thoughtful empty state messaging.

The empty state provides context-specific messages based on the current filter and search state, improving UX.

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 (1)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx (1)

34-41: Consider a more explicit pattern for the workspaceId parameter.

The query correctly uses enabled to prevent execution when workspaceId is falsy. However, providing an empty string fallback (?? "") on line 35 is unclear since the parameter won't actually be used when invalid. For better code clarity, consider one of these approaches:

  1. Use undefined as the fallback if the tRPC procedure accepts optional parameters
  2. Add a comment explaining why the fallback is safe
  3. Restructure to make the disabled state more explicit in the types

This doesn't affect functionality but improves code maintainability.

🔎 Optional refactor for clarity
-	const { data: githubStatus } = trpc.workspaces.getGitHubStatus.useQuery(
-		{ workspaceId: workspace.workspaceId ?? "" },
-		{
-			enabled:
-				hasHovered && workspace.type === "worktree" && !!workspace.workspaceId,
-			staleTime: GITHUB_STATUS_STALE_TIME,
-		},
-	);
+	const { data: githubStatus } = trpc.workspaces.getGitHubStatus.useQuery(
+		{ workspaceId: workspace.workspaceId ?? "" }, // Safe: query disabled when workspaceId is falsy
+		{
+			enabled:
+				hasHovered && workspace.type === "worktree" && !!workspace.workspaceId,
+			staleTime: GITHUB_STATUS_STALE_TIME,
+		},
+	);

Or if the tRPC procedure type allows:

-	const { data: githubStatus } = trpc.workspaces.getGitHubStatus.useQuery(
-		{ workspaceId: workspace.workspaceId ?? "" },
+	const { data: githubStatus } = trpc.workspaces.getGitHubStatus.useQuery(
+		{ workspaceId: workspace.workspaceId! },
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0d1130 and ccdfede.

📒 Files selected for processing (2)
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/utils.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/utils.ts
🧰 Additional context used
📓 Path-based instructions (6)
apps/desktop/**/*.{ts,tsx}

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

apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc
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.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from @trpc/server/observable instead of async generators, as the library explicitly checks isObservable(result) and throws an error otherwise

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use object parameters for functions with 2+ parameters instead of positional arguments
Functions with 2+ parameters should accept a single params object with named properties for self-documentation and extensibility
Use prefixed console logging with context pattern: [domain/operation] message
Extract magic numbers and hardcoded values to named constants at module top
Use lookup objects/maps instead of repeated if (type === ...) conditionals
Avoid using any type - maintain type safety in TypeScript code
Never swallow errors silently - at minimum log them with context
Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies
Avoid deep nesting (4+ levels) - use early returns, extract functions, and invert conditions
Use named properties in options objects instead of boolean parameters to avoid boolean blindness

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
apps/desktop/src/renderer/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules (fs, path, os, net) in renderer process or shared code - they are externalized for browser compatibility

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

One component per file - do not create multi-component files

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
apps/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Drizzle ORM for all database operations - never use raw SQL

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Biome for formatting and linting - run at root level with bun run lint:fix or biome check --write

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
⏰ 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 (4)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx (4)

1-13: LGTM! Imports and constant definition follow best practices.

The imports are appropriate for the renderer process, use path aliases correctly, and the stale time constant is properly extracted at the module level.


15-21: LGTM! Type definitions are clean and follow object parameter guidelines.

The interface properly types all props without using any, and the component signature follows the object parameters pattern for functions with multiple parameters.


30-31: LGTM! Component logic is well-structured.

The hover-based lazy loading pattern with useState is appropriate for this component-local feature. The derived values and click handler are clear and correct.

Also applies to: 43-56


58-146: LGTM! JSX structure and accessibility are well-implemented.

The button element is properly structured with:

  • Semantic HTML (type="button")
  • Appropriate accessibility (disabled state, text content provides accessible name)
  • Clear conditional rendering and styling
  • Readable Tailwind classes with the cn utility
  • Proper React 19 patterns

The hover-based UI transitions and conditional indicators provide good UX feedback.

@AviPeltz AviPeltz merged commit 4b76a6f into main Jan 6, 2026
5 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 6, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ⚠️ Neon database branch
  • ⚠️ Electric Fly.io app

Thank you for your contribution! 🎉

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