fix: resolve macOS build race condition and update download button unresponsive

CI 修复 (electron-builder.yml):
- 移除 mac target 的 arch: [arm64, x64],改由 CI matrix 的 --arch flag 控制
- 根因:两个 macOS job 各自构建两个架构的 DMG,产生两个 draft release,
  导致 release job 只发布了没有 DMG 的那个,macOS 产物丢失

下载按钮无响应修复:
- electron/updater.ts: downloadUpdate IPC handler 加 try-catch,
  失败时通过 sendStatus 发送 error 事件给前端,避免静默失败
- AppShell.tsx: downloadUpdate 回调点击后立即设置 downloadProgress=0
  提供即时 UI 反馈;加 await + catch 处理下载失败并重置状态
- AppShell.tsx: error 事件处理中重置 downloadProgress 为 null,
  使下载按钮在失败后重新出现
- UpdateDialog.tsx / GeneralSection.tsx: isDownloading 判断移除 > 0 条件,
  downloadProgress === 0 时也显示下载中状态,消除点击后无反馈的间隙

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
7418andClaude Opus 4.6 committed 2026-02-27 12:11:20 +08:00
1 parent 40a78ea0fc
commit 09908cfcb7
5 files changed
+22 -6

No files matched your search

-1
View File
@@ -49,7 +49,6 @@ mac:
artifactName: "${productName}-${version}-${arch}.${ext}"
target:
- target: dmg
arch: [arm64, x64]
win:
icon: build/icon.ico
target:
+8 -1
View File
@@ -98,7 +98,14 @@ export function initAutoUpdater(win: BrowserWindow) {
});
ipcMain.handle('updater:download', async () => {
return autoUpdater.downloadUpdate();
try {
return await autoUpdater.downloadUpdate();
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
console.error('[updater] Download failed:', message);
sendStatus({ status: 'error', error: message });
throw err;
}
});
ipcMain.handle('updater:quit-and-install', () => {
+12 -2
View File
@@ -280,6 +280,8 @@ export function AppShell({ children }: { children: React.ReactNode }) {
case 'error':
setChecking(false);
// Reset download progress so the download button re-appears
setUpdateInfo((prev) => prev ? { ...prev, downloadProgress: null } : prev);
console.warn('[updater] Error:', event.error);
break;
}
@@ -300,8 +302,16 @@ export function AppShell({ children }: { children: React.ReactNode }) {
setShowDialog(false);
}, []);
const downloadUpdate = useCallback(() => {
window.electronAPI?.updater?.downloadUpdate();
const downloadUpdate = useCallback(async () => {
// Immediately show downloading state so user gets feedback
setUpdateInfo((prev) => prev ? { ...prev, downloadProgress: 0 } : prev);
try {
await window.electronAPI?.updater?.downloadUpdate();
} catch (err) {
console.warn('[updater] Download failed:', err);
// Reset progress so the download button re-appears
setUpdateInfo((prev) => prev ? { ...prev, downloadProgress: null } : prev);
}
}, []);
const quitAndInstall = useCallback(() => {
+1 -1
View File
@@ -20,7 +20,7 @@ export function UpdateDialog() {
if (!updateInfo?.updateAvailable) return null;
const { isNativeUpdate, readyToInstall, downloadProgress } = updateInfo;
const isDownloading = isNativeUpdate && !readyToInstall && downloadProgress != null && downloadProgress > 0;
const isDownloading = isNativeUpdate && !readyToInstall && downloadProgress != null;
return (
<Dialog open={showDialog} onOpenChange={(open) => {
+1 -1
View File
@@ -26,7 +26,7 @@ function UpdateCard() {
const currentVersion = process.env.NEXT_PUBLIC_APP_VERSION || "0.0.0";
const isDownloading = updateInfo?.isNativeUpdate && !updateInfo.readyToInstall
&& updateInfo.downloadProgress != null && updateInfo.downloadProgress > 0;
&& updateInfo.downloadProgress != null;
return (
<div className="rounded-lg border border-border/50 p-4 transition-shadow hover:shadow-sm">