fix: 为检查更新按钮添加加载状态

- 在更新管理 hook 中暴露检查更新中的 loading 状态
- 检查更新请求结束后统一复位 loading 状态
- 关于页检查更新按钮接入 loading 动画
- 补充测试覆盖检查中的 pending 状态

Fixes #730
This commit is contained in:
liuqiufeng
2026-07-27 22:09:20 +08:00
parent 70282286fc
commit c4d172030e
3 changed files with 51 additions and 3 deletions

View File

@@ -2368,6 +2368,7 @@ function App() {
hideUpdateDownloadProgress,
isAboutOpen,
isBackgroundProgressForLatestUpdate,
isCheckingForUpdates,
isLatestUpdateDownloaded,
isUpdateChannelLoading,
isUpdateChannelSaving,
@@ -5162,7 +5163,14 @@ function App() {
lastUpdateInfo?.hasUpdate && !isLatestUpdateDownloaded && !isBackgroundProgressForLatestUpdate ? (
<Button key="mute" onClick={muteLatestUpdate}>{t('app.about.action.mute_this_version')}</Button>
) : null,
<Button key="check" icon={<CloudDownloadOutlined />} onClick={() => checkForUpdates(false)}>{t('app.about.action.check_updates')}</Button>,
<Button
key="check"
icon={<CloudDownloadOutlined />}
loading={isCheckingForUpdates}
onClick={() => checkForUpdates(false)}
>
{t('app.about.action.check_updates')}
</Button>,
closeAction ?? null,
lastUpdateInfo?.hasUpdate && !isLatestUpdateDownloaded && !isBackgroundProgressForLatestUpdate ? (
<Button key="download" type="primary" icon={<DownloadOutlined />} onClick={() => downloadUpdate(lastUpdateInfo, false)}>{updateDownloadActionLabel}</Button>

View File

@@ -198,6 +198,38 @@ describe('useAppUpdateManager', () => {
expect(backendApp.CheckForUpdates).not.toHaveBeenCalled();
});
it('exposes a loading state while checking for updates', async () => {
let resolveCheck: ((result: Record<string, unknown>) => void) | undefined;
const checkPromise = new Promise<Record<string, unknown>>((resolve) => {
resolveCheck = resolve;
});
backendApp.CheckForUpdates.mockReturnValue(checkPromise);
renderHook();
let pendingCheck: Promise<void> | undefined;
act(() => {
pendingCheck = hook?.checkForUpdates(false);
});
expect(hook?.isCheckingForUpdates).toBe(true);
expect(hook?.aboutUpdateStatus).toBe('app.about.update_status.checking');
await act(async () => {
resolveCheck?.({
success: true,
data: {
hasUpdate: false,
currentVersion: '0.8.1',
latestVersion: '0.8.1',
},
});
await pendingCheck;
});
expect(hook?.isCheckingForUpdates).toBe(false);
});
it('merges complete MSI download metadata returned by the backend', async () => {
backendApp.CheckForUpdates.mockResolvedValue({
success: true,

View File

@@ -221,6 +221,7 @@ export const useAppUpdateManager = ({
const [installMode, setInstallMode] = useState<UpdateInstallMode>('unknown');
const [isUpdateChannelLoading, setIsUpdateChannelLoading] = useState(false);
const [isUpdateChannelSaving, setIsUpdateChannelSaving] = useState(false);
const [isCheckingForUpdates, setIsCheckingForUpdates] = useState(false);
const [aboutInfo, setAboutInfo] = useState<AboutInfo>(() => DEFAULT_ABOUT_INFO);
const [aboutUpdateStatus, setAboutUpdateStatus] = useState<string>('');
const [lastUpdateInfo, setLastUpdateInfo] = useState<UpdateInfo | null>(null);
@@ -470,6 +471,7 @@ export const useAppUpdateManager = ({
const checkForUpdates = useCallback(async (silent: boolean) => {
if (updateCheckInFlightRef.current) return;
updateCheckInFlightRef.current = true;
setIsCheckingForUpdates(true);
if (!silent) {
setAboutUpdateStatus(t('app.about.update_status.checking'));
}
@@ -477,8 +479,13 @@ export const useAppUpdateManager = ({
const checkFn = silent && typeof updateAPI.CheckForUpdatesSilently === 'function'
? updateAPI.CheckForUpdatesSilently
: updateAPI.CheckForUpdates;
const res = await checkFn();
updateCheckInFlightRef.current = false;
let res: any = null;
try {
res = await checkFn();
} finally {
updateCheckInFlightRef.current = false;
setIsCheckingForUpdates(false);
}
if (!res?.success) {
if (!silent) {
const error = res?.message || t('common.unknown');
@@ -785,6 +792,7 @@ export const useAppUpdateManager = ({
hideUpdateDownloadProgress,
isAboutOpen,
isBackgroundProgressForLatestUpdate,
isCheckingForUpdates,
isLatestUpdateDownloaded,
isUpdateChannelLoading,
isUpdateChannelSaving,