"use client"; import {useState, useRef, useEffect, useCallback} from "react"; import { RefreshCw, CheckCircle2, AlertCircle, Loader2, Terminal, Calendar, FileText, } from "lucide-react"; import {Button} from "@/components/ui/button"; interface VersionFile { version: string; release_date: string; changelog: string; } interface VersionInfo { current: VersionFile; latest: VersionFile | null; hasUpdate: boolean; currentCommit?: string; latestCommit?: string; message?: string; } type CheckState = "idle" | "checking" | "done" | "error"; type UpdateState = "idle" | "updating" | "done" | "error"; export default function UpdatePage() { const [versionInfo, setVersionInfo] = useState(null); const [checkState, setCheckState] = useState("idle"); const [updateState, setUpdateState] = useState("idle"); const [logs, setLogs] = useState([]); const [errorMsg, setErrorMsg] = useState(""); const logEndRef = useRef(null); useEffect(() => { logEndRef.current?.scrollIntoView({behavior: "smooth"}); }, [logs]); // 检查更新 const handleCheckUpdate = useCallback(async () => { setCheckState("checking"); setErrorMsg(""); setUpdateState("idle"); try { const response = await fetch("/api/update/check"); const result = await response.json(); if (result.success) { setVersionInfo(result.data); setCheckState("done"); } else { throw new Error(result.error || "检查更新失败"); } } catch (err) { setErrorMsg(err instanceof Error ? err.message : "检查更新失败"); setCheckState("error"); } }, []); // 执行更新 const handleExecuteUpdate = useCallback(async () => { setUpdateState("updating"); setLogs([]); setErrorMsg(""); try { const response = await fetch("/api/update/execute", { method: "POST", }); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } const reader = response.body?.getReader(); if (!reader) { throw new Error("无法读取响应流"); } const decoder = new TextDecoder(); let buffer = ""; while (true) { const {done, value} = await reader.read(); if (done) break; buffer += decoder.decode(value, {stream: true}); const lines = buffer.split("\n\n"); buffer = lines.pop() || ""; for (const line of lines) { if (!line.startsWith("data: ")) continue; const data = line.slice(6); try { const parsed = JSON.parse(data); if (parsed.log) { setLogs((prev) => [...prev, parsed.log]); } if (parsed.done) { setUpdateState(parsed.success ? "done" : "error"); if (!parsed.success) { setErrorMsg(parsed.message || "更新失败"); } } } catch { // ignore } } } } catch (err) { setErrorMsg(err instanceof Error ? err.message : "更新执行失败"); setUpdateState("error"); } }, []); // 解析 changelog 为列表项显示 const parseChangelog = (text: string): string[] => { if (!text) return []; // 支持逗号、分号、换行分隔,也支持 "xxx1,xxx2" 中文逗号 return text .split(/[,;,;\n]/) .map((s) => s.trim()) .filter(Boolean); }; return (

版本更新

检查并更新到最新版本

{/* 版本信息卡片 */}
{/* 当前版本 */}
当前版本
{versionInfo?.current.version || "-"} {versionInfo?.current.release_date && ( {versionInfo.current.release_date} )}
{/* 当前版本更新内容(无最新版本时展示) */} {versionInfo?.current.changelog && !versionInfo?.latest?.changelog && (
当前版本更新内容
    {parseChangelog(versionInfo.current.changelog).map((item, i) => (
  • {item}
  • ))}
)}
{/* 最新版本 */} {versionInfo && (
最新版本 {versionInfo.hasUpdate && ( 有新版本 )} {checkState === "done" && !versionInfo.hasUpdate && ( 已是最新 )}
{versionInfo.latest ? ( <>
{versionInfo.latest.version} {versionInfo.latest.release_date && ( {versionInfo.latest.release_date} )}
{/* 最新版本更新内容 */} {versionInfo.latest.changelog && (
更新内容
    {parseChangelog(versionInfo.latest.changelog).map((item, i) => (
  • {item}
  • ))}
)} ) : versionInfo.message ? (
{versionInfo.message}
) : (

{checkState === "checking" ? "检查中..." : "无法获取远程版本信息"}

)}
)}
{/* 操作按钮 */}
{checkState === "checking" ? ( ) : ( )}
{/* 错误提示 */} {errorMsg && (
{errorMsg}
)} {/* 状态提示 */} {checkState === "idle" && !versionInfo && (

点击"检查更新"查看是否有新版本可用

更新功能需要在 Docker 容器中运行,且已配置 ONEDEV_ACCESS_TOKEN

)} {/* 更新执行日志 */} {(updateState !== "idle" || logs.length > 0) && (
执行日志
              {logs.map((log, i) => (
                
{log}
))} {updateState === "updating" && (
执行中...
)} {updateState === "done" && logs.length > 0 && (
✓ 更新完成
)} {updateState === "error" && logs.length > 0 && (
✗ 更新失败
)}
)} {/* 完成状态 */} {updateState === "done" && (

更新完成

服务已重启,请刷新页面以加载最新版本

)}
); }