mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-13 02:26:36 +08:00
feat(nodes): 调整节点详情 Tab 并新增边缘部署命令
将数据看板并入概览,运行状态与配置合并为状态与部署; 边缘节点支持自动填充 Server URL 与 Agent Token 的 Docker 部署卡片。
This commit is contained in:
@@ -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 (
|
||||
<div className='py-6 px-1 space-y-6'>
|
||||
<section className='overflow-hidden rounded-2xl border bg-gradient-to-br from-card via-card to-muted/30'>
|
||||
@@ -144,11 +154,7 @@ export function NodeDetailShell({
|
||||
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
onValueChange={(value) => {
|
||||
if (isValidTab(value)) {
|
||||
setActiveTab(value);
|
||||
}
|
||||
}}
|
||||
onValueChange={handleTabChange}
|
||||
className='w-full gap-0'
|
||||
>
|
||||
<div className='space-y-3 pb-1'>
|
||||
@@ -174,9 +180,6 @@ export function NodeDetailShell({
|
||||
<TabsContent value='overview' className='mt-6 outline-none'>
|
||||
{activeTab === 'overview' ? overview : null}
|
||||
</TabsContent>
|
||||
<TabsContent value='dashboard' className='mt-6 outline-none'>
|
||||
{activeTab === 'dashboard' ? dashboard : null}
|
||||
</TabsContent>
|
||||
<TabsContent value='manage' className='mt-6 outline-none'>
|
||||
{activeTab === 'manage' ? manage : null}
|
||||
</TabsContent>
|
||||
|
||||
Reference in New Issue
Block a user