@sleep2agi/agent-network-dashboard 0.4.5-preview.0 → 0.4.5-preview.10
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 +37 -37
- 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.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.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.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.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.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.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.js.nft.json +1 -1
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- 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.js.nft.json +1 -1
- 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]__0a0ffmv._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0a0ffmv._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0epcm6p._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0epcm6p._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0to~xqw._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0to~xqw._.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/[root-of-the-server]__0xo8x6b._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0xo8x6b._.js.map +1 -0
- package/.next/server/chunks/ssr/_13_v7-3._.js +3 -0
- package/.next/server/chunks/ssr/_13_v7-3._.js.map +1 -0
- package/.next/server/chunks/ssr/app_10b5blc._.js +9 -0
- package/.next/server/chunks/ssr/app_10b5blc._.js.map +1 -0
- package/.next/server/chunks/ssr/app_components_08ys5y3._.js +9 -0
- package/.next/server/chunks/ssr/app_components_08ys5y3._.js.map +1 -0
- 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_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/03wwuo3wor.05.js +1 -0
- package/.next/static/chunks/04nx85kn48m6a.css +2 -0
- package/.next/static/chunks/09xm65~ucg19e.js +1 -0
- package/.next/static/chunks/0bbx5m_hcs39u.js +1 -0
- package/.next/static/chunks/0f0tgtns1m6zh.js +1 -0
- package/.next/static/chunks/10ir.g.n~hre0.js +7 -0
- package/.next/static/chunks/12dcb86elsl-e.js +7 -0
- package/.next/static/chunks/12xk2ohuxsyo5.js +1 -0
- package/.next/static/chunks/132e__998_q9r.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/AppShell.tsx +9 -1
- package/app/components/CommandPalette.tsx +391 -0
- package/app/components/HealthBanner.tsx +132 -0
- package/app/components/HelpOverlay.tsx +121 -0
- package/app/components/LoadingSkeleton.tsx +81 -25
- package/app/components/Sidebar.tsx +18 -0
- package/app/components/TaskChatPanel.tsx +7 -5
- package/app/components/TopoGraph.tsx +16 -3
- package/app/components/UserBar.tsx +16 -2
- package/app/globals.css +244 -0
- package/app/messages/page.tsx +79 -48
- package/app/nodes/page.tsx +21 -23
- package/app/page.tsx +96 -20
- package/app/tasks/page.tsx +130 -40
- package/docs/loop-design-rounds.md +298 -3
- package/docs/screenshots/0.4.5-preview.1/cyber-admin.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-cmdk-search.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-cmdk.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-login.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-overview.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-settings.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/cyber-tasks.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-admin.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-cmdk-search.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-cmdk.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-login.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-overview.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-settings.png +0 -0
- package/docs/screenshots/0.4.5-preview.1/light-tasks.png +0 -0
- package/package.json +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__013i9e9._.js +0 -9
- package/.next/server/chunks/ssr/[root-of-the-server]__013i9e9._.js.map +0 -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_0ff~kjj._.js +0 -9
- package/.next/server/chunks/ssr/app_0ff~kjj._.js.map +0 -1
- package/.next/static/chunks/06t_vzei8s9_h.js +0 -1
- package/.next/static/chunks/07okhs5561y5y.js +0 -1
- package/.next/static/chunks/0hyhubmh-__wg.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/0snd~q2ucn.h1.css +0 -2
- package/.next/static/chunks/0xn9.0ejo1s_a.js +0 -7
- package/.next/static/chunks/0y0lo-~k2c~00.js +0 -1
- /package/.next/static/{2m1yIfZCIYDWMYrrJEKSC → kfcVh72WCbkWVFpnWl0vE}/_buildManifest.js +0 -0
- /package/.next/static/{2m1yIfZCIYDWMYrrJEKSC → kfcVh72WCbkWVFpnWl0vE}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{2m1yIfZCIYDWMYrrJEKSC → kfcVh72WCbkWVFpnWl0vE}/_ssgManifest.js +0 -0
package/app/tasks/page.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import Link from 'next/link';
|
|
|
6
6
|
import { useNetworkId } from '../lib/network-context';
|
|
7
7
|
import { TaskDrawer } from '../components/TaskDrawer';
|
|
8
8
|
import { EmptyState } from '../components/EmptyState';
|
|
9
|
+
import { AliasAvatar } from '../components/AliasAvatar';
|
|
9
10
|
|
|
10
11
|
interface Task {
|
|
11
12
|
task_id: string;
|
|
@@ -48,6 +49,21 @@ const STATUS_COLORS: Record<string, string> = {
|
|
|
48
49
|
expired: 'bg-orange-500/10 text-orange-300 border-orange-500/20',
|
|
49
50
|
};
|
|
50
51
|
|
|
52
|
+
/** Small colored dot per status — visible on every tab (active + inactive)
|
|
53
|
+
* so users can scan the row at a glance. Hex inlined to avoid Tailwind
|
|
54
|
+
* purging dynamic `bg-${family}-400` class names. */
|
|
55
|
+
const STATUS_DOTS: Record<string, string> = {
|
|
56
|
+
created: '#9ca3af',
|
|
57
|
+
delivered: '#60a5fa',
|
|
58
|
+
acked: '#22d3ee',
|
|
59
|
+
running: '#4ade80',
|
|
60
|
+
replied: '#a78bfa',
|
|
61
|
+
closed: '#6b7280',
|
|
62
|
+
failed: '#f87171',
|
|
63
|
+
cancelled: '#facc15',
|
|
64
|
+
expired: '#fb923c',
|
|
65
|
+
};
|
|
66
|
+
|
|
51
67
|
function statusBadge(status: string) {
|
|
52
68
|
const color = STATUS_COLORS[status] || 'bg-gray-500/10 text-gray-400 border-gray-500/20';
|
|
53
69
|
return `text-xs px-2 py-0.5 rounded-md border ${color}`;
|
|
@@ -134,36 +150,66 @@ function TasksContent() {
|
|
|
134
150
|
</span>
|
|
135
151
|
</div>
|
|
136
152
|
|
|
137
|
-
{/* Status Tabs
|
|
138
|
-
|
|
153
|
+
{/* Status Tabs — color-coded dots per status family so users can
|
|
154
|
+
scan the row at a glance. Active tab gets full chip styling
|
|
155
|
+
(bg + border + text color), inactive tabs only carry the dot
|
|
156
|
+
+ neutral label so the active state remains the strong cue.
|
|
157
|
+
On narrow viewports (<sm) the row scrolls horizontally with
|
|
158
|
+
subtle gradient fade-edges (via .anet-tabstrip-wrap pseudo
|
|
159
|
+
elements) hinting more content. */}
|
|
160
|
+
<div className="anet-tabstrip-wrap mb-4">
|
|
161
|
+
<div className="anet-tabstrip flex sm:flex-wrap gap-1 bg-[#111128] rounded-lg border border-[#2a2a4a] p-1 overflow-x-auto sm:overflow-x-visible scrollbar-thin">
|
|
139
162
|
{['', ...STATUS_OPTIONS.filter(Boolean)].map(s => (
|
|
140
163
|
<button key={s} onClick={() => setFilterStatus(s)}
|
|
141
|
-
className={`px-3 py-1.5 rounded-md text-xs transition-colors ${
|
|
164
|
+
className={`px-3 py-1.5 rounded-md text-xs transition-colors flex items-center gap-1.5 shrink-0 whitespace-nowrap ${
|
|
142
165
|
filterStatus === s
|
|
143
166
|
? `${STATUS_COLORS[s] || 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20'} border`
|
|
144
|
-
: 'text-gray-500 hover:text-gray-300'
|
|
167
|
+
: 'text-gray-500 hover:text-gray-300 hover:bg-[#1a1a2a]/40'
|
|
145
168
|
}`}>
|
|
146
|
-
{s
|
|
169
|
+
{s && (
|
|
170
|
+
<span
|
|
171
|
+
aria-hidden
|
|
172
|
+
className="inline-block w-1.5 h-1.5 rounded-full shrink-0"
|
|
173
|
+
style={{ backgroundColor: STATUS_DOTS[s] || '#6b7280' }}
|
|
174
|
+
/>
|
|
175
|
+
)}
|
|
176
|
+
<span>{s || 'All'}</span>
|
|
147
177
|
</button>
|
|
148
178
|
))}
|
|
149
179
|
</div>
|
|
180
|
+
</div>
|
|
150
181
|
|
|
151
|
-
{/* From/To Filters */}
|
|
152
|
-
<div className="flex flex-wrap gap-
|
|
153
|
-
<
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
182
|
+
{/* From/To Filters — same visual block as the status tabs above. */}
|
|
183
|
+
<div className="flex flex-wrap items-center gap-2 mb-6">
|
|
184
|
+
<div className="flex items-center gap-1.5 rounded-lg border border-[#2a2a4a] bg-[#111128] px-2.5 py-1.5 focus-within:border-blue-500/40">
|
|
185
|
+
<span className="text-[10px] uppercase tracking-wide text-gray-600">From</span>
|
|
186
|
+
<input
|
|
187
|
+
type="text"
|
|
188
|
+
value={filterFrom}
|
|
189
|
+
onChange={e => setFilterFrom(e.target.value)}
|
|
190
|
+
placeholder="any node"
|
|
191
|
+
className="w-28 bg-transparent text-sm text-white placeholder-gray-700 focus:outline-none"
|
|
192
|
+
/>
|
|
193
|
+
</div>
|
|
194
|
+
<div className="flex items-center gap-1.5 rounded-lg border border-[#2a2a4a] bg-[#111128] px-2.5 py-1.5 focus-within:border-blue-500/40">
|
|
195
|
+
<span className="text-[10px] uppercase tracking-wide text-gray-600">To</span>
|
|
196
|
+
<input
|
|
197
|
+
type="text"
|
|
198
|
+
value={filterTo}
|
|
199
|
+
onChange={e => setFilterTo(e.target.value)}
|
|
200
|
+
placeholder="any node"
|
|
201
|
+
className="w-28 bg-transparent text-sm text-white placeholder-gray-700 focus:outline-none"
|
|
202
|
+
/>
|
|
203
|
+
</div>
|
|
204
|
+
{(filterStatus || filterFrom || filterTo) && (
|
|
205
|
+
<button
|
|
206
|
+
type="button"
|
|
207
|
+
onClick={() => { setFilterStatus(''); setFilterFrom(''); setFilterTo(''); }}
|
|
208
|
+
className="rounded-lg border border-gray-700 px-2.5 py-1.5 text-[11px] text-gray-500 hover:text-gray-200 hover:border-gray-600"
|
|
209
|
+
>
|
|
210
|
+
Clear filters
|
|
211
|
+
</button>
|
|
212
|
+
)}
|
|
167
213
|
</div>
|
|
168
214
|
|
|
169
215
|
{/* Status distribution */}
|
|
@@ -220,22 +266,39 @@ function TasksContent() {
|
|
|
220
266
|
<div className="col-span-2">Time</div>
|
|
221
267
|
</div>
|
|
222
268
|
|
|
223
|
-
{tasks.map(t =>
|
|
269
|
+
{tasks.map(t => {
|
|
270
|
+
const isOpen = expanded.has(t.task_id);
|
|
271
|
+
return (
|
|
224
272
|
<div
|
|
225
273
|
key={t.task_id}
|
|
226
|
-
className=
|
|
274
|
+
className={`anet-task-row group bg-[#111128] border rounded-lg px-4 py-3 transition-all duration-200 cursor-pointer ${
|
|
275
|
+
isOpen
|
|
276
|
+
? 'border-[#3a3a5a] shadow-lg shadow-black/20'
|
|
277
|
+
: 'border-[#2a2a4a] hover:border-[#3a3a5a] hover:bg-[#15152e]'
|
|
278
|
+
}`}
|
|
227
279
|
onClick={() => toggleExpand(t.task_id)}
|
|
280
|
+
role="button"
|
|
281
|
+
tabIndex={0}
|
|
282
|
+
aria-expanded={isOpen}
|
|
283
|
+
onKeyDown={(e) => {
|
|
284
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
285
|
+
e.preventDefault();
|
|
286
|
+
toggleExpand(t.task_id);
|
|
287
|
+
}
|
|
288
|
+
}}
|
|
228
289
|
>
|
|
229
290
|
{/* Desktop row */}
|
|
230
291
|
<div className="hidden sm:grid sm:grid-cols-12 gap-2 items-center">
|
|
231
292
|
<div className="col-span-1">
|
|
232
293
|
<span className={statusBadge(t.status)}>{t.status}</span>
|
|
233
294
|
</div>
|
|
234
|
-
<div className="col-span-2
|
|
235
|
-
{t.from_name
|
|
295
|
+
<div className="col-span-2 flex items-center gap-1.5 min-w-0" title={t.from_name}>
|
|
296
|
+
{t.from_name && <AliasAvatar alias={t.from_name} size={18} />}
|
|
297
|
+
<span className="truncate text-sm text-gray-200">{t.from_name || '--'}</span>
|
|
236
298
|
</div>
|
|
237
|
-
<div className="col-span-2
|
|
238
|
-
{t.to_name
|
|
299
|
+
<div className="col-span-2 flex items-center gap-1.5 min-w-0" title={t.to_name}>
|
|
300
|
+
{t.to_name && <AliasAvatar alias={t.to_name} size={18} />}
|
|
301
|
+
<span className="truncate text-sm text-gray-200">{t.to_name || '--'}</span>
|
|
239
302
|
</div>
|
|
240
303
|
<div className="col-span-4 text-xs text-gray-400 truncate" title={t.content}>
|
|
241
304
|
{t.content || '--'}
|
|
@@ -243,8 +306,15 @@ function TasksContent() {
|
|
|
243
306
|
<div className="col-span-1">
|
|
244
307
|
<span className={`text-xs ${priorityBadge(t.priority)}`}>{t.priority || 'normal'}</span>
|
|
245
308
|
</div>
|
|
246
|
-
<div className="col-span-2 text-xs text-gray-500" title={t.created_at}>
|
|
247
|
-
{timeAgo(t.created_at)}
|
|
309
|
+
<div className="col-span-2 text-xs text-gray-500 flex items-center justify-between gap-2" title={t.created_at}>
|
|
310
|
+
<span className="truncate">{timeAgo(t.created_at)}</span>
|
|
311
|
+
<svg
|
|
312
|
+
aria-hidden
|
|
313
|
+
className={`shrink-0 text-gray-600 group-hover:text-gray-400 transition-transform duration-200 ${isOpen ? 'rotate-180' : ''}`}
|
|
314
|
+
width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"
|
|
315
|
+
>
|
|
316
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M6 9l6 6 6-6" />
|
|
317
|
+
</svg>
|
|
248
318
|
</div>
|
|
249
319
|
</div>
|
|
250
320
|
|
|
@@ -252,20 +322,38 @@ function TasksContent() {
|
|
|
252
322
|
<div className="sm:hidden space-y-2">
|
|
253
323
|
<div className="flex items-center justify-between">
|
|
254
324
|
<span className={statusBadge(t.status)}>{t.status}</span>
|
|
255
|
-
<
|
|
325
|
+
<div className="flex items-center gap-2">
|
|
326
|
+
<span className={`text-xs ${priorityBadge(t.priority)}`}>{t.priority || 'normal'}</span>
|
|
327
|
+
<svg
|
|
328
|
+
aria-hidden
|
|
329
|
+
className={`text-gray-600 transition-transform duration-200 ${isOpen ? 'rotate-180' : ''}`}
|
|
330
|
+
width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"
|
|
331
|
+
>
|
|
332
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M6 9l6 6 6-6" />
|
|
333
|
+
</svg>
|
|
334
|
+
</div>
|
|
256
335
|
</div>
|
|
257
|
-
<div className="text-xs text-gray-
|
|
258
|
-
<
|
|
259
|
-
<span className="
|
|
260
|
-
<span className="text-
|
|
336
|
+
<div className="flex items-center gap-1.5 text-xs text-gray-300 min-w-0">
|
|
337
|
+
{t.from_name && <AliasAvatar alias={t.from_name} size={16} />}
|
|
338
|
+
<span className="truncate max-w-[40%]">{t.from_name || '--'}</span>
|
|
339
|
+
<span className="text-gray-600">→</span>
|
|
340
|
+
{t.to_name && <AliasAvatar alias={t.to_name} size={16} />}
|
|
341
|
+
<span className="truncate max-w-[40%]">{t.to_name || '--'}</span>
|
|
261
342
|
</div>
|
|
262
|
-
<div className="text-xs text-gray-400
|
|
343
|
+
<div className="text-xs text-gray-400 line-clamp-1">{t.content || '--'}</div>
|
|
263
344
|
<div className="text-xs text-gray-600">{timeAgo(t.created_at)}</div>
|
|
264
345
|
</div>
|
|
265
346
|
|
|
266
|
-
{/* Expanded detail
|
|
267
|
-
|
|
268
|
-
|
|
347
|
+
{/* Expanded detail — always mounted; grid-rows 0fr↔1fr trick gives
|
|
348
|
+
content-aware smooth max-height animation without measuring DOM. */}
|
|
349
|
+
<div
|
|
350
|
+
className={`grid transition-all duration-300 ease-out ${
|
|
351
|
+
isOpen ? 'grid-rows-[1fr] opacity-100 mt-3' : 'grid-rows-[0fr] opacity-0'
|
|
352
|
+
}`}
|
|
353
|
+
aria-hidden={!isOpen}
|
|
354
|
+
>
|
|
355
|
+
<div className="overflow-hidden">
|
|
356
|
+
<div className="pt-3 border-t border-[#2a2a4a] space-y-3">
|
|
269
357
|
{t.content && (
|
|
270
358
|
<div>
|
|
271
359
|
<div className="text-xs text-gray-600 mb-1">Content</div>
|
|
@@ -327,9 +415,11 @@ function TasksContent() {
|
|
|
327
415
|
</div>
|
|
328
416
|
</div>
|
|
329
417
|
</div>
|
|
330
|
-
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
331
420
|
</div>
|
|
332
|
-
|
|
421
|
+
);
|
|
422
|
+
})}
|
|
333
423
|
</div>
|
|
334
424
|
)}
|
|
335
425
|
|
|
@@ -497,6 +497,301 @@ Natural ship-point. Round 8 = the publish itself:
|
|
|
497
497
|
4. Tell 通信龙 to bump CLI preview's PINNED_DASHBOARD_VERSION
|
|
498
498
|
5. Telegram Vincent: `npm i -g @sleep2agi/agent-network@preview`
|
|
499
499
|
|
|
500
|
-
After ship, rounds 9+ accumulate toward
|
|
501
|
-
|
|
502
|
-
|
|
500
|
+
After ship, rounds 9+ accumulate toward the **next** preview in the
|
|
501
|
+
SAME `0.4.5-preview.N` series (Vincent's policy: don't burn base version
|
|
502
|
+
numbers on preview-only work). Backlog ideas: layout collision
|
|
503
|
+
avoidance in TopoGraph, hover affordances on KPI cards, Cmd+K command
|
|
504
|
+
palette, header health banner, mobile audit.
|
|
505
|
+
|
|
506
|
+
> **Version policy (round 8 + Vincent telegram)**: stable stays at
|
|
507
|
+
> `0.4.2` until Vincent explicitly promotes a preview. All new previews
|
|
508
|
+
> bump only the `-preview.N` suffix on the same `0.4.5` base. The
|
|
509
|
+
> `latest` npm tag never moves without sign-off.
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## Round 9 — Header health banner
|
|
514
|
+
|
|
515
|
+
### What changed
|
|
516
|
+
- New `app/components/HealthBanner.tsx`: thin sticky strip mounted in
|
|
517
|
+
`AppShell` between sidebar and page content, visible on every
|
|
518
|
+
non-login page.
|
|
519
|
+
- Three states, priority-ranked:
|
|
520
|
+
- **red** — `CommHub unreachable — agents may be offline` + CTA
|
|
521
|
+
"Open Settings →"
|
|
522
|
+
- **amber** — `N task(s) failed recently` + CTA "Review failures →"
|
|
523
|
+
(links to `/tasks?status=failed`). Dot pulses with the same 1.6s
|
|
524
|
+
opacity drift as the sidebar online pulse.
|
|
525
|
+
- **green** — `All systems go`. Quiet. No CTA. Doesn't render until
|
|
526
|
+
at least one stats response confirms (avoids flashing green on
|
|
527
|
+
first paint before data arrives).
|
|
528
|
+
- Pulls from `/api/hub/stats` + `/api/hub/health` via SWR (15s refresh,
|
|
529
|
+
5s dedupe). Both endpoints are already polled elsewhere — request
|
|
530
|
+
dedupes free, banner has zero net cost.
|
|
531
|
+
- Dismissible per-session via `sessionStorage.anet-hb-dismissed = '1'`.
|
|
532
|
+
Re-shows on next session.
|
|
533
|
+
- Light/mint themes get bumped color saturation via `.anet-health-banner`
|
|
534
|
+
override rules in globals.css so red/amber/green read crisply on
|
|
535
|
+
white surfaces.
|
|
536
|
+
|
|
537
|
+
### Self-score: **8.7 / 10**
|
|
538
|
+
|
|
539
|
+
| Dimension | Score | Notes |
|
|
540
|
+
|--------------------------|------:|------------------------------------------------------------------------|
|
|
541
|
+
| Information value | 9 | Fleet health visible from every page without navigating to /nodes |
|
|
542
|
+
| Restraint | 9 | 32px-tall strip; opacity-only pulse; no glow; auto-dismissible |
|
|
543
|
+
| Affordance (CTAs) | 9 | Each non-green state has a clear "fix this" link |
|
|
544
|
+
| Theme parity | 9 | All 3 states verified in light + cyber |
|
|
545
|
+
| Failure-state robustness | 8 | "Red" fires only when both `/stats` AND `/health` fail; safer than either alone |
|
|
546
|
+
| Mobile | 7 | Strip wraps at 390px viewport; could collapse "Review failures →" copy further |
|
|
547
|
+
|
|
548
|
+
**Deductions**:
|
|
549
|
+
- −0.6: on very narrow mobile (<340px) the CTA + dismiss can wrap or
|
|
550
|
+
overlap. Could collapse CTA to icon-only at that breakpoint.
|
|
551
|
+
- −0.4: red state has a single message; doesn't distinguish "hub down"
|
|
552
|
+
vs "auth expired" vs "network error". Future round could add error
|
|
553
|
+
classification.
|
|
554
|
+
- −0.3: dismiss is session-scoped. Some users may want
|
|
555
|
+
"dismiss for this session only" vs "dismiss forever". Defer.
|
|
556
|
+
|
|
557
|
+
### Round 10 plan: **KPI card rich hover preview**
|
|
558
|
+
|
|
559
|
+
Overview's stat strip (round 3) shows top-level numbers — `Nodes 4/5`,
|
|
560
|
+
`Tasks 0`, `Failed 0` — but a power user wants to see the breakdown
|
|
561
|
+
without clicking through. Add small CSS-only popovers that appear on
|
|
562
|
+
hover:
|
|
563
|
+
- Nodes hover → "3 working · 2 idle · 0 offline"
|
|
564
|
+
- Tasks hover → "by status: 4 running, 2 replied, 1 failed, 0 expired"
|
|
565
|
+
- Failed hover → "5 in last hour · last failure 12m ago"
|
|
566
|
+
|
|
567
|
+
Pure CSS popover (no JS state), 200ms delay-show, fades out on
|
|
568
|
+
unhover. Both themes. Doesn't affect mobile (touch shows full card
|
|
569
|
+
already).
|
|
570
|
+
|
|
571
|
+
Estimated work: 25 min. Fires next `*/5`.
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## Round 10 — KPI card rich hover preview
|
|
576
|
+
|
|
577
|
+
### What changed
|
|
578
|
+
- The 3-stat strip on Overview (Nodes / Tasks / Failed) now gets a
|
|
579
|
+
**hover popover** showing the breakdown that the headline number
|
|
580
|
+
abstracts away.
|
|
581
|
+
- **Nodes** hover → `● working {n}` / `● idle {n}` / `● offline {n}`
|
|
582
|
+
- **Tasks** hover → list of all populated statuses in priority
|
|
583
|
+
order (running → replied → failed → cancelled → expired → closed
|
|
584
|
+
→ created → delivered → acked), each with its color dot + count
|
|
585
|
+
- **Failed** hover → `no failures yet` or `{n} in current view`
|
|
586
|
+
- **Pure CSS** popover: hidden by default, `opacity-0 translate-y-[-2px]`
|
|
587
|
+
transitions to `opacity-100 translate-y-0` on `group-hover`. 100ms
|
|
588
|
+
delay-show so a quick mouse-pass doesn't flicker. No React state.
|
|
589
|
+
- `pointer-events-none` on the popover so it never intercepts the
|
|
590
|
+
click through to the underlying Link target.
|
|
591
|
+
- **Mobile gate**: `hidden md:block` — touch devices don't get the
|
|
592
|
+
popover (no `:hover`). The card itself still navigates on tap, so no
|
|
593
|
+
functionality lost.
|
|
594
|
+
- Dot colors inlined as hex (`#4ade80` green, `#a78bfa` purple, etc.)
|
|
595
|
+
to dodge Tailwind's purge of dynamic `bg-${family}-400` class names.
|
|
596
|
+
|
|
597
|
+
### Self-score: **8.5 / 10**
|
|
598
|
+
|
|
599
|
+
**Deductions**: no `:focus-within` trigger (keyboard users miss
|
|
600
|
+
popover); "Failed" copy doesn't show time bucket; dot hex inlined
|
|
601
|
+
rather than centralized in a constants palette.
|
|
602
|
+
|
|
603
|
+
### Round 11 plan: **Mobile audit + polish pass**
|
|
604
|
+
|
|
605
|
+
Nine rounds in, the desktop story is solid. Mobile hasn't gotten a
|
|
606
|
+
dedicated round since the initial audit. Likely findings:
|
|
607
|
+
|
|
608
|
+
- Health banner at <340px: CTA + dismiss button + truncated message
|
|
609
|
+
competes for ~280px usable width. Collapse CTA to icon-only or
|
|
610
|
+
move it below the message.
|
|
611
|
+
- Stat strip 3-col at 360-390px: "View →" affordance shrinks below
|
|
612
|
+
legibility. Either drop "View →" on mobile or stack 1-col.
|
|
613
|
+
- Sidebar mobile drawer: not screenshot-audited against the latest
|
|
614
|
+
brand-mark + pulse changes.
|
|
615
|
+
- Footer text spacing on /login at 320px: wraps awkwardly.
|
|
616
|
+
|
|
617
|
+
Action: capture mobile screenshots across 5-6 key pages at 390×844
|
|
618
|
+
AND 360×740, identify worst offenders, fix the top 3.
|
|
619
|
+
|
|
620
|
+
Estimated work: 30 min. Fires next `*/5`.
|
|
621
|
+
|
|
622
|
+
---
|
|
623
|
+
|
|
624
|
+
## Round 11 — Mobile audit + polish pass
|
|
625
|
+
|
|
626
|
+
### Findings (390×844 + 360×740)
|
|
627
|
+
Captured 12 screenshots (6 pages × 2 themes × 2 viewports). Three
|
|
628
|
+
clear regressions at narrow widths:
|
|
629
|
+
|
|
630
|
+
1. **Health banner** ran into the fixed-position hamburger button at
|
|
631
|
+
top-left (top:4 left:3, ~44×44 hit area). Message text was
|
|
632
|
+
truncated to "...sks failed recently" because the leading 6
|
|
633
|
+
characters sat under the hamburger.
|
|
634
|
+
2. **UserBar** "Edit" + "Sign out" text links cramped against the
|
|
635
|
+
user name + role on narrow screens, wrapping "Sign out" onto
|
|
636
|
+
two lines.
|
|
637
|
+
3. **Stat strip** "View →" affordance in each card's top-right took
|
|
638
|
+
horizontal space the headline number needed, making the 3-col
|
|
639
|
+
grid feel cramped at 360px.
|
|
640
|
+
|
|
641
|
+
### What changed
|
|
642
|
+
- **HealthBanner**: `pl-3` → `pl-14` on mobile (clears the hamburger
|
|
643
|
+
button), CTA text "Review failures" / "Open Settings" collapses to
|
|
644
|
+
a bare arrow on `<sm` with a proper `aria-label` so screen
|
|
645
|
+
readers still hear the destination.
|
|
646
|
+
- **UserBar Edit / Sign out**: text on `>=sm`, single inline-svg icon
|
|
647
|
+
on `<sm` (pencil for edit, doorway-arrow for sign out). Both stay
|
|
648
|
+
same hit area, just label-trimmed.
|
|
649
|
+
- **Stat strip "View →"**: `hidden sm:block` so the affordance only
|
|
650
|
+
appears on desktop. Mobile cards are fully tappable, so the
|
|
651
|
+
affordance is implicit.
|
|
652
|
+
|
|
653
|
+
### Self-score: **9.0 / 10**
|
|
654
|
+
|
|
655
|
+
| Dimension | Score | Notes |
|
|
656
|
+
|------------------------|------:|------------------------------------------------------------------|
|
|
657
|
+
| Defect closure | 10 | All three observed mobile regressions resolved |
|
|
658
|
+
| Desktop non-regression | 9 | All changes wrapped in `sm:` breakpoint — pixel-identical >640px |
|
|
659
|
+
| Restraint | 9 | Icons are simple line SVGs matching the design system |
|
|
660
|
+
| Accessibility | 9 | `aria-label` on collapsed CTAs and icon-only buttons |
|
|
661
|
+
| Touch target | 8 | Icons are 16px visual; full `<button>` is still 44px hit area |
|
|
662
|
+
|
|
663
|
+
**Deductions**:
|
|
664
|
+
- −0.5: not tested below 360px (e.g. 320px iPhone SE first-gen).
|
|
665
|
+
Probably still fine but unverified.
|
|
666
|
+
- −0.3: sidebar drawer mobile state (when hamburger is tapped) not
|
|
667
|
+
re-screenshotted post round-4 brand changes.
|
|
668
|
+
- −0.2: existing chip filter rows on Tasks/Messages still wrap at
|
|
669
|
+
narrow widths. Not the most painful, deferred.
|
|
670
|
+
|
|
671
|
+
### Round 12 plan: **Loading skeleton refresh**
|
|
672
|
+
|
|
673
|
+
The `LoadingSkeleton` component in `app/components/LoadingSkeleton.tsx`
|
|
674
|
+
still uses `bg-gray-800` / `bg-gray-800/40` patterns from the
|
|
675
|
+
pre-theme-token era. It works (CSS shim catches `bg-gray-800` in
|
|
676
|
+
light), but it's the only surface that didn't get a deliberate
|
|
677
|
+
restyle. Refresh to use:
|
|
678
|
+
- subtle bg + animated pulse using the same `anet-brand-pulse`
|
|
679
|
+
rhythm (1.6s opacity drift) for visual cohesion
|
|
680
|
+
- proper card structure matching round 3's stat-strip shape
|
|
681
|
+
- both themes, no AI-noise
|
|
682
|
+
|
|
683
|
+
Estimated work: 20 min. Fires next `*/5`.
|
|
684
|
+
|
|
685
|
+
---
|
|
686
|
+
|
|
687
|
+
## Round 14 — Cmd+K command palette (scaffold)
|
|
688
|
+
|
|
689
|
+
### What changed
|
|
690
|
+
- New `app/components/CommandPalette.tsx` mounted in `AppShell` so it's
|
|
691
|
+
globally available on every non-login page.
|
|
692
|
+
- **Keyboard shortcuts** (global, not per-page):
|
|
693
|
+
- `⌘K` / `Ctrl+K` toggles open/closed
|
|
694
|
+
- `/` opens when no input is focused (Linear-style)
|
|
695
|
+
- `↑↓` navigates results, `Enter` activates, `Esc` closes
|
|
696
|
+
- **Layout**: centered modal at 10vh-15vh from top, max-w-xl, backdrop
|
|
697
|
+
blur over content. Search input + grouped results + footer hint bar.
|
|
698
|
+
- **Initial command set**: 10 navigation entries covering every
|
|
699
|
+
primary page (Overview / Tasks / Failed tasks / Nodes / Messages /
|
|
700
|
+
Networks / Audit Log / Server Logs / Admin / Settings). Each carries
|
|
701
|
+
a hint subtitle and a thin-stroke icon.
|
|
702
|
+
- **Filter behavior**: case-insensitive search over title + hint + id.
|
|
703
|
+
Active row gets emerald tint + `↵` glyph; mouse hover updates the
|
|
704
|
+
selected index so keyboard and pointer stay in sync.
|
|
705
|
+
- **Light/mint surface**: white modal with real soft shadow (vs the
|
|
706
|
+
default `bg-[#0d0d1a]` navy that CSS shim would translate). Override
|
|
707
|
+
ruled in globals.css.
|
|
708
|
+
|
|
709
|
+
### Self-score: **8.7 / 10**
|
|
710
|
+
|
|
711
|
+
| Dimension | Score | Notes |
|
|
712
|
+
|------------------------|------:|------------------------------------------------------------------------|
|
|
713
|
+
| Adoption signal | 9 | Stripe/Linear/Vercel staple — sets reader expectation that we're modern |
|
|
714
|
+
| Keyboard-first | 9 | All keys wired; mouse + keyboard stay in sync |
|
|
715
|
+
| Restraint | 9 | Mono-stroke icons, single accent color, no AI shimmer |
|
|
716
|
+
| Theme parity | 9 | Light gets a proper white surface w/ shadow; cyber uses navy |
|
|
717
|
+
| Discoverability | 7 | No visible "press ⌘K" hint anywhere on the page yet |
|
|
718
|
+
| Mobile | 6 | Works on mobile (tap to open via UI) — but no on-screen launcher yet |
|
|
719
|
+
|
|
720
|
+
**Deductions**:
|
|
721
|
+
- −0.7: zero on-page hint that the palette exists. Most users will
|
|
722
|
+
never find `⌘K` without docs. Should add a tiny "⌘K" badge in
|
|
723
|
+
sidebar footer or in the UserBar.
|
|
724
|
+
- −0.4: no mobile launcher. Mobile has no obvious affordance.
|
|
725
|
+
- −0.2: command set is navigation-only. Round 15 will add actions
|
|
726
|
+
(theme toggle / sign out / Dispatch open) and recent-commands.
|
|
727
|
+
|
|
728
|
+
### Round 15 plan: **Cmd+K actions + recent-commands**
|
|
729
|
+
|
|
730
|
+
Extend the scaffold with the "Actions" group:
|
|
731
|
+
- Toggle theme (cyber ↔ light)
|
|
732
|
+
- Open Dispatch dialog (current page's Dispatch button)
|
|
733
|
+
- Sign out
|
|
734
|
+
- Copy current URL
|
|
735
|
+
|
|
736
|
+
Plus add a `Recents` group at the top that surfaces the last 3-5
|
|
737
|
+
commands the user invoked (ring buffer in `sessionStorage`).
|
|
738
|
+
|
|
739
|
+
Plus a discoverability nudge — tiny `⌘K` chip in sidebar footer +
|
|
740
|
+
UserBar tooltip.
|
|
741
|
+
|
|
742
|
+
Estimated work: 25 min. Fires next `*/5`.
|
|
743
|
+
|
|
744
|
+
---
|
|
745
|
+
|
|
746
|
+
## Round 12 — Loading skeleton refresh
|
|
747
|
+
|
|
748
|
+
### What changed
|
|
749
|
+
- `LoadingSkeleton` now **mirrors the actual Overview layout** so the
|
|
750
|
+
page doesn't shift on data arrival. Old version was generic header
|
|
751
|
+
+ broadcast + topology + 4-card grid; new version shows: 4 KPI
|
|
752
|
+
cards, Dispatch+UserBar row, Config bar, 3-card stat strip, 3-tile
|
|
753
|
+
nav rail, Broadcast bar, 4-card agent grid.
|
|
754
|
+
- Switched from Tailwind's `animate-pulse` (1s opacity drift) to a
|
|
755
|
+
custom `anet-skeleton-pulse` (1.6s) to match the same rhythm as
|
|
756
|
+
`anet-brand-pulse` in the sidebar and the health banner amber dot.
|
|
757
|
+
Visual cohesion across the design system.
|
|
758
|
+
- Introduced `anet-skeleton-bar` class with explicit per-theme
|
|
759
|
+
background: `#1a1a2a` on dark (lighter navy on dark card),
|
|
760
|
+
`#d4d8df` on light/mint (mid-grey on white card). The previous
|
|
761
|
+
attempt to reuse the `bg-[#1a1a2a]` shim was too subtle (light
|
|
762
|
+
card #ffffff vs bar mapped to bg-elevated #eef0f4 = only ~7
|
|
763
|
+
brightness levels different = invisible bars).
|
|
764
|
+
- All bar dimensions use rem-based explicit values via inline style
|
|
765
|
+
so they don't depend on Tailwind purge correctness.
|
|
766
|
+
- `prefers-reduced-motion: reduce` kills the pulse on both classes.
|
|
767
|
+
|
|
768
|
+
### Self-score: **9.0 / 10**
|
|
769
|
+
|
|
770
|
+
| Dimension | Score | Notes |
|
|
771
|
+
|------------------------|------:|------------------------------------------------------------------|
|
|
772
|
+
| No content shift | 9 | Skeleton matches Overview structure cell-for-cell |
|
|
773
|
+
| Theme parity | 10 | Both themes get visible bars (the original sin of round 11 plan) |
|
|
774
|
+
| Restraint | 9 | No shimmer-gradient, no animation noise, just 1.6s opacity drift |
|
|
775
|
+
| Design-system cohesion | 9 | Same pulse rhythm as brand pulse + health banner amber |
|
|
776
|
+
| Accessibility | 9 | prefers-reduced-motion respected on both classes |
|
|
777
|
+
|
|
778
|
+
**Deductions**:
|
|
779
|
+
- −0.5: skeleton shows the FULL Overview (8+ blocks). Most actual
|
|
780
|
+
page-loads complete in <300ms so user barely sees this. Slower
|
|
781
|
+
hubs may see the whole thing; some users might prefer a shorter
|
|
782
|
+
skeleton. Could trim agent grid to 2 cards if it feels long in
|
|
783
|
+
practice.
|
|
784
|
+
- −0.5: the agent-card skeleton is generic (status dot + alias bar
|
|
785
|
+
+ 3 detail bars). Real cards carry status chip + agent type +
|
|
786
|
+
server hostname + uptime — could mirror more specifically.
|
|
787
|
+
|
|
788
|
+
### Round 13 plan: **Tasks status tabs — color coding**
|
|
789
|
+
|
|
790
|
+
The Tasks page filter tab strip (`All / created / delivered / acked /
|
|
791
|
+
running / replied / closed / failed / cancelled / expired`) is all
|
|
792
|
+
neutral-styled — no visual scannability. Color-code each by its
|
|
793
|
+
status family using the same tokens as the chips system used
|
|
794
|
+
elsewhere (running=green, replied=purple, failed=red, etc.), so the
|
|
795
|
+
user can spot "failed" without reading every label.
|
|
796
|
+
|
|
797
|
+
Estimated work: 20 min. Fires next `*/5`.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
module.exports=[18622,(a,b,c)=>{b.exports=a.x("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js"))},56704,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-async-storage.external.js",()=>require("next/dist/server/app-render/work-async-storage.external.js"))},32319,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-unit-async-storage.external.js",()=>require("next/dist/server/app-render/work-unit-async-storage.external.js"))},24725,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/after-task-async-storage.external.js",()=>require("next/dist/server/app-render/after-task-async-storage.external.js"))},20635,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/action-async-storage.external.js",()=>require("next/dist/server/app-render/action-async-storage.external.js"))},43285,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/dynamic-access-async-storage.external.js",()=>require("next/dist/server/app-render/dynamic-access-async-storage.external.js"))},42602,(a,b,c)=>{"use strict";b.exports=a.r(18622)},87924,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactJsxRuntime},72131,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].React},9270,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.AppRouterContext},38783,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactServerDOMTurbopackClient},36313,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.HooksClientContext},18341,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.ServerInsertedHtml},22397,a=>{"use strict";var b=a.i(87924),c=a.i(72131);let d=(0,c.createContext)({networkId:"",setNetworkId:()=>{}});a.s(["NetworkProvider",0,function({children:a}){let[e,f]=(0,c.useState)("");return(0,c.useEffect)(()=>{let a=sessionStorage.getItem("anet_network_id");a&&f(a)},[]),(0,b.jsx)(d.Provider,{value:{networkId:e,setNetworkId:a=>{f(a),sessionStorage.setItem("anet_network_id",a)}},children:a})},"useNetworkId",0,function(){return(0,c.useContext)(d)}])},76194,a=>{"use strict";var b=a.i(87924),c=a.i(72131);let d=[{id:"cyber",label:"Cyber",emoji:"🌃",desc:"默认深色"},{id:"light",label:"Light",emoji:"☀️",desc:"浅色简洁"},{id:"mint",label:"Mint",emoji:"🌿",desc:"薄荷绿"},{id:"sunset",label:"Sunset",emoji:"🌅",desc:"暖色橙紫"}],e="anet-theme";function f(a){"u">typeof document&&document.documentElement.setAttribute("data-theme",a)}a.s(["ThemeProvider",0,function({children:a}){return(0,c.useEffect)(()=>{f(localStorage.getItem(e)||"cyber")},[]),(0,b.jsx)(b.Fragment,{children:a})},"ThemeSwitcher",0,function({compact:a=!1}){let[g,h]=(0,c.useState)("cyber"),[i,j]=(0,c.useState)(!1);(0,c.useEffect)(()=>{let a=localStorage.getItem(e)||"cyber";h(a),f(a)},[]);let k=d.find(a=>a.id===g)||d[0];return(0,b.jsxs)("div",{className:"relative",children:[(0,b.jsxs)("button",{"aria-label":"切换主题",onClick:()=>j(!i),className:"px-2.5 py-1.5 rounded-md text-xs flex items-center gap-1.5 hover:opacity-80 transition-opacity",style:{background:"var(--bg-elevated)",color:"var(--fg)",border:"1px solid var(--border)"},children:[(0,b.jsx)("span",{"aria-hidden":!0,children:k.emoji}),!a&&(0,b.jsx)("span",{children:k.label})]}),i&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)("div",{className:"fixed inset-0 z-40",onClick:()=>j(!1)}),(0,b.jsx)("div",{className:"absolute right-0 top-full mt-1 z-50 rounded-md min-w-[160px] py-1 shadow-lg",style:{background:"var(--bg-secondary)",border:"1px solid var(--border)"},children:d.map(a=>(0,b.jsxs)("button",{onClick:()=>{var b;h(b=a.id),localStorage.setItem(e,b),f(b),j(!1)},className:"w-full px-3 py-2 text-left text-xs flex items-center gap-2 hover:opacity-80",style:{background:a.id===g?"var(--bg-elevated)":"transparent",color:"var(--fg)"},children:[(0,b.jsx)("span",{"aria-hidden":!0,children:a.emoji}),(0,b.jsx)("span",{className:"flex-1",children:a.label}),(0,b.jsx)("span",{style:{color:"var(--fg-dim)"},className:"text-[10px]",children:a.desc}),a.id===g&&(0,b.jsx)("span",{style:{color:"var(--accent)"},children:"•"})]},a.id))})]})]})}])},42588,a=>{"use strict";var b=a.i(87924),c=a.i(50944),d=a.i(38246),e=a.i(72131),f=a.i(72596),g=a.i(22397),h=a.i(76194);let i=a=>fetch(a).then(a=>a.ok?a.json():{networks:[]}),j=[{href:"/",label:"Overview",icon:"M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"},{href:"/tasks",label:"Tasks",icon:"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"},{href:"/nodes",label:"Nodes",icon:"M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"},{href:"/messages",label:"Messages",icon:"M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"},{href:"/settings/networks",label:"Networks",icon:"M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9"},{href:"/logs",label:"Audit Log",icon:"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"},{href:"/server-logs",label:"Server Logs",icon:"M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"},{href:"/admin",label:"Admin",icon:"M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"},{href:"/settings",label:"Settings",icon:"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z M15 12a3 3 0 11-6 0 3 3 0 016 0z"}],k={owner:"⭐",admin:"🔧",member:"👤",viewer:"👁"};function l(){let a=(0,c.usePathname)(),[l,m]=(0,e.useState)(!1),[o,p]=(0,e.useState)(!1),{networkId:q,setNetworkId:r}=(0,g.useNetworkId)(),{data:s}=(0,f.default)("/api/hub/networks",i,{refreshInterval:15e3,dedupingInterval:1e4}),t=s?.networks||[],u=(0,b.jsx)("nav",{className:"flex flex-col gap-1 px-2 py-4",children:j.map(c=>{var e;return(0,b.jsxs)(d.default,{href:c.href,prefetch:!1,onClick:()=>p(!1),className:`relative flex items-center gap-3 px-3 py-3 rounded-lg text-sm transition-colors active:bg-[#1a1a3a] ${("/"===(e=c.href)?"/"===a:"/settings"===e?"/settings"===a:a.startsWith(e))?"bg-cyan-500/10 text-cyan-300 border border-cyan-500/20 anet-nav-active":"text-gray-400 hover:text-gray-200 hover:bg-[#1a1a2a]"} ${l?"justify-center":""}`,children:[(0,b.jsx)("svg",{className:"w-5 h-5 shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:c.icon})}),!l&&(0,b.jsx)("span",{children:c.label})]},c.href)})});return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)("button",{onClick:()=>p(!o),className:"fixed top-4 left-3 z-50 lg:hidden bg-[#111128] border border-[#2a2a4a] rounded-lg p-2.5 text-gray-400 hover:text-white active:bg-[#1a1a3a]","aria-label":"Toggle menu",children:(0,b.jsx)("svg",{className:"w-5 h-5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:o?(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M6 18L18 6M6 6l12 12"}):(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M4 6h16M4 12h16M4 18h16"})})}),o&&(0,b.jsx)("div",{className:"fixed inset-0 bg-black/50 z-30 lg:hidden",onClick:()=>p(!1)}),(0,b.jsxs)("aside",{"data-anet-sidebar":"true",className:`
|
|
2
|
-
fixed top-0 left-0 h-full z-40 bg-[#0d0d1a] border-r border-[#2a2a4a]
|
|
3
|
-
transition-all duration-200
|
|
4
|
-
${l?"w-16":"w-52"}
|
|
5
|
-
${o?"translate-x-0":"-translate-x-full"}
|
|
6
|
-
lg:translate-x-0 lg:static lg:shrink-0
|
|
7
|
-
`,children:[(0,b.jsx)(n,{collapsed:l}),(0,b.jsx)("div",{className:"border-b border-[#2a2a4a]"}),!l&&t.length>0&&(0,b.jsxs)("div",{className:"px-2 py-3 border-b border-[#2a2a4a]",children:[(0,b.jsx)("div",{className:"px-3 text-[10px] text-gray-600 uppercase mb-2",children:"Networks"}),(0,b.jsx)("div",{className:"space-y-0.5 max-h-32 overflow-y-auto",children:t.map(a=>(0,b.jsxs)("button",{onClick:()=>{r(a.network_id),p(!1)},className:`w-full flex items-center gap-2 px-3 py-1.5 rounded-md text-xs transition-colors text-left ${q===a.network_id?"bg-cyan-500/10 text-cyan-300":"text-gray-500 hover:text-gray-300 hover:bg-[#1a1a2a]"}`,children:[(0,b.jsx)("span",{children:k[a.role||"member"]||"👤"}),(0,b.jsx)("span",{className:"truncate",children:a.network_name})]},a.network_id))})]}),(0,b.jsx)("div",{className:"pb-20",children:u}),(0,b.jsxs)("div",{className:"absolute bottom-0 left-0 right-0 border-t border-[#2a2a4a] bg-[#0d0d1a]",children:[!l&&(0,b.jsxs)("button",{onClick:async()=>{await fetch("/api/auth/logout",{method:"POST"}).catch(()=>{}),sessionStorage.removeItem("anet_v3_auth"),window.location.assign("/login")},className:"w-full flex items-center gap-3 px-5 py-3 text-xs text-gray-500 hover:text-red-400 hover:bg-red-500/5 transition-colors",children:[(0,b.jsx)("svg",{className:"w-4 h-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9"})}),"Sign out"]}),(0,b.jsxs)("div",{className:`flex items-center gap-2 px-3 py-2 ${l?"justify-center":"justify-between"}`,children:[(0,b.jsx)(h.ThemeSwitcher,{compact:l}),(0,b.jsx)("button",{onClick:()=>m(!l),className:"hidden lg:flex p-1.5 rounded text-gray-600 hover:text-gray-400 transition-colors","aria-label":l?"Expand sidebar":"Collapse sidebar",children:(0,b.jsx)("svg",{className:`w-4 h-4 transition-transform ${l?"rotate-180":""}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M15 19l-7-7 7-7"})})})]})]})]})]})}let m=a=>fetch(a).then(a=>a.ok?a.json():{sessions:[]});function n({collapsed:a}){let{data:c}=(0,f.default)("/api/hub/status",m,{refreshInterval:1e4,dedupingInterval:4e3}),e=c?.sessions||[],g=e.filter(a=>a.status&&"offline"!==a.status).length,h=e.length;return a?(0,b.jsx)(d.default,{href:"/",className:"block px-3 py-4 flex justify-center hover:opacity-80 transition-opacity","aria-label":"Agent Network — home",children:(0,b.jsx)(o,{size:32})}):(0,b.jsxs)(d.default,{href:"/",className:"block px-4 py-4 flex items-center gap-3 hover:bg-[#11112a]/40 transition-colors rounded-r-xl","aria-label":"Agent Network — home",children:[(0,b.jsx)(o,{size:32}),(0,b.jsxs)("div",{className:"min-w-0",children:[(0,b.jsx)("div",{className:"text-white text-[13px] font-semibold leading-tight",children:"Agent Network"}),(0,b.jsxs)("div",{className:"text-[10px] text-gray-500 flex items-center gap-1.5 mt-0.5",children:[(0,b.jsx)("span",{className:`inline-block w-1.5 h-1.5 rounded-full ${g>0?"bg-emerald-400 anet-brand-pulse":"bg-gray-600"}`,"aria-hidden":!0}),0===h?(0,b.jsx)("span",{children:"waiting for agents"}):(0,b.jsxs)("span",{children:[(0,b.jsx)("span",{className:"text-gray-300 font-medium tabular-nums",children:g}),(0,b.jsxs)("span",{className:"text-gray-600",children:["/",h]})," online"]})]})]})]})}function o({size:a}){return(0,b.jsxs)("svg",{width:a,height:a,viewBox:"0 0 32 32","aria-hidden":!0,className:"shrink-0",children:[(0,b.jsx)("circle",{cx:"16",cy:"16",r:"10",fill:"none",stroke:"currentColor",strokeWidth:"1.5",opacity:"0.2",className:"text-cyan-400"}),(0,b.jsx)("line",{x1:"16",y1:"10",x2:"10",y2:"20",stroke:"currentColor",strokeWidth:"1",opacity:"0.45",className:"text-cyan-400"}),(0,b.jsx)("line",{x1:"16",y1:"10",x2:"22",y2:"20",stroke:"currentColor",strokeWidth:"1",opacity:"0.45",className:"text-cyan-400"}),(0,b.jsx)("line",{x1:"10",y1:"20",x2:"22",y2:"20",stroke:"currentColor",strokeWidth:"1",opacity:"0.45",className:"text-cyan-400"}),(0,b.jsx)("circle",{cx:"16",cy:"10",r:"2.5",fill:"currentColor",className:"text-cyan-400"}),(0,b.jsx)("circle",{cx:"10",cy:"20",r:"2.5",fill:"currentColor",className:"text-green-400"}),(0,b.jsx)("circle",{cx:"22",cy:"20",r:"2.5",fill:"currentColor",className:"text-violet-400"})]})}let p=["/login"];a.s(["AppShell",0,function({children:a}){let d=(0,c.usePathname)();return p.includes(d)?(0,b.jsx)(b.Fragment,{children:a}):(0,b.jsxs)("div",{className:"flex min-h-screen",children:[(0,b.jsx)(l,{}),(0,b.jsx)("main",{className:"flex-1 min-w-0",children:a})]})}],42588)}];
|
|
8
|
-
|
|
9
|
-
//# sourceMappingURL=%5Broot-of-the-server%5D__013i9e9._.js.map
|