@sleep2agi/agent-network-dashboard 0.4.5-preview.2 → 0.4.5-preview.21
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 +3 -3
- package/.next/diagnostics/route-bundle-stats.json +46 -46
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-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_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_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_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.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.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.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.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.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +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.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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- 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]__02ee4km._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__02ee4km._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0jjqrcf._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0jjqrcf._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0o8yj3c._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0o8yj3c._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0xm3h9x._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0xm3h9x._.js.map +1 -1
- package/.next/server/chunks/ssr/_0nne7mz._.js +3 -0
- package/.next/server/chunks/ssr/_0nne7mz._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0.zbtn5._.js +9 -0
- package/.next/server/chunks/ssr/app_0.zbtn5._.js.map +1 -0
- package/.next/server/chunks/ssr/app_04n78pr._.js +3 -0
- package/.next/server/chunks/ssr/app_04n78pr._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0_agk0r._.js +3 -0
- package/.next/server/chunks/ssr/app_0_agk0r._.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_components_08ys5y3._.js +2 -2
- package/.next/server/chunks/ssr/app_components_08ys5y3._.js.map +1 -1
- package/.next/server/chunks/ssr/app_components_0lhp_k.._.js +3 -0
- package/.next/server/chunks/ssr/app_components_0lhp_k.._.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_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/middleware-build-manifest.js +3 -3
- 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/00-ce-5_uu76b.js +1 -0
- package/.next/static/chunks/0943n0t.9c-o2.js +1 -0
- package/.next/static/chunks/{07okhs5561y5y.js → 0c1bp~g7.8ru..js} +1 -1
- package/.next/static/chunks/0eajktwdxy7qt.js +1 -0
- package/.next/static/chunks/0hqhvq6f83m38.js +1 -0
- package/.next/static/chunks/0irp6cdaafs7m.css +2 -0
- package/.next/static/chunks/0l3gf0ickq445.js +1 -0
- package/.next/static/chunks/0pf4_9.-8s34p.js +1 -0
- package/.next/static/chunks/0q4rltx2ngh5m.js +1 -0
- package/.next/static/chunks/0qnpc7rbxn12u.js +1 -0
- package/.next/static/chunks/10-ka4k4ni9u2.js +1 -0
- package/.next/static/chunks/15nn5pyy3l5zo.js +7 -0
- package/.next/static/chunks/169v~dd1tdxdm.js +7 -0
- package/.next/static/chunks/17uwnuk~0zoo3.js +1 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/AgentCard.tsx +6 -2
- package/app/components/AliasAvatar.tsx +51 -0
- package/app/components/CommandPalette.tsx +53 -20
- package/app/components/HelpOverlay.tsx +50 -10
- package/app/components/Sidebar.tsx +40 -35
- package/app/components/TaskChatPanel.tsx +8 -10
- package/app/components/TaskDrawer.tsx +62 -23
- package/app/components/TopoGraph.tsx +16 -3
- package/app/globals.css +129 -0
- package/app/login/page.tsx +37 -7
- package/app/logs/page.tsx +28 -4
- package/app/messages/page.tsx +79 -48
- package/app/nodes/page.tsx +21 -23
- package/app/page.tsx +66 -13
- package/app/server-logs/page.tsx +37 -3
- package/app/settings/networks/page.tsx +37 -13
- package/app/settings/page.tsx +33 -8
- package/app/tasks/page.tsx +95 -35
- package/package.json +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0_jnflc._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0_jnflc._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0nrckjd._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0nrckjd._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__12mpoig._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__12mpoig._.js.map +0 -1
- package/.next/server/chunks/ssr/_0d-fuox._.js +0 -3
- package/.next/server/chunks/ssr/_0d-fuox._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0.0wpa~._.js +0 -3
- package/.next/server/chunks/ssr/app_0.0wpa~._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0et5yua._.js +0 -3
- package/.next/server/chunks/ssr/app_0et5yua._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0ff~kjj._.js +0 -9
- package/.next/server/chunks/ssr/app_0ff~kjj._.js.map +0 -1
- package/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js +0 -3
- package/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js.map +0 -1
- package/.next/static/chunks/051gslfjka1kj.js +0 -1
- package/.next/static/chunks/06t_vzei8s9_h.js +0 -1
- package/.next/static/chunks/0b1ymo-btjfha.js +0 -1
- package/.next/static/chunks/0e7c40p~wq665.js +0 -1
- package/.next/static/chunks/0g7m7zk.v7g6h.js +0 -1
- package/.next/static/chunks/0khpyxpdrp~ty.js +0 -1
- package/.next/static/chunks/0lo_g.q1fm-hr.js +0 -7
- package/.next/static/chunks/0ogeals5ufhho.js +0 -1
- package/.next/static/chunks/0qgc758gz3on4.js +0 -7
- package/.next/static/chunks/0xxk2ms76kkuz.css +0 -2
- package/.next/static/chunks/1031v6nw33ud3.js +0 -1
- package/.next/static/chunks/10njj7kn9ylkf.js +0 -1
- package/.next/static/chunks/13.dst7liziwo.js +0 -1
- /package/.next/static/{dvjBKNMRovte6RFP_k8Lq → I8oYGCFqEglZXHP7xG8Cd}/_buildManifest.js +0 -0
- /package/.next/static/{dvjBKNMRovte6RFP_k8Lq → I8oYGCFqEglZXHP7xG8Cd}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{dvjBKNMRovte6RFP_k8Lq → I8oYGCFqEglZXHP7xG8Cd}/_ssgManifest.js +0 -0
package/app/globals.css
CHANGED
|
@@ -577,6 +577,30 @@ body {
|
|
|
577
577
|
box-shadow: 0 6px 18px -10px rgba(15, 23, 42, 0.12);
|
|
578
578
|
}
|
|
579
579
|
|
|
580
|
+
/* Task row hover bg (round 19) — dark hex would land on a white card and
|
|
581
|
+
look like a stripe. Re-map to a faint accent tint per theme. */
|
|
582
|
+
[data-theme="light"] .anet-task-row:hover {
|
|
583
|
+
background-color: #f5f7fb !important;
|
|
584
|
+
}
|
|
585
|
+
[data-theme="mint"] .anet-task-row:hover {
|
|
586
|
+
background-color: #ecf6f1 !important;
|
|
587
|
+
}
|
|
588
|
+
[data-theme="sunset"] .anet-task-row:hover {
|
|
589
|
+
background-color: #fff4ec !important;
|
|
590
|
+
}
|
|
591
|
+
/* Open state — slightly stronger fill so users can see "this one is the
|
|
592
|
+
open row" while scrolling. */
|
|
593
|
+
[data-theme="light"] .anet-task-row[aria-expanded="true"] {
|
|
594
|
+
background-color: #fafbfd !important;
|
|
595
|
+
box-shadow: 0 4px 14px -10px rgba(15, 23, 42, 0.14) !important;
|
|
596
|
+
}
|
|
597
|
+
[data-theme="mint"] .anet-task-row[aria-expanded="true"] {
|
|
598
|
+
background-color: #f3faf6 !important;
|
|
599
|
+
}
|
|
600
|
+
[data-theme="sunset"] .anet-task-row[aria-expanded="true"] {
|
|
601
|
+
background-color: #fff8f1 !important;
|
|
602
|
+
}
|
|
603
|
+
|
|
580
604
|
/* ─────────────────────────────────────────────────────────────────────
|
|
581
605
|
Login surface (round 1 polish)
|
|
582
606
|
Restrained, minimal — first impression for new Agent Network users.
|
|
@@ -684,6 +708,45 @@ body {
|
|
|
684
708
|
background-color: rgba(0, 158, 126, 0.08) !important;
|
|
685
709
|
}
|
|
686
710
|
|
|
711
|
+
/* Round 20 — matched-char highlight inside cmdk titles/hints. Inherits
|
|
712
|
+
line color (`color`) instead of forcing one — keeps text readable on
|
|
713
|
+
both inactive (gray) and active (cyan-300) rows. <mark> default is a
|
|
714
|
+
garish yellow block, which we override. */
|
|
715
|
+
.anet-cmdk-mark {
|
|
716
|
+
background: transparent;
|
|
717
|
+
color: inherit;
|
|
718
|
+
font-weight: 600;
|
|
719
|
+
/* Subtle underline so the mark stays visible even on the active row
|
|
720
|
+
where the background tint matches the accent color. */
|
|
721
|
+
text-decoration: underline;
|
|
722
|
+
text-decoration-color: currentColor;
|
|
723
|
+
text-decoration-thickness: 1px;
|
|
724
|
+
text-underline-offset: 2px;
|
|
725
|
+
text-decoration-skip-ink: none;
|
|
726
|
+
}
|
|
727
|
+
/* Cyber: accent the matched glyph color so it pops on the dark bg. */
|
|
728
|
+
[data-theme="cyber"] .anet-cmdk-mark,
|
|
729
|
+
:root:not([data-theme]) .anet-cmdk-mark {
|
|
730
|
+
color: #22d3ee;
|
|
731
|
+
}
|
|
732
|
+
/* Light/mint: use the brand teal — undertone matches the active row. */
|
|
733
|
+
[data-theme="light"] .anet-cmdk-mark,
|
|
734
|
+
[data-theme="mint"] .anet-cmdk-mark {
|
|
735
|
+
color: #0d9488;
|
|
736
|
+
}
|
|
737
|
+
[data-theme="sunset"] .anet-cmdk-mark {
|
|
738
|
+
color: #ea580c;
|
|
739
|
+
}
|
|
740
|
+
/* On the active (cyan-tinted) row, the title is already cyan-300 — use
|
|
741
|
+
white-with-underline so the highlight reads as emphasis, not redundancy. */
|
|
742
|
+
.anet-cmdk-row.bg-cyan-500\/10 .anet-cmdk-mark {
|
|
743
|
+
color: #f0fdff;
|
|
744
|
+
}
|
|
745
|
+
[data-theme="light"] .anet-cmdk-row.bg-cyan-500\/10 .anet-cmdk-mark,
|
|
746
|
+
[data-theme="mint"] .anet-cmdk-row.bg-cyan-500\/10 .anet-cmdk-mark {
|
|
747
|
+
color: #064e3b;
|
|
748
|
+
}
|
|
749
|
+
|
|
687
750
|
/* Help overlay — same white-card-with-shadow treatment as cmdk on light */
|
|
688
751
|
[data-theme="light"] .anet-help > div:not([aria-hidden]),
|
|
689
752
|
[data-theme="mint"] .anet-help > div:not([aria-hidden]) {
|
|
@@ -748,3 +811,69 @@ body {
|
|
|
748
811
|
color: #92400e !important;
|
|
749
812
|
border-color: rgba(217, 119, 6, 0.28) !important;
|
|
750
813
|
}
|
|
814
|
+
|
|
815
|
+
/* Round 30 — global drawer entrance keyframes so TaskDrawer, TaskChatPanel,
|
|
816
|
+
and any future right-side panel share one source. Previously the
|
|
817
|
+
keyframe lived inside TaskChatPanel's <style jsx global>; if that
|
|
818
|
+
component never mounted, the keyframe was missing for TaskDrawer. */
|
|
819
|
+
@keyframes anet-slide-in {
|
|
820
|
+
from { transform: translateX(100%); }
|
|
821
|
+
to { transform: translateX(0); }
|
|
822
|
+
}
|
|
823
|
+
.animate-slide-in { animation: anet-slide-in 0.2s ease-out; }
|
|
824
|
+
|
|
825
|
+
@keyframes anet-fade-in {
|
|
826
|
+
from { opacity: 0; }
|
|
827
|
+
to { opacity: 1; }
|
|
828
|
+
}
|
|
829
|
+
.anet-fade-in { animation: anet-fade-in 0.15s ease-out; }
|
|
830
|
+
|
|
831
|
+
/* Round 36 — current-step ring pulse on TaskDrawer timeline. Halo gently
|
|
832
|
+
breathes around the active step's dot so users can spot "task is here". */
|
|
833
|
+
@keyframes anet-current-step-pulse-kf {
|
|
834
|
+
0%, 100% { transform: scale(1); opacity: 0.6; }
|
|
835
|
+
50% { transform: scale(1.25); opacity: 0.0; }
|
|
836
|
+
}
|
|
837
|
+
.anet-current-step-pulse {
|
|
838
|
+
animation: anet-current-step-pulse-kf 1.6s ease-in-out infinite;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
/* ─────────────────────────────────────────────────────────────────────
|
|
842
|
+
Round 29 — prefers-reduced-motion a11y sweep
|
|
843
|
+
|
|
844
|
+
Rounds 19~27 accumulated a lot of small animations: Tasks row 0fr↔1fr
|
|
845
|
+
expand, chevron rotate, hover bg shifts, Cmd+K popover, TaskChatPanel
|
|
846
|
+
slide-in, brand/skeleton pulses already had their own guards.
|
|
847
|
+
|
|
848
|
+
For users who set system "reduce motion": neutralise everything in one
|
|
849
|
+
pass. Don't kill state changes outright — only their durations and
|
|
850
|
+
keyframes. Hover and focus colours still apply, just instantly.
|
|
851
|
+
───────────────────────────────────────────────────────────────────── */
|
|
852
|
+
@media (prefers-reduced-motion: reduce) {
|
|
853
|
+
*,
|
|
854
|
+
*::before,
|
|
855
|
+
*::after {
|
|
856
|
+
animation-duration: 0.001ms !important;
|
|
857
|
+
animation-iteration-count: 1 !important;
|
|
858
|
+
transition-duration: 0.001ms !important;
|
|
859
|
+
scroll-behavior: auto !important;
|
|
860
|
+
}
|
|
861
|
+
/* Skeleton pulse already has its own guard; harden in case the bar
|
|
862
|
+
class is reused without anet-skeleton-pulse. */
|
|
863
|
+
.anet-skeleton-bar {
|
|
864
|
+
animation: none !important;
|
|
865
|
+
}
|
|
866
|
+
/* Brand pulse hidden — green/red dot still indicates state via color. */
|
|
867
|
+
.anet-brand-pulse {
|
|
868
|
+
animation: none !important;
|
|
869
|
+
}
|
|
870
|
+
/* Drawer entrance kills — keyframes promoted to globals in r30. */
|
|
871
|
+
.animate-slide-in,
|
|
872
|
+
.anet-fade-in,
|
|
873
|
+
.anet-current-step-pulse {
|
|
874
|
+
animation: none !important;
|
|
875
|
+
}
|
|
876
|
+
/* Tasks row grid 0fr↔1fr keep working (it's the toggle mechanism),
|
|
877
|
+
but the smooth transition just snaps. Already handled via the
|
|
878
|
+
blanket transition-duration override above. */
|
|
879
|
+
}
|
package/app/login/page.tsx
CHANGED
|
@@ -6,6 +6,7 @@ export default function LoginPage() {
|
|
|
6
6
|
const [mode, setMode] = useState<'login' | 'register'>('login');
|
|
7
7
|
const [username, setUsername] = useState('');
|
|
8
8
|
const [password, setPassword] = useState('');
|
|
9
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
9
10
|
const [error, setError] = useState('');
|
|
10
11
|
const [pending, setPending] = useState(false);
|
|
11
12
|
|
|
@@ -68,7 +69,9 @@ export default function LoginPage() {
|
|
|
68
69
|
</div>
|
|
69
70
|
<h1 className="text-[22px] sm:text-2xl font-semibold text-white tracking-tight">Agent Network</h1>
|
|
70
71
|
<p className="text-[13px] text-gray-500 mt-1.5 leading-snug">
|
|
71
|
-
|
|
72
|
+
{mode === 'login'
|
|
73
|
+
? <>Welcome back · <span className="text-gray-600">Tasks · Mesh · Messages</span></>
|
|
74
|
+
: <>Create your account · <span className="text-gray-600">Free preview · no credit card</span></>}
|
|
72
75
|
</p>
|
|
73
76
|
</div>
|
|
74
77
|
|
|
@@ -93,17 +96,44 @@ export default function LoginPage() {
|
|
|
93
96
|
<label htmlFor="password" className="block text-xs text-gray-500 mb-2 uppercase tracking-wider">
|
|
94
97
|
Password
|
|
95
98
|
</label>
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
<div className="relative">
|
|
100
|
+
<input id="password" type={showPassword ? 'text' : 'password'} value={password} onChange={e => setPassword(e.target.value)}
|
|
101
|
+
placeholder="Enter password"
|
|
102
|
+
className="w-full bg-[#0a0a15] border border-[#2a2a4a] rounded-lg px-4 pr-11 py-3 text-sm text-white placeholder-gray-600 focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/20 focus:outline-none transition-all" />
|
|
103
|
+
<button
|
|
104
|
+
type="button"
|
|
105
|
+
onClick={() => setShowPassword(s => !s)}
|
|
106
|
+
tabIndex={-1}
|
|
107
|
+
aria-label={showPassword ? 'Hide password' : 'Show password'}
|
|
108
|
+
className="absolute inset-y-0 right-0 flex items-center px-3 text-gray-600 hover:text-gray-300 transition-colors"
|
|
109
|
+
>
|
|
110
|
+
{showPassword ? (
|
|
111
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
112
|
+
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" />
|
|
113
|
+
<line x1="1" y1="1" x2="23" y2="23" />
|
|
114
|
+
</svg>
|
|
115
|
+
) : (
|
|
116
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
117
|
+
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
|
|
118
|
+
<circle cx="12" cy="12" r="3" />
|
|
119
|
+
</svg>
|
|
120
|
+
)}
|
|
121
|
+
</button>
|
|
122
|
+
</div>
|
|
99
123
|
|
|
100
124
|
{error && (
|
|
101
125
|
<div className="mt-3 text-sm text-red-300 bg-red-500/5 border border-red-500/10 rounded-lg px-3 py-2">{error}</div>
|
|
102
126
|
)}
|
|
103
127
|
|
|
104
|
-
<button type="submit" disabled={pending || !password}
|
|
105
|
-
className="mt-5 w-full px-4 py-3 bg-gradient-to-r from-cyan-600 to-blue-600 hover:from-cyan-500 hover:to-blue-500 disabled:from-gray-800 disabled:to-gray-800 disabled:text-gray-600 text-white text-sm font-medium rounded-lg transition-all shadow-lg shadow-cyan-500/10 hover:shadow-cyan-500/20 disabled:shadow-none">
|
|
106
|
-
{pending
|
|
128
|
+
<button type="submit" disabled={pending || !password || !username.trim()}
|
|
129
|
+
className="mt-5 w-full flex items-center justify-center gap-2 px-4 py-3 bg-gradient-to-r from-cyan-600 to-blue-600 hover:from-cyan-500 hover:to-blue-500 disabled:from-gray-800 disabled:to-gray-800 disabled:text-gray-600 text-white text-sm font-medium rounded-lg transition-all shadow-lg shadow-cyan-500/10 hover:shadow-cyan-500/20 disabled:shadow-none">
|
|
130
|
+
{pending && (
|
|
131
|
+
<svg aria-hidden className="w-4 h-4 animate-spin" viewBox="0 0 24 24" fill="none">
|
|
132
|
+
<circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="3" opacity="0.25" />
|
|
133
|
+
<path d="M4 12a8 8 0 018-8" stroke="currentColor" strokeWidth="3" strokeLinecap="round" />
|
|
134
|
+
</svg>
|
|
135
|
+
)}
|
|
136
|
+
<span>{pending ? (mode === 'login' ? 'Signing in…' : 'Registering…') : (mode === 'login' ? 'Sign in' : 'Create account')}</span>
|
|
107
137
|
</button>
|
|
108
138
|
</form>
|
|
109
139
|
|
package/app/logs/page.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import Link from 'next/link';
|
|
|
5
5
|
import { timeAgo } from '../components/utils';
|
|
6
6
|
import { useNetworkId } from '../lib/network-context';
|
|
7
7
|
import { EmptyState } from '../components/EmptyState';
|
|
8
|
+
import { AliasAvatar } from '../components/AliasAvatar';
|
|
8
9
|
|
|
9
10
|
interface AuditLog {
|
|
10
11
|
id: string;
|
|
@@ -26,6 +27,18 @@ const ACTION_COLORS: Record<string, string> = {
|
|
|
26
27
|
send_task: 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20',
|
|
27
28
|
};
|
|
28
29
|
|
|
30
|
+
/** 2px left-rail stripe color per audit action — reuses the r32 server-logs
|
|
31
|
+
* pattern so failed logins / token rotations spike out of a wall of
|
|
32
|
+
* registers and logins without users reading every chip. Inline hex
|
|
33
|
+
* prevents Tailwind v4 from purging dynamic class names. */
|
|
34
|
+
const ACTION_STRIPE: Record<string, string> = {
|
|
35
|
+
register: '#4ade80',
|
|
36
|
+
login: '#60a5fa',
|
|
37
|
+
login_failed: '#ef4444',
|
|
38
|
+
create_network: '#a78bfa',
|
|
39
|
+
send_task: '#22d3ee',
|
|
40
|
+
};
|
|
41
|
+
|
|
29
42
|
export default function LogsPage() {
|
|
30
43
|
const { networkId } = useNetworkId();
|
|
31
44
|
const [logs, setLogs] = useState<AuditLog[]>([]);
|
|
@@ -125,13 +138,23 @@ export default function LogsPage() {
|
|
|
125
138
|
<EmptyState variant="logs" />
|
|
126
139
|
) : (
|
|
127
140
|
<div className="space-y-2">
|
|
128
|
-
{logs.map(log =>
|
|
129
|
-
|
|
141
|
+
{logs.map(log => {
|
|
142
|
+
const userName = log.username || log.user_id;
|
|
143
|
+
return (
|
|
144
|
+
<div key={log.id} className="relative bg-[#111128] border border-[#2a2a4a] rounded-lg pl-4 pr-4 py-3 hover:border-[#3a3a5a] transition-colors overflow-hidden">
|
|
145
|
+
{/* 2px left rail per action (round 33) — failed logins, token
|
|
146
|
+
rotations spike out of a wall of register/login rows. */}
|
|
147
|
+
<span
|
|
148
|
+
aria-hidden
|
|
149
|
+
className="absolute left-0 top-0 bottom-0 w-0.5"
|
|
150
|
+
style={{ backgroundColor: ACTION_STRIPE[log.action] || 'transparent' }}
|
|
151
|
+
/>
|
|
130
152
|
<div className="flex flex-wrap items-center gap-2 mb-1">
|
|
131
153
|
<span className={`text-xs px-2 py-0.5 rounded-md border ${ACTION_COLORS[log.action] || 'bg-gray-500/10 text-gray-400 border-gray-500/20'}`}>
|
|
132
154
|
{log.action}
|
|
133
155
|
</span>
|
|
134
|
-
<
|
|
156
|
+
{userName && <AliasAvatar alias={userName} size={16} />}
|
|
157
|
+
<span className="text-sm text-gray-200 font-medium">{userName}</span>
|
|
135
158
|
{log.target_type && (
|
|
136
159
|
<>
|
|
137
160
|
<span className="text-xs text-gray-600">→</span>
|
|
@@ -143,7 +166,8 @@ export default function LogsPage() {
|
|
|
143
166
|
{log.detail && <div className="text-xs text-gray-500">{log.detail}</div>}
|
|
144
167
|
{log.ip && log.ip !== 'unknown' && <div className="text-[10px] text-gray-700">IP: {log.ip}</div>}
|
|
145
168
|
</div>
|
|
146
|
-
|
|
169
|
+
);
|
|
170
|
+
})}
|
|
147
171
|
</div>
|
|
148
172
|
)}
|
|
149
173
|
</div>
|
package/app/messages/page.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import { useMemo, useState } from 'react';
|
|
|
4
4
|
import { useMessages } from '../lib/hooks';
|
|
5
5
|
import { timeAgo } from '../components/utils';
|
|
6
6
|
import { EmptyState } from '../components/EmptyState';
|
|
7
|
+
import { AliasAvatar } from '../components/AliasAvatar';
|
|
7
8
|
|
|
8
9
|
interface MessageItem {
|
|
9
10
|
id: string;
|
|
@@ -40,6 +41,17 @@ function bubbleVariant(message: MessageItem) {
|
|
|
40
41
|
return 'incoming';
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
/** Render message content, highlighting the search match inline (skips the
|
|
45
|
+
* `from:` filter prefix since it filters by sender, not by content). */
|
|
46
|
+
function renderHighlighted(content: string | undefined, search: string) {
|
|
47
|
+
const text = content || '--';
|
|
48
|
+
const q = search.trim();
|
|
49
|
+
if (!q || q.startsWith('from:')) return text;
|
|
50
|
+
const idx = text.toLowerCase().indexOf(q.toLowerCase());
|
|
51
|
+
if (idx < 0) return text;
|
|
52
|
+
return <>{text.slice(0, idx)}<mark className="bg-yellow-500/30 text-yellow-200 rounded px-0.5">{text.slice(idx, idx + q.length)}</mark>{text.slice(idx + q.length)}</>;
|
|
53
|
+
}
|
|
54
|
+
|
|
43
55
|
export default function MessagesPage() {
|
|
44
56
|
const { messages, isLoading } = useMessages(200);
|
|
45
57
|
const [filterType, setFilterType] = useState('');
|
|
@@ -213,13 +225,21 @@ export default function MessagesPage() {
|
|
|
213
225
|
))}
|
|
214
226
|
</div>
|
|
215
227
|
) : (
|
|
216
|
-
<div className="space-y-
|
|
228
|
+
<div className="space-y-1">
|
|
217
229
|
{filtered.map((message: MessageItem, index) => {
|
|
218
230
|
const previous = filtered[index - 1];
|
|
219
231
|
const gapExceeded = previous
|
|
220
232
|
? normalizeDate(message.created_at) - normalizeDate(previous.created_at) > 5 * 60 * 1000
|
|
221
233
|
: false;
|
|
222
234
|
const variant = bubbleVariant(message);
|
|
235
|
+
// Cluster: same sender + same direction + same to_alias and no
|
|
236
|
+
// time-gap divider → tighter spacing and hide repeated header.
|
|
237
|
+
const samePrev = !!previous
|
|
238
|
+
&& !gapExceeded
|
|
239
|
+
&& bubbleVariant(previous) === variant
|
|
240
|
+
&& (previous.from_alias || '') === (message.from_alias || '')
|
|
241
|
+
&& (previous.to_alias || '') === (message.to_alias || '');
|
|
242
|
+
const fromAlias = message.from_alias || '?';
|
|
223
243
|
|
|
224
244
|
return (
|
|
225
245
|
<div key={message.id}>
|
|
@@ -231,60 +251,71 @@ export default function MessagesPage() {
|
|
|
231
251
|
</div>
|
|
232
252
|
)}
|
|
233
253
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
254
|
+
{/* Broadcasts span full width — no avatar gutter. */}
|
|
255
|
+
{variant === 'broadcast' ? (
|
|
256
|
+
<div className={samePrev ? 'mt-1' : 'mt-3'}>
|
|
257
|
+
<div className="rounded-2xl border border-purple-500/20 bg-purple-500/10 px-4 py-3 shadow-sm w-full">
|
|
258
|
+
<div className="mb-2 flex flex-wrap items-center gap-2">
|
|
259
|
+
<span className={`text-xs px-2 py-0.5 rounded-md border ${TYPE_COLORS[message.type || ''] || 'bg-gray-500/10 text-gray-400 border-gray-500/20'}`}>
|
|
260
|
+
{message.type || 'unknown'}
|
|
261
|
+
</span>
|
|
262
|
+
<span className="text-sm font-medium text-purple-200">{fromAlias}</span>
|
|
263
|
+
{message.to_alias && <span className="text-xs text-purple-200/80">to {message.to_alias}</span>}
|
|
264
|
+
{message.priority === 'high' && <span className="text-xs text-red-400">HIGH</span>}
|
|
265
|
+
<span className="ml-auto text-xs text-gray-500">{message.created_at ? timeAgo(message.created_at) : '--'}</span>
|
|
266
|
+
</div>
|
|
267
|
+
<div className="whitespace-pre-wrap text-sm leading-relaxed text-gray-200">
|
|
268
|
+
{renderHighlighted(message.content, search)}
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
) : (
|
|
273
|
+
<div className={`${samePrev ? 'mt-1' : 'mt-3'} flex gap-2 ${variant === 'outgoing' ? 'flex-row-reverse' : 'flex-row'}`}>
|
|
274
|
+
{/* Avatar gutter — fixed width keeps bubble columns aligned even on streaks */}
|
|
275
|
+
<div className="w-8 shrink-0 pt-1">
|
|
276
|
+
{!samePrev && <AliasAvatar alias={fromAlias} size={32} />}
|
|
277
|
+
</div>
|
|
278
|
+
<div className={`min-w-0 max-w-3xl rounded-2xl border px-4 py-3 shadow-sm ${
|
|
279
|
+
variant === 'outgoing'
|
|
280
|
+
? 'border-green-500/20 bg-green-500/10'
|
|
281
|
+
: 'border-blue-500/20 bg-blue-500/10'
|
|
282
|
+
}`}>
|
|
283
|
+
{!samePrev && (
|
|
284
|
+
<div className="mb-2 flex flex-wrap items-center gap-2">
|
|
285
|
+
<span className={`text-xs px-2 py-0.5 rounded-md border ${TYPE_COLORS[message.type || ''] || 'bg-gray-500/10 text-gray-400 border-gray-500/20'}`}>
|
|
286
|
+
{message.type || 'unknown'}
|
|
287
|
+
</span>
|
|
288
|
+
<span className={`text-sm font-medium ${variant === 'outgoing' ? 'text-green-300' : 'text-blue-300'}`}>
|
|
289
|
+
{fromAlias}
|
|
290
|
+
</span>
|
|
257
291
|
<span className="text-xs text-gray-600">→</span>
|
|
258
292
|
<span className="text-sm text-gray-300">{message.to_alias || '--'}</span>
|
|
259
|
-
|
|
293
|
+
{message.priority === 'high' && <span className="text-xs text-red-400">HIGH</span>}
|
|
294
|
+
<span className="ml-auto text-xs text-gray-500">{message.created_at ? timeAgo(message.created_at) : '--'}</span>
|
|
295
|
+
</div>
|
|
260
296
|
)}
|
|
261
|
-
|
|
262
|
-
|
|
297
|
+
|
|
298
|
+
<div className="whitespace-pre-wrap text-sm leading-relaxed text-gray-200">
|
|
299
|
+
{renderHighlighted(message.content, search)}
|
|
300
|
+
</div>
|
|
301
|
+
|
|
302
|
+
{/* When in a streak, surface the timestamp inline-right so users still know cadence */}
|
|
303
|
+
{samePrev && (
|
|
304
|
+
<div className="mt-1 text-[10px] text-gray-600 text-right">
|
|
305
|
+
{message.created_at ? timeAgo(message.created_at) : ''}
|
|
306
|
+
</div>
|
|
263
307
|
)}
|
|
264
|
-
{message.priority === 'high' && <span className="text-xs text-red-400">HIGH</span>}
|
|
265
|
-
<span className="ml-auto text-xs text-gray-500">{message.created_at ? timeAgo(message.created_at) : '--'}</span>
|
|
266
|
-
</div>
|
|
267
308
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
return <>{text.slice(0, idx)}<mark className="bg-yellow-500/30 text-yellow-200 rounded px-0.5">{text.slice(idx, idx + q.length)}</mark>{text.slice(idx + q.length)}</>;
|
|
276
|
-
})()}
|
|
309
|
+
{debug && (
|
|
310
|
+
<div className="mt-3 border-t border-white/10 pt-3 text-xs text-gray-500 space-y-1">
|
|
311
|
+
<div>ID: {message.id}</div>
|
|
312
|
+
{message.task_id && <div>Task ID: {message.task_id}</div>}
|
|
313
|
+
<div>Created: {message.created_at}</div>
|
|
314
|
+
</div>
|
|
315
|
+
)}
|
|
277
316
|
</div>
|
|
278
|
-
|
|
279
|
-
{debug && (
|
|
280
|
-
<div className="mt-3 border-t border-white/10 pt-3 text-xs text-gray-500 space-y-1">
|
|
281
|
-
<div>ID: {message.id}</div>
|
|
282
|
-
{message.task_id && <div>Task ID: {message.task_id}</div>}
|
|
283
|
-
<div>Created: {message.created_at}</div>
|
|
284
|
-
</div>
|
|
285
|
-
)}
|
|
286
317
|
</div>
|
|
287
|
-
|
|
318
|
+
)}
|
|
288
319
|
</div>
|
|
289
320
|
);
|
|
290
321
|
})}
|
package/app/nodes/page.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import { timeAgo } from '../components/utils';
|
|
|
6
6
|
import { useSessions, useHealth } from '../lib/hooks';
|
|
7
7
|
import { TaskChatPanel } from '../components/TaskChatPanel';
|
|
8
8
|
import { EmptyState } from '../components/EmptyState';
|
|
9
|
+
import { AliasAvatar } from '../components/AliasAvatar';
|
|
9
10
|
import type { Session } from '../components/types';
|
|
10
11
|
|
|
11
12
|
const STATUS_COLORS: Record<string, string> = {
|
|
@@ -188,14 +189,18 @@ export default function NodesPage() {
|
|
|
188
189
|
</span>
|
|
189
190
|
</div>
|
|
190
191
|
)}
|
|
191
|
-
<div className="flex items-start
|
|
192
|
+
<div className="flex items-start gap-3">
|
|
193
|
+
<AliasAvatar alias={s.alias} size={36} />
|
|
192
194
|
<Link href={`/node?alias=${encodeURIComponent(s.alias)}`} className="min-w-0 flex-1 hover:text-cyan-300">
|
|
193
195
|
<div className="flex items-center gap-2">
|
|
194
196
|
<span className="truncate text-base font-semibold text-white">{s.alias}</span>
|
|
195
|
-
<span className={`shrink-0 rounded-md border px-2 py-0.5 text-[
|
|
197
|
+
<span className={`shrink-0 rounded-md border px-2 py-0.5 text-[10px] uppercase tracking-wide ${STATUS_COLORS[statusKey] || STATUS_COLORS.offline}`}>
|
|
196
198
|
{statusKey}
|
|
197
199
|
</span>
|
|
198
200
|
</div>
|
|
201
|
+
<div className="mt-0.5 truncate text-xs text-gray-500">
|
|
202
|
+
{(s.agent || '—')}<span className="text-gray-700 mx-1.5">·</span>{(s.server || '—')}
|
|
203
|
+
</div>
|
|
199
204
|
</Link>
|
|
200
205
|
<div className="flex gap-1.5 shrink-0">
|
|
201
206
|
<button type="button" onClick={() => setChatAlias(s.alias)}
|
|
@@ -209,25 +214,16 @@ export default function NodesPage() {
|
|
|
209
214
|
</div>
|
|
210
215
|
</div>
|
|
211
216
|
|
|
212
|
-
<div className="mt-3
|
|
213
|
-
<div className="flex justify-between gap-3">
|
|
214
|
-
<span>
|
|
215
|
-
<span className="
|
|
216
|
-
</div>
|
|
217
|
-
<div className="flex justify-between gap-3">
|
|
218
|
-
<span>Server</span>
|
|
219
|
-
<span className="truncate text-gray-300">{s.server || '--'}</span>
|
|
217
|
+
<div className="mt-3 rounded-lg border border-[#1a1a2a] bg-[#0a0a15] px-3 py-2 text-xs">
|
|
218
|
+
<div className="flex items-center justify-between gap-3">
|
|
219
|
+
<span className="text-[10px] uppercase tracking-wide text-gray-600">Current task</span>
|
|
220
|
+
<span className="text-[10px] text-gray-600">{timeAgo(s.last_seen_at || s.updated_at)}</span>
|
|
220
221
|
</div>
|
|
221
|
-
<div className=
|
|
222
|
-
|
|
223
|
-
<span className="text-gray-300">{timeAgo(s.last_seen_at || s.updated_at)}</span>
|
|
222
|
+
<div className={`mt-1 line-clamp-2 ${s.task ? 'text-gray-300' : 'text-gray-600 italic'}`}>
|
|
223
|
+
{s.task || 'No current task'}
|
|
224
224
|
</div>
|
|
225
225
|
</div>
|
|
226
226
|
|
|
227
|
-
<div className="mt-3 rounded-lg border border-[#1a1a2a] bg-[#0a0a15] px-3 py-2 text-xs text-gray-400">
|
|
228
|
-
{s.task ? s.task : 'No current task'}
|
|
229
|
-
</div>
|
|
230
|
-
|
|
231
227
|
{progress > 0 && progress < 100 && (
|
|
232
228
|
<div className="mt-3 h-1.5 overflow-hidden rounded-full bg-gray-800">
|
|
233
229
|
<div className="h-1.5 rounded-full bg-cyan-400 transition-all" style={{ width: `${progress}%` }} />
|
|
@@ -297,8 +293,9 @@ export default function NodesPage() {
|
|
|
297
293
|
</span>
|
|
298
294
|
</div>
|
|
299
295
|
<div className="col-span-2 min-w-0">
|
|
300
|
-
<Link href={`/node?alias=${encodeURIComponent(s.alias)}`} className="
|
|
301
|
-
{s.alias}
|
|
296
|
+
<Link href={`/node?alias=${encodeURIComponent(s.alias)}`} className="flex items-center gap-2 min-w-0 hover:text-cyan-300">
|
|
297
|
+
<AliasAvatar alias={s.alias} size={20} />
|
|
298
|
+
<span className="truncate text-sm font-medium text-white">{s.alias}</span>
|
|
302
299
|
</Link>
|
|
303
300
|
</div>
|
|
304
301
|
<div className="col-span-2 truncate text-xs text-gray-400">{s.agent || '--'}</div>
|
|
@@ -317,15 +314,16 @@ export default function NodesPage() {
|
|
|
317
314
|
</div>
|
|
318
315
|
</div>
|
|
319
316
|
<div className="sm:hidden space-y-2">
|
|
320
|
-
<div className="flex items-center
|
|
321
|
-
<
|
|
322
|
-
|
|
317
|
+
<div className="flex items-center gap-2.5">
|
|
318
|
+
<AliasAvatar alias={s.alias} size={28} />
|
|
319
|
+
<Link href={`/node?alias=${encodeURIComponent(s.alias)}`} className="min-w-0 flex-1 hover:text-cyan-300">
|
|
320
|
+
<div className="truncate text-sm font-medium text-white">{s.alias}</div>
|
|
321
|
+
<div className="truncate text-[10px] text-gray-500">{s.agent || '—'} · {timeAgo(s.last_seen_at || s.updated_at)}</div>
|
|
323
322
|
</Link>
|
|
324
323
|
<span className={`shrink-0 text-xs px-2 py-0.5 rounded-md border ${STATUS_COLORS[statusKey] || STATUS_COLORS.offline}`}>
|
|
325
324
|
{statusKey}
|
|
326
325
|
</span>
|
|
327
326
|
</div>
|
|
328
|
-
<div className="text-xs text-gray-500">{s.agent || '--'} · {timeAgo(s.last_seen_at || s.updated_at)}</div>
|
|
329
327
|
{s.task && <div className="truncate text-xs text-gray-500">{s.task}</div>}
|
|
330
328
|
<div className="flex gap-2">
|
|
331
329
|
<button type="button" onClick={() => setChatAlias(s.alias)}
|