Skip to content

refactor (desktop): Repository project image And Sidebar Changes#601

Merged
AviPeltz merged 14 commits intomainfrom
repository-project-image
Jan 6, 2026
Merged

refactor (desktop): Repository project image And Sidebar Changes#601
AviPeltz merged 14 commits intomainfrom
repository-project-image

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

    • GitHub avatar support in project thumbnails.
    • Collapsible workspace sidebar with icon-only compact mode and improved toggle/collapse behavior.
  • UI Improvements

    • Richer project headers and compact thumbnails; updated sidebar/list item layouts, icons, spacing, and sizing across many panels.
    • Visual refinements in changes/commit views, group strips, and toolbars.
    • Enter+Meta/Ctrl now submits commits from the commit input.
  • Chores

    • Local database schema updated to store GitHub owner.
    • Content Security Policy expanded to allow GitHub avatar images.

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 5, 2026

📝 Walkthrough

Walkthrough

Adds GitHub avatar lookup and caching via a new TRPC route and utilities, a DB migration for githubOwner, a ProjectThumbnail component, CSP updates for GitHub images, and a collapsed (icon‑only) workspace sidebar UX with store and component changes.

Changes

Cohort / File(s) Summary
Projects TRPC & GitHub utils
apps/desktop/src/lib/trpc/routers/projects/projects.ts, apps/desktop/src/lib/trpc/routers/projects/utils/github.ts
New projects.getGitHubAvatar query; fetchGitHubOwner runs gh repo view --json owner and getGitHubAvatarUrl builds avatar URL. Loads project, may persist githubOwner, returns { owner, avatarUrl } or null.
DB schema & migrations
packages/local-db/src/schema/schema.ts, packages/local-db/drizzle/0009_add_github_owner_to_projects.sql, packages/local-db/drizzle/meta/0009_snapshot.json, packages/local-db/drizzle/meta/_journal.json
Adds github_owner column (mapped as githubOwner) to projects; migration SQL, snapshot and journal entry added; two settings columns removed; snapshot updated.
Project thumbnail & UI wiring
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/*, .../ProjectHeader.tsx, .../ProjectSection.tsx, .../ProjectThumbnail/index.ts
New ProjectThumbnail component queries projects.getGitHubAvatar (5m stale), prefers fetched owner, renders avatar or initials; githubOwner prop threaded through ProjectHeader/ProjectSection.
Workspace sidebar store & collapse UX
apps/desktop/src/renderer/stores/workspace-sidebar-state.ts, apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/*.tsx, ResizableWorkspaceSidebar.tsx
Introduces COLLAPSED_WORKSPACE_SIDEBAR_WIDTH, collapse threshold; renames lastOpenWidthlastExpandedWidth; bumps persistence version to 2; adds isCollapsed(), toggleCollapsed(), setOpen(); many components accept isCollapsed and render compact variants.
TopBar / sidebar controls & hotkeys
apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsx, apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx, apps/desktop/src/renderer/screens/main/index.tsx, apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
Store API usage updated: opening via setOpen(true) opens collapsed; toggling collapse uses toggleCollapsed. Icon import/usage swaps.
CSP update
apps/desktop/src/renderer/index.html
img-src CSP expanded to include https://github.com and https://avatars.githubusercontent.com.
ChangesView & assorted UI refinements
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/*, FileItem.tsx, FolderRow.tsx, CommitInput.tsx, CommitItem.tsx, CategorySection.tsx, ViewModeToggle.tsx
Visual/spacing/typography adjustments, unify chevrons to a rotating right chevron, Enter+Meta/Ctrl triggers commit, smaller sizing tokens and spacing tweaks across changes UI.
Icon & minor UI swaps
apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx, .../ModeCarousel/constants.ts, GroupStrip/GroupItem.tsx, WorkspacesListView.tsx
Several icon replacements and small styling adjustments across UIs.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Thumbnail as ProjectThumbnail (React)
    participant TRPC as TRPC Client
    participant Router as projects.getGitHubAvatar (Server)
    participant DB as LocalDB
    participant GH as GitHub CLI (gh)

    User->>Thumbnail: mount (projectId)
    Thumbnail->>TRPC: query getGitHubAvatar({ id })
    TRPC->>Router: invoke handler
    Router->>DB: load project by id
    alt project not found
        Router-->>TRPC: null
    else project found
        alt githubOwner cached
            Router-->>TRPC: { owner, avatarUrl }
        else not cached
            Router->>GH: gh repo view --json owner (cwd=repoPath)
            alt CLI success & valid
                GH-->>Router: { owner: { login } }
                Router->>DB: update projects.github_owner = owner
                Router-->>TRPC: { owner, avatarUrl }
            else CLI failure or invalid
                Router-->>TRPC: null
            end
        end
    end
    TRPC-->>Thumbnail: response
    Thumbnail->>User: render avatar image or initials
Loading
sequenceDiagram
    participant User
    participant UI as Sidebar Toggle UI
    participant Store as useWorkspaceSidebarStore
    participant Sidebar as WorkspaceSidebar Components

    User->>UI: click toggle or press hotkey
    alt Sidebar closed
        UI->>Store: setOpen(true)
        Store->>Store: isOpen=true, width=COLLAPSED_WORKSPACE_SIDEBAR_WIDTH
    else Sidebar open
        UI->>Store: toggleCollapsed()
        Store->>Store: flip isCollapsed
        alt now collapsed
            Store->>Store: width = COLLAPSED_WORKSPACE_SIDEBAR_WIDTH
        else now expanded
            Store->>Store: width = lastExpandedWidth
        end
    end
    Store-->>Sidebar: emit isOpen/isCollapsed/width
    Sidebar->>User: render collapsed or expanded UI
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • CharlieHelps
  • saddlepaddle

"🐇
I hopped to fetch a tiny face,
From GitHub's garden, pixel-grace.
Sidebars shrink and thumbnails glow,
Carrots, code, and avatars in tow. ✨"

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description follows the template structure but is largely incomplete. All major sections are present (Description, Related Issues, Type of Change, Testing, Screenshots, Additional Notes) but contain no substantive content, implementation details, testing steps, linked issues, or explanations. Fill in the Description section with a clear summary of changes. Add testing steps, any related issue links, and additional context. The template sections exist but require meaningful content.
Docstring Coverage ⚠️ Warning Docstring coverage is 6.90% 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 title 'refactor (desktop): Repository project image And Sidebar Changes' is partially related to the changeset. It mentions 'Repository project image' and 'Sidebar Changes' which align with key modifications (GitHub avatar integration, sidebar collapse state), but it is overly broad and doesn't clearly highlight the main change.
✨ 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 changed the title Repository project image refactor (desktop): Repository project image And Sidebar Changes Jan 5, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 5, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

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

Thank you for your contribution! 🎉

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: 7

Fix all issues with AI Agents 🤖
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx:
- Around line 220-234: The chevron rotation is inverted: in ProjectHeader.tsx
update the HiChevronRight className logic (inside the cn call) so that when
isCollapsed is true there is no rotation and when false it applies a 90°
rotation; i.e., change the ternary that currently returns rotate-180 for
collapsed to instead return no rotation for collapsed and "rotate-90" for
expanded so the icon points right when collapsed and down when expanded.

In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsx:
- Around line 22-54: The imageError state (useState imageError / setImageError)
is never reset when owner changes, so after one load failure the component will
permanently show initials; add a useEffect inside ProjectThumbnail that depends
on owner (and/or projectId/avatarData) and calls setImageError(false) whenever
owner changes (or becomes non-null) so the new owner's avatar can be retried.

In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx:
- Around line 191-217: The collapsed icon button in WorkspaceListItem lacks an
accessible label; add an aria-label prop to the button element (the one with
onClick={handleClick} and onMouseEnter={handleMouseEnter}) inside
WorkspaceListItem.tsx, constructing a descriptive label that uses the component
state/props (isBranchWorkspace, isActive, needsAttention and, if available, the
workspace name) so screen readers can identify the control (e.g. "Open branch
workspace: <name>, active, needs attention" or similar based on those flags).

In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx:
- Around line 109-128: The expanded-mode toggle button in WorkspaceSidebarHeader
is wrapped with Tooltip and TooltipTrigger but lacks a TooltipContent; update
the expanded toggle block (the button using handleToggleSidebar, getToggleIcon,
and isHovering) to include a TooltipContent (e.g., <TooltipContent
side="right">Toggle sidebar</TooltipContent>) matching the collapsed-mode
implementation, or alternatively remove the Tooltip wrapper entirely — ensure
the TooltipContent is added next to TooltipTrigger when keeping the tooltip.

In
@apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx:
- Around line 27-35: The ChangesHeader component is accepting unused props
(ahead, behind, isRefreshing) — remove these from the ChangesHeaderProps
interface and from the ChangesHeader function signature (delete ahead/_ahead,
behind/_behind, isRefreshing/_isRefreshing), then update all call sites (notably
the <ChangesHeader> invocation in ChangesView.tsx) to stop passing those props;
ensure you only keep the actually used props (onRefresh, viewMode,
onViewModeChange, worktreePath) and run a compile to catch any remaining
references to the removed symbols.
- Around line 36-50: The timeout created in handleRefresh (stored in timeoutRef)
isn't cleared on component unmount; add a cleanup effect using useEffect that
clears timeoutRef.current (clearTimeout and set to null) to prevent calling
setIsManualRefresh after unmount, and ensure you import useEffect alongside
useState/useRef; reference symbols: isManualRefresh, setIsManualRefresh,
timeoutRef, handleRefresh.

In
@apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx:
- Around line 250-257: The dropdown trigger Button (the Button element rendering
the HiChevronDown icon, with props variant="default", size="sm",
disabled={isPending}, className="h-7 px-1.5") lacks an accessible label; add an
aria-label (for example aria-label="Open commit options" or similar descriptive
text) to the Button so screen readers announce its purpose; optionally also add
aria-expanded or aria-haspopup if this button toggles a menu.

Caution

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

⚠️ Outside diff range comments (2)
apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx (1)

14-19: Remove the empty div left over from WorkspaceSidebarControl removal.

After removing the WorkspaceSidebarControl component, this div now serves no purpose. The platform-specific padding logic (88px for Mac traffic lights, 16px otherwise) and flex layout properties are unused. Remove the entire div to complete the refactoring.

🔎 Proposed cleanup
 	return (
 		<div className="drag gap-2 h-12 w-full flex items-center justify-between bg-background border-b border-border">
-			<div
-				className="flex items-center gap-2 h-full"
-				style={{
-					paddingLeft: isMac ? "88px" : "16px",
-				}}
-			/>
-
 			<div className="flex-1" />
 
 			<div className="flex items-center gap-3 h-full pr-4 shrink-0">
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx (1)

110-110: Use tRPC to open external URLs from the renderer process.

In this renderer component, external URLs should be opened through the tRPC external.openUrl mutation rather than window.open() to properly communicate with the main process. The codebase already has this pattern established via apps/desktop/src/lib/trpc/routers/external/index.ts. Reference how UpdateToast.tsx and UpdateRequiredPage.tsx correctly use trpc.external.openUrl.useMutation() for opening external links.

🧹 Nitpick comments (7)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx (1)

89-101: Consider accessibility of text-[10px] font size.

The 10px font size is below the commonly recommended 12px minimum for readability. While this is acceptable for secondary stats information with opacity-60, ensure this remains legible across different display densities and for users with visual impairments.

The rest of the styling changes (status badge text-xs, opacity-60 for subtlety) are appropriate refinements.

apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx (1)

68-74: Consider extracting repeated text-[10px] for design system consistency.

The compact text size is used twice in this component (hash and date labels) and likely appears elsewhere in the collapsible sidebar UI. If this is a standard "compact label" size in your design system, consider:

  1. Adding it to your Tailwind config theme extension (e.g., text-2xs)
  2. Creating a shared constant for reuse

This would improve maintainability if you need to adjust compact text sizing across the sidebar.

💡 Example Tailwind config extension

In your Tailwind config:

theme: {
  extend: {
    fontSize: {
      '2xs': '10px',
    }
  }
}

Then use text-2xs instead of text-[10px].

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

24-56: Consider extracting the button element to reduce duplication.

Both the collapsed and expanded rendering paths contain similar button logic. The primary differences are the className and tooltip wrapper.

🔎 Proposed refactor to reduce duplication
 export function NewWorkspaceButton({
 	isCollapsed = false,
 }: NewWorkspaceButtonProps) {
 	const openModal = useOpenNewWorkspaceModal();
 	const { data: activeWorkspace, isLoading } =
 		trpc.workspaces.getActive.useQuery();
 
 	const handleClick = () => {
 		const projectId = activeWorkspace?.projectId;
 		openModal(projectId);
 	};
+
+	const icon = (
+		<div className="flex items-center justify-center size-5 rounded bg-accent">
+			<LuPlus className="size-3" />
+		</div>
+	);
+
+	const button = (
+		<button
+			type="button"
+			onClick={handleClick}
+			disabled={isLoading}
+			className={
+				isCollapsed
+					? "flex items-center justify-center size-8 rounded-md hover:bg-accent/50 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
+					: "flex items-center gap-2 px-2 py-1.5 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-accent/50 rounded-md transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
+			}
+		>
+			{icon}
+			{!isCollapsed && <span>New Workspace</span>}
+		</button>
+	);
 
 	if (isCollapsed) {
 		return (
 			<Tooltip delayDuration={300}>
-				<TooltipTrigger asChild>
-					<button
-						type="button"
-						onClick={handleClick}
-						disabled={isLoading}
-						className="flex items-center justify-center size-8 rounded-md hover:bg-accent/50 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
-					>
-						<div className="flex items-center justify-center size-5 rounded bg-accent">
-							<LuPlus className="size-3" />
-						</div>
-					</button>
-				</TooltipTrigger>
+				<TooltipTrigger asChild>{button}</TooltipTrigger>
 				<TooltipContent side="right">New Workspace</TooltipContent>
 			</Tooltip>
 		);
 	}
 
-	return (
-		<button
-			type="button"
-			onClick={handleClick}
-			disabled={isLoading}
-			className="flex items-center gap-2 px-2 py-1.5 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-accent/50 rounded-md transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
-		>
-			<div className="flex items-center justify-center size-5 rounded bg-accent">
-				<LuPlus className="size-3" />
-			</div>
-			<span>New Workspace</span>
-		</button>
-	);
+	return button;
 }
apps/desktop/src/lib/trpc/routers/projects/utils/github.ts (1)

46-48: Code duplication: getGitHubAvatarUrl differs from ProjectThumbnail implementation.

This function constructs https://github.com/{owner}.png, but ProjectThumbnail.tsx (line 13) duplicates this logic and adds ?size=64. This creates two implementations with different behavior.

🔎 Proposed fix to consolidate and parameterize the URL construction
 /**
  * Constructs the GitHub avatar URL for a user or organization.
  * GitHub serves avatars at https://github.com/{owner}.png
  */
-export function getGitHubAvatarUrl(owner: string): string {
-	return `https://github.com/${owner}.png`;
+export function getGitHubAvatarUrl(owner: string, size?: number): string {
+	const baseUrl = `https://github.com/${owner}.png`;
+	return size ? `${baseUrl}?size=${size}` : baseUrl;
 }

Then update ProjectThumbnail.tsx to use the shared utility:

-function getGitHubAvatarUrl(owner: string): string {
-	return `https://github.com/${owner}.png?size=64`;
-}
+import { getGitHubAvatarUrl } from "lib/trpc/routers/projects/utils/github";

 export function ProjectThumbnail({
 	// ...
 }) {
 	// ...
 	if (owner && !imageError) {
 		return (
 			<div className={/* ... */}>
 				<img
-					src={getGitHubAvatarUrl(owner)}
+					src={getGitHubAvatarUrl(owner, 64)}
 					alt={`${projectName} avatar`}
 					// ...
 				/>
 			</div>
 		);
 	}
 	// ...
 }
apps/desktop/src/renderer/stores/workspace-sidebar-state.ts (1)

115-126: Consider adding a migration handler for the version bump.

The persistence version was bumped from 1 to 2 with lastOpenWidth renamed to lastExpandedWidth. Zustand persist doesn't automatically migrate renamed fields—existing users may lose their saved width preference.

🔎 Proposed fix: Add migrate function
 			{
 				name: "workspace-sidebar-store",
 				version: 2,
+				migrate: (persistedState: unknown, version: number) => {
+					if (version === 1) {
+						const state = persistedState as { lastOpenWidth?: number };
+						return {
+							...state,
+							lastExpandedWidth: state.lastOpenWidth ?? DEFAULT_WORKSPACE_SIDEBAR_WIDTH,
+						};
+					}
+					return persistedState as WorkspaceSidebarState;
+				},
 				// Exclude ephemeral state from persistence
 				partialize: (state) => ({
 					isOpen: state.isOpen,
 					width: state.width,
 					lastExpandedWidth: state.lastExpandedWidth,
 					collapsedProjectIds: state.collapsedProjectIds,
 					// isResizing intentionally excluded - ephemeral UI state
 				}),
 			},
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx (1)

23-39: Consider using an object parameter pattern for the many props.

The ProjectHeaderProps interface has grown to 13 properties. Per coding guidelines, functions with 2+ parameters should use object parameters—this component already does that, but the large number of props suggests the component might be taking on too much responsibility.

This is acceptable for now, but if the interface continues to grow, consider:

  • Grouping related props (e.g., dropdownState: { open, onChange })
  • Extracting sub-components for the dropdown or collapse behavior
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx (1)

207-211: Simplify count badge formatting for readability.

The nested ternary operators and template literal make this logic hard to parse. Consider extracting to a helper function or using conditional blocks.

🔎 Proposed refactor for improved readability
-	// Format count badge
-	const countBadge =
-		pushCount > 0 || pullCount > 0
-			? `${pullCount > 0 ? pullCount : ""}${pullCount > 0 && pushCount > 0 ? "/" : ""}${pushCount > 0 ? pushCount : ""}`
-			: null;
+	// Format count badge
+	const getCountBadge = (): string | null => {
+		if (pullCount === 0 && pushCount === 0) return null;
+		if (pullCount > 0 && pushCount > 0) return `${pullCount}/${pushCount}`;
+		return pullCount > 0 ? `${pullCount}` : `${pushCount}`;
+	};
+	const countBadge = getCountBadge();
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b76a6f and cbef340.

📒 Files selected for processing (35)
  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
  • apps/desktop/src/lib/trpc/routers/projects/utils/github.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/renderer/index.html
  • apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.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/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CategorySection/CategorySection.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ModeCarousel/constants.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/stores/tabs/utils.ts
  • apps/desktop/src/renderer/stores/workspace-sidebar-state.ts
  • packages/local-db/drizzle/0009_add_github_owner_to_projects.sql
  • packages/local-db/drizzle/meta/0009_snapshot.json
  • packages/local-db/drizzle/meta/_journal.json
  • packages/local-db/src/schema/schema.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/WorkspaceSidebar/ProjectSection/ProjectThumbnail/index.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ModeCarousel/constants.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsx
  • apps/desktop/src/lib/trpc/routers/projects/utils/github.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsx
  • apps/desktop/src/renderer/stores/workspace-sidebar-state.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/stores/tabs/utils.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx
  • apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CategorySection/CategorySection.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/WorkspaceSidebar/ProjectSection/ProjectThumbnail/index.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ModeCarousel/constants.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
  • packages/local-db/src/schema/schema.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsx
  • apps/desktop/src/lib/trpc/routers/projects/utils/github.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsx
  • apps/desktop/src/renderer/stores/workspace-sidebar-state.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/stores/tabs/utils.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx
  • apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CategorySection/CategorySection.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/WorkspaceSidebar/ProjectSection/ProjectThumbnail/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ModeCarousel/constants.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsx
  • apps/desktop/src/renderer/stores/workspace-sidebar-state.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/stores/tabs/utils.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx
  • apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CategorySection/CategorySection.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/WorkspaceSidebar/ProjectSection/ProjectThumbnail/index.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ModeCarousel/constants.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsx
  • apps/desktop/src/lib/trpc/routers/projects/utils/github.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsx
  • apps/desktop/src/renderer/stores/workspace-sidebar-state.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/stores/tabs/utils.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx
  • apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CategorySection/CategorySection.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/WorkspaceSidebar/ProjectSection/ProjectThumbnail/index.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ModeCarousel/constants.ts
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
  • packages/local-db/src/schema/schema.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsx
  • apps/desktop/src/lib/trpc/routers/projects/utils/github.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsx
  • apps/desktop/src/renderer/stores/workspace-sidebar-state.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/stores/tabs/utils.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx
  • apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CategorySection/CategorySection.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/TopBar/index.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx
  • apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CategorySection/CategorySection.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/WorkspaceSidebar/ProjectSection/ProjectThumbnail/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} : Use alias as defined in `tsconfig.json` when possible

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/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/*/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/TopBar/index.tsx
  • apps/desktop/src/renderer/screens/main/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx
  • apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CategorySection/CategorySection.tsx
📚 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 packages/db/src/**/*.ts : Schema definitions must be in packages/db/src/ using Drizzle ORM

Applied to files:

  • packages/local-db/drizzle/meta/0009_snapshot.json
🧬 Code graph analysis (12)
apps/desktop/src/renderer/screens/main/index.tsx (1)
apps/desktop/src/renderer/stores/workspace-sidebar-state.ts (1)
  • useWorkspaceSidebarStore (30-130)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsx (3)
apps/desktop/src/lib/trpc/routers/projects/utils/github.ts (1)
  • getGitHubAvatarUrl (46-48)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/index.ts (1)
  • ProjectThumbnail (1-1)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop/src/lib/trpc/routers/projects/utils/github.ts (1)
apps/desktop/src/lib/trpc/routers/workspaces/utils/shell-env.ts (1)
  • execWithShellEnv (122-173)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx (2)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsx (1)
  • ProjectThumbnail (16-68)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx (2)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
packages/ui/src/components/ui/collapsible.tsx (2)
  • CollapsibleTrigger (33-33)
  • CollapsibleContent (33-33)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsx (1)
packages/ui/src/components/ui/tooltip.tsx (3)
  • Tooltip (76-76)
  • TooltipTrigger (76-76)
  • TooltipContent (76-76)
apps/desktop/src/renderer/stores/workspace-sidebar-state.ts (1)
apps/cli/src/lib/storage/lowdb-adapter.ts (1)
  • set (162-172)
