mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-09-28 23:56:36 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 91d79b6b3a | |||
| fc7df6bd64 | |||
| 25dfb84324 |
@@ -180,13 +180,41 @@ func (e *systemUpgradeExecutor) selectComposeAsset(current []byte) string {
|
||||
}
|
||||
|
||||
func (e *systemUpgradeExecutor) helperScript() string {
|
||||
return strings.Join([]string{
|
||||
"set -eu",
|
||||
`cd "$PANEL_DEPLOY_DIR"`,
|
||||
"docker compose pull backend frontend",
|
||||
"sleep 5",
|
||||
"docker compose up -d backend frontend",
|
||||
}, "\n")
|
||||
return `set -eu
|
||||
LOGFILE="$PANEL_DEPLOY_DIR/upgrade.log"
|
||||
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOGFILE"; }
|
||||
|
||||
cd "$PANEL_DEPLOY_DIR"
|
||||
echo "" > "$LOGFILE"
|
||||
log "开始面板升级"
|
||||
log "工作目录: $(pwd)"
|
||||
|
||||
if [ ! -f docker-compose.yml ]; then
|
||||
log "错误: docker-compose.yml 不存在"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f .env ]; then
|
||||
log "错误: .env 不存在"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "拉取新镜像..."
|
||||
if ! docker compose pull backend frontend 2>&1 | tee -a "$LOGFILE"; then
|
||||
log "错误: 拉取镜像失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "等待旧容器释放资源..."
|
||||
sleep 3
|
||||
|
||||
log "重启服务(force-recreate)..."
|
||||
if ! docker compose up -d --force-recreate --remove-orphans backend frontend 2>&1 | tee -a "$LOGFILE"; then
|
||||
log "错误: 重启服务失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "升级完成"
|
||||
`
|
||||
}
|
||||
|
||||
func (e *systemUpgradeExecutor) buildHelperRunArgs(imageID, helperName string) ([]string, error) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 多阶段构建 - 构建阶段
|
||||
FROM node:20.19.0 AS builder
|
||||
FROM node:22-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
@@ -508,8 +508,7 @@ export interface SystemUpgradeVersionApiData {
|
||||
capability: SystemUpgradeCapabilityApiData;
|
||||
}
|
||||
|
||||
export interface SystemUpgradeCheckApiData
|
||||
extends SystemUpgradeVersionApiData {
|
||||
export interface SystemUpgradeCheckApiData extends SystemUpgradeVersionApiData {
|
||||
releases: SystemUpgradeReleaseApiItem[];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
import type {
|
||||
SystemUpgradeCheckApiData,
|
||||
SystemUpgradeRunApiData,
|
||||
SystemUpgradeReleaseApiItem,
|
||||
SystemUpgradeVersionApiData,
|
||||
} from "@/api/types";
|
||||
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
@@ -32,12 +39,6 @@ import {
|
||||
runSystemUpgrade,
|
||||
type AnnouncementData,
|
||||
} from "@/api";
|
||||
import type {
|
||||
SystemUpgradeCheckApiData,
|
||||
SystemUpgradeRunApiData,
|
||||
SystemUpgradeReleaseApiItem,
|
||||
SystemUpgradeVersionApiData,
|
||||
} from "@/api/types";
|
||||
import { BackIcon, SettingsIcon } from "@/components/icons";
|
||||
import { ThemeSettings } from "@/components/theme-settings";
|
||||
import { isAdmin } from "@/utils/auth";
|
||||
@@ -328,6 +329,12 @@ export default function ConfigPage() {
|
||||
systemUpgradeReleasesMatchChannel &&
|
||||
systemUpgradeReleases.length > 0,
|
||||
);
|
||||
const canTriggerSystemUpgrade = Boolean(
|
||||
!systemUpgradeLoading &&
|
||||
!systemUpgradeChecking &&
|
||||
!systemUpgradeExecuting &&
|
||||
systemUpgradeInfo?.capability.capable !== false,
|
||||
);
|
||||
const canOpenSystemUpgradeModal = Boolean(
|
||||
systemUpgradeInfo?.capability.capable &&
|
||||
systemUpgradeHasConfirmedUpdate &&
|
||||
@@ -421,7 +428,9 @@ export default function ConfigPage() {
|
||||
hasUpdate:
|
||||
response.data.channel === channel ? response.data.hasUpdate : false,
|
||||
latestVersion:
|
||||
response.data.channel === channel ? response.data.latestVersion : "",
|
||||
response.data.channel === channel
|
||||
? response.data.latestVersion
|
||||
: "",
|
||||
});
|
||||
} else {
|
||||
setSystemUpgradeInfo(null);
|
||||
@@ -512,7 +521,9 @@ export default function ConfigPage() {
|
||||
: "未获取到可用版本",
|
||||
);
|
||||
|
||||
return Boolean(data.capability.capable && data.hasUpdate && data.releases?.length);
|
||||
return Boolean(
|
||||
data.capability.capable && data.hasUpdate && data.releases?.length,
|
||||
);
|
||||
} else {
|
||||
setSystemUpgradeReleases([]);
|
||||
setSystemUpgradeCheckedChannel(null);
|
||||
@@ -1568,7 +1579,8 @@ export default function ConfigPage() {
|
||||
<div>
|
||||
<p className="text-xs text-default-500">部署目录</p>
|
||||
<p className="mt-1 break-all font-medium">
|
||||
{systemUpgradeInfo?.capability.deployDir || "未获取到部署目录"}
|
||||
{systemUpgradeInfo?.capability.deployDir ||
|
||||
"未获取到部署目录"}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
@@ -1625,7 +1637,9 @@ export default function ConfigPage() {
|
||||
size="md"
|
||||
variant="bordered"
|
||||
onSelectionChange={(keys) => {
|
||||
const selected = Array.from(keys)[0] as string | undefined;
|
||||
const selected = Array.from(keys)[0] as
|
||||
| string
|
||||
| undefined;
|
||||
|
||||
setSystemUpgradeSelectedVersion(selected || "");
|
||||
}}
|
||||
@@ -1648,17 +1662,15 @@ export default function ConfigPage() {
|
||||
|
||||
<div className="flex flex-col gap-3 pt-1 sm:flex-row sm:justify-end">
|
||||
<Button
|
||||
variant="flat"
|
||||
isLoading={systemUpgradeChecking}
|
||||
variant="flat"
|
||||
onPress={handleCheckSystemUpgrade}
|
||||
>
|
||||
检查更新
|
||||
</Button>
|
||||
<Button
|
||||
color="primary"
|
||||
isDisabled={
|
||||
!canOpenSystemUpgradeModal
|
||||
}
|
||||
isDisabled={!canTriggerSystemUpgrade}
|
||||
isLoading={systemUpgradeExecuting}
|
||||
onPress={handleOpenSystemUpgradeModal}
|
||||
>
|
||||
@@ -1925,10 +1937,12 @@ export default function ConfigPage() {
|
||||
<ModalBody>
|
||||
<div className="space-y-3 text-sm text-default-700 dark:text-default-300">
|
||||
<p>
|
||||
升级过程需要访问 Docker Socket,并会在短时间内中断当前面板服务。
|
||||
升级过程需要访问 Docker
|
||||
Socket,并会在短时间内中断当前面板服务。
|
||||
</p>
|
||||
<p>
|
||||
请确认已经允许面板管理容器与宿主机 Docker 交互,并且可以接受升级期间的临时不可用。
|
||||
请确认已经允许面板管理容器与宿主机 Docker
|
||||
交互,并且可以接受升级期间的临时不可用。
|
||||
</p>
|
||||
<div className="space-y-2 rounded-lg border border-warning-200 bg-warning-50 px-4 py-3 text-warning-800 dark:border-warning-900/40 dark:bg-warning-950/30 dark:text-warning-200">
|
||||
<p className="text-xs font-medium">升级前请确认</p>
|
||||
|
||||
@@ -204,6 +204,7 @@ const isObjectRecord = (value: unknown): value is Record<string, unknown> =>
|
||||
const toSafeString = (value: unknown): string => {
|
||||
if (typeof value === "string") return value;
|
||||
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
@@ -265,11 +266,13 @@ const normalizeBestExitState = (value: unknown): BestExitState | undefined => {
|
||||
|
||||
const bestExitOwnerRoleText = (role?: string) => {
|
||||
if (role === "chain") return "中转";
|
||||
|
||||
return "入口";
|
||||
};
|
||||
|
||||
const bestExitDetailTitle = (state?: BestExitState) => {
|
||||
if (!state?.items?.length) return undefined;
|
||||
|
||||
return state.items
|
||||
.map(
|
||||
(item) =>
|
||||
@@ -3108,7 +3111,9 @@ export default function TunnelPage() {
|
||||
}}
|
||||
>
|
||||
<SelectItem key="1">单向计算(仅上传)</SelectItem>
|
||||
<SelectItem key="2">双向计算(上传+下载)</SelectItem>
|
||||
<SelectItem key="2">
|
||||
双向计算(上传+下载)
|
||||
</SelectItem>
|
||||
</Select>
|
||||
|
||||
<Input
|
||||
@@ -3171,7 +3176,9 @@ export default function TunnelPage() {
|
||||
)}
|
||||
|
||||
<div>
|
||||
<div className="text-sm font-medium">质量检测目标</div>
|
||||
<div className="text-sm font-medium">
|
||||
质量检测目标
|
||||
</div>
|
||||
<p className="text-xs text-default-500 mt-0.5">
|
||||
用于实时隧道质量检测、诊断目标和 best
|
||||
最优出口评分,留空使用 www.bing.com:443
|
||||
|
||||
@@ -401,6 +401,7 @@ export function Select<T>({
|
||||
</div>
|
||||
) : (
|
||||
<select
|
||||
aria-label={label ? undefined : ariaLabel}
|
||||
className={cn(
|
||||
"w-full rounded-md border border-input bg-background px-3 py-2 text-foreground shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-ring dark:[color-scheme:dark]",
|
||||
sizeClass(size),
|
||||
@@ -409,7 +410,6 @@ export function Select<T>({
|
||||
)}
|
||||
disabled={isDisabled}
|
||||
id={generatedId}
|
||||
aria-label={label ? undefined : ariaLabel}
|
||||
required={isRequired}
|
||||
value={singleValue}
|
||||
onChange={handleChange}
|
||||
|
||||
Reference in New Issue
Block a user