import { useTranslation } from 'react-i18next'; import { Alert, Button, Modal, Tag } from 'antd'; import { CloudDownloadOutlined } from '@ant-design/icons'; import axios from 'axios'; import { HttpUtil, PromiseUtil } from '@/utils'; import './PanelUpdateModal.css'; export interface PanelUpdateInfo { currentVersion: string; latestVersion: string; updateAvailable: boolean; } interface BusyEvent { busy: boolean; tip?: string; } interface PanelUpdateModalProps { open: boolean; info: PanelUpdateInfo; onClose: () => void; onBusy: (e: BusyEvent) => void; } export default function PanelUpdateModal({ open, info, onClose, onBusy }: PanelUpdateModalProps) { const { t } = useTranslation(); const [modal, contextHolder] = Modal.useModal(); async function pollUntilBack(): Promise { await PromiseUtil.sleep(5000); const deadline = Date.now() + 90_000; while (Date.now() < deadline) { try { const r = await axios.get('/panel/api/server/status', { timeout: 2000 }); if (r?.data?.success) return true; } catch { /* still restarting */ } await PromiseUtil.sleep(2000); } return false; } function updatePanel() { modal.confirm({ title: t('pages.index.panelUpdateDialog'), content: t('pages.index.panelUpdateDialogDesc').replace('#version#', info.latestVersion || ''), 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('/panel/api/server/updatePanel'); if (!result?.success) { onBusy({ busy: false }); return; } const back = await pollUntilBack(); if (back) await PromiseUtil.sleep(800); window.location.reload(); }, }); } return ( <> {contextHolder} {info.updateAvailable && ( )}
{t('pages.index.currentPanelVersion')} v{info.currentVersion || '?'}
{info.updateAvailable ? (
{t('pages.index.latestPanelVersion')} {info.latestVersion || '-'}
) : (
{t('pages.index.panelUpToDate')} {t('pages.index.panelUpToDate')}
)}
); }