diff --git a/docs/changelog/index.md b/docs/changelog/index.md index 7304b1f4..4ec2e39e 100644 --- a/docs/changelog/index.md +++ b/docs/changelog/index.md @@ -11,11 +11,12 @@ sidebar: false ## 重大变更 > [!IMPORTANT] -> +> > 3.1.2 版本更新了 CLickHouse 部署配置。 -> +> > 3.0.0 版本为 Wavelet 平台迁移与架构重构版本,涉及数据库表结构、环境变量以及前后端底层架构的重大变更。请务必在升级前备份数据库,并且更新到 V2.3.4。 > 目前已知的兼容性问题: +> > - Pages 无法迁移, 升级前请先手动下载并备份 Pages 静态站点的 ZIP 包,升级后重新创建。 > - 性能调优参数重置, 升级后请重新配置 @@ -28,6 +29,7 @@ sidebar: false ### 改进 +- 节点详情页 Tab 调整为「概览」与「状态与部署」:原数据看板并入概览;运行状态与配置信息并入状态与部署;边缘节点新增可自动填充 Server URL 与 Agent Token 的 Docker 部署命令卡片。 - WAF 规则编辑器支持为节点自定义显示名称,并从节点库拖放到画布指定位置添加节点。 - WAF 规则画布支持右键删除节点或连线,并屏蔽浏览器默认右键菜单。 - WAF 规则编辑器支持一键格式化布局,按流程层次自动整理节点位置。 @@ -90,7 +92,6 @@ sidebar: false - 移除了 WAF 旧版固定名单与人机验证配置;升级后请在发布前使用新的可视化规则重新编排防护策略。 - ## [v3.2.0] - 2026-07-12 ### 新增 @@ -177,7 +178,6 @@ sidebar: false - 网站管理拆分为域名、路由、静态托管、WAF 和缓存等独立能力,更适合维护复杂站点配置。 - Tunnel 节点统一纳入节点管理,配置发布和运行状态查看更加一致。 - ## [v2.3.4] - 2026-06-17 ### 变更 diff --git a/frontend/app/(main)/nodes/components/edge-node-detail.tsx b/frontend/app/(main)/nodes/components/edge-node-detail.tsx index ce24e72b..436c729e 100644 --- a/frontend/app/(main)/nodes/components/edge-node-detail.tsx +++ b/frontend/app/(main)/nodes/components/edge-node-detail.tsx @@ -37,6 +37,7 @@ import type { import { NodeService } from '@/lib/services/openflare'; import { AgentUpdateDialog } from './agent-update-dialog'; +import { InstallCommand } from './install-command'; import { NodeDetailShell } from './node-detail-shell'; import { NodeErrorBanner, @@ -199,7 +200,7 @@ export function EdgeNodeDetail({ node }: { node: NodeItem }) { > ); - const overviewTab = ( + const manageTab = (
{meta.scriptLabel}
-
- {scriptCommand}
-
- {meta.scriptLabel}
+
+ {scriptCommand}
+
+ {meta.dockerLabel}
diff --git a/frontend/app/(main)/nodes/components/node-detail-shell.tsx b/frontend/app/(main)/nodes/components/node-detail-shell.tsx
index 0e278d1c..8e0849ca 100644
--- a/frontend/app/(main)/nodes/components/node-detail-shell.tsx
+++ b/frontend/app/(main)/nodes/components/node-detail-shell.tsx
@@ -14,7 +14,7 @@ import { NodeKpiCard } from './node-detail-primitives';
import { NodeStatusBadge } from './node-status-badge';
import type { StatusTone } from './node-utils';
-export type NodeDetailTabId = 'overview' | 'dashboard' | 'manage';
+export type NodeDetailTabId = 'overview' | 'manage';
export type NodeDetailTabConfig = {
id: NodeDetailTabId;
@@ -33,18 +33,20 @@ const TAB_CONFIGS: NodeDetailTabConfig[] = [
id: 'overview',
label: '概览',
},
- {
- id: 'dashboard',
- label: '数据看板',
- },
{
id: 'manage',
- label: '配置与部署',
+ label: '状态与部署',
},
];
-function isValidTab(value: string | null): value is NodeDetailTabId {
- return value === 'overview' || value === 'dashboard' || value === 'manage';
+function resolveTab(value: string | null): NodeDetailTabId | null {
+ if (value === 'overview' || value === 'dashboard') {
+ return 'overview';
+ }
+ if (value === 'manage') {
+ return 'manage';
+ }
+ return null;
}
export function NodeDetailShell({
@@ -55,7 +57,6 @@ export function NodeDetailShell({
actions,
kpis,
overview,
- dashboard,
manage,
defaultTab = 'overview',
}: {
@@ -66,7 +67,6 @@ export function NodeDetailShell({
actions: ReactNode;
kpis: NodeDetailKpi[];
overview: ReactNode;
- dashboard: ReactNode;
manage: ReactNode;
defaultTab?: NodeDetailTabId;
}) {
@@ -76,7 +76,7 @@ export function NodeDetailShell({
const activeTab = useMemo(() => {
const tab = searchParams.get('tab');
- return isValidTab(tab) ? tab : defaultTab;
+ return resolveTab(tab) ?? defaultTab;
}, [defaultTab, searchParams]);
const setActiveTab = useCallback(
@@ -88,6 +88,16 @@ export function NodeDetailShell({
[pathname, router, searchParams],
);
+ const handleTabChange = useCallback(
+ (value: string) => {
+ const tab = resolveTab(value);
+ if (tab) {
+ setActiveTab(tab);
+ }
+ },
+ [setActiveTab],
+ );
+
return (
@@ -144,11 +154,7 @@ export function NodeDetailShell({
{
- if (isValidTab(value)) {
- setActiveTab(value);
- }
- }}
+ onValueChange={handleTabChange}
className='w-full gap-0'
>
@@ -174,9 +180,6 @@ export function NodeDetailShell({
{activeTab === 'overview' ? overview : null}
-
- {activeTab === 'dashboard' ? dashboard : null}
-
{activeTab === 'manage' ? manage : null}
diff --git a/frontend/app/(main)/nodes/components/node-utils.ts b/frontend/app/(main)/nodes/components/node-utils.ts
index 1c29c8d7..4f33a9ef 100644
--- a/frontend/app/(main)/nodes/components/node-utils.ts
+++ b/frontend/app/(main)/nodes/components/node-utils.ts
@@ -138,6 +138,25 @@ export function getImageTag(version?: string): string {
return 'latest';
}
+export function buildEdgeDockerInstallCommand(
+ serverUrl: string,
+ agentToken: string,
+ version?: string,
+) {
+ const tag = getImageTag(version);
+ const image = `ghcr.io/rain-kl/openflare-agent:${tag}`;
+
+ return [
+ `docker pull ${image}`,
+ `docker rm -f openflare-agent 2>/dev/null || true`,
+ `docker run -d --name openflare-agent --restart unless-stopped \\`,
+ ` -p 80:80 -p 443:443/tcp -p 443:443/udp \\`,
+ ` -e OPENFLARE_SERVER_URL=${serverUrl} \\`,
+ ` -e OPENFLARE_AGENT_TOKEN=${agentToken} \\`,
+ ` ${image}`,
+ ].join('\n');
+}
+
export function buildRelayInstallCommand(
serverUrl: string,
discoveryToken: string,
diff --git a/frontend/app/(main)/nodes/components/relay-node-detail.tsx b/frontend/app/(main)/nodes/components/relay-node-detail.tsx
index 8299a6fe..d50ef612 100644
--- a/frontend/app/(main)/nodes/components/relay-node-detail.tsx
+++ b/frontend/app/(main)/nodes/components/relay-node-detail.tsx
@@ -278,7 +278,7 @@ export function RelayNodeDetail({ node }: { node: NodeItem }) {
>
);
- const overviewTab = (
+ const manageTab = (
{node.last_error ? : null}
@@ -359,11 +359,7 @@ export function RelayNodeDetail({ node }: { node: NodeItem }) {
-
- );
- const manageTab = (
-
);
- const overviewTab = (
+ const manageTab = (
{node.last_error ? : null}
@@ -271,11 +271,9 @@ export function TunnelNodeDetail({ node }: { node: NodeItem }) {
-