mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-04-15 00:27:29 +08:00
feat: surface node p2p runtime visibility
This commit is contained in:
@@ -9,6 +9,7 @@ type RuntimeSnapshot = {
|
||||
nodes?: {
|
||||
nodes?: any[];
|
||||
trees?: any[];
|
||||
p2p?: Record<string, any>;
|
||||
};
|
||||
sessions?: {
|
||||
sessions?: Array<{ key: string; title?: string; channel?: string }>;
|
||||
@@ -43,6 +44,8 @@ interface AppContextType {
|
||||
setNodes: (nodes: string) => void;
|
||||
nodeTrees: string;
|
||||
setNodeTrees: (trees: string) => void;
|
||||
nodeP2P: Record<string, any>;
|
||||
setNodeP2P: React.Dispatch<React.SetStateAction<Record<string, any>>>;
|
||||
cron: CronJob[];
|
||||
setCron: (cron: CronJob[]) => void;
|
||||
skills: Skill[];
|
||||
@@ -103,6 +106,7 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
const [configEditing, setConfigEditing] = useState(false);
|
||||
const [nodes, setNodes] = useState('[]');
|
||||
const [nodeTrees, setNodeTrees] = useState('[]');
|
||||
const [nodeP2P, setNodeP2P] = useState<Record<string, any>>({});
|
||||
const [cron, setCron] = useState<CronJob[]>([]);
|
||||
const [skills, setSkills] = useState<Skill[]>([]);
|
||||
const [clawhubInstalled, setClawhubInstalled] = useState(false);
|
||||
@@ -161,6 +165,7 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
const j = await r.json();
|
||||
setNodes(JSON.stringify(j.nodes || [], null, 2));
|
||||
setNodeTrees(JSON.stringify(j.trees || [], null, 2));
|
||||
setNodeP2P(j.p2p || {});
|
||||
setIsGatewayOnline(true);
|
||||
} catch (e) {
|
||||
setIsGatewayOnline(false);
|
||||
@@ -265,6 +270,7 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
if (snapshot.nodes) {
|
||||
setNodes(JSON.stringify(Array.isArray(snapshot.nodes.nodes) ? snapshot.nodes.nodes : [], null, 2));
|
||||
setNodeTrees(JSON.stringify(Array.isArray(snapshot.nodes.trees) ? snapshot.nodes.trees : [], null, 2));
|
||||
setNodeP2P(snapshot.nodes.p2p || {});
|
||||
}
|
||||
if (snapshot.sessions) {
|
||||
const arr = Array.isArray(snapshot.sessions.sessions) ? snapshot.sessions.sessions : [];
|
||||
@@ -343,7 +349,7 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
return (
|
||||
<AppContext.Provider value={{
|
||||
token, setToken, sidebarOpen, setSidebarOpen, sidebarCollapsed, setSidebarCollapsed, isGatewayOnline, setIsGatewayOnline,
|
||||
cfg, setCfg, cfgRaw, setCfgRaw, configEditing, setConfigEditing, nodes, setNodes, nodeTrees, setNodeTrees,
|
||||
cfg, setCfg, cfgRaw, setCfgRaw, configEditing, setConfigEditing, nodes, setNodes, nodeTrees, setNodeTrees, nodeP2P, setNodeP2P,
|
||||
cron, setCron, skills, setSkills, clawhubInstalled, clawhubPath,
|
||||
sessions, setSessions,
|
||||
taskQueueItems, setTaskQueueItems, ekgSummary, setEkgSummary,
|
||||
|
||||
@@ -24,6 +24,7 @@ const resources = {
|
||||
tasks: 'Tasks',
|
||||
subagentProfiles: 'Subagent Profiles',
|
||||
subagentsRuntime: 'Agents',
|
||||
nodeP2P: 'Node P2P',
|
||||
agentTopology: 'Agent Topology',
|
||||
agentTopologyHint: 'Unified graph for local agents, registered nodes, and mirrored remote agent branches.',
|
||||
runningTasks: 'running',
|
||||
@@ -549,6 +550,7 @@ const resources = {
|
||||
tasks: '任务管理',
|
||||
subagentProfiles: '子代理档案',
|
||||
subagentsRuntime: 'Agents',
|
||||
nodeP2P: '节点 P2P',
|
||||
agentTopology: 'Agent 拓扑',
|
||||
agentTopologyHint: '统一展示本地 agent、注册 node 以及远端镜像 agent 分支的关系图。',
|
||||
runningTasks: '运行中',
|
||||
|
||||
@@ -14,6 +14,7 @@ const Dashboard: React.FC = () => {
|
||||
webuiVersion,
|
||||
skills,
|
||||
cfg,
|
||||
nodeP2P,
|
||||
taskQueueItems,
|
||||
ekgSummary,
|
||||
} = useAppContext();
|
||||
@@ -36,6 +37,9 @@ const Dashboard: React.FC = () => {
|
||||
const ekgEscalationCount = Number(ekgSummary?.escalation_count || 0);
|
||||
const ekgTopProvider = (Array.isArray(ekgSummary?.provider_top_workload) ? ekgSummary.provider_top_workload[0]?.key : '') || '-';
|
||||
const ekgTopErrSig = (Array.isArray(ekgSummary?.errsig_top_workload) ? ekgSummary.errsig_top_workload[0]?.key : '') || '-';
|
||||
const p2pEnabled = Boolean(nodeP2P?.enabled);
|
||||
const p2pTransport = String(nodeP2P?.transport || (p2pEnabled ? 'enabled' : 'disabled'));
|
||||
const p2pSessions = Number(nodeP2P?.active_sessions || 0);
|
||||
|
||||
return (
|
||||
<div className="p-4 md:p-6 xl:p-8 w-full space-y-6 xl:space-y-8">
|
||||
@@ -53,12 +57,13 @@ const Dashboard: React.FC = () => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-5 gap-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-6 gap-4">
|
||||
<StatCard title={t('gatewayStatus')} value={isGatewayOnline ? t('online') : t('offline')} icon={<Activity className={`w-6 h-6 ${isGatewayOnline ? 'text-emerald-400' : 'text-red-400'}`} />} />
|
||||
<StatCard title={t('activeSessions')} value={sessions.length} icon={<MessageSquare className="w-6 h-6 text-blue-400" />} />
|
||||
<StatCard title={t('skills')} value={skills.length} icon={<Sparkles className="w-6 h-6 text-pink-400" />} />
|
||||
<StatCard title={t('subagentsRuntime')} value={subagentCount} icon={<Wrench className="w-6 h-6 text-cyan-400" />} />
|
||||
<StatCard title={t('taskAudit')} value={recentTasks.length} icon={<Activity className="w-6 h-6 text-amber-400" />} />
|
||||
<StatCard title={t('nodeP2P')} value={p2pEnabled ? `${p2pSessions} · ${p2pTransport}` : t('disabled')} icon={<Workflow className="w-6 h-6 text-violet-400" />} />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||
|
||||
Reference in New Issue
Block a user