apps/desktop/src/lib/trpc/routers/projects/projects.ts (3)
apps/desktop/src/main/lib/local-db/index.ts (1)
  • localDb (82-82)
packages/local-db/src/schema/schema.ts (1)
  • projects (16-42)
apps/desktop/src/lib/trpc/routers/projects/utils/github.ts (2)
  • getGitHubAvatarUrl (46-48)
  • fetchGitHubOwner (14-40)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsx (2)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx (1)
  • WorkspaceSidebar (12-62)
apps/desktop/src/renderer/stores/workspace-sidebar-state.ts (1)
  • COLLAPSED_WORKSPACE_SIDEBAR_WIDTH (5-5)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx (1)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx (5)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/index.ts (1)
  • WorkspaceSidebarHeader (1-1)
apps/desktop/src/renderer/stores/app-state.ts (3)
  • useCurrentView (86-86)
  • useOpenWorkspacesList (102-103)
  • useCloseWorkspacesList (104-105)
apps/desktop/src/renderer/stores/workspace-sidebar-state.ts (1)
  • useWorkspaceSidebarStore (30-130)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsx (1)
  • NewWorkspaceButton (10-57)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx (3)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx (1)
  • WorkspaceSidebarHeader (22-150)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsx (1)
  • ProjectSection (34-169)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsx (1)
  • WorkspaceSidebarFooter (12-90)
⏰ 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). (6)
  • GitHub Check: Deploy Admin
  • GitHub Check: Deploy Docs
  • GitHub Check: Deploy Marketing
  • GitHub Check: Deploy Web
  • GitHub Check: Deploy API
  • GitHub Check: Build

Comment on lines +220 to +234
{/* Collapse chevron */}
<button
type="button"
onClick={onToggleCollapse}
onContextMenu={(e) => e.stopPropagation()}
aria-expanded={!isCollapsed}
className="p-1 rounded hover:bg-muted transition-colors shrink-0 ml-1"
>
<HiChevronRight
className={cn(
"size-3.5 text-muted-foreground transition-transform duration-150",
isCollapsed ? "rotate-180" : "rotate-90",
)}
/>
</button>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

