@sleep2agi/agent-network-dashboard 0.4.3-preview.1 → 0.4.5-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +6 -6
- package/.next/diagnostics/route-bundle-stats.json +106 -92
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/server/app/_global-error/page/build-manifest.json +3 -3
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page/build-manifest.json +3 -3
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +2 -2
- package/.next/server/app/_not-found.rsc +12 -12
- package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
- package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin/page/build-manifest.json +3 -3
- package/.next/server/app/admin/page.js.nft.json +1 -1
- package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
- package/.next/server/app/admin.html +2 -2
- package/.next/server/app/admin.rsc +14 -14
- package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
- package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
- package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
- package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
- package/.next/server/app/index.html +2 -2
- package/.next/server/app/index.rsc +14 -14
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/server/app/index.segments/_index.segment.rsc +7 -7
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login/page/build-manifest.json +3 -3
- package/.next/server/app/login/page.js.nft.json +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +2 -2
- package/.next/server/app/login.rsc +14 -14
- package/.next/server/app/login.segments/_full.segment.rsc +14 -14
- package/.next/server/app/login.segments/_head.segment.rsc +4 -4
- package/.next/server/app/login.segments/_index.segment.rsc +7 -7
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/login.segments/login.segment.rsc +3 -3
- package/.next/server/app/logs/page/build-manifest.json +3 -3
- package/.next/server/app/logs/page.js.nft.json +1 -1
- package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/logs.html +2 -2
- package/.next/server/app/logs.rsc +14 -14
- package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
- package/.next/server/app/messages/page/build-manifest.json +3 -3
- package/.next/server/app/messages/page.js.nft.json +1 -1
- package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
- package/.next/server/app/messages.html +2 -2
- package/.next/server/app/messages.rsc +14 -14
- package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
- package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
- package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
- package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
- package/.next/server/app/node/page/build-manifest.json +3 -3
- package/.next/server/app/node/page.js.nft.json +1 -1
- package/.next/server/app/node/page_client-reference-manifest.js +1 -1
- package/.next/server/app/node.html +2 -2
- package/.next/server/app/node.rsc +14 -14
- package/.next/server/app/node.segments/_full.segment.rsc +14 -14
- package/.next/server/app/node.segments/_head.segment.rsc +4 -4
- package/.next/server/app/node.segments/_index.segment.rsc +7 -7
- package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/node.segments/node.segment.rsc +3 -3
- package/.next/server/app/nodes/page/build-manifest.json +3 -3
- package/.next/server/app/nodes/page.js.nft.json +1 -1
- package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/nodes.html +2 -2
- package/.next/server/app/nodes.rsc +14 -14
- package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
- package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
- package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
- package/.next/server/app/page/build-manifest.json +3 -3
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs/page/build-manifest.json +3 -3
- package/.next/server/app/server-logs/page.js.nft.json +1 -1
- package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs.html +2 -2
- package/.next/server/app/server-logs.rsc +14 -14
- package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
- package/.next/server/app/settings/networks/page/build-manifest.json +3 -3
- package/.next/server/app/settings/networks/page.js.nft.json +1 -1
- package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/networks.html +2 -2
- package/.next/server/app/settings/networks.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
- package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings/page/build-manifest.json +3 -3
- package/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens/page/build-manifest.json +3 -3
- package/.next/server/app/settings/tokens/page.js.nft.json +1 -1
- package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens.html +2 -2
- package/.next/server/app/settings/tokens.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
- package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings.html +2 -2
- package/.next/server/app/settings.rsc +14 -14
- package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
- package/.next/server/app/tasks/[id]/page/build-manifest.json +3 -3
- package/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
- package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks/page/build-manifest.json +3 -3
- package/.next/server/app/tasks/page.js.nft.json +1 -1
- package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks.html +2 -2
- package/.next/server/app/tasks.rsc +14 -14
- package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__013i9e9._.js +9 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__013i9e9._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0_jnflc._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0_jnflc._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__12mpoig._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__12mpoig._.js.map +1 -0
- package/.next/server/chunks/ssr/_0d-fuox._.js +3 -0
- package/.next/server/chunks/ssr/_0d-fuox._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0.0wpa~._.js +3 -0
- package/.next/server/chunks/ssr/app_0.0wpa~._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0dk5wao._.js +1 -1
- package/.next/server/chunks/ssr/app_0dk5wao._.js.map +1 -1
- package/.next/server/chunks/ssr/app_0et5yua._.js +3 -0
- package/.next/server/chunks/ssr/app_0et5yua._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0ff~kjj._.js +9 -0
- package/.next/server/chunks/ssr/app_0ff~kjj._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0izi28j._.js +3 -0
- package/.next/server/chunks/ssr/app_0izi28j._.js.map +1 -0
- package/.next/server/chunks/ssr/app_login_page_tsx_0z71ad3._.js +1 -1
- package/.next/server/chunks/ssr/app_login_page_tsx_0z71ad3._.js.map +1 -1
- package/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js +1 -1
- package/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js.map +1 -1
- package/.next/server/chunks/ssr/app_server-logs_page_tsx_0_kpp1p._.js +1 -1
- package/.next/server/chunks/ssr/app_server-logs_page_tsx_0_kpp1p._.js.map +1 -1
- package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js +1 -1
- package/.next/server/chunks/ssr/app_tasks_page_tsx_0z-d6mp._.js.map +1 -1
- package/.next/server/chunks/ssr/node_modules_0ck2~9g._.js +3 -0
- package/.next/server/chunks/ssr/node_modules_0ck2~9g._.js.map +1 -0
- package/.next/server/middleware-build-manifest.js +6 -6
- package/.next/server/pages/404.html +2 -2
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/0257pdz1-imal.js +2 -0
- package/.next/static/chunks/02flrewxlf_m_.js +1 -0
- package/.next/static/chunks/051gslfjka1kj.js +1 -0
- package/.next/static/chunks/06t_vzei8s9_h.js +1 -0
- package/.next/static/chunks/0e-.zgw81gela.js +31 -0
- package/.next/static/chunks/0e7c40p~wq665.js +1 -0
- package/.next/static/chunks/0g7m7zk.v7g6h.js +1 -0
- package/.next/static/chunks/0hyhubmh-__wg.js +1 -0
- package/.next/static/chunks/0khpyxpdrp~ty.js +1 -0
- package/.next/static/chunks/0lo_g.q1fm-hr.js +7 -0
- package/.next/static/chunks/0snd~q2ucn.h1.css +2 -0
- package/.next/static/chunks/0w1zwt8kq_7nb.js +1 -0
- package/.next/static/chunks/0xn9.0ejo1s_a.js +7 -0
- package/.next/static/chunks/0y0lo-~k2c~00.js +1 -0
- package/.next/static/chunks/10njj7kn9ylkf.js +1 -0
- package/.next/static/chunks/13.dst7liziwo.js +1 -0
- package/.next/static/chunks/{turbopack-0vsvjs02l449s.js → turbopack-01f1xs~cq_~si.js} +1 -1
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/EmptyState.tsx +189 -0
- package/app/components/LoadingSkeleton.tsx +3 -18
- package/app/components/Sidebar.tsx +72 -11
- package/app/components/StatsBar.tsx +7 -1
- package/app/components/TopoGraph.tsx +151 -62
- package/app/globals.css +108 -8
- package/app/login/page.tsx +26 -13
- package/app/logs/page.tsx +24 -11
- package/app/messages/page.tsx +2 -5
- package/app/nodes/page.tsx +6 -1
- package/app/page.tsx +36 -12
- package/app/server-logs/page.tsx +22 -11
- package/app/settings/networks/page.tsx +6 -1
- package/app/settings/page.tsx +56 -29
- package/app/settings/tokens/page.tsx +6 -1
- package/app/tasks/page.tsx +7 -9
- package/docs/loop-design-rounds.md +502 -0
- package/docs/oss-readiness-report.md +189 -0
- package/package.json +1 -1
- package/.mcp.json +0 -11
- package/.next/server/chunks/ssr/[root-of-the-server]__093ymui._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__093ymui._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0i1gizm._.js +0 -9
- package/.next/server/chunks/ssr/[root-of-the-server]__0i1gizm._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0~yad5w._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0~yad5w._.js.map +0 -1
- package/.next/server/chunks/ssr/_06_xh1~._.js +0 -3
- package/.next/server/chunks/ssr/_06_xh1~._.js.map +0 -1
- package/.next/server/chunks/ssr/app_01vhyfx._.js +0 -9
- package/.next/server/chunks/ssr/app_01vhyfx._.js.map +0 -1
- package/.next/server/chunks/ssr/app_023a94i._.js +0 -3
- package/.next/server/chunks/ssr/app_023a94i._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0basiqb._.js +0 -3
- package/.next/server/chunks/ssr/app_0basiqb._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0pljk5o._.js +0 -3
- package/.next/server/chunks/ssr/app_0pljk5o._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_0t-hj0x._.js +0 -3
- package/.next/server/chunks/ssr/node_modules_next_dist_0t-hj0x._.js.map +0 -1
- package/.next/static/chunks/0.z~9klrgd.t-.js +0 -1
- package/.next/static/chunks/08aj9~75raaah.js +0 -7
- package/.next/static/chunks/08iom_z8w-wmz.js +0 -7
- package/.next/static/chunks/08v0-ki6vwpxf.js +0 -1
- package/.next/static/chunks/0agna31q2fjq1.css +0 -2
- package/.next/static/chunks/0dkkv90do9a4r.js +0 -1
- package/.next/static/chunks/0e-wrhqh4h3r5.js +0 -2
- package/.next/static/chunks/0ejz4zwhu3a3y.js +0 -1
- package/.next/static/chunks/0o5zj~5vjeks3.js +0 -1
- package/.next/static/chunks/0ttvcv6~g0f6i.js +0 -1
- package/.next/static/chunks/0uqfv6rc-xdru.js +0 -1
- package/.next/static/chunks/0xrnwfefpke-g.js +0 -31
- package/.next/static/chunks/0y_po~f~fk~ap.js +0 -1
- package/.next/static/chunks/0~93h~zb55yh9.js +0 -1
- package/.next/static/chunks/140l7~i5q9wrv.js +0 -1
- package/AGENTS.md +0 -5
- package/DASHBOARD_OPTIMIZATION_PLAN.md +0 -414
- package/docs/iteration-plan.md +0 -62
- package/docs/v4-plan.md +0 -38
- /package/.next/static/{7dwKlhAm5uyghPmkAubQK → 2m1yIfZCIYDWMYrrJEKSC}/_buildManifest.js +0 -0
- /package/.next/static/{7dwKlhAm5uyghPmkAubQK → 2m1yIfZCIYDWMYrrJEKSC}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{7dwKlhAm5uyghPmkAubQK → 2m1yIfZCIYDWMYrrJEKSC}/_ssgManifest.js +0 -0
|
@@ -63,42 +63,123 @@ function truncate(value: string, max: number) {
|
|
|
63
63
|
return value.length > max ? `${value.slice(0, max - 1)}...` : value;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
function nodeStatus(session: Session, isOnline: boolean) {
|
|
66
|
+
function nodeStatus(session: Session, isOnline: boolean, isLight: boolean) {
|
|
67
67
|
if (!isOnline) {
|
|
68
68
|
return {
|
|
69
69
|
label: 'offline',
|
|
70
|
-
primary: '#6b7280',
|
|
71
|
-
halo: '#111827',
|
|
72
|
-
text: '#9ca3af',
|
|
70
|
+
primary: isLight ? '#94a3b8' : '#6b7280',
|
|
71
|
+
halo: isLight ? '#e2e8f0' : '#111827',
|
|
72
|
+
text: isLight ? '#475569' : '#9ca3af',
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
|
-
|
|
76
75
|
if (session.status === 'working') {
|
|
77
76
|
return {
|
|
78
77
|
label: 'working',
|
|
79
|
-
primary: '#22c55e',
|
|
80
|
-
halo: '#14532d',
|
|
81
|
-
text: '#dcfce7',
|
|
78
|
+
primary: isLight ? '#059669' : '#22c55e',
|
|
79
|
+
halo: isLight ? '#d1fae5' : '#14532d',
|
|
80
|
+
text: isLight ? '#065f46' : '#dcfce7',
|
|
82
81
|
};
|
|
83
82
|
}
|
|
84
|
-
|
|
85
83
|
if (session.status === 'idle') {
|
|
86
84
|
return {
|
|
87
85
|
label: 'idle',
|
|
88
|
-
primary: '#2dd4bf',
|
|
89
|
-
halo: '#134e4a',
|
|
90
|
-
text: '#ccfbf1',
|
|
86
|
+
primary: isLight ? '#0d9488' : '#2dd4bf',
|
|
87
|
+
halo: isLight ? '#ccfbf1' : '#134e4a',
|
|
88
|
+
text: isLight ? '#115e59' : '#ccfbf1',
|
|
91
89
|
};
|
|
92
90
|
}
|
|
93
|
-
|
|
94
91
|
return {
|
|
95
92
|
label: session.status || 'online',
|
|
96
|
-
primary: '#38bdf8',
|
|
97
|
-
halo: '#0c4a6e',
|
|
98
|
-
text: '#e0f2fe',
|
|
93
|
+
primary: isLight ? '#0284c7' : '#38bdf8',
|
|
94
|
+
halo: isLight ? '#dbeafe' : '#0c4a6e',
|
|
95
|
+
text: isLight ? '#0c4a6e' : '#e0f2fe',
|
|
99
96
|
};
|
|
100
97
|
}
|
|
101
98
|
|
|
99
|
+
/** Theme-aware color palette for the topology SVG. */
|
|
100
|
+
interface Palette {
|
|
101
|
+
panelStops: [string, string, string];
|
|
102
|
+
radarStops: { color: string; opacity: number }[];
|
|
103
|
+
arrowFill: string;
|
|
104
|
+
ringStroke: string;
|
|
105
|
+
spokeStroke: { active: string; idle: string };
|
|
106
|
+
flowEdge: string;
|
|
107
|
+
flowPath: string;
|
|
108
|
+
flowParticle: string;
|
|
109
|
+
nodeFill: { online: string; offline: string };
|
|
110
|
+
labelBox: { fill: string; stroke: string };
|
|
111
|
+
legendBox: { fill: string; stroke: string };
|
|
112
|
+
legendText: string;
|
|
113
|
+
legendHeadline: string;
|
|
114
|
+
legendAccent: string;
|
|
115
|
+
containerBg: string;
|
|
116
|
+
containerBorder: string;
|
|
117
|
+
topRailGradient: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const DARK_PALETTE: Palette = {
|
|
121
|
+
panelStops: ['#0b1220', '#080814', '#101018'],
|
|
122
|
+
radarStops: [
|
|
123
|
+
{ color: '#22d3ee', opacity: 0.18 },
|
|
124
|
+
{ color: '#22c55e', opacity: 0.045 },
|
|
125
|
+
{ color: '#020617', opacity: 0 },
|
|
126
|
+
],
|
|
127
|
+
arrowFill: '#67e8f9',
|
|
128
|
+
ringStroke: '#164e63',
|
|
129
|
+
spokeStroke: { active: '#22d3ee', idle: '#155e75' },
|
|
130
|
+
flowEdge: '#67e8f9',
|
|
131
|
+
flowPath: '#e0f2fe',
|
|
132
|
+
flowParticle: '#fef08a',
|
|
133
|
+
nodeFill: { online: '#020617', offline: '#080814' },
|
|
134
|
+
labelBox: { fill: '#020617', stroke: '#1f2937' },
|
|
135
|
+
legendBox: { fill: '#020617', stroke: '#1f2937' },
|
|
136
|
+
legendText: '#94a3b8',
|
|
137
|
+
legendHeadline: '#e5e7eb',
|
|
138
|
+
legendAccent: '#67e8f9',
|
|
139
|
+
containerBg: '#080814',
|
|
140
|
+
containerBorder: '#2a2a4a',
|
|
141
|
+
topRailGradient: 'from-transparent via-cyan-400/70 to-transparent',
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const LIGHT_PALETTE: Palette = {
|
|
145
|
+
panelStops: ['#f8fafc', '#ffffff', '#f1f5f9'],
|
|
146
|
+
radarStops: [
|
|
147
|
+
{ color: '#10b981', opacity: 0.06 },
|
|
148
|
+
{ color: '#3b82f6', opacity: 0.03 },
|
|
149
|
+
{ color: '#ffffff', opacity: 0 },
|
|
150
|
+
],
|
|
151
|
+
arrowFill: '#10b981',
|
|
152
|
+
ringStroke: '#cbd5e1',
|
|
153
|
+
spokeStroke: { active: '#10b981', idle: '#cbd5e1' },
|
|
154
|
+
flowEdge: '#10b981',
|
|
155
|
+
flowPath: '#475569',
|
|
156
|
+
flowParticle: '#f59e0b',
|
|
157
|
+
nodeFill: { online: '#ffffff', offline: '#f8fafc' },
|
|
158
|
+
labelBox: { fill: '#ffffff', stroke: '#e2e8f0' },
|
|
159
|
+
legendBox: { fill: '#ffffff', stroke: '#e2e8f0' },
|
|
160
|
+
legendText: '#475569',
|
|
161
|
+
legendHeadline: '#0f172a',
|
|
162
|
+
legendAccent: '#0d9488',
|
|
163
|
+
containerBg: '#ffffff',
|
|
164
|
+
containerBorder: '#e3e6eb',
|
|
165
|
+
topRailGradient: 'from-transparent via-emerald-500/40 to-transparent',
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
function useTheme(): 'light' | 'dark' {
|
|
169
|
+
const [theme, setTheme] = useState<'light' | 'dark'>('dark');
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
const read = () => {
|
|
172
|
+
const t = document.documentElement.getAttribute('data-theme') || 'cyber';
|
|
173
|
+
setTheme(t === 'light' || t === 'mint' ? 'light' : 'dark');
|
|
174
|
+
};
|
|
175
|
+
read();
|
|
176
|
+
const obs = new MutationObserver(read);
|
|
177
|
+
obs.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
|
|
178
|
+
return () => obs.disconnect();
|
|
179
|
+
}, []);
|
|
180
|
+
return theme;
|
|
181
|
+
}
|
|
182
|
+
|
|
102
183
|
function buildFlowLinks(messages: MessageFlow[], positions: Record<string, Point>) {
|
|
103
184
|
const links = new Map<string, FlowLink>();
|
|
104
185
|
|
|
@@ -127,6 +208,9 @@ function buildFlowLinks(messages: MessageFlow[], positions: Record<string, Point
|
|
|
127
208
|
}
|
|
128
209
|
|
|
129
210
|
export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
211
|
+
const theme = useTheme();
|
|
212
|
+
const isLight = theme === 'light';
|
|
213
|
+
const pal = isLight ? LIGHT_PALETTE : DARK_PALETTE;
|
|
130
214
|
const [messages, setMessages] = useState<MessageFlow[]>([]);
|
|
131
215
|
|
|
132
216
|
useEffect(() => {
|
|
@@ -206,30 +290,35 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
206
290
|
</div>
|
|
207
291
|
</div>
|
|
208
292
|
|
|
209
|
-
<div
|
|
210
|
-
|
|
293
|
+
<div
|
|
294
|
+
className={`relative overflow-hidden rounded-lg border shadow-2xl ${isLight ? 'shadow-zinc-900/5' : 'shadow-cyan-950/30'}`}
|
|
295
|
+
style={{ background: pal.containerBg, borderColor: pal.containerBorder }}
|
|
296
|
+
>
|
|
297
|
+
<div className={`absolute inset-x-0 top-0 h-px bg-gradient-to-r ${pal.topRailGradient}`} />
|
|
211
298
|
|
|
212
299
|
<svg viewBox="0 0 1000 680" className="w-full h-auto block" preserveAspectRatio="xMidYMid meet">
|
|
213
300
|
<defs>
|
|
214
301
|
<linearGradient id="topo-panel" x1="0" x2="1" y1="0" y2="1">
|
|
215
|
-
<stop offset="0%"
|
|
216
|
-
<stop offset="48%"
|
|
217
|
-
<stop offset="100%" stopColor=
|
|
302
|
+
<stop offset="0%" stopColor={pal.panelStops[0]} />
|
|
303
|
+
<stop offset="48%" stopColor={pal.panelStops[1]} />
|
|
304
|
+
<stop offset="100%" stopColor={pal.panelStops[2]} />
|
|
218
305
|
</linearGradient>
|
|
219
306
|
<radialGradient id="topo-radar" cx="50%" cy="50%" r="55%">
|
|
220
|
-
<stop offset="0%"
|
|
221
|
-
<stop offset="45%"
|
|
222
|
-
<stop offset="100%" stopColor=
|
|
307
|
+
<stop offset="0%" stopColor={pal.radarStops[0].color} stopOpacity={pal.radarStops[0].opacity} />
|
|
308
|
+
<stop offset="45%" stopColor={pal.radarStops[1].color} stopOpacity={pal.radarStops[1].opacity} />
|
|
309
|
+
<stop offset="100%" stopColor={pal.radarStops[2].color} stopOpacity={pal.radarStops[2].opacity} />
|
|
223
310
|
</radialGradient>
|
|
224
|
-
|
|
225
|
-
<
|
|
226
|
-
|
|
227
|
-
<
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
311
|
+
{!isLight && (
|
|
312
|
+
<filter id="topo-glow">
|
|
313
|
+
<feGaussianBlur stdDeviation="4" result="blur" />
|
|
314
|
+
<feMerge>
|
|
315
|
+
<feMergeNode in="blur" />
|
|
316
|
+
<feMergeNode in="SourceGraphic" />
|
|
317
|
+
</feMerge>
|
|
318
|
+
</filter>
|
|
319
|
+
)}
|
|
231
320
|
<marker id="topo-arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="5" markerHeight="5" orient="auto-start-reverse">
|
|
232
|
-
<path d="M 0 0 L 10 5 L 0 10 z" fill=
|
|
321
|
+
<path d="M 0 0 L 10 5 L 0 10 z" fill={pal.arrowFill} />
|
|
233
322
|
</marker>
|
|
234
323
|
</defs>
|
|
235
324
|
|
|
@@ -238,7 +327,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
238
327
|
|
|
239
328
|
{/* radar rings */}
|
|
240
329
|
{[90, 170, 250, 330].map(radius => (
|
|
241
|
-
<circle key={radius} cx={cx} cy={cy} r={radius} fill="none" stroke=
|
|
330
|
+
<circle key={radius} cx={cx} cy={cy} r={radius} fill="none" stroke={pal.ringStroke} strokeWidth="1" opacity={isLight ? 0.6 : 0.35} />
|
|
242
331
|
))}
|
|
243
332
|
{[0, 30, 60, 90, 120, 150].map(angle => (
|
|
244
333
|
<line
|
|
@@ -247,9 +336,9 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
247
336
|
y1={cy - 360 * Math.sin(angle * Math.PI / 180)}
|
|
248
337
|
x2={cx + 360 * Math.cos(angle * Math.PI / 180)}
|
|
249
338
|
y2={cy + 360 * Math.sin(angle * Math.PI / 180)}
|
|
250
|
-
stroke=
|
|
339
|
+
stroke={pal.ringStroke}
|
|
251
340
|
strokeWidth="1"
|
|
252
|
-
opacity=
|
|
341
|
+
opacity={isLight ? 0.35 : 0.18}
|
|
253
342
|
/>
|
|
254
343
|
))}
|
|
255
344
|
|
|
@@ -264,7 +353,7 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
264
353
|
key={`hub-${session.alias}`}
|
|
265
354
|
d={path}
|
|
266
355
|
fill="none"
|
|
267
|
-
stroke={activeAliases.has(session.alias) ?
|
|
356
|
+
stroke={activeAliases.has(session.alias) ? pal.spokeStroke.active : pal.spokeStroke.idle}
|
|
268
357
|
strokeWidth={activeAliases.has(session.alias) ? 2 : 1}
|
|
269
358
|
strokeDasharray={activeAliases.has(session.alias) ? 'none' : '8 10'}
|
|
270
359
|
opacity={activeAliases.has(session.alias) ? 0.65 : 0.35}
|
|
@@ -288,22 +377,22 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
288
377
|
<path
|
|
289
378
|
d={path}
|
|
290
379
|
fill="none"
|
|
291
|
-
stroke=
|
|
380
|
+
stroke={pal.flowEdge}
|
|
292
381
|
strokeWidth={width}
|
|
293
|
-
opacity=
|
|
294
|
-
filter=
|
|
382
|
+
opacity={isLight ? 0.22 : 0.28}
|
|
383
|
+
filter={isLight ? undefined : 'url(#topo-glow)'}
|
|
295
384
|
markerEnd="url(#topo-arrow)"
|
|
296
385
|
/>
|
|
297
386
|
<path
|
|
298
387
|
id={`flow-path-${index}`}
|
|
299
388
|
d={path}
|
|
300
389
|
fill="none"
|
|
301
|
-
stroke=
|
|
390
|
+
stroke={pal.flowPath}
|
|
302
391
|
strokeWidth="1"
|
|
303
392
|
strokeDasharray="2 12"
|
|
304
|
-
opacity=
|
|
393
|
+
opacity={isLight ? 0.4 : 0.75}
|
|
305
394
|
/>
|
|
306
|
-
<circle r="4" fill=
|
|
395
|
+
<circle r="4" fill={pal.flowParticle} filter={isLight ? undefined : 'url(#topo-glow)'}>
|
|
307
396
|
<animateMotion dur={`${duration}s`} repeatCount="indefinite" path={path} />
|
|
308
397
|
</circle>
|
|
309
398
|
</g>
|
|
@@ -340,38 +429,38 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
340
429
|
|
|
341
430
|
const sseCountFor = (session.network_id ? sseSessions[`${session.network_id}:${session.alias}`] : undefined) ?? sseSessions[session.alias];
|
|
342
431
|
const isOnline = session.status !== 'offline' || !!sseCountFor;
|
|
343
|
-
const status = nodeStatus(session, isOnline);
|
|
432
|
+
const status = nodeStatus(session, isOnline, isLight);
|
|
344
433
|
const isActive = activeAliases.has(session.alias);
|
|
345
434
|
const radius = isOnline ? 26 : 18;
|
|
346
435
|
|
|
347
436
|
return (
|
|
348
437
|
<g key={session.alias} className="transition-opacity">
|
|
349
438
|
{isActive && (
|
|
350
|
-
<circle cx={pos.x} cy={pos.y} r={radius + 14} fill={status.primary} opacity=
|
|
439
|
+
<circle cx={pos.x} cy={pos.y} r={radius + 14} fill={status.primary} opacity={isLight ? 0.08 : 0.12}>
|
|
351
440
|
<animate attributeName="r" values={`${radius + 8};${radius + 22};${radius + 8}`} dur="2.4s" repeatCount="indefinite" />
|
|
352
|
-
<animate attributeName="opacity" values=
|
|
441
|
+
<animate attributeName="opacity" values={isLight ? '0.12;0.02;0.12' : '0.18;0.04;0.18'} dur="2.4s" repeatCount="indefinite" />
|
|
353
442
|
</circle>
|
|
354
443
|
)}
|
|
355
|
-
<circle cx={pos.x} cy={pos.y} r={radius + 8} fill={status.halo} opacity={isOnline ? 0.55 : 0.25} />
|
|
444
|
+
<circle cx={pos.x} cy={pos.y} r={radius + 8} fill={status.halo} opacity={isOnline ? (isLight ? 0.85 : 0.55) : (isLight ? 0.4 : 0.25)} />
|
|
356
445
|
<circle
|
|
357
446
|
cx={pos.x}
|
|
358
447
|
cy={pos.y}
|
|
359
448
|
r={radius}
|
|
360
|
-
fill={isOnline ?
|
|
449
|
+
fill={isOnline ? pal.nodeFill.online : pal.nodeFill.offline}
|
|
361
450
|
stroke={status.primary}
|
|
362
451
|
strokeWidth={isOnline ? 3 : 1.5}
|
|
363
452
|
strokeDasharray={isOnline ? 'none' : '5 5'}
|
|
364
|
-
filter={isOnline ? 'url(#topo-glow)' : undefined}
|
|
453
|
+
filter={isOnline && !isLight ? 'url(#topo-glow)' : undefined}
|
|
365
454
|
/>
|
|
366
455
|
<circle cx={pos.x} cy={pos.y} r={isOnline ? 8 : 5} fill={status.primary} />
|
|
367
456
|
{session.status === 'working' && (
|
|
368
|
-
<path d={`M${pos.x - 9},${pos.y + 11} h18`} stroke=
|
|
457
|
+
<path d={`M${pos.x - 9},${pos.y + 11} h18`} stroke={pal.flowParticle} strokeWidth="3" strokeLinecap="round">
|
|
369
458
|
<animate attributeName="opacity" values="1;0.25;1" dur="1.1s" repeatCount="indefinite" />
|
|
370
459
|
</path>
|
|
371
460
|
)}
|
|
372
461
|
|
|
373
462
|
<g transform={`translate(${pos.x}, ${pos.y + radius + 22})`}>
|
|
374
|
-
<rect x="-62" y="-14" width="124" height="42" rx="6" fill=
|
|
463
|
+
<rect x="-62" y="-14" width="124" height="42" rx="6" fill={pal.labelBox.fill} stroke={pal.labelBox.stroke} opacity={isLight ? 1 : 0.94} />
|
|
375
464
|
<text x="0" y="1" textAnchor="middle" fill={status.text} fontSize="12" fontFamily="monospace" fontWeight="700">
|
|
376
465
|
{truncate(session.alias, 14)}
|
|
377
466
|
</text>
|
|
@@ -385,11 +474,11 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
385
474
|
|
|
386
475
|
{/* latest flow labels */}
|
|
387
476
|
<g transform="translate(28, 34)">
|
|
388
|
-
<rect x="0" y="0" width="285" height={60 + Math.min(flowLinks.length, 4) * 20} rx="8" fill=
|
|
389
|
-
<text x="16" y="26" fill=
|
|
390
|
-
<text x="178" y="26" fill=
|
|
477
|
+
<rect x="0" y="0" width="285" height={60 + Math.min(flowLinks.length, 4) * 20} rx="8" fill={pal.legendBox.fill} stroke={pal.legendBox.stroke} opacity={isLight ? 1 : 0.94} />
|
|
478
|
+
<text x="16" y="26" fill={pal.legendHeadline} fontSize="13" fontFamily="monospace" fontWeight="700">recent signal</text>
|
|
479
|
+
<text x="178" y="26" fill={pal.legendAccent} fontSize="11" fontFamily="monospace">{messages.length} messages</text>
|
|
391
480
|
{flowLinks.slice(0, 4).map((link, index) => (
|
|
392
|
-
<text key={link.key} x="16" y={54 + index * 20} fill=
|
|
481
|
+
<text key={link.key} x="16" y={54 + index * 20} fill={pal.legendText} fontSize="10" fontFamily="monospace">
|
|
393
482
|
{truncate(link.from, 8)} {'->'} {truncate(link.to, 8)} / {link.count} / {truncate(link.content, 18)}
|
|
394
483
|
</text>
|
|
395
484
|
))}
|
|
@@ -397,14 +486,14 @@ export function TopoGraph({ sessions, sseSessions }: TopoGraphProps) {
|
|
|
397
486
|
|
|
398
487
|
{/* legend */}
|
|
399
488
|
<g transform="translate(720, 34)">
|
|
400
|
-
<rect x="0" y="0" width="250" height="112" rx="8" fill=
|
|
401
|
-
<circle cx="18" cy="26" r="6" fill=
|
|
402
|
-
<text x="34" y="30" fill=
|
|
403
|
-
<circle cx="18" cy="52" r="6" fill=
|
|
404
|
-
<text x="34" y="56" fill=
|
|
405
|
-
<circle cx="18" cy="78" r="6" fill=
|
|
406
|
-
<text x="34" y="82" fill=
|
|
407
|
-
<path d="M150,78 Q176,52 210,78" fill="none" stroke=
|
|
489
|
+
<rect x="0" y="0" width="250" height="112" rx="8" fill={pal.legendBox.fill} stroke={pal.legendBox.stroke} opacity={isLight ? 1 : 0.94} />
|
|
490
|
+
<circle cx="18" cy="26" r="6" fill={isLight ? '#059669' : '#22c55e'} />
|
|
491
|
+
<text x="34" y="30" fill={pal.legendText} fontSize="11" fontFamily="monospace">working node</text>
|
|
492
|
+
<circle cx="18" cy="52" r="6" fill={isLight ? '#0d9488' : '#2dd4bf'} />
|
|
493
|
+
<text x="34" y="56" fill={pal.legendText} fontSize="11" fontFamily="monospace">online idle</text>
|
|
494
|
+
<circle cx="18" cy="78" r="6" fill={isLight ? '#94a3b8' : '#6b7280'} />
|
|
495
|
+
<text x="34" y="82" fill={pal.legendText} fontSize="11" fontFamily="monospace">offline / no SSE</text>
|
|
496
|
+
<path d="M150,78 Q176,52 210,78" fill="none" stroke={pal.flowEdge} strokeWidth="3" markerEnd="url(#topo-arrow)" />
|
|
408
497
|
</g>
|
|
409
498
|
</svg>
|
|
410
499
|
</div>
|
package/app/globals.css
CHANGED
|
@@ -429,20 +429,21 @@ body {
|
|
|
429
429
|
keep the existing tinted-pill look. */
|
|
430
430
|
[data-theme="light"] .anet-nav-active,
|
|
431
431
|
[data-theme="mint"] .anet-nav-active {
|
|
432
|
-
/*
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
432
|
+
/* 通信龙 final spec (Q1 + 3-piece lockdown): active nav = ONE cue.
|
|
433
|
+
4px left bar emerald, text in --fg (NOT emerald), NO bg tint.
|
|
434
|
+
Reads as a calm "current page" indicator without competing emerald
|
|
435
|
+
surfaces. (Earlier 0.4.3 had 3px + faint tint + emerald text.) */
|
|
436
|
+
background-color: transparent !important;
|
|
436
437
|
border-color: transparent !important;
|
|
437
|
-
border-left:
|
|
438
|
+
border-left: 4px solid var(--accent) !important;
|
|
438
439
|
border-radius: 0 8px 8px 0 !important;
|
|
439
|
-
padding-left: calc(0.75rem -
|
|
440
|
-
color: var(--
|
|
440
|
+
padding-left: calc(0.75rem - 4px) !important;
|
|
441
|
+
color: var(--fg) !important;
|
|
441
442
|
font-weight: 600;
|
|
442
443
|
}
|
|
443
444
|
[data-theme="light"] .anet-nav-active:hover,
|
|
444
445
|
[data-theme="mint"] .anet-nav-active:hover {
|
|
445
|
-
background-color:
|
|
446
|
+
background-color: var(--bg-elevated) !important;
|
|
446
447
|
}
|
|
447
448
|
/* When sidebar is collapsed (w-16, justify-center) the left bar would look
|
|
448
449
|
weird against a centered icon — switch to a left-bg accent instead. */
|
|
@@ -450,6 +451,105 @@ body {
|
|
|
450
451
|
[data-theme="mint"] aside.w-16 .anet-nav-active {
|
|
451
452
|
border-radius: 8px !important;
|
|
452
453
|
padding-left: 0 !important;
|
|
454
|
+
border-left: 0 !important;
|
|
455
|
+
background-color: var(--bg-elevated) !important;
|
|
456
|
+
color: var(--accent) !important;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* Q6: native <select> theming for light/mint.
|
|
460
|
+
Without this, dropdowns on Nodes / Messages / Logs / Settings render with
|
|
461
|
+
the OS default chrome (heavy chevron, off-spec font weight, no border
|
|
462
|
+
radius). We strip the native chrome with appearance-none, then paint our
|
|
463
|
+
own chevron via a background-image SVG. ~10 LOC. */
|
|
464
|
+
[data-theme="light"] select,
|
|
465
|
+
[data-theme="mint"] select {
|
|
466
|
+
-webkit-appearance: none !important;
|
|
467
|
+
-moz-appearance: none !important;
|
|
468
|
+
appearance: none !important;
|
|
469
|
+
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%23525a66' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 8l5 5 5-5'/%3E%3C/svg%3E") !important;
|
|
470
|
+
background-repeat: no-repeat !important;
|
|
471
|
+
background-position: right 0.6rem center !important;
|
|
472
|
+
background-size: 1rem 1rem !important;
|
|
473
|
+
padding-right: 2rem !important;
|
|
474
|
+
background-color: var(--bg-secondary) !important;
|
|
475
|
+
border-radius: 8px;
|
|
476
|
+
}
|
|
477
|
+
[data-theme="light"] select:focus,
|
|
478
|
+
[data-theme="mint"] select:focus {
|
|
479
|
+
outline: 2px solid rgba(0, 158, 126, 0.2);
|
|
480
|
+
outline-offset: -1px;
|
|
481
|
+
border-color: var(--accent) !important;
|
|
482
|
+
}
|
|
483
|
+
/* Mint reuses the same chevron — color picker would need its own gray, but
|
|
484
|
+
accent is similar enough that the default chevron color reads OK. */
|
|
485
|
+
|
|
486
|
+
/* KPI stat cards in light mode: kill the gradient wash (which reads as
|
|
487
|
+
pale-mud on white), replace with a 2px top accent strip per color
|
|
488
|
+
family + real elevation shadow. Dark themes keep the gradient. */
|
|
489
|
+
[data-theme="light"] .anet-stat-card,
|
|
490
|
+
[data-theme="mint"] .anet-stat-card {
|
|
491
|
+
border-top-width: 2px;
|
|
492
|
+
box-shadow: 0 1px 0 rgba(15, 23, 42, 0.04), 0 4px 12px -8px rgba(15, 23, 42, 0.08);
|
|
493
|
+
}
|
|
494
|
+
[data-theme="light"] .anet-stat-card:hover,
|
|
495
|
+
[data-theme="mint"] .anet-stat-card:hover {
|
|
496
|
+
box-shadow: 0 1px 0 rgba(15, 23, 42, 0.06), 0 12px 24px -12px rgba(15, 23, 42, 0.16);
|
|
497
|
+
}
|
|
498
|
+
/* Top-strip colors per stat family */
|
|
499
|
+
[data-theme="light"] .anet-stat-card[data-anet-stat-card="green"] { border-top-color: #10b981; }
|
|
500
|
+
[data-theme="light"] .anet-stat-card[data-anet-stat-card="cyan"] { border-top-color: var(--accent); }
|
|
501
|
+
[data-theme="light"] .anet-stat-card[data-anet-stat-card="gray"] { border-top-color: #94a3b8; }
|
|
502
|
+
[data-theme="light"] .anet-stat-card[data-anet-stat-card="white"] { border-top-color: #3b82f6; }
|
|
503
|
+
[data-theme="mint"] .anet-stat-card[data-anet-stat-card="green"] { border-top-color: #16a34a; }
|
|
504
|
+
[data-theme="mint"] .anet-stat-card[data-anet-stat-card="cyan"] { border-top-color: var(--accent); }
|
|
505
|
+
[data-theme="mint"] .anet-stat-card[data-anet-stat-card="gray"] { border-top-color: #4ade80; }
|
|
506
|
+
[data-theme="mint"] .anet-stat-card[data-anet-stat-card="white"] { border-top-color: #0891b2; }
|
|
507
|
+
/* Drop the gradient wash in light themes — looks like dust on white. */
|
|
508
|
+
[data-theme="light"] .anet-stat-card > .pointer-events-none,
|
|
509
|
+
[data-theme="mint"] .anet-stat-card > .pointer-events-none {
|
|
510
|
+
display: none;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/* Generic card hover elevation — every white card on light bg gets a
|
|
514
|
+
subtle lift on hover so clickability is obvious. */
|
|
515
|
+
[data-theme="light"] .bg-\[\#111128\]:hover,
|
|
516
|
+
[data-theme="mint"] .bg-\[\#111128\]:hover {
|
|
517
|
+
box-shadow: 0 6px 18px -10px rgba(15, 23, 42, 0.12);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/* ─────────────────────────────────────────────────────────────────────
|
|
521
|
+
Login surface (round 1 polish)
|
|
522
|
+
Restrained, minimal — first impression for new Agent Network users.
|
|
523
|
+
─────────────────────────────────────────────────────────────────── */
|
|
524
|
+
.anet-login-bg {
|
|
525
|
+
background:
|
|
526
|
+
radial-gradient(circle at 50% 30%, rgba(34, 211, 238, 0.05), transparent 55%),
|
|
527
|
+
radial-gradient(circle at 33% 75%, rgba(59, 130, 246, 0.045), transparent 55%);
|
|
528
|
+
}
|
|
529
|
+
[data-theme="light"] .anet-login-bg,
|
|
530
|
+
[data-theme="mint"] .anet-login-bg {
|
|
531
|
+
background-image:
|
|
532
|
+
radial-gradient(circle at 50% 35%, rgba(0, 158, 126, 0.06), transparent 60%),
|
|
533
|
+
radial-gradient(circle, rgba(15, 23, 42, 0.05) 1px, transparent 1px);
|
|
534
|
+
background-size: 100% 100%, 24px 24px;
|
|
535
|
+
}
|
|
536
|
+
[data-theme="light"] .anet-login-mark,
|
|
537
|
+
[data-theme="mint"] .anet-login-mark {
|
|
538
|
+
background: var(--bg-secondary) !important;
|
|
539
|
+
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06), 0 0 0 1px var(--border);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/* Sidebar brand "online" pulse — slow, restrained, NO glow.
|
|
543
|
+
1.6s opacity drift between 1.0 and 0.5; nothing scales, nothing blurs. */
|
|
544
|
+
@keyframes anet-brand-pulse-kf {
|
|
545
|
+
0%, 100% { opacity: 1; }
|
|
546
|
+
50% { opacity: 0.4; }
|
|
547
|
+
}
|
|
548
|
+
.anet-brand-pulse {
|
|
549
|
+
animation: anet-brand-pulse-kf 1.6s ease-in-out infinite;
|
|
550
|
+
}
|
|
551
|
+
@media (prefers-reduced-motion: reduce) {
|
|
552
|
+
.anet-brand-pulse { animation: none; }
|
|
453
553
|
}
|
|
454
554
|
|
|
455
555
|
/* P0-3 baseline: error / warning chip colors for light themes.
|
package/app/login/page.tsx
CHANGED
|
@@ -44,21 +44,32 @@ export default function LoginPage() {
|
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
return (
|
|
47
|
-
<main className="min-h-screen bg-[#0a0a1a] text-gray-100 font-mono flex items-center justify-center relative overflow-hidden">
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
<main className="min-h-screen bg-[#0a0a1a] text-gray-100 font-mono flex items-center justify-center relative overflow-hidden px-4 py-10 sm:py-16">
|
|
48
|
+
{/* Subtle off-grid background — restraint over AI-glow.
|
|
49
|
+
Dark themes get a faint radial wash; light themes show a low-contrast
|
|
50
|
+
dotted grid for surface texture without noise. */}
|
|
51
|
+
<div className="absolute inset-0 pointer-events-none anet-login-bg" aria-hidden />
|
|
52
52
|
|
|
53
|
-
<div className="relative w-full max-w-sm
|
|
54
|
-
<div className="text-center mb-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
<div className="relative w-full max-w-sm">
|
|
54
|
+
<div className="text-center mb-7">
|
|
55
|
+
{/* Brand mark — uses the favicon 3-node mesh SVG which IS the
|
|
56
|
+
agent-network concept (nodes + edges). Replaces the previous
|
|
57
|
+
flat emerald square placeholder. */}
|
|
58
|
+
<div className="inline-flex items-center justify-center w-16 h-16 mb-4 rounded-2xl bg-[#111128] border border-[#2a2a4a] anet-login-mark">
|
|
59
|
+
<svg className="w-9 h-9" viewBox="0 0 32 32" aria-hidden>
|
|
60
|
+
<circle cx="16" cy="16" r="10" fill="none" stroke="currentColor" strokeWidth="1.5" opacity="0.25" className="text-cyan-400 anet-login-mark-ring" />
|
|
61
|
+
<line x1="16" y1="10" x2="10" y2="20" stroke="currentColor" strokeWidth="1" opacity="0.5" className="text-cyan-400 anet-login-mark-edge" />
|
|
62
|
+
<line x1="16" y1="10" x2="22" y2="20" stroke="currentColor" strokeWidth="1" opacity="0.5" className="text-cyan-400 anet-login-mark-edge" />
|
|
63
|
+
<line x1="10" y1="20" x2="22" y2="20" stroke="currentColor" strokeWidth="1" opacity="0.5" className="text-cyan-400 anet-login-mark-edge" />
|
|
64
|
+
<circle cx="16" cy="10" r="3" fill="currentColor" className="text-cyan-400 anet-login-mark-node-a" />
|
|
65
|
+
<circle cx="10" cy="20" r="3" fill="currentColor" className="text-green-400 anet-login-mark-node-b" />
|
|
66
|
+
<circle cx="22" cy="20" r="3" fill="currentColor" className="text-violet-400 anet-login-mark-node-c" />
|
|
58
67
|
</svg>
|
|
59
68
|
</div>
|
|
60
|
-
<h1 className="text-2xl font-
|
|
61
|
-
<p className="text-
|
|
69
|
+
<h1 className="text-[22px] sm:text-2xl font-semibold text-white tracking-tight">Agent Network</h1>
|
|
70
|
+
<p className="text-[13px] text-gray-500 mt-1.5 leading-snug">
|
|
71
|
+
One control plane for your AI agents · <span className="text-gray-600">Tasks · Mesh · Messages</span>
|
|
72
|
+
</p>
|
|
62
73
|
</div>
|
|
63
74
|
|
|
64
75
|
{/* Mode toggle */}
|
|
@@ -96,7 +107,9 @@ export default function LoginPage() {
|
|
|
96
107
|
</button>
|
|
97
108
|
</form>
|
|
98
109
|
|
|
99
|
-
<p className="text-center text-
|
|
110
|
+
<p className="text-center text-[11px] text-gray-700 mt-6">
|
|
111
|
+
Sleep2AGI · Apache-2.0 · <a href="https://anet.sh" className="hover:text-gray-500 transition-colors">anet.sh</a>
|
|
112
|
+
</p>
|
|
100
113
|
</div>
|
|
101
114
|
</main>
|
|
102
115
|
);
|
package/app/logs/page.tsx
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect, useCallback } from 'react';
|
|
4
|
+
import Link from 'next/link';
|
|
4
5
|
import { timeAgo } from '../components/utils';
|
|
5
6
|
import { useNetworkId } from '../lib/network-context';
|
|
7
|
+
import { EmptyState } from '../components/EmptyState';
|
|
6
8
|
|
|
7
9
|
interface AuditLog {
|
|
8
10
|
id: string;
|
|
@@ -84,17 +86,32 @@ export default function LogsPage() {
|
|
|
84
86
|
</div>
|
|
85
87
|
|
|
86
88
|
{error && (() => {
|
|
87
|
-
// Don't dump raw error JSON to users — translate known patterns
|
|
89
|
+
// Don't dump raw error JSON to users — translate known patterns,
|
|
90
|
+
// and give them a clickable recovery affordance.
|
|
88
91
|
const isAuth = /unauthor|401|forbidden|403|admin/i.test(error);
|
|
89
|
-
const human = isAuth
|
|
90
|
-
? '需要登录才能查看审计日志(admin 角色可看全部)'
|
|
91
|
-
: '加载失败 —— 请稍后重试';
|
|
92
92
|
return (
|
|
93
93
|
<div className="anet-warn-chip bg-yellow-900/20 border border-yellow-800/40 text-yellow-300 px-4 py-3 rounded-lg mb-6 text-sm flex items-start gap-3" role="alert">
|
|
94
94
|
<span aria-hidden className="text-base leading-none">⚠</span>
|
|
95
95
|
<div className="flex-1">
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
{isAuth ? (
|
|
97
|
+
<>
|
|
98
|
+
<div className="font-medium">需要 admin 权限查看审计日志</div>
|
|
99
|
+
<div className="text-xs opacity-80 mt-1">
|
|
100
|
+
审计日志记录用户注册 / 登录 / 网络变更等事件,需要 admin 角色。
|
|
101
|
+
</div>
|
|
102
|
+
<Link href="/login" className="inline-block mt-2 text-xs font-medium underline underline-offset-4 hover:opacity-80">
|
|
103
|
+
切到 admin 账号 →
|
|
104
|
+
</Link>
|
|
105
|
+
</>
|
|
106
|
+
) : (
|
|
107
|
+
<>
|
|
108
|
+
<div className="font-medium">加载失败</div>
|
|
109
|
+
<div className="text-xs opacity-80 mt-1">请检查 CommHub 是否在线,或稍后重试。</div>
|
|
110
|
+
<button onClick={() => window.location.reload()} className="inline-block mt-2 text-xs font-medium underline underline-offset-4 hover:opacity-80">
|
|
111
|
+
重新加载 →
|
|
112
|
+
</button>
|
|
113
|
+
</>
|
|
114
|
+
)}
|
|
98
115
|
</div>
|
|
99
116
|
</div>
|
|
100
117
|
);
|
|
@@ -105,11 +122,7 @@ export default function LogsPage() {
|
|
|
105
122
|
{[1,2,3,4,5].map(i => <div key={i} className="h-14 bg-gray-800/20 rounded-lg" />)}
|
|
106
123
|
</div>
|
|
107
124
|
) : logs.length === 0 ? (
|
|
108
|
-
<
|
|
109
|
-
<div className="text-gray-600 text-4xl mb-4">--</div>
|
|
110
|
-
<h3 className="text-gray-400 text-lg font-medium mb-2">No audit logs</h3>
|
|
111
|
-
<p className="text-gray-600 text-sm">Events will appear here when users register, login, or perform actions.</p>
|
|
112
|
-
</div>
|
|
125
|
+
<EmptyState variant="logs" />
|
|
113
126
|
) : (
|
|
114
127
|
<div className="space-y-2">
|
|
115
128
|
{logs.map(log => (
|
package/app/messages/page.tsx
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useMemo, useState } from 'react';
|
|
4
4
|
import { useMessages } from '../lib/hooks';
|
|
5
5
|
import { timeAgo } from '../components/utils';
|
|
6
|
+
import { EmptyState } from '../components/EmptyState';
|
|
6
7
|
|
|
7
8
|
interface MessageItem {
|
|
8
9
|
id: string;
|
|
@@ -186,11 +187,7 @@ export default function MessagesPage() {
|
|
|
186
187
|
{[1, 2, 3, 4, 5].map(i => <div key={i} className="h-20 rounded-2xl bg-gray-800/20" />)}
|
|
187
188
|
</div>
|
|
188
189
|
) : filtered.length === 0 ? (
|
|
189
|
-
<
|
|
190
|
-
<div className="text-gray-600 text-4xl mb-4">--</div>
|
|
191
|
-
<h3 className="text-gray-400 text-lg font-medium mb-2">No messages</h3>
|
|
192
|
-
<p className="text-gray-600 text-sm">Messages between agents will appear here.</p>
|
|
193
|
-
</div>
|
|
190
|
+
<EmptyState variant="messages" />
|
|
194
191
|
) : viewMode === 'grouped' ? (
|
|
195
192
|
<div className="space-y-4">
|
|
196
193
|
{conversations.map((conv, ci) => (
|