Skip to content

Bug 71: Git operation loading state leak and feedback gap in GitPanel #68

@sp643541-bit

Description

@sp643541-bit

Bug Report: Git Branch Operation State Leak & Feedback Gap

Description

A critical UI/UX flaw exists in both the standard GitPanel and the premium CortexGitPanel where local operation loading states are not safely reset following a failed Git operation. When an asynchronous operation such as branch creation, checkout, or deletion fails (e.g., due to a Git lock, invalid branch name, or network error), the components fail to catch the error in a finally block for their local signals. This results in the UI being stuck in a permanent "loading" state with spinning icons, while simultaneously providing no visual error feedback to the user about the operation's failure.

Components Affected

  • src/components/git/GitPanel.tsx
  • src/components/cortex/CortexGitPanel.tsx
  • src/context/MultiRepoContext.tsx (Lack of handled feedback propagation to local component signals)

Technical Signature

In GitPanel.tsx:

const createBranch = async (name: string) => {
  const repo = activeRepo();
  if (!repo) return;
  setOperationLoading("create-branch"); // State set to true
  try {
    await multiRepo.createBranch(repo.id, name);
    await multiRepo.refreshRepository(repo.id);
    // Success path resets loading
    setOperationLoading(null);
  } catch (err) {
    showError(`Failed to create branch: ${err}`);
    console.error("Failed to create branch:", err);
    // BUG: Missing setOperationLoading(null) here or in finally
  }
};

In CortexGitPanel.tsx:

const handleAbortMerge = async () => {
  const r = repo();
  if (!r || mergeAbortLoading()) return;
  setError(null);
  setMergeAbortLoading(true); // State set to true
  try {
    await gitMergeAbort(r.path);
    setShowAbortMergeDialog(false);
    refresh();
    // Success path resets loading
  } catch (err) {
    setError(`Abort merge failed: ${err}`);
    // BUG: Missing setMergeAbortLoading(false) here or in finally
  } finally {
    // Note: handleAbortMerge HAS a finally block, but handleCommit/onBranchChange DO NOT.
    setMergeAbortLoading(false); 
  }
};

Reproduction Steps

  1. Open the Git Sidebar.
  2. Attempt to create a branch with an invalid name or in a repository with a post-checkout hook that fails.
  3. Observe the "spinner" icon appearing next to the branch selector or in the commit button.
  4. Note that after the operation fails, the spinner continues to spin indefinitely.
  5. Note that the UI remains partially non-interactive (buttons disabled due to operationLoading check).

Impact

  • Micro-interaction Failure: The UI enters a "zombie" state where it accurately reflects that an operation started but fails to reflect that it ended in error.
  • Stale UI State: User is forced to manually refresh or restart the IDE to clear the stuck loading indicators.
  • User Frustration: Lack of immediate, actionable error feedback makes the IDE appear broken or unresponsive.

Verification

  1. Audit src/components/git/GitPanel.tsx lines 620-680, 715-730, and 831-842.
  2. Audit src/components/cortex/CortexGitPanel.tsx lines 114-128 and 138-157.
  3. Observe that onBranchChange, createBranch, checkout, handleCommit, stageAll, and unstageAll lack defensive finally blocks for local state management.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions