From 39dc5db0799e304c08975866c055f49fdc2b4a4d Mon Sep 17 00:00:00 2001 From: arookieofc Date: Sat, 7 Nov 2026 08:26:57 +0800 Subject: [PATCH] fix(vcs): surface stage/unstage failures instead of swallowing them (#1893) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(vcs): surface stage/unstage failures instead of swallowing them The Commit tab's Stage/Unstage items ran the IPC call and only attached a .finally(refreshNow) handler. call() rejects with IpcError on any backend failure (require_trust, git add failure, path routing), so the rejection went unhandled: no notification, no console line, and the UI silently showed the file still unstaged — reported as 'Stage/Unstage doesn't work' (#1890). Route the four handlers through runOp(), the same helper every other mutating VCS op uses: it logs the command to the Git console, shows an error balloon with the backend's message on failure, and refreshes the status afterwards (so the manual .finally is dropped). This doesn't change the success path; it makes the failure visible, which is what the reporter needed to diagnose the real backend error. * fix(vcs): add text catalog entries for the stage/unstage op titles --- src/features/vcs/CommitView.tsx | 9 +++++---- src/platform/locales/text/zh.json | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/features/vcs/CommitView.tsx b/src/features/vcs/CommitView.tsx index bda64cb79..d9beae481 100644 --- a/src/features/vcs/CommitView.tsx +++ b/src/features/vcs/CommitView.tsx @@ -76,6 +76,7 @@ import { KIND_COLOR, KIND_LABEL, fileCount, formatTime, stashLabel, stripSlash } import { call, commands } from "@/platform/ipc"; import type { FileStatus } from "@/bindings"; import { OperationBanner } from "./operations"; +import { runOp } from "./ops"; import { ShelfPanel, loadShelves, useShelf } from "./shelf"; import { refreshNow, repoName, selectRepo, useVcs } from "./store"; import styles from "./CommitView.module.css"; @@ -220,13 +221,13 @@ export function listMenu(id: string, active: boolean, files: readonly FileStatus label: "Stage", icon: "plus", disabled: !files.some((f) => f.unstaged), - run: () => void call(commands.vcsStage(paths)).finally(() => void refreshNow()), + run: () => void runOp(tx`Stage ${count} files`, () => call(commands.vcsStage(paths))), }, { label: "Unstage", icon: "minus", disabled: !files.some((f) => f.staged), - run: () => void call(commands.vcsUnstage(paths)).finally(() => void refreshNow()), + run: () => void runOp(tx`Unstage ${count} files`, () => call(commands.vcsUnstage(paths))), }, { kind: "separator" }, ...(count @@ -335,13 +336,13 @@ export function nodeMenu( label: "Stage", icon: "plus", disabled: !files.some((f) => f.unstaged), - run: () => void call(commands.vcsStage(paths)).finally(() => void refreshNow()), + run: () => void runOp(tx`Stage ${paths.length} files`, () => call(commands.vcsStage(paths))), }, { label: "Unstage", icon: "minus", disabled: !files.some((f) => f.staged), - run: () => void call(commands.vcsUnstage(paths)).finally(() => void refreshNow()), + run: () => void runOp(tx`Unstage ${paths.length} files`, () => call(commands.vcsUnstage(paths))), }, { kind: "separator" }, ...(nodes.some((n) => n.changelist) diff --git a/src/platform/locales/text/zh.json b/src/platform/locales/text/zh.json index 09544039f..0d87f187e 100644 --- a/src/platform/locales/text/zh.json +++ b/src/platform/locales/text/zh.json @@ -6421,5 +6421,7 @@ "Recommended": "推荐", "No preview": "无预览", "Running in the background": "后台运行中", - "Couldn't stop the background task": "无法停止后台任务" + "Couldn't stop the background task": "无法停止后台任务", + "Stage {count} files": "暂存 {count} 个文件", + "Unstage {count} files": "取消暂存 {count} 个文件" }