import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Alert, Button, Modal, Switch, Tag } from 'antd'; import { CloudDownloadOutlined } from '@ant-design/icons'; import axios from 'axios'; import { HttpUtil, PromiseUtil } from '@/utils'; import { formatPanelVersion } from '@/lib/panel-version'; import './PanelUpdateModal.css'; export interface PanelUpdateInfo { channel?: string; currentVersion: string; latestVersion: string; currentCommit?: string; latestCommit?: string; updateAvailable: boolean; } interface BusyEvent { busy: boolean; tip?: string; } interface PanelUpdateModalProps { open: boolean; info: PanelUpdateInfo; devChannelEnable?: boolean; onChannelChange?: (dev: boolean) => void | Promise; onClose: () => void; onBusy: (e: BusyEvent) => void; } export default function PanelUpdateModal({ open, info, devChannelEnable, onChannelChange, onClose, onBusy, }: PanelUpdateModalProps) { const { t } = useTranslation(); const [modal, contextHolder] = Modal.useModal(); const [channelBusy, setChannelBusy] = useState(false); const isDev = info.channel === 'dev'; 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; } async function handleChannel(checked: boolean) { if (!onChannelChange) return; setChannelBusy(true); try { await onChannelChange(checked); } finally { setChannelBusy(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.devChannel')}
{devChannelEnable && ( )}
{isDev ? t('pages.index.currentCommit') : t('pages.index.currentPanelVersion')} {isDev ? ( {info.currentCommit || '?'} ) : ( {formatPanelVersion(window.X_UI_CUR_VER || info.currentVersion) || '?'} )}
{info.updateAvailable ? (
{isDev ? t('pages.index.latestCommit') : t('pages.index.latestPanelVersion')} {(isDev ? info.latestCommit : info.latestVersion) || '-'}
) : (
{t('pages.index.panelUpToDate')} {t('pages.index.panelUpToDate')}
)}
); }