rg -n "rotate-90|rotate-180" --type tsx --type ts -B2 -A2

Repository: superset-sh/superset

Length of output: 91


🏁 Script executed:

rg "rotate-90|rotate-180" -B2 -A2

Repository: superset-sh/superset

Length of output: 11951


Fix inverted chevron rotation logic.

The rotation is backwards compared to similar components in the codebase (PortsList.tsx, FolderRow.tsx). The HiChevronRight icon should:

  • Have no rotation (pointing right) when collapsed—indicates expandable content
  • Rotate 90° (pointing down) when expanded—indicates collapsible content

Change from:

isCollapsed ? "rotate-180" : "rotate-90"

to:

isCollapsed ? "" : "rotate-90"

This matches the established pattern used throughout the sidebar components.

🤖 Prompt for AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsx
around lines 220-234, The chevron rotation is inverted: in ProjectHeader.tsx
update the HiChevronRight className logic (inside the cn call) so that when
isCollapsed is true there is no rotation and when false it applies a 90°
rotation; i.e., change the ternary that currently returns rotate-180 for
collapsed to instead return no rotation for collapsed and "rotate-90" for
expanded so the icon points right when collapsed and down when expanded.

Comment on lines +22 to +54
const [imageError, setImageError] = useState(false);

// Always fetch to ensure we get the latest - the backend caches it
const { data: avatarData } = trpc.projects.getGitHubAvatar.useQuery(
{ id: projectId },
{
staleTime: 1000 * 60 * 5, // Consider stale after 5 minutes
refetchOnWindowFocus: false,
},
);

// Prefer fetched data, fall back to prop
const owner = avatarData?.owner ?? githubOwner;
const firstLetter = projectName.charAt(0).toUpperCase();

