@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
package/app/nodes/page.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import Link from 'next/link';
|
|
|
5
5
|
import { timeAgo } from '../components/utils';
|
|
6
6
|
import { useSessions, useHealth } from '../lib/hooks';
|
|
7
7
|
import { TaskChatPanel } from '../components/TaskChatPanel';
|
|
8
|
+
import { EmptyState } from '../components/EmptyState';
|
|
8
9
|
import type { Session } from '../components/types';
|
|
9
10
|
|
|
10
11
|
const STATUS_COLORS: Record<string, string> = {
|
|
@@ -163,7 +164,11 @@ export default function NodesPage() {
|
|
|
163
164
|
{[1,2,3,4].map(i => <div key={i} className="h-16 bg-gray-800/20 rounded-lg" />)}
|
|
164
165
|
</div>
|
|
165
166
|
) : filtered.length === 0 ? (
|
|
166
|
-
<
|
|
167
|
+
<EmptyState
|
|
168
|
+
variant="nodes"
|
|
169
|
+
title="No nodes match your filters"
|
|
170
|
+
sub="Try clearing search or status filters, or wait for an agent to register."
|
|
171
|
+
/>
|
|
167
172
|
) : viewMode === 'grid' ? (
|
|
168
173
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
|
169
174
|
{filtered.map(s => {
|
package/app/page.tsx
CHANGED
|
@@ -8,7 +8,8 @@ import { BroadcastBar } from './components/BroadcastBar';
|
|
|
8
8
|
import { TopoGraph } from './components/TopoGraph';
|
|
9
9
|
import { AgentCard } from './components/AgentCard';
|
|
10
10
|
import { InboxPanel } from './components/InboxPanel';
|
|
11
|
-
import { LoadingSkeleton
|
|
11
|
+
import { LoadingSkeleton } from './components/LoadingSkeleton';
|
|
12
|
+
import { NodesEmptyState as EmptyState } from './components/EmptyState';
|
|
12
13
|
import { UserBar } from './components/UserBar';
|
|
13
14
|
import { CommandCenter, useCommandCenter } from './components/CommandCenter';
|
|
14
15
|
import { DispatchPanel } from './components/DispatchPanel';
|
|
@@ -185,19 +186,42 @@ export default function Dashboard() {
|
|
|
185
186
|
</section>
|
|
186
187
|
)}
|
|
187
188
|
|
|
188
|
-
{/* Quick Actions
|
|
189
|
-
|
|
189
|
+
{/* Quick Actions — split into two distinct intents:
|
|
190
|
+
(1) Top: live stat cards (carry data, drill-in on click)
|
|
191
|
+
(2) Bottom: pure nav rail (no number, icon + label)
|
|
192
|
+
Previously these were mixed in one row of 6, mixing data cells
|
|
193
|
+
("0/0", "--", "0") with placeholder arrows ("→ Messages").
|
|
194
|
+
Users couldn't tell which were stats vs which were navigation. */}
|
|
195
|
+
<section className="mb-3 grid grid-cols-3 gap-2 sm:gap-3">
|
|
190
196
|
{[
|
|
191
|
-
{ href: '/nodes', label: 'Nodes', value: `${online}/${total}`, color: 'text-green-400 border-green-500/
|
|
192
|
-
{ href: '/tasks', label: 'Tasks', value: String(Object.values(taskStats).reduce((a, b) => a + b, 0) || '
|
|
193
|
-
{ href: '/tasks?status=failed', label: 'Failed', value: String(taskStats['failed'] || 0), color: taskStats['failed'] ? 'text-red-400 border-red-500/
|
|
194
|
-
{ href: '/messages', label: 'Messages', value: '→', color: 'text-blue-400 border-blue-500/15' },
|
|
195
|
-
{ href: '/logs', label: 'Logs', value: '→', color: 'text-purple-400 border-purple-500/15' },
|
|
196
|
-
{ href: '/admin', label: 'Admin', value: '→', color: 'text-gray-400 border-gray-500/15' },
|
|
197
|
+
{ href: '/nodes', label: 'Nodes', value: `${online}/${total}`, sub: `${online > 0 ? Math.round((online/total)*100) : 0}% online`, color: 'text-green-400 border-green-500/20' },
|
|
198
|
+
{ href: '/tasks', label: 'Tasks', value: String(Object.values(taskStats).reduce((a, b) => a + b, 0) || 0), sub: 'all-time', color: 'text-cyan-400 border-cyan-500/20' },
|
|
199
|
+
{ href: '/tasks?status=failed', label: 'Failed', value: String(taskStats['failed'] || 0), sub: taskStats['failed'] ? 'needs review' : 'none', color: taskStats['failed'] ? 'text-red-400 border-red-500/25' : 'text-gray-500 border-gray-700/30' },
|
|
197
200
|
].map(a => (
|
|
198
|
-
<Link key={a.href} href={a.href} prefetch={false} className={`
|
|
199
|
-
<div className=
|
|
200
|
-
|
|
201
|
+
<Link key={a.href} href={a.href} prefetch={false} className={`anet-stat-link group relative rounded-xl border ${a.color} bg-[#111128] px-3 py-3 transition-all hover:-translate-y-px`}>
|
|
202
|
+
<div className="flex items-baseline justify-between">
|
|
203
|
+
<div className={`text-xl font-semibold tabular-nums ${a.color.split(' ')[0]}`}>{a.value}</div>
|
|
204
|
+
<div className="text-[10px] text-gray-600 group-hover:text-gray-400 transition-colors">View →</div>
|
|
205
|
+
</div>
|
|
206
|
+
<div className="text-[11px] text-gray-400 mt-0.5">{a.label}</div>
|
|
207
|
+
<div className="text-[10px] text-gray-600 mt-px">{a.sub}</div>
|
|
208
|
+
</Link>
|
|
209
|
+
))}
|
|
210
|
+
</section>
|
|
211
|
+
|
|
212
|
+
{/* Nav rail — pure navigation, icon + label, no data */}
|
|
213
|
+
<section className="mb-6 grid grid-cols-3 gap-2 sm:gap-3">
|
|
214
|
+
{[
|
|
215
|
+
{ href: '/messages', label: 'Messages', icon: 'M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z' },
|
|
216
|
+
{ href: '/logs', label: 'Audit log', icon: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6 M16 13H8 M16 17H8 M10 9H8' },
|
|
217
|
+
{ href: '/admin', label: 'Admin', icon: 'M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4z M6 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2' },
|
|
218
|
+
].map(a => (
|
|
219
|
+
<Link key={a.href} href={a.href} prefetch={false}
|
|
220
|
+
className="anet-nav-tile flex items-center justify-center gap-2 rounded-xl border border-[#2a2a4a] bg-[#111128] px-3 py-2.5 text-[12px] text-gray-400 hover:text-gray-200 transition-colors">
|
|
221
|
+
<svg className="w-4 h-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
222
|
+
<path d={a.icon} />
|
|
223
|
+
</svg>
|
|
224
|
+
<span>{a.label}</span>
|
|
201
225
|
</Link>
|
|
202
226
|
))}
|
|
203
227
|
</section>
|
package/app/server-logs/page.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
4
|
+
import Link from 'next/link';
|
|
4
5
|
|
|
5
6
|
interface LogLine {
|
|
6
7
|
ts: string;
|
|
@@ -142,22 +143,32 @@ export default function ServerLogsPage() {
|
|
|
142
143
|
</div>
|
|
143
144
|
|
|
144
145
|
{error && (() => {
|
|
145
|
-
// Translate server error to user-friendly copy
|
|
146
|
-
//
|
|
147
|
-
// stays human.
|
|
146
|
+
// Translate server error to user-friendly copy + actionable recovery.
|
|
147
|
+
// Raw error stays in title tooltip for debugging.
|
|
148
148
|
const isAuth = /401|unauthor|forbidden|403|admin/i.test(error);
|
|
149
|
-
const human = isAuth
|
|
150
|
-
? '需要 admin 角色才能查看服务器日志'
|
|
151
|
-
: '服务器日志暂时无法加载';
|
|
152
|
-
const sub = isAuth
|
|
153
|
-
? '请用 admin 账号登录后查看。当前账号没有这个权限。'
|
|
154
|
-
: '请检查 CommHub 是否在线,或稍后重试。';
|
|
155
149
|
return (
|
|
156
150
|
<div className="anet-error-chip mb-3 p-3 rounded border border-red-500/30 bg-red-500/10 text-red-300 text-sm flex items-start gap-3" role="alert">
|
|
157
151
|
<span aria-hidden className="text-base leading-none">⛔</span>
|
|
158
152
|
<div className="flex-1">
|
|
159
|
-
|
|
160
|
-
|
|
153
|
+
{isAuth ? (
|
|
154
|
+
<>
|
|
155
|
+
<div className="font-medium">需要 admin 角色才能查看服务器日志</div>
|
|
156
|
+
<div className="text-xs opacity-80 mt-0.5" title={error}>
|
|
157
|
+
服务器日志包含运行时 stdout/stderr,仅 admin 角色可读。
|
|
158
|
+
</div>
|
|
159
|
+
<Link href="/login" className="inline-block mt-2 text-xs font-medium underline underline-offset-4 hover:opacity-80">
|
|
160
|
+
切到 admin 账号 →
|
|
161
|
+
</Link>
|
|
162
|
+
</>
|
|
163
|
+
) : (
|
|
164
|
+
<>
|
|
165
|
+
<div className="font-medium">服务器日志暂时无法加载</div>
|
|
166
|
+
<div className="text-xs opacity-80 mt-0.5" title={error}>请检查 CommHub 是否在线,或稍后重试。</div>
|
|
167
|
+
<button onClick={() => window.location.reload()} className="inline-block mt-2 text-xs font-medium underline underline-offset-4 hover:opacity-80">
|
|
168
|
+
重新加载 →
|
|
169
|
+
</button>
|
|
170
|
+
</>
|
|
171
|
+
)}
|
|
161
172
|
</div>
|
|
162
173
|
</div>
|
|
163
174
|
);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useEffect, useState, useCallback } from 'react';
|
|
4
4
|
import Link from 'next/link';
|
|
5
5
|
import { timeAgo } from '../../components/utils';
|
|
6
|
+
import { EmptyState } from '../../components/EmptyState';
|
|
6
7
|
import useSWR from 'swr';
|
|
7
8
|
|
|
8
9
|
const fetcher = (url: string) => fetch(url).then(r => r.json());
|
|
@@ -126,7 +127,11 @@ export default function NetworksPage() {
|
|
|
126
127
|
{loading ? (
|
|
127
128
|
<div className="animate-pulse space-y-2">{[1,2].map(i => <div key={i} className="h-14 bg-gray-800/20 rounded" />)}</div>
|
|
128
129
|
) : networks.length === 0 ? (
|
|
129
|
-
<
|
|
130
|
+
<EmptyState
|
|
131
|
+
variant="networks"
|
|
132
|
+
compact
|
|
133
|
+
sub="Create your first network above, or sign in with V3 auth to see existing ones."
|
|
134
|
+
/>
|
|
130
135
|
) : (
|
|
131
136
|
<div className="space-y-3">
|
|
132
137
|
{networks.map(n => (
|
package/app/settings/page.tsx
CHANGED
|
@@ -20,7 +20,11 @@ export default function SettingsPage() {
|
|
|
20
20
|
<div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono">
|
|
21
21
|
<h1 className="text-2xl font-bold text-white mb-6 lg:ml-0 ml-10">Settings</h1>
|
|
22
22
|
|
|
23
|
-
<div className="max-w-2xl space-y-
|
|
23
|
+
<div className="max-w-2xl space-y-8">
|
|
24
|
+
{/* ── Group: Connection ─────────────────────────────────── */}
|
|
25
|
+
<div className="space-y-4">
|
|
26
|
+
<div className="text-[10px] uppercase tracking-[0.12em] text-gray-600 px-1">Connection</div>
|
|
27
|
+
|
|
24
28
|
{/* CommHub Connection */}
|
|
25
29
|
<section className="bg-[#111128] border border-[#2a2a4a] rounded-xl p-5">
|
|
26
30
|
<h2 className="text-sm font-semibold text-gray-300 mb-4">CommHub Connection</h2>
|
|
@@ -96,25 +100,41 @@ export default function SettingsPage() {
|
|
|
96
100
|
</div>
|
|
97
101
|
</div>
|
|
98
102
|
</section>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
{/* ── Group: Account ────────────────────────────────────── */}
|
|
106
|
+
<div className="space-y-4">
|
|
107
|
+
<div className="text-[10px] uppercase tracking-[0.12em] text-gray-600 px-1">Account</div>
|
|
99
108
|
|
|
100
109
|
{/* License */}
|
|
101
110
|
<section className="bg-[#111128] border border-[#2a2a4a] rounded-xl p-5">
|
|
102
|
-
<h2 className="text-sm font-semibold text-gray-300 mb-4">
|
|
111
|
+
<h2 className="text-sm font-semibold text-gray-300 mb-4 flex items-center gap-2">
|
|
112
|
+
License
|
|
113
|
+
{licData?.license && (
|
|
114
|
+
<span
|
|
115
|
+
className={`inline-flex items-center gap-1.5 text-[10px] font-medium px-2 py-0.5 rounded-full border ${
|
|
116
|
+
licData.license.type === 'pro'
|
|
117
|
+
? 'text-green-300 bg-green-500/10 border-green-500/30'
|
|
118
|
+
: licData.license.days_left <= 7
|
|
119
|
+
? 'text-red-300 bg-red-500/10 border-red-500/30'
|
|
120
|
+
: 'text-amber-300 bg-amber-500/10 border-amber-500/30'
|
|
121
|
+
}`}
|
|
122
|
+
>
|
|
123
|
+
<span aria-hidden className="w-1.5 h-1.5 rounded-full bg-current" />
|
|
124
|
+
{licData.license.type}{licData.license.days_left ? ` · ${licData.license.days_left}d left` : ''}
|
|
125
|
+
</span>
|
|
126
|
+
)}
|
|
127
|
+
</h2>
|
|
103
128
|
{licData?.license ? (
|
|
104
129
|
<div className="space-y-3 text-sm">
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
<span className={`${licData.license.days_left <= 7 ? 'text-red-400' : 'text-gray-300'}`}>
|
|
114
|
-
{licData.license.days_left} days
|
|
115
|
-
{licData.license.days_left <= 7 && ' — expiring soon!'}
|
|
116
|
-
</span>
|
|
117
|
-
</div>
|
|
130
|
+
{/* Type + Days Left are summarized in the inline chip in the
|
|
131
|
+
header. Surface "expiring soon" only when relevant. */}
|
|
132
|
+
{licData.license.days_left <= 7 && (
|
|
133
|
+
<div className={rowClass}>
|
|
134
|
+
<span className="text-red-400 font-medium">⚠ Expiring soon</span>
|
|
135
|
+
<span className="text-red-400">{licData.license.days_left} days left</span>
|
|
136
|
+
</div>
|
|
137
|
+
)}
|
|
118
138
|
<div className={rowClass}>
|
|
119
139
|
<span className="text-gray-500">Expires</span>
|
|
120
140
|
<span className={`text-gray-300 ${valueClass}`}>{licData.license.expires_at}</span>
|
|
@@ -195,6 +215,26 @@ export default function SettingsPage() {
|
|
|
195
215
|
{pwdResult && <div className={`mt-2 text-xs ${pwdResult.startsWith('Failed') ? 'text-red-400' : 'text-green-400'}`}>{pwdResult}</div>}
|
|
196
216
|
</section>
|
|
197
217
|
|
|
218
|
+
{/* Session — tone-neutral, no longer "danger zone" red */}
|
|
219
|
+
<section className="bg-[#111128] border border-[#2a2a4a] rounded-xl p-5">
|
|
220
|
+
<h2 className="text-sm font-semibold text-gray-300 mb-4">Sign out</h2>
|
|
221
|
+
<p className="text-xs text-gray-500 mb-3">Signing out clears your dashboard session cookie. You'll return to the login page.</p>
|
|
222
|
+
<button
|
|
223
|
+
onClick={async () => {
|
|
224
|
+
await fetch('/api/auth/logout', { method: 'POST' }).catch(() => {});
|
|
225
|
+
window.location.assign('/login');
|
|
226
|
+
}}
|
|
227
|
+
className="px-4 py-2 bg-transparent hover:bg-[#1a1a2a] text-gray-300 text-sm rounded-lg border border-[#2a2a4a] hover:border-[#3a3a5a] transition-colors"
|
|
228
|
+
>
|
|
229
|
+
Sign out
|
|
230
|
+
</button>
|
|
231
|
+
</section>
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
{/* ── Group: Resources ──────────────────────────────────── */}
|
|
235
|
+
<div className="space-y-4">
|
|
236
|
+
<div className="text-[10px] uppercase tracking-[0.12em] text-gray-600 px-1">Resources</div>
|
|
237
|
+
|
|
198
238
|
{/* API Tokens + Networks */}
|
|
199
239
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
200
240
|
<Link href="/settings/tokens" className="bg-[#111128] border border-[#2a2a4a] rounded-xl p-5 hover:border-cyan-500/30 transition-colors">
|
|
@@ -208,21 +248,8 @@ export default function SettingsPage() {
|
|
|
208
248
|
<span className="text-xs text-cyan-400 mt-3 inline-block">Manage →</span>
|
|
209
249
|
</Link>
|
|
210
250
|
</div>
|
|
251
|
+
</div>
|
|
211
252
|
|
|
212
|
-
{/* Danger Zone */}
|
|
213
|
-
<section className="bg-[#111128] border border-red-900/30 rounded-xl p-5">
|
|
214
|
-
<h2 className="text-sm font-semibold text-red-400 mb-4">Session</h2>
|
|
215
|
-
<p className="text-xs text-gray-500 mb-3">Sign out will clear your dashboard session cookie.</p>
|
|
216
|
-
<button
|
|
217
|
-
onClick={async () => {
|
|
218
|
-
await fetch('/api/auth/logout', { method: 'POST' }).catch(() => {});
|
|
219
|
-
window.location.assign('/login');
|
|
220
|
-
}}
|
|
221
|
-
className="px-4 py-2 bg-red-600/20 hover:bg-red-600/30 text-red-300 text-sm rounded-lg border border-red-800/30 transition-colors"
|
|
222
|
-
>
|
|
223
|
-
Sign out
|
|
224
|
-
</button>
|
|
225
|
-
</section>
|
|
226
253
|
</div>
|
|
227
254
|
</div>
|
|
228
255
|
);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useEffect, useState, useCallback } from 'react';
|
|
4
4
|
import Link from 'next/link';
|
|
5
5
|
import { timeAgo } from '../../components/utils';
|
|
6
|
+
import { EmptyState } from '../../components/EmptyState';
|
|
6
7
|
|
|
7
8
|
interface Token {
|
|
8
9
|
token_id: string;
|
|
@@ -100,7 +101,11 @@ export default function TokensPage() {
|
|
|
100
101
|
{loading ? (
|
|
101
102
|
<div className="animate-pulse space-y-2">{[1,2].map(i => <div key={i} className="h-12 bg-gray-800/20 rounded" />)}</div>
|
|
102
103
|
) : tokens.length === 0 ? (
|
|
103
|
-
<
|
|
104
|
+
<EmptyState
|
|
105
|
+
variant="tokens"
|
|
106
|
+
compact
|
|
107
|
+
sub="Tokens authenticate CLI tools and external integrations. Sign in with V3 auth, then create one above."
|
|
108
|
+
/>
|
|
104
109
|
) : (
|
|
105
110
|
<div className="space-y-2">
|
|
106
111
|
{tokens.map(t => (
|
package/app/tasks/page.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import { useSearchParams } from 'next/navigation';
|
|
|
5
5
|
import Link from 'next/link';
|
|
6
6
|
import { useNetworkId } from '../lib/network-context';
|
|
7
7
|
import { TaskDrawer } from '../components/TaskDrawer';
|
|
8
|
+
import { EmptyState } from '../components/EmptyState';
|
|
8
9
|
|
|
9
10
|
interface Task {
|
|
10
11
|
task_id: string;
|
|
@@ -201,15 +202,12 @@ function TasksContent() {
|
|
|
201
202
|
))}
|
|
202
203
|
</div>
|
|
203
204
|
) : tasks.length === 0 ? (
|
|
204
|
-
<
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
: 'Tasks will appear here when agents send them via CommHub.'}
|
|
211
|
-
</p>
|
|
212
|
-
</div>
|
|
205
|
+
<EmptyState
|
|
206
|
+
variant="tasks"
|
|
207
|
+
sub={(filterStatus || filterFrom || filterTo)
|
|
208
|
+
? 'No tasks match the current filters. Try clearing them.'
|
|
209
|
+
: 'Tasks will appear here when agents send them via CommHub.'}
|
|
210
|
+
/>
|
|
213
211
|
) : (
|
|
214
212
|
<div className="space-y-2">
|
|
215
213
|
{/* Table header */}
|