desktop (fix): init git if project has no git#265
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded@AviPeltz has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 3 minutes and 21 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
WalkthroughOpen-new flow now returns a typed result that can require Git initialization; a new initGitAndOpen mutation initializes a repo and upserts a project; worktree start-point logic is remote-aware; UI dialog and client flows surface the new init flow and explicit error/result handling. Changes
Sequence DiagramsequenceDiagram
actor User
participant StartView as StartView UI
participant TRPC as TRPC Server
participant Projects as Projects Router
participant GitUtil as Git Utils
participant InitDialog as InitGitDialog UI
participant Workspaces as Workspace Router
User->>StartView: Click "Open Project" (selectedPath)
StartView->>TRPC: openNew(selectedPath)
TRPC->>GitUtil: resolve git root / check repo
alt selectedPath is not a git repo
TRPC-->>StartView: OpenNewNeedsGitInit(selectedPath)
StartView->>InitDialog: show InitGitDialog(selectedPath)
User->>InitDialog: Click "Initialize Git"
InitDialog->>TRPC: initGitAndOpen(path)
TRPC->>GitUtil: git init, create initial commit, detect defaultBranch
TRPC->>Projects: upsertProject(path, defaultBranch)
Projects-->>TRPC: Project
TRPC-->>InitDialog: { project }
InitDialog->>Workspaces: createWorkspace(project.id)
Workspaces-->>InitDialog: Workspace created
InitDialog-->>StartView: close dialog / success
else selectedPath is a git repo
TRPC->>Projects: upsertProject(path, defaultBranch)
Projects-->>TRPC: Project
TRPC-->>StartView: OpenNewSuccess(project)
StartView->>Workspaces: createWorkspace(project.id)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20–30 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
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: 1
🧹 Nitpick comments (2)
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx (2)
53-72: Consider awaiting workspace creation before closing the dialog.
onClose()is called immediately after triggeringcreateWorkspace.mutate(), which means the dialog closes before the workspace is actually created. If workspace creation fails, the user won't see the error since the dialog is already closed.Consider using
mutateAsyncand awaiting it, or movingonClose()into the workspace mutation's success callback:const handleInitGit = () => { if (isLoading) return; // Prevent double-clicks initGitAndOpen.mutate( { path: selectedPath }, { onSuccess: (result) => { if (result.project) { utils.projects.getRecents.invalidate(); - createWorkspace.mutate({ projectId: result.project.id }); - onClose(); + createWorkspace.mutate( + { projectId: result.project.id }, + { + onSuccess: () => onClose(), + onError: (err) => onError(err.message || "Failed to create workspace"), + }, + ); } else { onError("Unexpected error: project was not created"); } }, onError: (err) => { onError(err.message || "Failed to initialize git repository"); }, }, ); };
6-11: Minor: Consider extracting or co-locating shared path utilities.
getBasenameduplicates similar path normalization logic found inStartView/index.tsx(normalizeSeparators) andWorkspaceDropdown.tsx(formatPath). If this pattern grows, consider extracting to a shared utility.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/desktop/src/lib/trpc/routers/projects/projects.ts(3 hunks)apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts(1 hunks)apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts(2 hunks)apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx(1 hunks)apps/desktop/src/renderer/screens/main/components/StartView/index.tsx(3 hunks)apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceDropdown.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
apps/desktop/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)
For Electron interprocess communication, ALWAYS use tRPC as defined in
src/lib/trpc
Files:
apps/desktop/src/lib/trpc/routers/workspaces/utils/git.tsapps/desktop/src/renderer/screens/main/components/StartView/index.tsxapps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceDropdown.tsxapps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsxapps/desktop/src/lib/trpc/routers/projects/projects.tsapps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
apps/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)
apps/desktop/**/*.{ts,tsx}: Please use alias as defined intsconfig.jsonwhen possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary
Files:
apps/desktop/src/lib/trpc/routers/workspaces/utils/git.tsapps/desktop/src/renderer/screens/main/components/StartView/index.tsxapps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceDropdown.tsxapps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsxapps/desktop/src/lib/trpc/routers/projects/projects.tsapps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Co-locate component dependencies (utils, hooks, constants, config, tests, stories) next to the file using them
Avoidanytype in TypeScript unless absolutely necessary
Files:
apps/desktop/src/lib/trpc/routers/workspaces/utils/git.tsapps/desktop/src/renderer/screens/main/components/StartView/index.tsxapps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceDropdown.tsxapps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsxapps/desktop/src/lib/trpc/routers/projects/projects.tsapps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts
**/{components,pages}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/{components,pages}/**/*.tsx: Use one folder per component with structureComponentName/ComponentName.tsxplusindex.tsfor barrel export
Create one component per file - do not use multi-component files
Files:
apps/desktop/src/renderer/screens/main/components/StartView/index.tsxapps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceDropdown.tsxapps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx
apps/desktop/src/{renderer,shared,preload}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Never import Node.js modules in renderer process code or shared code in the desktop app
Files:
apps/desktop/src/renderer/screens/main/components/StartView/index.tsxapps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceDropdown.tsxapps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx
🧬 Code graph analysis (4)
apps/desktop/src/renderer/screens/main/components/StartView/index.tsx (1)
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx (1)
InitGitDialog(20-117)
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx (2)
apps/website/src/app/api/trpc/[trpc]/route.ts (1)
onError(26-28)packages/ui/src/components/button.tsx (1)
Button(61-61)
apps/desktop/src/lib/trpc/routers/projects/projects.ts (3)
apps/desktop/src/main/lib/db/schemas.ts (1)
Project(1-11)apps/desktop/src/lib/trpc/routers/projects/utils/colors/colors.ts (1)
assignRandomColor(3-7)apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts (1)
getDefaultBranch(302-331)
apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts (1)
apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts (3)
hasOriginRemote(286-294)fetchDefaultBranch(339-347)createWorktree(132-223)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Build
🔇 Additional comments (10)
apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts (1)
283-294: LGTM!Clean implementation that correctly checks for an 'origin' remote. The silent error handling is appropriate since the function is designed to return a boolean, and errors (e.g., invalid repo path) should be treated the same as "no origin".
apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts (1)
60-82: LGTM!Good implementation of remote-aware start point logic. The fallback to local
defaultBranchfor repos without origin is essential for the new Git initialization workflow. The best-effort fetch with silent failure is appropriate since the local branch still exists.apps/desktop/src/renderer/screens/main/components/StartView/index.tsx (3)
60-63: LGTM!Clean state shape for tracking the dialog's visibility and selected path.
67-95: LGTM!Good handling of all
OpenNewResultvariants. The early returns forcanceled,error, andneedsGitInitkeep the logic clean and readable.
272-277: LGTM!Dialog integration is correct. The
onClosecallback properly resets bothisOpenandselectedPath.apps/desktop/src/renderer/screens/main/components/TopBar/WorkspaceTabs/WorkspaceDropdown.tsx (1)
97-125: LGTM!Good defensive handling of all result variants. The decision to show a toast directing users to the Start view (rather than opening a dialog inline) is a reasonable UX choice for this secondary entry point.
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx (1)
78-116: LGTM!Clean modal implementation with proper accessibility considerations (biome-ignore for the backdrop pattern is appropriate). The loading state is correctly reflected in button text and disabled states.
apps/desktop/src/lib/trpc/routers/projects/projects.ts (3)
16-29: LGTM!Clean discriminated union types for
OpenNewResult. The structure makes it easy for consumers to narrow the result type using property checks.
154-189: LGTM!The updated
openNewmutation correctly returns theneedsGitInitvariant whengetGitRootfails, allowing the UI to offer Git initialization.
191-236: Good fallback handling for Git version differences.The fallback from
--initial-branch=mainto plaininitcorrectly handles older Git versions. The error detection for missing user config is helpful. After the fallbackgit.init(), the code correctly handles the case where the default branch might bemasterinstead ofmainby readingbranchSummary.current.
| async function upsertProject( | ||
| mainRepoPath: string, | ||
| defaultBranch: string, | ||
| ): Promise<Project> { | ||
| const name = basename(mainRepoPath); | ||
|
|
||
| let project = db.data.projects.find((p) => p.mainRepoPath === mainRepoPath); | ||
|
|
||
| if (project) { | ||
| await db.update((data) => { | ||
| const p = data.projects.find((p) => p.id === project?.id); | ||
| if (p) { | ||
| p.lastOpenedAt = Date.now(); | ||
| p.defaultBranch = defaultBranch; | ||
| } | ||
| }); | ||
| } else { | ||
| project = { | ||
| id: nanoid(), | ||
| mainRepoPath, | ||
| name, | ||
| color: assignRandomColor(), | ||
| tabOrder: null, | ||
| lastOpenedAt: Date.now(), | ||
| createdAt: Date.now(), | ||
| defaultBranch, | ||
| }; | ||
|
|
||
| await db.update((data) => { | ||
| // biome-ignore lint/style/noNonNullAssertion: project is assigned above, TypeScript can't see it inside callback | ||
| data.projects.push(project!); | ||
| }); | ||
| } | ||
|
|
||
| return project; | ||
| } |
There was a problem hiding this comment.
Potential stale reference when returning updated project.
When updating an existing project, the function modifies the database but returns the original project reference from line 42, which won't reflect the updated lastOpenedAt and defaultBranch values.
Consider re-fetching the project after update or constructing the return value with updated fields:
if (project) {
await db.update((data) => {
const p = data.projects.find((p) => p.id === project?.id);
if (p) {
p.lastOpenedAt = Date.now();
p.defaultBranch = defaultBranch;
}
});
+ // Re-fetch to get updated values
+ project = db.data.projects.find((p) => p.mainRepoPath === mainRepoPath);
}🤖 Prompt for AI Agents
In apps/desktop/src/lib/trpc/routers/projects/projects.ts around lines 36 to 71,
when updating an existing project the function currently returns the stale local
`project` reference that doesn't include the updated `lastOpenedAt` and
`defaultBranch`; re-fetch the project from `db.data.projects` after the `await
db.update(...)` completes (or build a new object merging the original `project`
with the updated fields) and return that up-to-date object so the caller
receives the updated values.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx (1)
1-129: Consider reorganizing to match component folder structure guideline.Per the coding guidelines, components should follow the pattern
ComponentName/ComponentName.tsxwith anindex.tsfor barrel exports.Current structure:
StartView/InitGitDialog.tsxRecommended structure:
StartView/InitGitDialog/InitGitDialog.tsx StartView/InitGitDialog/index.tsThis improves organization and makes it easier to co-locate related files (tests, utilities, etc.) with the component.
Based on coding guidelines: "Use one folder per component with structure
ComponentName/ComponentName.tsxplusindex.tsfor barrel export"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
apps/desktop/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)
For Electron interprocess communication, ALWAYS use tRPC as defined in
src/lib/trpc
Files:
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx
apps/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)
apps/desktop/**/*.{ts,tsx}: Please use alias as defined intsconfig.jsonwhen possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary
Files:
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx
**/{components,pages}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/{components,pages}/**/*.tsx: Use one folder per component with structureComponentName/ComponentName.tsxplusindex.tsfor barrel export
Create one component per file - do not use multi-component files
Files:
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Co-locate component dependencies (utils, hooks, constants, config, tests, stories) next to the file using them
Avoidanytype in TypeScript unless absolutely necessary
Files:
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx
apps/desktop/src/{renderer,shared,preload}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Never import Node.js modules in renderer process code or shared code in the desktop app
Files:
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx
🧬 Code graph analysis (1)
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx (2)
apps/website/src/app/api/trpc/[trpc]/route.ts (1)
onError(26-28)packages/ui/src/components/button.tsx (1)
Button(61-61)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Build
🔇 Additional comments (7)
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsx (7)
1-4: LGTM! Imports follow Electron and TypeScript guidelines.The imports correctly use tRPC for IPC, leverage path aliases, and avoid Node.js modules in renderer code.
6-11: LGTM! Cross-platform path handling is correct.The utility properly normalizes both Unix and Windows paths and handles edge cases appropriately.
13-18: LGTM! Props interface is well-defined.Clear, type-safe interface with appropriate props for a modal dialog component.
33-44: LGTM! Proper Escape key handling with cleanup.This is a legitimate use of
useEffectfor keyboard event handling, which is necessary per the guidelines. The cleanup prevents memory leaks.
46-51: LGTM! Correct backdrop dismiss pattern.The handler properly distinguishes backdrop clicks from content clicks and prevents dismissal during loading.
53-84: LGTM! Robust async flow with proper error handling.The mutation sequence is well-structured with appropriate error boundaries, user-friendly messages, and intentional non-blocking cache invalidation. The double-click guard is a nice touch.
26-30: This review comment references code that does not exist in the repository.The file
apps/desktop/src/renderer/screens/main/components/StartView/InitGitDialog.tsxand all hooks/mutations mentioned (useCreateWorkspace,initGitAndOpen,trpc.useUtils()) are not found in the codebase. This may be a stale review comment from a previous PR state, or the paths have changed since the review was created.Likely an incorrect or invalid review comment.
Description
Related Issues
Type of Change
Testing
Screenshots (if applicable)
Additional Notes
Summary by CodeRabbit
New Features
Bug Fixes / Improvements
✏️ Tip: You can customize this high-level summary in your review settings.