mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-28 00:24:19 +00:00
8e4c368200
The panel version button opened the GitHub releases page on a stable, up-to-date build, and the dev-channel toggle only rendered on dev builds, so there was no in-panel path from stable to dev. Drop the IsDevBuild() guard in devChannelActive (the toggle alone drives the channel now), always open the update modal instead of releases, and always render the Dev channel switch.
170 lines
4.7 KiB
TypeScript
170 lines
4.7 KiB
TypeScript
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<void>;
|
|
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<boolean> {
|
|
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}
|
|
<Modal
|
|
open={open}
|
|
title={t('pages.index.updatePanel')}
|
|
footer={null}
|
|
onCancel={onClose}
|
|
>
|
|
{info.updateAvailable && (
|
|
<Alert
|
|
type="warning"
|
|
className="mb-12"
|
|
title={t('pages.index.panelUpdateDesc')}
|
|
showIcon
|
|
/>
|
|
)}
|
|
|
|
<div className="version-list">
|
|
<div className="version-list-item">
|
|
<span>{t('pages.index.devChannel')}</span>
|
|
<Switch
|
|
checked={!!devChannelEnable}
|
|
loading={channelBusy}
|
|
onChange={handleChannel}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{devChannelEnable && (
|
|
<Alert
|
|
type="info"
|
|
className="mb-12"
|
|
title={t('pages.index.devChannelWarning')}
|
|
showIcon
|
|
/>
|
|
)}
|
|
|
|
<div className="version-list">
|
|
<div className="version-list-item">
|
|
<span>{isDev ? t('pages.index.currentCommit') : t('pages.index.currentPanelVersion')}</span>
|
|
{isDev ? (
|
|
<Tag color="green">{info.currentCommit || '?'}</Tag>
|
|
) : (
|
|
<Tag color="green">{formatPanelVersion(window.X_UI_CUR_VER || info.currentVersion) || '?'}</Tag>
|
|
)}
|
|
</div>
|
|
{info.updateAvailable ? (
|
|
<div className="version-list-item">
|
|
<span>{isDev ? t('pages.index.latestCommit') : t('pages.index.latestPanelVersion')}</span>
|
|
<Tag color="purple">{(isDev ? info.latestCommit : info.latestVersion) || '-'}</Tag>
|
|
</div>
|
|
) : (
|
|
<div className="version-list-item">
|
|
<span>{t('pages.index.panelUpToDate')}</span>
|
|
<Tag color="green">{t('pages.index.panelUpToDate')}</Tag>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="actions-row">
|
|
<Button
|
|
type="primary"
|
|
disabled={!info.updateAvailable}
|
|
onClick={updatePanel}
|
|
icon={<CloudDownloadOutlined />}
|
|
>
|
|
{t('pages.index.updatePanel')}
|
|
</Button>
|
|
</div>
|
|
</Modal>
|
|
</>
|
|
);
|
|
}
|