// Show avatar if we have an owner and no image loading error
if (owner && !imageError) {
return (
<div
className={cn(
"relative size-6 rounded overflow-hidden flex-shrink-0 bg-muted",
className,
)}
>
<img
src={getGitHubAvatarUrl(owner)}
alt={`${projectName} avatar`}
className="size-full object-cover"
onError={() => setImageError(true)}
/>
</div>
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

imageError state doesn't reset when owner changes.

The imageError state is set to true when an avatar fails to load, but it's never reset back to false. If the owner prop changes to a different value (e.g., when switching projects), the component will continue showing the fallback initials even if the new owner has a valid avatar.

🔎 Proposed fix to reset imageError when owner changes
+import { useEffect, useState } from "react";
-import { useState } from "react";

 export function ProjectThumbnail({
 	projectId,
 	projectName,
 	githubOwner,
 	className,
 }: ProjectThumbnailProps) {
 	const [imageError, setImageError] = useState(false);
 
 	// Always fetch to ensure we get the latest - the backend caches it
 	const { data: avatarData } = trpc.projects.getGitHubAvatar.useQuery(
 		{ id: projectId },
 		{
 			staleTime: 1000 * 60 * 5, // Consider stale after 5 minutes
 			refetchOnWindowFocus: false,
 		},
 	);
 
 	// Prefer fetched data, fall back to prop
 	const owner = avatarData?.owner ?? githubOwner;
+
+	// Reset error state when owner changes
+	useEffect(() => {
+		setImageError(false);
+	}, [owner]);
+
 	const firstLetter = projectName.charAt(0).toUpperCase();
 
 	// Show avatar if we have an owner and no image loading error
 	if (owner && !imageError) {
 		return (
 			<div
 				className={cn(
 					"relative size-6 rounded overflow-hidden flex-shrink-0 bg-muted",
 					className,
 				)}
 			>
 				<img
 					src={getGitHubAvatarUrl(owner)}
 					alt={`${projectName} avatar`}
 					className="size-full object-cover"
 					onError={() => setImageError(true)}
 				/>
 			</div>
 		);
 	}
 
 	// Fallback: show first letter with subtle background
 	return (
 		<div
 			className={cn(
 				"size-6 rounded flex items-center justify-center flex-shrink-0",
 				"bg-muted text-muted-foreground text-xs font-medium",
 				className,
 			)}
 		>
 			{firstLetter}
 		</div>
 	);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const [imageError, setImageError] = useState(false);
// Always fetch to ensure we get the latest - the backend caches it
const { data: avatarData } = trpc.projects.getGitHubAvatar.useQuery(
{ id: projectId },
{
staleTime: 1000 * 60 * 5, // Consider stale after 5 minutes
refetchOnWindowFocus: false,
},
);
// Prefer fetched data, fall back to prop
const owner = avatarData?.owner ?? githubOwner;
const firstLetter = projectName.charAt(0).toUpperCase();
// Show avatar if we have an owner and no image loading error
if (owner && !imageError) {
return (
<div
className={cn(
"relative size-6 rounded overflow-hidden flex-shrink-0 bg-muted",
className,
)}
>
<img
src={getGitHubAvatarUrl(owner)}
alt={`${projectName} avatar`}
className="size-full object-cover"
onError={() => setImageError(true)}
/>
</div>
);
}
import { useEffect, useState } from "react";
export function ProjectThumbnail({
projectId,
projectName,
githubOwner,
className,
}: ProjectThumbnailProps) {
const [imageError, setImageError] = useState(false);
// Always fetch to ensure we get the latest - the backend caches it
const { data: avatarData } = trpc.projects.getGitHubAvatar.useQuery(
{ id: projectId },
{
staleTime: 1000 * 60 * 5, // Consider stale after 5 minutes
refetchOnWindowFocus: false,
},
);
// Prefer fetched data, fall back to prop
const owner = avatarData?.owner ?? githubOwner;
// Reset error state when owner changes
useEffect(() => {
setImageError(false);
}, [owner]);
const firstLetter = projectName.charAt(0).toUpperCase();
// Show avatar if we have an owner and no image loading error
if (owner && !imageError) {
return (
<div
className={cn(
"relative size-6 rounded overflow-hidden flex-shrink-0 bg-muted",
className,
)}
>
<img
src={getGitHubAvatarUrl(owner)}
alt={`${projectName} avatar`}
className="size-full object-cover"
onError={() => setImageError(true)}
/>
</div>
);
}
// Fallback: show first letter with subtle background
return (
<div
className={cn(
"size-6 rounded flex items-center justify-center flex-shrink-0",
"bg-muted text-muted-foreground text-xs font-medium",
className,
)}
>
{firstLetter}
</div>
);
}
🤖 Prompt for AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsx
around lines 22-54, The imageError state (useState imageError / setImageError)
is never reset when owner changes, so after one load failure the component will
permanently show initials; add a useEffect inside ProjectThumbnail that depends
on owner (and/or projectId/avatarData) and calls setImageError(false) whenever
owner changes (or becomes non-null) so the new owner's avatar can be retried.

Comment on lines +191 to +217
<button
type="button"
onClick={handleClick}
onMouseEnter={handleMouseEnter}
className={cn(
"relative flex items-center justify-center size-8 rounded-md",
"hover:bg-muted/50 transition-colors",
isActive && "bg-muted",
)}
>
{/* Active indicator */}
{isActive && (
<div className="absolute left-0 top-1 bottom-1 w-0.5 bg-primary rounded-r" />
)}
{isBranchWorkspace ? (
<LuFolder className="size-4 text-muted-foreground" />
) : (
<LuFolderGit2 className="size-4 text-muted-foreground" />
)}
{/* Notification dot */}
{needsAttention && (
<span className="absolute top-1 right-1 flex size-2">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-red-400 opacity-75" />
<span className="relative inline-flex size-2 rounded-full bg-red-500" />
</span>
)}
</button>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Add aria-label to collapsed button for accessibility.

The collapsed button lacks an accessible label, making it unusable for screen reader users.

🔎 Proposed fix
 <button
   type="button"
   onClick={handleClick}
   onMouseEnter={handleMouseEnter}
+  aria-label={`${name || branch} workspace`}
   className={cn(
     "relative flex items-center justify-center size-8 rounded-md",
     "hover:bg-muted/50 transition-colors",
     isActive && "bg-muted",
   )}
 >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button
type="button"
onClick={handleClick}
onMouseEnter={handleMouseEnter}
className={cn(
"relative flex items-center justify-center size-8 rounded-md",
"hover:bg-muted/50 transition-colors",
isActive && "bg-muted",
)}
>
{/* Active indicator */}
{isActive && (
<div className="absolute left-0 top-1 bottom-1 w-0.5 bg-primary rounded-r" />
)}
{isBranchWorkspace ? (
<LuFolder className="size-4 text-muted-foreground" />
) : (
<LuFolderGit2 className="size-4 text-muted-foreground" />
)}
{/* Notification dot */}
{needsAttention && (
<span className="absolute top-1 right-1 flex size-2">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-red-400 opacity-75" />
<span className="relative inline-flex size-2 rounded-full bg-red-500" />
</span>
)}
</button>
<button
type="button"
onClick={handleClick}
onMouseEnter={handleMouseEnter}
aria-label={`${name || branch} workspace`}
className={cn(
"relative flex items-center justify-center size-8 rounded-md",
"hover:bg-muted/50 transition-colors",
isActive && "bg-muted",
)}
>
{/* Active indicator */}
{isActive && (
<div className="absolute left-0 top-1 bottom-1 w-0.5 bg-primary rounded-r" />
)}
{isBranchWorkspace ? (
<LuFolder className="size-4 text-muted-foreground" />
) : (
<LuFolderGit2 className="size-4 text-muted-foreground" />
)}
{/* Notification dot */}
{needsAttention && (
<span className="absolute top-1 right-1 flex size-2">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-red-400 opacity-75" />
<span className="relative inline-flex size-2 rounded-full bg-red-500" />
</span>
)}
</button>
🤖 Prompt for AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
around lines 191-217, The collapsed icon button in WorkspaceListItem lacks an
accessible label; add an aria-label prop to the button element (the one with
onClick={handleClick} and onMouseEnter={handleMouseEnter}) inside
WorkspaceListItem.tsx, constructing a descriptive label that uses the component
state/props (isBranchWorkspace, isActive, needsAttention and, if available, the
workspace name) so screen readers can identify the control (e.g. "Open branch
workspace: <name>, active, needs attention" or similar based on those flags).

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: 2

🤖 Fix all issues with AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx:
- Around line 250-257: The dropdown trigger Button rendering the HiChevronDown
icon lacks an accessible label; update the Button component (the instance using
variant="default", size="sm", disabled={isPending}) to include an appropriate
aria-label (e.g., aria-label="Toggle commit options" or similar) and, if it
opens a menu, add aria-haspopup="menu" and aria-expanded tied to the dropdown
open state; ensure the label text conveys the button's purpose and avoid visual
changes.
- Line 214: The UI currently uses a custom 10px font class (`text-[10px]`) in
CommitInput (the JSX elements around the div with className "flex flex-col..."
and the textarea/count badge inside this component), which reduces readability;
replace those `text-[10px]` instances (including the occurrences referenced near
the div and the textarea/count badge) with a larger Tailwind size such as
`text-xs` (or make the size configurable via a prop or CSS variable) and run a
quick visual/accessibility check to ensure the sidebar copy is legible across
DPI settings.
🧹 Nitpick comments (1)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx (1)

52-52: Consider extracting magic numbers to named constants.

The hardcoded values 150 (hover delay) and "160px" (tab width) could be extracted to named constants at the module top for better maintainability and self-documentation.

Example refactor
+const HOVER_DELAY_MS = 150;
+const TAB_WIDTH_PX = "160px";
+
 export function GroupStrip() {
   // ... existing code ...
   
   hoverTimeoutRef.current = setTimeout(() => {
     setDropdownOpen(true);
-  }, 150);
+  }, HOVER_DELAY_MS);
   
   // ... and similarly for line 61 ...
   
   <div
     key={tab.id}
     className="h-full shrink-0"
-    style={{ width: "160px" }}
+    style={{ width: TAB_WIDTH_PX }}
   >

Also applies to: 61-61, 135-135

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cbef340 and 1bcbe33.

📒 Files selected for processing (4)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsx
🧰 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/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.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/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.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/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.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/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.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/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.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/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
🧠 Learnings (1)
📚 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/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
🧬 Code graph analysis (1)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx (3)
packages/ui/src/components/ui/textarea.tsx (1)
  • Textarea (18-18)
packages/ui/src/components/ui/button.tsx (1)
  • Button (60-60)
packages/ui/src/components/ui/dropdown-menu.tsx (4)
  • DropdownMenuTrigger (251-251)
  • DropdownMenuContent (252-252)
  • DropdownMenuItem (255-255)
  • DropdownMenuSeparator (259-259)
🔇 Additional comments (5)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx (1)

201-201: LGTM! Minor styling improvement.

The change from rounded to rounded-md makes the border radius more explicit and consistent with Tailwind CSS conventions.

apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx (2)

128-128: LGTM: Spacing refinement aligns with UI improvements.

The reduction in right padding from pr-8 to pr-2 tightens the layout and aligns with the PR's overall UI spacing improvements.


149-149: LGTM: Tighter spacing improves visual cohesion.

Removing the left margin on the dropdown wrapper creates a more compact and cohesive header layout.

apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx (2)

220-225: Good UX enhancement with keyboard shortcut.

The Cmd/Ctrl+Enter shortcut for committing is a standard pattern that improves keyboard-driven workflows. The implementation correctly guards with canCommit and prevents default behavior before triggering the commit action.


261-341: Consistent styling updates across dropdown menu items.

The dropdown menu items have been systematically updated with consistent text sizing (text-xs), icon sizing (size-3.5), and alignment. All functional handlers and disabled states remain properly configured.


return (
<div className="flex flex-col gap-2 p-3 border-b border-border">
<div className="flex flex-col gap-1.5 px-2 py-2 border-b border-border">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Consider readability impact of text-[10px] custom size.

The UI sizing has been significantly reduced, including the use of text-[10px] (10 pixels) for the textarea and count badge. This is below Tailwind's smallest default size (text-xs = 12px) and may impact readability, particularly on lower-DPI displays or for users with visual impairments. While compact design may be intentional for a sidebar, ensure this meets your accessibility requirements and consider user testing to validate readability.

Also applies to: 219-219, 234-234, 241-241, 259-259

🤖 Prompt for AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
around line 214, The UI currently uses a custom 10px font class (`text-[10px]`)
in CommitInput (the JSX elements around the div with className "flex
flex-col..." and the textarea/count badge inside this component), which reduces
readability; replace those `text-[10px]` instances (including the occurrences
referenced near the div and the textarea/count badge) with a larger Tailwind
size such as `text-xs` (or make the size configurable via a prop or CSS
variable) and run a quick visual/accessibility check to ensure the sidebar copy
is legible across DPI settings.

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/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx:
- Around line 33-44: The 600ms literal in handleRefresh is a magic
number—declare a descriptive module-level constant (e.g.,
MANUAL_REFRESH_SPIN_MS) near the top of the file after imports and replace the
hardcoded 600 in the setTimeout call with that constant; ensure related symbols
are handleRefresh, timeoutRef, and setIsManualRefresh so the timeout behavior is
clear and maintainable.
🧹 Nitpick comments (1)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx (1)

109-129: Remove redundant tooltip in expanded mode.

The expanded toggle button now has both an inline hover label (lines 121-125) and a tooltip (line 128) that display the same text. When hovering, both would appear simultaneously, creating visual redundancy. The inline label already provides clear affordance, and the pattern established by the Workspaces button (lines 132-146) shows that expanded-mode buttons use inline text without tooltips.

🔎 Proposed fix: Remove the Tooltip wrapper
-		<Tooltip delayDuration={300}>
-			<TooltipTrigger asChild>
-				<button
-					type="button"
-					onClick={handleToggleSidebar}
-					onMouseEnter={() => setIsHovering(true)}
-					onMouseLeave={() => setIsHovering(false)}
-					className="flex items-center gap-2 px-2 py-1.5 w-full rounded-md text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors"
-				>
-					<div className="flex items-center justify-center size-5">
-						{getToggleIcon()}
-					</div>
-					{isHovering && (
-						<span className="text-sm font-medium flex-1 text-left">
-							Toggle sidebar
-						</span>
-					)}
-				</button>
-			</TooltipTrigger>
-			<TooltipContent side="right">Toggle sidebar</TooltipContent>
-		</Tooltip>
+		<button
+			type="button"
+			onClick={handleToggleSidebar}
+			onMouseEnter={() => setIsHovering(true)}
+			onMouseLeave={() => setIsHovering(false)}
+			className="flex items-center gap-2 px-2 py-1.5 w-full rounded-md text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors"
+		>
+			<div className="flex items-center justify-center size-5">
+				{getToggleIcon()}
+			</div>
+			{isHovering && (
+				<span className="text-sm font-medium flex-1 text-left">
+					Toggle sidebar
+				</span>
+			)}
+		</button>
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1bcbe33 and c72cc2e.

📒 Files selected for processing (3)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
🧰 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/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.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/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.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/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.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/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.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/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.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/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
🧬 Code graph analysis (1)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsx (6)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/index.ts (1)
  • WorkspaceSidebarHeader (1-1)
apps/desktop/src/renderer/stores/app-state.ts (3)
  • useCurrentView (86-86)
  • useOpenWorkspacesList (102-103)
  • useCloseWorkspacesList (104-105)
apps/desktop/src/renderer/stores/workspace-sidebar-state.ts (1)
  • useWorkspaceSidebarStore (30-130)
packages/ui/src/components/ui/tooltip.tsx (3)
  • Tooltip (76-76)
  • TooltipTrigger (76-76)
  • TooltipContent (76-76)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsx (1)
  • NewWorkspaceButton (10-57)
🔇 Additional comments (2)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx (2)

46-54: Excellent fix for the timeout cleanup!

The cleanup effect correctly addresses the memory leak flagged in the previous review. Clearing the timeout and nullifying the ref ensures no state updates occur after unmount.


17-29: Past review feedback successfully addressed.

The unused props (ahead, behind, isRefreshing) have been removed from the interface and component signature, and the memory leak from the timeout has been fixed with proper cleanup. Well done!

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: 2

🤖 Fix all issues with AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx:
- Line 36: The timeoutRef is typed as NodeJS.Timeout which is incorrect in the
renderer (browser) where setTimeout returns a number; change the type used in
the useRef declaration for timeoutRef (currently useRef<NodeJS.Timeout |
null>(null)) to a browser-compatible type such as useRef<number | null>(null) or
useRef<ReturnType<typeof setTimeout> | null>(null) so the runtime value and the
TypeScript type match.
- Around line 38-49: Extract the hardcoded 600ms magic number in handleRefresh
into a module-level constant (e.g., MANUAL_REFRESH_SPIN_DURATION_MS) declared
after imports and before the component, then replace the literal 600 in the
setTimeout call with that constant; update any references to timeoutRef and
setIsManualRefresh remain unchanged.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c72cc2e and e6dadd2.

📒 Files selected for processing (2)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
🧰 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/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.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/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.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/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.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/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.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/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.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/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
🧠 Learnings (1)
📚 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 **/*.{ts,tsx} : Extract magic numbers and hardcoded values to named constants at module top

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.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). (6)
  • GitHub Check: Deploy Admin
  • GitHub Check: Deploy API
  • GitHub Check: Deploy Marketing
  • GitHub Check: Deploy Web
  • GitHub Check: Deploy Docs
  • GitHub Check: Build

workspaceId,
}: ChangesHeaderProps) {
const [isManualRefresh, setIsManualRefresh] = useState(false);
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use browser-compatible timeout type in renderer process.

In the renderer process, setTimeout returns a number (browser API), not NodeJS.Timeout. Using NodeJS.Timeout creates a type mismatch with the actual runtime value.

🔎 Proposed fix
-	const timeoutRef = useRef<NodeJS.Timeout | null>(null);
+	const timeoutRef = useRef<number | null>(null);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const timeoutRef = useRef<number | null>(null);
🤖 Prompt for AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
around line 36, The timeoutRef is typed as NodeJS.Timeout which is incorrect in
the renderer (browser) where setTimeout returns a number; change the type used
in the useRef declaration for timeoutRef (currently useRef<NodeJS.Timeout |
null>(null)) to a browser-compatible type such as useRef<number | null>(null) or
useRef<ReturnType<typeof setTimeout> | null>(null) so the runtime value and the
TypeScript type match.

Comment on lines +38 to +49
const handleRefresh = () => {
setIsManualRefresh(true);
onRefresh();
// Clear any existing timeout
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
// Stop spinning after a short delay
timeoutRef.current = setTimeout(() => {
setIsManualRefresh(false);
}, 600);
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Extract the hardcoded timeout duration to a named constant.

The 600 millisecond value on line 48 remains hardcoded and should be extracted to a module-level constant for maintainability and self-documentation, as specified in the coding guidelines.

🔎 Proposed refactor

Add this constant after the imports, before the interface:

 import type { ChangesViewMode } from "../../types";
 import { ViewModeToggle } from "../ViewModeToggle";
 
+const MANUAL_REFRESH_SPINNER_DURATION_MS = 600;
+
 interface ChangesHeaderProps {

Then use it in the timeout:

 	const handleRefresh = () => {
 		setIsManualRefresh(true);
 		onRefresh();
 		// Clear any existing timeout
 		if (timeoutRef.current) {
 			clearTimeout(timeoutRef.current);
 		}
 		// Stop spinning after a short delay
 		timeoutRef.current = setTimeout(() => {
 			setIsManualRefresh(false);
-		}, 600);
+		}, MANUAL_REFRESH_SPINNER_DURATION_MS);
 	};

As per coding guidelines and learnings, magic numbers should be extracted to named constants at module top.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
around lines 38-49, Extract the hardcoded 600ms magic number in handleRefresh
into a module-level constant (e.g., MANUAL_REFRESH_SPIN_DURATION_MS) declared
after imports and before the component, then replace the literal 600 in the
setTimeout call with that constant; update any references to timeoutRef and
setIsManualRefresh remain unchanged.

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/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx (1)

214-341: Consider extracting size constants and removing redundant text-xs classes.

Multiple hardcoded size values (h-7, text-[10px], text-xs, w-48, gap-1.5, px-2, py-2) appear throughout the component. Additionally, text-xs is set on the DropdownMenuContent (line 257) and then redundantly on every DropdownMenuItem (lines 262, 270, 279, 291, 306, 319, 328, 333).

Consider:

  1. Extracting repeated size values to named constants at the module top (per coding guidelines)
  2. Removing the redundant text-xs from individual menu items since it cascades from the parent
Example refactor for size constants
// At module top
const COMPACT_HEIGHT = "h-7" as const;
const COMPACT_TEXT = "text-[10px]" as const;
const DROPDOWN_WIDTH = "w-48" as const;

For the redundant classes, simply remove className="text-xs" from each DropdownMenuItem since the parent DropdownMenuContent already sets text-xs.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1cea7e5 and 546255d.

📒 Files selected for processing (1)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
🧰 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/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.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/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.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/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.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/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.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/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.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/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
🧠 Learnings (1)
📚 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/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx
🧬 Code graph analysis (1)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx (3)
packages/ui/src/components/ui/textarea.tsx (1)
  • Textarea (18-18)
packages/ui/src/components/ui/button.tsx (1)
  • Button (60-60)
packages/ui/src/components/ui/dropdown-menu.tsx (3)
  • DropdownMenuTrigger (251-251)
  • DropdownMenuContent (252-252)
  • DropdownMenuItem (255-255)
⏰ 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). (6)
  • GitHub Check: Deploy Marketing
  • GitHub Check: Deploy Docs
  • GitHub Check: Deploy Web
  • GitHub Check: Deploy API
  • GitHub Check: Deploy Admin
  • GitHub Check: Build
🔇 Additional comments (2)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsx (2)

220-225: LGTM: Enter key handler now commits correctly.

The addition of the explicit handleCommit() call ensures that pressing Enter+Cmd/Ctrl actually commits the changes, rather than just preventing the default behavior. The canCommit guard prevents invalid submissions.


249-249: Verify the button variant change impact.

The dropdown trigger button variant changed from "secondary" to "default". Ensure this visual change aligns with your design system and maintains adequate contrast/affordance for the collapsed sidebar context.

@AviPeltz AviPeltz merged commit 35a982c into main Jan 6, 2026
12 of 13 checks passed
@Kitenite Kitenite deleted the repository-project-image branch January 7, 2026 01:31
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