fix(frontend): close panel update confirmation before progress (#6766)

* fix(frontend): close panel update confirmation promptly

* chore(ci): rerun flaky checks
This commit is contained in:
libmur-dev
2026-10-12 02:32:15 +03:00
committed by GitHub
parent 2e8af64745
commit dbfa369632
2 changed files with 97 additions and 31 deletions
+35 -31
View File
@@ -80,6 +80,39 @@ export default function PanelUpdateModal({
}
}
async function runPanelUpdate() {
const baseTip = t('pages.index.dontRefresh');
const tip = info.latestVersion ? `${baseTip} (${info.latestVersion})` : baseTip;
onClose();
onBusy({ busy: true, tip });
const result = await HttpUtil.post<{ runId: string }>('/panel/api/server/updatePanel');
if (!result?.success) {
onBusy({ busy: false });
return;
}
const outcome = await pollUpdateStatus(result.obj?.runId ?? '');
onBusy({ busy: false });
if (outcome === 'success') {
await PromiseUtil.sleep(800);
window.location.reload();
return;
}
modal[outcome === 'failed' ? 'error' : 'warning']({
title: t(
outcome === 'failed'
? 'pages.index.panelUpdateFailedTitle'
: 'pages.index.panelUpdateUnknownTitle',
),
content: t(
outcome === 'failed'
? 'pages.index.panelUpdateFailedDesc'
: 'pages.index.panelUpdateUnknownDesc',
),
okText: t('refresh'),
onOk: () => window.location.reload(),
});
}
function updatePanel() {
modal.confirm({
title: t('pages.index.panelUpdateDialog'),
@@ -89,37 +122,8 @@ export default function PanelUpdateModal({
),
okText: t('confirm'),
cancelText: t('cancel'),
onOk: async () => {
const baseTip = t('pages.index.dontRefresh');
const tip = info.latestVersion ? `${baseTip} (${info.latestVersion})` : baseTip;
onClose();
onBusy({ busy: true, tip });
const result = await HttpUtil.post<{ runId: string }>('/panel/api/server/updatePanel');
if (!result?.success) {
onBusy({ busy: false });
return;
}
const outcome = await pollUpdateStatus(result.obj?.runId ?? '');
onBusy({ busy: false });
if (outcome === 'success') {
await PromiseUtil.sleep(800);
window.location.reload();
return;
}
modal[outcome === 'failed' ? 'error' : 'warning']({
title: t(
outcome === 'failed'
? 'pages.index.panelUpdateFailedTitle'
: 'pages.index.panelUpdateUnknownTitle',
),
content: t(
outcome === 'failed'
? 'pages.index.panelUpdateFailedDesc'
: 'pages.index.panelUpdateUnknownDesc',
),
okText: t('refresh'),
onOk: () => window.location.reload(),
});
onOk: () => {
void runPanelUpdate();
},
});
}
@@ -0,0 +1,62 @@
import { fireEvent, screen } from '@testing-library/react';
import { Modal } from 'antd';
import { afterEach, describe, expect, it, vi } from 'vitest';
import PanelUpdateModal from '@/pages/index/PanelUpdateModal';
import { HttpUtil } from '@/utils';
import { renderWithProviders } from './test-utils';
let restoreUseModal = () => {};
describe('panel update modal', () => {
afterEach(() => {
restoreUseModal();
restoreUseModal = () => {};
vi.mocked(HttpUtil.post).mockReset();
});
it('lets the confirmation close before the update request finishes', () => {
const confirm = vi.fn();
const useModal = vi.spyOn(Modal, 'useModal').mockReturnValue([
{
confirm,
error: vi.fn(),
warning: vi.fn(),
} as unknown as ReturnType<typeof Modal.useModal>[0],
<span key="modal-context" />,
]);
restoreUseModal = () => useModal.mockRestore();
vi.mocked(HttpUtil.post).mockReturnValue(new Promise(() => {}));
const onClose = vi.fn();
const onBusy = vi.fn();
renderWithProviders(
<PanelUpdateModal
open
info={{
channel: 'dev',
currentVersion: 'dev+old',
latestVersion: 'dev+new',
currentCommit: 'old',
latestCommit: 'new',
updateAvailable: true,
}}
devChannelEnable
onClose={onClose}
onBusy={onBusy}
/>,
);
fireEvent.click(screen.getByRole('button', { name: /Update Panel/ }));
expect(confirm).toHaveBeenCalledOnce();
const config = confirm.mock.calls[0]?.[0];
if (!config?.onOk) throw new Error('Confirmation onOk handler was not registered');
expect(config.onOk()).toBeUndefined();
expect(onClose).toHaveBeenCalledOnce();
expect(HttpUtil.post).toHaveBeenCalledWith('/panel/api/server/updatePanel');
expect(onBusy).toHaveBeenCalledWith({
busy: true,
tip: 'Installation is in progress, please do not refresh this page (dev+new)',
});
});
});