Skip to content

fix(projects): prevent duplicate project creation#2224

Open
janburzinski wants to merge 2 commits into
mainfrom
emdash/double-project-on-lag-9yrto
Open

fix(projects): prevent duplicate project creation#2224
janburzinski wants to merge 2 commits into
mainfrom
emdash/double-project-on-lag-9yrto

Conversation

@janburzinski
Copy link
Copy Markdown
Collaborator

summary

my macbook was lagging and through that it created two proejcts one healthy one and one corrupted one. this should fix that

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 25, 2026

Greptile Summary

This PR fixes duplicate project creation triggered by lag-induced double-clicks. It adds a two-layer defense: a one-shot useRef guard in the modal component and an in-flight deduplication map keyed by effective project path in the store. It also fixes a pre-existing bug where inspectProjectPath always used pickState.path regardless of the active mode, meaning new and clone modes were inspecting the wrong path.

  • Modal guard (add-project-modal.tsx): isSubmittingRef blocks any second invocation of handleSubmit for the lifetime of the modal, and projectPath is now computed per-mode (pick / new / clone) before the inspection RPC call.
  • Store dedup (project-manager.ts): _pendingCreationsByPath maps the effective project path to its in-flight promise, coalescing concurrent createProject calls for the same path into a single result. _doCreateProject is also fixed to use _effectiveProjectPath when calling inspectProjectPath.

Confidence Score: 4/5

Safe to merge — the duplicate-creation bug is correctly addressed at two independent layers, and the pre-existing wrong-path bug in new/clone modes is fixed.

Both fixes are mechanically correct and well-commented. The only concern is that isSubmittingRef is never reset, which silently relies on onClose() always being reached — a reasonable invariant today, but one that would silently break retry UX if error handling is added later.

The submit guard logic in add-project-modal.tsx (lines 259–260) deserves a second look if error-handling UX is ever added to keep the modal open on failure.

Important Files Changed

Filename Overview
src/renderer/features/projects/components/add-project-modal/add-project-modal.tsx Adds a one-shot useRef guard against double-submit and fixes path computation for new/clone modes (was incorrectly using pickState.path for all modes). The guard is intentionally non-resetting, relying on the invariant that onClose() is always called.
src/renderer/features/projects/stores/project-manager.ts Adds _pendingCreationsByPath in-flight dedup map keyed by effective project path, and fixes _doCreateProject to use _effectiveProjectPath (full path for new/clone modes) rather than data.path directly.

Sequence Diagram

sequenceDiagram
    participant User
    participant Modal as AddProjectModal
    participant Store as ProjectManagerStore
    participant RPC

    User->>Modal: Click Submit (1st click)
    Modal->>Modal: "isSubmittingRef.current = false → set true"
    Modal->>RPC: inspectProjectPath(projectPath)
    RPC-->>Modal: "{ existingProject: null }"

    User->>Modal: Click Submit (2nd click, lag)
    Modal->>Modal: "isSubmittingRef.current = true → return early"

    Modal->>Store: createProject(type, data, id)
    Store->>Store: _pendingCreationsByPath.get(pathKey) → null
    Store->>Store: Store promise in _pendingCreationsByPath
    Store->>RPC: _doCreateProject → inspectProjectPath(effectivePath)
    RPC-->>Store: "{ existingProject: null }"
    Store->>RPC: createProject(...)
    RPC-->>Store: project created
    Store->>Store: _pendingCreationsByPath.delete(pathKey)
    Store-->>Modal: projectId

    Note over Modal: If concurrent call reached store (bypassing ref guard),
    Note over Modal: it would return the in-flight promise instead
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
src/renderer/features/projects/components/add-project-modal/add-project-modal.tsx:253-260
**One-shot guard creates a no-retry footgun**

`isSubmittingRef.current` is set to `true` on the very first submit attempt and never reset. The comment justifies this by saying "the modal always closes after a submit," which is currently true because every code path eventually calls `onClose()`. However, if a future change adds an error toast and early-returns (keeping the modal open after, e.g., a failed inspection), users will find the Submit button permanently silenced for that modal instance with no visible explanation. Resetting the ref in the `catch` block (before the fall-through) would remove this assumption without harming the dedup goal.

Reviews (1): Last reviewed commit: "fix(projects): prevent duplicate project..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant