refactor (desktop): Repository project image And Sidebar Changes#601
refactor (desktop): Repository project image And Sidebar Changes#601
Conversation
📝 WalkthroughWalkthroughAdds GitHub avatar lookup and caching via a new TRPC route and utilities, a DB migration for Changes
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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
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. Comment |
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
There was a problem hiding this comment.
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.openUrlmutation rather thanwindow.open()to properly communicate with the main process. The codebase already has this pattern established viaapps/desktop/src/lib/trpc/routers/external/index.ts. Reference howUpdateToast.tsxandUpdateRequiredPage.tsxcorrectly usetrpc.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 oftext-[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-60for subtlety) are appropriate refinements.apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx (1)
68-74: Consider extracting repeatedtext-[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:
- Adding it to your Tailwind config theme extension (e.g.,
text-2xs)- 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-2xsinstead oftext-[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
lastOpenWidthrenamed tolastExpandedWidth. 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
ProjectHeaderPropsinterface 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
📒 Files selected for processing (35)
apps/desktop/src/lib/trpc/routers/projects/projects.tsapps/desktop/src/lib/trpc/routers/projects/utils/github.tsapps/desktop/src/lib/trpc/routers/workspaces/workspaces.tsapps/desktop/src/renderer/index.htmlapps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsxapps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsxapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CategorySection/CategorySection.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ModeCarousel/constants.tsapps/desktop/src/renderer/screens/main/index.tsxapps/desktop/src/renderer/stores/tabs/utils.tsapps/desktop/src/renderer/stores/workspace-sidebar-state.tspackages/local-db/drizzle/0009_add_github_owner_to_projects.sqlpackages/local-db/drizzle/meta/0009_snapshot.jsonpackages/local-db/drizzle/meta/_journal.jsonpackages/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 insrc/lib/trpc
Use alias as defined intsconfig.jsonwhen 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/observableinstead of async generators, as the library explicitly checksisObservable(result)and throws an error otherwise
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/index.tsapps/desktop/src/lib/trpc/routers/workspaces/workspaces.tsapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ModeCarousel/constants.tsapps/desktop/src/renderer/screens/main/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsxapps/desktop/src/lib/trpc/routers/projects/utils/github.tsapps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsxapps/desktop/src/renderer/stores/workspace-sidebar-state.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsxapps/desktop/src/lib/trpc/routers/projects/projects.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/stores/tabs/utils.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsxapps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsxapps/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 usinganytype - 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.tsapps/desktop/src/lib/trpc/routers/workspaces/workspaces.tsapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ModeCarousel/constants.tsapps/desktop/src/renderer/screens/main/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsxpackages/local-db/src/schema/schema.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsxapps/desktop/src/lib/trpc/routers/projects/utils/github.tsapps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsxapps/desktop/src/renderer/stores/workspace-sidebar-state.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsxapps/desktop/src/lib/trpc/routers/projects/projects.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/stores/tabs/utils.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsxapps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsxapps/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.tsapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ModeCarousel/constants.tsapps/desktop/src/renderer/screens/main/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsxapps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsxapps/desktop/src/renderer/stores/workspace-sidebar-state.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/stores/tabs/utils.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsxapps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsxapps/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.tsapps/desktop/src/lib/trpc/routers/workspaces/workspaces.tsapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ModeCarousel/constants.tsapps/desktop/src/renderer/screens/main/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsxapps/desktop/src/lib/trpc/routers/projects/utils/github.tsapps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsxapps/desktop/src/renderer/stores/workspace-sidebar-state.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsxapps/desktop/src/lib/trpc/routers/projects/projects.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/stores/tabs/utils.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsxapps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsxapps/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:fixorbiome check --write
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/index.tsapps/desktop/src/lib/trpc/routers/workspaces/workspaces.tsapps/desktop/src/renderer/screens/main/components/TopBar/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ModeCarousel/constants.tsapps/desktop/src/renderer/screens/main/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsxpackages/local-db/src/schema/schema.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsxapps/desktop/src/lib/trpc/routers/projects/utils/github.tsapps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsxapps/desktop/src/renderer/stores/workspace-sidebar-state.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsxapps/desktop/src/lib/trpc/routers/projects/projects.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/stores/tabs/utils.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsxapps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsxapps/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.tsxapps/desktop/src/renderer/screens/main/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectThumbnail/ProjectThumbnail.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsxapps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceSidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FolderRow/FolderRow.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarFooter.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectSection.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ResizableWorkspaceSidebar.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsxapps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsxapps/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.tsxapps/desktop/src/renderer/screens/main/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ProjectSection/ProjectHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/NewWorkspaceButton.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ViewModeToggle/ViewModeToggle.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsxapps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsxapps/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
| {/* 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> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n "rotate-90|rotate-180" --type tsx --type ts -B2 -A2Repository: superset-sh/superset
Length of output: 91
🏁 Script executed:
rg "rotate-90|rotate-180" -B2 -A2Repository: 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.
| 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> | ||
| ); | ||
| } |
There was a problem hiding this comment.
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.
| 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.
| <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> |
There was a problem hiding this comment.
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.
| <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).
There was a problem hiding this comment.
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
📒 Files selected for processing (4)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitInput/CommitInput.tsxapps/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 insrc/lib/trpc
Use alias as defined intsconfig.jsonwhen 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/observableinstead of async generators, as the library explicitly checksisObservable(result)and throws an error otherwise
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/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 usinganytype - 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.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/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.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/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.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/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.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/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:fixorbiome check --write
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsxapps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsxapps/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.tsxapps/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
roundedtorounded-mdmakes 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-8topr-2tightens 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
canCommitand 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"> |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
📒 Files selected for processing (3)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsxapps/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 insrc/lib/trpc
Use alias as defined intsconfig.jsonwhen 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/observableinstead of async generators, as the library explicitly checksisObservable(result)and throws an error otherwise
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsxapps/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 usinganytype - 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.tsxapps/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.tsxapps/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.tsxapps/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.tsxapps/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:fixorbiome check --write
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/WorkspaceSidebarHeader.tsxapps/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!
There was a problem hiding this comment.
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
📒 Files selected for processing (2)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsxapps/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 insrc/lib/trpc
Use alias as defined intsconfig.jsonwhen 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/observableinstead of async generators, as the library explicitly checksisObservable(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 usinganytype - 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:fixorbiome 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); |
There was a problem hiding this comment.
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.
| 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.
| 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); | ||
| }; |
There was a problem hiding this comment.
🛠️ 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.
There was a problem hiding this comment.
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-xsis set on theDropdownMenuContent(line 257) and then redundantly on everyDropdownMenuItem(lines 262, 270, 279, 291, 306, 319, 328, 333).Consider:
- Extracting repeated size values to named constants at the module top (per coding guidelines)
- Removing the redundant
text-xsfrom individual menu items since it cascades from the parentExample 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 eachDropdownMenuItemsince the parentDropdownMenuContentalready setstext-xs.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 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 insrc/lib/trpc
Use alias as defined intsconfig.jsonwhen 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/observableinstead of async generators, as the library explicitly checksisObservable(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 usinganytype - 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:fixorbiome 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. ThecanCommitguard 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.
Description
Related Issues
Type of Change
Testing
Screenshots (if applicable)
Additional Notes
Summary by CodeRabbit
New Features
UI Improvements
Chores
✏️ Tip: You can customize this high-level summary in your review settings.