@sleep2agi/agent-network-dashboard 0.4.5-preview.7 → 0.4.5-preview.71
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 +49 -49
- 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 +4 -4
- 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 +4 -4
- 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 +4 -4
- 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 +4 -4
- 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 +4 -4
- 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 +4 -4
- 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 +4 -4
- 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 +4 -4
- 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 +4 -4
- 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_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens.html +4 -4
- 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 +4 -4
- 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 +4 -4
- 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]__0n4l2is._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0n4l2is._.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_01y-~mp._.js +3 -0
- package/.next/server/chunks/ssr/app_01y-~mp._.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_0aum_g5._.js +3 -0
- package/.next/server/chunks/ssr/app_0aum_g5._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0esuljp._.js +3 -0
- package/.next/server/chunks/ssr/app_0esuljp._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0izi28j._.js +1 -1
- package/.next/server/chunks/ssr/app_0izi28j._.js.map +1 -1
- package/.next/server/chunks/ssr/app_0py1sns._.js +3 -0
- package/.next/server/chunks/ssr/app_0py1sns._.js.map +1 -0
- package/.next/server/chunks/ssr/app_0tncr1_._.js +3 -0
- package/.next/server/chunks/ssr/app_0tncr1_._.js.map +1 -0
- package/.next/server/chunks/ssr/app_components_08ys5y3._.js +5 -5
- package/.next/server/chunks/ssr/app_components_08ys5y3._.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 +4 -4
- 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/013_kw~b7_tqy.js +1 -0
- package/.next/static/chunks/04dbz0h45njew.js +1 -0
- package/.next/static/chunks/06uku.~mtk9zz.js +1 -0
- package/.next/static/chunks/07gtk5bhf8gn9.js +1 -0
- package/.next/static/chunks/08scyy1.s_5my.js +1 -0
- package/.next/static/chunks/09oxaqu0qn3c9.js +1 -0
- package/.next/static/chunks/0b8qzoyn-7e~f.js +1 -0
- package/.next/static/chunks/{07okhs5561y5y.js → 0c1bp~g7.8ru..js} +1 -1
- package/.next/static/chunks/0dj5~edkdwh1n.js +1 -0
- package/.next/static/chunks/0glm3gl882al6.js +1 -0
- package/.next/static/chunks/0gnf.w4c8z.l~.js +1 -0
- package/.next/static/chunks/0iwn.7hiigyrz.js +7 -0
- package/.next/static/chunks/0l8112gmzl31s.js +1 -0
- package/.next/static/chunks/0rk5zmyp19fv8.js +7 -0
- package/.next/static/chunks/0uh.dd0_.y_dh.js +1 -0
- package/.next/static/chunks/0vn.u7tcybvik.js +1 -0
- package/.next/static/chunks/13u~uqoww_0ib.css +2 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/admin/page.tsx +90 -26
- package/app/components/AgentCard.tsx +19 -5
- package/app/components/BroadcastBar.tsx +22 -4
- package/app/components/DispatchPanel.tsx +9 -5
- package/app/components/EmptyState.tsx +77 -4
- package/app/components/HealthBanner.tsx +11 -2
- package/app/components/HelpOverlay.tsx +50 -10
- package/app/components/InboxPanel.tsx +7 -4
- package/app/components/Sidebar.tsx +49 -41
- package/app/components/StatsBar.tsx +59 -36
- package/app/components/TaskChatPanel.tsx +8 -10
- package/app/components/TaskDrawer.tsx +72 -28
- package/app/components/TopoGraph.tsx +118 -24
- package/app/components/utils.ts +13 -0
- package/app/globals.css +90 -0
- package/app/lib/status.ts +63 -0
- package/app/lib/version.ts +7 -0
- package/app/login/page.tsx +40 -7
- package/app/logs/page.tsx +70 -21
- package/app/messages/page.tsx +24 -7
- package/app/node/page.tsx +48 -25
- package/app/nodes/page.tsx +37 -9
- package/app/page.tsx +107 -36
- package/app/server-logs/page.tsx +97 -25
- package/app/settings/networks/page.tsx +37 -13
- package/app/settings/page.tsx +39 -11
- package/app/tasks/[id]/page.tsx +2 -13
- package/app/tasks/page.tsx +66 -73
- package/package.json +1 -1
- package/scripts/fold-only.mjs +44 -0
- package/scripts/loop-review.mjs +226 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__06pu~4t._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__06pu~4t._.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/_0uw5cjt._.js +0 -3
- package/.next/server/chunks/ssr/_0uw5cjt._.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_0ap_oiq._.js +0 -3
- package/.next/server/chunks/ssr/app_0ap_oiq._.js.map +0 -1
- package/.next/server/chunks/ssr/app_0dk5wao._.js +0 -3
- package/.next/server/chunks/ssr/app_0dk5wao._.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_0k8xbx~._.js +0 -9
- package/.next/server/chunks/ssr/app_0k8xbx~._.js.map +0 -1
- package/.next/server/chunks/ssr/app_11vl967._.js +0 -3
- package/.next/server/chunks/ssr/app_11vl967._.js.map +0 -1
- package/.next/server/chunks/ssr/app_login_page_tsx_0z71ad3._.js +0 -3
- package/.next/server/chunks/ssr/app_login_page_tsx_0z71ad3._.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/02flrewxlf_m_.js +0 -1
- package/.next/static/chunks/051gslfjka1kj.js +0 -1
- package/.next/static/chunks/06t_vzei8s9_h.js +0 -1
- package/.next/static/chunks/07oobuohrpigy.js +0 -1
- package/.next/static/chunks/09al3qm76q7nd.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/0ogeals5ufhho.js +0 -1
- package/.next/static/chunks/0v~9m62eciynd.js +0 -1
- package/.next/static/chunks/0xh3wr5rwvifr.css +0 -2
- package/.next/static/chunks/0z.pzy8zpa~js.js +0 -7
- package/.next/static/chunks/1031v6nw33ud3.js +0 -1
- package/.next/static/chunks/10ir.g.n~hre0.js +0 -7
- package/.next/static/chunks/10njj7kn9ylkf.js +0 -1
- package/.next/static/chunks/11v5tec4s1168.js +0 -1
- package/.next/static/chunks/13.dst7liziwo.js +0 -1
- package/public/file.svg +0 -1
- package/public/globe.svg +0 -1
- package/public/next.svg +0 -1
- package/public/vercel.svg +0 -1
- package/public/window.svg +0 -1
- /package/.next/static/{kyIvxswGu-u-KGQRAaXfV → C7A8u316NGa1ZA9zcEOFm}/_buildManifest.js +0 -0
- /package/.next/static/{kyIvxswGu-u-KGQRAaXfV → C7A8u316NGa1ZA9zcEOFm}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{kyIvxswGu-u-KGQRAaXfV → C7A8u316NGa1ZA9zcEOFm}/_ssgManifest.js +0 -0
package/app/tasks/page.tsx
CHANGED
|
@@ -7,6 +7,8 @@ import { useNetworkId } from '../lib/network-context';
|
|
|
7
7
|
import { TaskDrawer } from '../components/TaskDrawer';
|
|
8
8
|
import { EmptyState } from '../components/EmptyState';
|
|
9
9
|
import { AliasAvatar } from '../components/AliasAvatar';
|
|
10
|
+
import { previewContent } from '../components/utils';
|
|
11
|
+
import { TASK_STATUSES, STATUS_CHIP_CLASS, STATUS_DOT_HEX, STATUS_BAR_CLASS } from '../lib/status';
|
|
10
12
|
|
|
11
13
|
interface Task {
|
|
12
14
|
task_id: string;
|
|
@@ -24,48 +26,8 @@ interface Task {
|
|
|
24
26
|
expires_at: string;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
const STATUS_OPTIONS = [
|
|
28
|
-
'',
|
|
29
|
-
'created',
|
|
30
|
-
'delivered',
|
|
31
|
-
'acked',
|
|
32
|
-
'running',
|
|
33
|
-
'replied',
|
|
34
|
-
'closed',
|
|
35
|
-
'failed',
|
|
36
|
-
'cancelled',
|
|
37
|
-
'expired',
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
const STATUS_COLORS: Record<string, string> = {
|
|
41
|
-
created: 'bg-gray-500/10 text-gray-400 border-gray-500/20',
|
|
42
|
-
delivered: 'bg-blue-500/10 text-blue-300 border-blue-500/20',
|
|
43
|
-
acked: 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20',
|
|
44
|
-
running: 'bg-green-500/10 text-green-300 border-green-500/20',
|
|
45
|
-
replied: 'bg-purple-500/10 text-purple-300 border-purple-500/20',
|
|
46
|
-
closed: 'bg-gray-500/10 text-gray-500 border-gray-500/20',
|
|
47
|
-
failed: 'bg-red-500/10 text-red-300 border-red-500/20',
|
|
48
|
-
cancelled: 'bg-yellow-500/10 text-yellow-300 border-yellow-500/20',
|
|
49
|
-
expired: 'bg-orange-500/10 text-orange-300 border-orange-500/20',
|
|
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
|
-
|
|
67
29
|
function statusBadge(status: string) {
|
|
68
|
-
const color =
|
|
30
|
+
const color = STATUS_CHIP_CLASS[status] || 'bg-gray-500/10 text-gray-400 border-gray-500/20';
|
|
69
31
|
return `text-xs px-2 py-0.5 rounded-md border ${color}`;
|
|
70
32
|
}
|
|
71
33
|
|
|
@@ -145,11 +107,25 @@ function TasksContent() {
|
|
|
145
107
|
{/* Header */}
|
|
146
108
|
<div className="flex items-center gap-4 mb-6">
|
|
147
109
|
<h1 className="text-2xl font-bold text-white lg:ml-0 ml-10">Tasks</h1>
|
|
148
|
-
|
|
149
|
-
|
|
110
|
+
{/* Round 88: pagination-aware chip. When tasks.length < count
|
|
111
|
+
the API has more rows than the current limit=100 slice;
|
|
112
|
+
show `loaded / total` so users notice. Otherwise just the
|
|
113
|
+
single total — matches r87 /logs pattern. */}
|
|
114
|
+
<span
|
|
115
|
+
className="text-xs bg-blue-900/30 text-blue-400 px-2 py-0.5 rounded-full border border-blue-800/30 tabular-nums"
|
|
116
|
+
title={tasks.length < count ? `Showing ${tasks.length} of ${count} tasks` : undefined}
|
|
117
|
+
>
|
|
118
|
+
{tasks.length < count ? `${tasks.length} / ${count}` : count}
|
|
150
119
|
</span>
|
|
151
120
|
</div>
|
|
152
121
|
|
|
122
|
+
{/* Round 75: hide the status tab strip + From/To filter row when
|
|
123
|
+
there are no tasks at all. Each tab would show "0" and the
|
|
124
|
+
filter inputs would have nothing to act on — pure noise above
|
|
125
|
+
the empty-state CTA. When at least one task exists, the chrome
|
|
126
|
+
comes back even if the current filter happens to hide
|
|
127
|
+
everything (so users can clear filters). */}
|
|
128
|
+
{tasks.length > 0 && <>
|
|
153
129
|
{/* Status Tabs — color-coded dots per status family so users can
|
|
154
130
|
scan the row at a glance. Active tab gets full chip styling
|
|
155
131
|
(bg + border + text color), inactive tabs only carry the dot
|
|
@@ -159,23 +135,39 @@ function TasksContent() {
|
|
|
159
135
|
elements) hinting more content. */}
|
|
160
136
|
<div className="anet-tabstrip-wrap mb-4">
|
|
161
137
|
<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">
|
|
162
|
-
{
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
138
|
+
{(() => {
|
|
139
|
+
// Round 56: compute per-status counts so the tab strip doubles as a
|
|
140
|
+
// status distribution dashboard. Matches Audit Log (r43) + Overview
|
|
141
|
+
// agent filter (r34) chip-with-count pattern.
|
|
142
|
+
const counts: Record<string, number> = {};
|
|
143
|
+
tasks.forEach(t => { counts[t.status] = (counts[t.status] || 0) + 1; });
|
|
144
|
+
return ['', ...TASK_STATUSES].map(s => {
|
|
145
|
+
const count = s === '' ? tasks.length : counts[s] || 0;
|
|
146
|
+
const isActive = filterStatus === s;
|
|
147
|
+
return (
|
|
148
|
+
<button
|
|
149
|
+
key={s}
|
|
150
|
+
onClick={() => setFilterStatus(s)}
|
|
151
|
+
disabled={count === 0 && s !== '' && !isActive}
|
|
152
|
+
className={`px-3 py-1.5 rounded-md text-xs transition-colors flex items-center gap-1.5 shrink-0 whitespace-nowrap disabled:opacity-30 disabled:cursor-not-allowed ${
|
|
153
|
+
isActive
|
|
154
|
+
? `${STATUS_CHIP_CLASS[s] || 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20'} border`
|
|
155
|
+
: 'text-gray-500 hover:text-gray-300 hover:bg-[#1a1a2a]/40'
|
|
156
|
+
}`}
|
|
157
|
+
>
|
|
158
|
+
{s && (
|
|
159
|
+
<span
|
|
160
|
+
aria-hidden
|
|
161
|
+
className="inline-block w-1.5 h-1.5 rounded-full shrink-0"
|
|
162
|
+
style={{ backgroundColor: STATUS_DOT_HEX[s] || '#6b7280' }}
|
|
163
|
+
/>
|
|
164
|
+
)}
|
|
165
|
+
<span>{s || 'All'}</span>
|
|
166
|
+
<span className={`text-[10px] tabular-nums ${isActive ? 'opacity-80' : 'text-gray-600'}`}>{count}</span>
|
|
167
|
+
</button>
|
|
168
|
+
);
|
|
169
|
+
});
|
|
170
|
+
})()}
|
|
179
171
|
</div>
|
|
180
172
|
</div>
|
|
181
173
|
|
|
@@ -211,27 +203,28 @@ function TasksContent() {
|
|
|
211
203
|
</button>
|
|
212
204
|
)}
|
|
213
205
|
</div>
|
|
206
|
+
</>}
|
|
214
207
|
|
|
215
208
|
{/* Status distribution */}
|
|
216
209
|
{tasks.length > 0 && !filterStatus && (() => {
|
|
217
210
|
const stats: Record<string, number> = {};
|
|
218
211
|
tasks.forEach(t => { stats[t.status] = (stats[t.status] || 0) + 1; });
|
|
219
212
|
const total = tasks.length || 1;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
{ key
|
|
225
|
-
|
|
226
|
-
].filter(b => stats[b.key]);
|
|
213
|
+
// Round 67: derive from shared TASK_STATUSES + STATUS_BAR_CLASS in
|
|
214
|
+
// app/lib/status.ts. Adding a new lifecycle status updates badge,
|
|
215
|
+
// tab dots, and bar in one edit.
|
|
216
|
+
const bars = TASK_STATUSES
|
|
217
|
+
.map(key => ({ key, color: STATUS_BAR_CLASS[key] }))
|
|
218
|
+
.filter(b => stats[b.key]);
|
|
227
219
|
if (!bars.length) return null;
|
|
220
|
+
// Round 63: removed the per-status legend row beneath the bar —
|
|
221
|
+
// it duplicated the counts already shown in the tab chip strip
|
|
222
|
+
// since r56. The proportional bar stays because it adds a visual
|
|
223
|
+
// "shape of workload" that the chip numbers don't convey.
|
|
228
224
|
return (
|
|
229
225
|
<div className="mb-6">
|
|
230
226
|
<div className="flex h-2 rounded-full overflow-hidden bg-gray-800">
|
|
231
|
-
{bars.map(b => <div key={b.key} className={b.color} style={{ width: `${(stats[b.key]/total)*100}%` }} />)}
|
|
232
|
-
</div>
|
|
233
|
-
<div className="flex flex-wrap gap-3 mt-1.5 text-[10px] text-gray-500">
|
|
234
|
-
{bars.map(b => <span key={b.key}><span className={`inline-block w-2 h-2 rounded-full ${b.color} mr-1`} />{stats[b.key]} {b.key}</span>)}
|
|
227
|
+
{bars.map(b => <div key={b.key} className={b.color} style={{ width: `${(stats[b.key]/total)*100}%` }} title={`${b.key}: ${stats[b.key]}`} />)}
|
|
235
228
|
</div>
|
|
236
229
|
</div>
|
|
237
230
|
);
|
|
@@ -301,7 +294,7 @@ function TasksContent() {
|
|
|
301
294
|
<span className="truncate text-sm text-gray-200">{t.to_name || '--'}</span>
|
|
302
295
|
</div>
|
|
303
296
|
<div className="col-span-4 text-xs text-gray-400 truncate" title={t.content}>
|
|
304
|
-
{t.content
|
|
297
|
+
{previewContent(t.content)}
|
|
305
298
|
</div>
|
|
306
299
|
<div className="col-span-1">
|
|
307
300
|
<span className={`text-xs ${priorityBadge(t.priority)}`}>{t.priority || 'normal'}</span>
|
|
@@ -340,7 +333,7 @@ function TasksContent() {
|
|
|
340
333
|
{t.to_name && <AliasAvatar alias={t.to_name} size={16} />}
|
|
341
334
|
<span className="truncate max-w-[40%]">{t.to_name || '--'}</span>
|
|
342
335
|
</div>
|
|
343
|
-
<div className="text-xs text-gray-400 line-clamp-1">{t.content
|
|
336
|
+
<div className="text-xs text-gray-400 line-clamp-1" title={t.content}>{previewContent(t.content)}</div>
|
|
344
337
|
<div className="text-xs text-gray-600">{timeAgo(t.created_at)}</div>
|
|
345
338
|
</div>
|
|
346
339
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* Captures the fold (viewport-only screenshot) for a given page so we
|
|
2
|
+
* can inspect what the user actually sees on first paint. */
|
|
3
|
+
|
|
4
|
+
import { chromium } from 'playwright';
|
|
5
|
+
import { mkdirSync } from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
|
|
8
|
+
const TOKEN = process.env.LOOP_REVIEW_TOKEN;
|
|
9
|
+
const OUT = path.resolve(process.cwd(), 'test-results/loop-review/folds');
|
|
10
|
+
mkdirSync(OUT, { recursive: true });
|
|
11
|
+
|
|
12
|
+
const targets = [
|
|
13
|
+
{ name: 'tasks-cyber-desktop', path: '/tasks', theme: 'cyber', w: 1440, h: 900 },
|
|
14
|
+
{ name: 'tasks-cyber-mobile', path: '/tasks', theme: 'cyber', w: 390, h: 844 },
|
|
15
|
+
{ name: 'nodes-cyber-desktop', path: '/nodes', theme: 'cyber', w: 1440, h: 900 },
|
|
16
|
+
{ name: 'nodes-cyber-mobile', path: '/nodes', theme: 'cyber', w: 390, h: 844 },
|
|
17
|
+
{ name: 'overview-cyber-desktop', path: '/', theme: 'cyber', w: 1440, h: 900 },
|
|
18
|
+
{ name: 'overview-light-desktop', path: '/', theme: 'light', w: 1440, h: 900 },
|
|
19
|
+
{ name: 'server-logs-cyber-desktop', path: '/server-logs', theme: 'cyber', w: 1440, h: 900 },
|
|
20
|
+
{ name: 'server-logs-cyber-mobile', path: '/server-logs', theme: 'cyber', w: 390, h: 844 },
|
|
21
|
+
{ name: 'admin-cyber-desktop', path: '/admin', theme: 'cyber', w: 1440, h: 900 },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const browser = await chromium.launch({ headless: true });
|
|
25
|
+
for (const t of targets) {
|
|
26
|
+
const ctx = await browser.newContext({ viewport: { width: t.w, height: t.h } });
|
|
27
|
+
await ctx.addCookies([{
|
|
28
|
+
name: 'anet_dashboard_session',
|
|
29
|
+
value: `v3:${TOKEN}`,
|
|
30
|
+
domain: '127.0.0.1', path: '/',
|
|
31
|
+
}]);
|
|
32
|
+
await ctx.addInitScript(theme => {
|
|
33
|
+
try { localStorage.setItem('anet-theme', theme); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
34
|
+
}, t.theme);
|
|
35
|
+
const page = await ctx.newPage();
|
|
36
|
+
await page.goto(`http://127.0.0.1:3000${t.path}`, { waitUntil: 'domcontentloaded' });
|
|
37
|
+
await page.waitForTimeout(2500);
|
|
38
|
+
await page.evaluate(theme => document.documentElement.setAttribute('data-theme', theme), t.theme);
|
|
39
|
+
await page.waitForTimeout(300);
|
|
40
|
+
await page.screenshot({ path: path.join(OUT, `${t.name}.png`), fullPage: false, animations: 'disabled' });
|
|
41
|
+
await ctx.close();
|
|
42
|
+
}
|
|
43
|
+
await browser.close();
|
|
44
|
+
console.log('captured', targets.length, 'fold-only screenshots to', OUT);
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/* Loop self-review — captures Overview in cyber+light × desktop+mobile,
|
|
2
|
+
* runs a few observable checks, prints a per-axis score. Not a regression
|
|
3
|
+
* test — the cron's "review and score then propose next round" output.
|
|
4
|
+
*
|
|
5
|
+
* Round 71: replaced the toy checks (overflow, sidebar visible, blur count)
|
|
6
|
+
* with checks that actually catch the bugs we keep shipping:
|
|
7
|
+
* - CTA-above-fold: does the primary "Spin up" / "Get started" / etc
|
|
8
|
+
* button live within the first viewport? (deduct 3)
|
|
9
|
+
* - Zero-card density: how many "0" stat cards are crammed in above the
|
|
10
|
+
* CTA? (deduct 1 per zero-card beyond the first 2)
|
|
11
|
+
* - Whitespace gap: any element-to-element vertical gap >200px in the
|
|
12
|
+
* top half? (deduct 1)
|
|
13
|
+
* - Misleading-copy: "All systems go" text rendered when nodes.total=0
|
|
14
|
+
* (deduct 2) — round-70-class bug guard
|
|
15
|
+
* - Old: theme, horizontal overflow, sidebar, glow tell — still in
|
|
16
|
+
*
|
|
17
|
+
* Score is 10 max; deductions accumulate. The pre-r70 design that scored
|
|
18
|
+
* 10/10 here should now score ~4–5.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { chromium } from 'playwright';
|
|
22
|
+
import { mkdirSync } from 'node:fs';
|
|
23
|
+
import path from 'node:path';
|
|
24
|
+
|
|
25
|
+
const BASE = process.env.LOOP_REVIEW_BASE || 'http://127.0.0.1:3000';
|
|
26
|
+
const TOKEN = process.env.LOOP_REVIEW_TOKEN; // utok_...
|
|
27
|
+
const OUT = path.resolve(process.cwd(), 'test-results/loop-review');
|
|
28
|
+
mkdirSync(OUT, { recursive: true });
|
|
29
|
+
|
|
30
|
+
if (!TOKEN) {
|
|
31
|
+
console.error('LOOP_REVIEW_TOKEN env var required (utok_...)');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const viewports = [
|
|
36
|
+
{ tag: 'desktop', width: 1440, height: 900 },
|
|
37
|
+
{ tag: 'mobile', width: 390, height: 844 },
|
|
38
|
+
];
|
|
39
|
+
const themes = ['cyber', 'light'];
|
|
40
|
+
const pages = [
|
|
41
|
+
{ name: 'overview', path: '/' },
|
|
42
|
+
{ name: 'nodes', path: '/nodes' },
|
|
43
|
+
{ name: 'tasks', path: '/tasks' },
|
|
44
|
+
{ name: 'messages', path: '/messages' },
|
|
45
|
+
{ name: 'admin', path: '/admin' },
|
|
46
|
+
{ name: 'settings', path: '/settings' },
|
|
47
|
+
{ name: 'networks', path: '/settings/networks' },
|
|
48
|
+
{ name: 'logs', path: '/logs' },
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
const matrix = [];
|
|
52
|
+
for (const t of themes) for (const v of viewports) for (const p of pages) {
|
|
53
|
+
matrix.push({ theme: t, viewport: { width: v.width, height: v.height }, tag: v.tag, pageName: p.name, pagePath: p.path });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const browser = await chromium.launch({ headless: true });
|
|
57
|
+
|
|
58
|
+
const report = [];
|
|
59
|
+
|
|
60
|
+
for (const m of matrix) {
|
|
61
|
+
const ctx = await browser.newContext({
|
|
62
|
+
viewport: m.viewport,
|
|
63
|
+
deviceScaleFactor: 1,
|
|
64
|
+
});
|
|
65
|
+
await ctx.addCookies([{
|
|
66
|
+
name: 'anet_dashboard_session',
|
|
67
|
+
value: `v3:${TOKEN}`,
|
|
68
|
+
domain: '127.0.0.1',
|
|
69
|
+
path: '/',
|
|
70
|
+
}]);
|
|
71
|
+
await ctx.addInitScript((theme) => {
|
|
72
|
+
try {
|
|
73
|
+
localStorage.setItem('anet-theme', theme);
|
|
74
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
75
|
+
} catch {}
|
|
76
|
+
}, m.theme);
|
|
77
|
+
|
|
78
|
+
const page = await ctx.newPage();
|
|
79
|
+
await page.goto(`${BASE}${m.pagePath}`, { waitUntil: 'domcontentloaded', timeout: 15000 });
|
|
80
|
+
await page.waitForTimeout(1200);
|
|
81
|
+
|
|
82
|
+
await page.evaluate((t) => document.documentElement.setAttribute('data-theme', t), m.theme);
|
|
83
|
+
await page.waitForTimeout(300);
|
|
84
|
+
|
|
85
|
+
const file = path.join(OUT, `${m.pageName}-${m.theme}-${m.tag}.png`);
|
|
86
|
+
// animations: 'disabled' so polling/spinner-induced render churn does
|
|
87
|
+
// not stall the screenshot when the dash is populated.
|
|
88
|
+
await page.screenshot({ path: file, fullPage: true, animations: 'disabled', timeout: 60000 });
|
|
89
|
+
|
|
90
|
+
const checks = await page.evaluate(() => {
|
|
91
|
+
const doc = document.documentElement;
|
|
92
|
+
const theme = doc.getAttribute('data-theme');
|
|
93
|
+
const body = document.body;
|
|
94
|
+
const bodyBg = getComputedStyle(body).backgroundColor;
|
|
95
|
+
const bodyFg = getComputedStyle(body).color;
|
|
96
|
+
|
|
97
|
+
const viewportH = window.innerHeight;
|
|
98
|
+
const viewportW = window.innerWidth;
|
|
99
|
+
|
|
100
|
+
// --- CTA-above-fold ---
|
|
101
|
+
// We treat any of these texts as the page's primary CTA:
|
|
102
|
+
// "Spin up your first agent" — empty Overview onboarding
|
|
103
|
+
// "Get started" — generic
|
|
104
|
+
// "Dispatch" (when not empty) — populated state primary action
|
|
105
|
+
const ctaTextRe = /Spin up your first agent|Get started/i;
|
|
106
|
+
const ctaCandidates = [...document.querySelectorAll('h1, h2, h3, p, div, button, a')]
|
|
107
|
+
.filter(el => ctaTextRe.test(el.textContent || ''));
|
|
108
|
+
let ctaTop = null;
|
|
109
|
+
if (ctaCandidates.length) {
|
|
110
|
+
// Pick the smallest (innermost) element matching to avoid catching a wrapping section
|
|
111
|
+
const sorted = ctaCandidates.sort((a, b) => (a.textContent?.length || 0) - (b.textContent?.length || 0));
|
|
112
|
+
const r = sorted[0].getBoundingClientRect();
|
|
113
|
+
ctaTop = r.top;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// --- Zero-card density ---
|
|
117
|
+
// Count visible elements whose trimmed text === "0". These are usually
|
|
118
|
+
// big stat-card values dominating prime real estate.
|
|
119
|
+
const zeroCards = [...document.querySelectorAll('div, span')]
|
|
120
|
+
.filter(el => {
|
|
121
|
+
const t = el.textContent?.trim();
|
|
122
|
+
if (t !== '0' && t !== '0/0') return false;
|
|
123
|
+
const r = el.getBoundingClientRect();
|
|
124
|
+
return r.top >= 0 && r.top < viewportH && r.width > 20 && r.height > 20;
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// --- Whitespace gap ---
|
|
128
|
+
// Look for sibling-to-sibling top gaps >200px in the page content
|
|
129
|
+
// container. AppShell wraps page children in
|
|
130
|
+
// <main><HealthBanner/><div><div class="min-h-screen ...">{page}</div></div></main>,
|
|
131
|
+
// so we walk into that inner page wrapper to read real section gaps.
|
|
132
|
+
const main = document.querySelector('main');
|
|
133
|
+
const inner = main?.querySelector(':scope > div:last-of-type > div') || main || document.body;
|
|
134
|
+
const directKids = [...inner.children].filter(el => {
|
|
135
|
+
const r = el.getBoundingClientRect();
|
|
136
|
+
return r.height > 0 && r.width > 0;
|
|
137
|
+
});
|
|
138
|
+
let maxGap = 0;
|
|
139
|
+
for (let i = 0; i + 1 < directKids.length; i++) {
|
|
140
|
+
const a = directKids[i].getBoundingClientRect();
|
|
141
|
+
const b = directKids[i + 1].getBoundingClientRect();
|
|
142
|
+
if (a.bottom < 1600 && b.top - a.bottom > maxGap) {
|
|
143
|
+
maxGap = Math.round(b.top - a.bottom);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// --- Misleading copy guard ---
|
|
148
|
+
// "All systems go" must not appear anywhere when nodes.total === 0.
|
|
149
|
+
// We can't read state directly, but if the page also shows
|
|
150
|
+
// "Waiting for first agent" then we know fleet is empty.
|
|
151
|
+
const bodyText = document.body.innerText;
|
|
152
|
+
const fleetEmpty = /Waiting for first agent/i.test(bodyText);
|
|
153
|
+
const sayingAllSystemsGo = /All systems go/i.test(bodyText);
|
|
154
|
+
const misleadingCopy = fleetEmpty && sayingAllSystemsGo;
|
|
155
|
+
|
|
156
|
+
// --- Carryover ---
|
|
157
|
+
const docWidth = doc.scrollWidth;
|
|
158
|
+
const horizontalOverflow = docWidth > viewportW + 2;
|
|
159
|
+
let glowyCount = 0;
|
|
160
|
+
for (const el of document.querySelectorAll('body *')) {
|
|
161
|
+
const cs = getComputedStyle(el);
|
|
162
|
+
if (cs.filter && cs.filter.includes('blur(') && !cs.filter.includes('blur(0px)')) glowyCount++;
|
|
163
|
+
}
|
|
164
|
+
const sidebar = document.querySelector('aside, [data-sidebar], nav');
|
|
165
|
+
const sidebarRect = sidebar?.getBoundingClientRect();
|
|
166
|
+
const sidebarVisible = !!(sidebarRect && sidebarRect.width > 0 && sidebarRect.height > 0);
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
theme, bodyBg, bodyFg,
|
|
170
|
+
viewportH, viewportW,
|
|
171
|
+
ctaTop, ctaPresent: ctaCandidates.length > 0,
|
|
172
|
+
zeroCardCount: zeroCards.length,
|
|
173
|
+
maxGap,
|
|
174
|
+
fleetEmpty, sayingAllSystemsGo, misleadingCopy,
|
|
175
|
+
docWidth, horizontalOverflow,
|
|
176
|
+
glowyCount, sidebarVisible,
|
|
177
|
+
};
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
let score = 10;
|
|
181
|
+
const notes = [];
|
|
182
|
+
if (checks.theme !== m.theme) { score -= 3; notes.push(`theme=${checks.theme}`); }
|
|
183
|
+
if (checks.horizontalOverflow) { score -= 2; notes.push(`horiz overflow ${checks.docWidth}/${checks.viewportW}`); }
|
|
184
|
+
if (m.tag === 'desktop' && !checks.sidebarVisible) { score -= 1; notes.push('sidebar missing on desktop'); }
|
|
185
|
+
if (checks.glowyCount > 8) { score -= 1; notes.push(`${checks.glowyCount} blur-filter elements (glow tell)`); }
|
|
186
|
+
|
|
187
|
+
// New checks — the ones that would have caught r70's bug
|
|
188
|
+
if (checks.ctaPresent && checks.ctaTop !== null) {
|
|
189
|
+
if (checks.ctaTop > checks.viewportH) {
|
|
190
|
+
score -= 3;
|
|
191
|
+
notes.push(`CTA below fold (top=${Math.round(checks.ctaTop)} > vh=${checks.viewportH})`);
|
|
192
|
+
} else if (checks.ctaTop > checks.viewportH * 0.7) {
|
|
193
|
+
score -= 1;
|
|
194
|
+
notes.push(`CTA low in fold (top=${Math.round(checks.ctaTop)})`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (checks.zeroCardCount > 4) {
|
|
198
|
+
const extra = Math.min(checks.zeroCardCount - 4, 3);
|
|
199
|
+
score -= extra;
|
|
200
|
+
notes.push(`${checks.zeroCardCount} zero-value cards above fold`);
|
|
201
|
+
}
|
|
202
|
+
if (checks.maxGap > 200) {
|
|
203
|
+
score -= 1;
|
|
204
|
+
notes.push(`whitespace gap ${checks.maxGap}px`);
|
|
205
|
+
}
|
|
206
|
+
if (checks.misleadingCopy) {
|
|
207
|
+
score -= 2;
|
|
208
|
+
notes.push(`'All systems go' shown while fleet empty`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
report.push({ ...m, file, checks, score: Math.max(score, 0), notes });
|
|
212
|
+
|
|
213
|
+
await page.close();
|
|
214
|
+
await ctx.close();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
await browser.close();
|
|
218
|
+
|
|
219
|
+
console.log('\n=== Loop self-review (harness r73) ===\n');
|
|
220
|
+
for (const r of report) {
|
|
221
|
+
console.log(`${r.pageName.padEnd(8)} ${r.theme}/${r.tag.padEnd(7)} score=${r.score}/10`);
|
|
222
|
+
console.log(` cta_top=${r.checks.ctaTop !== null ? Math.round(r.checks.ctaTop) : '--'} zero_cards=${r.checks.zeroCardCount} max_gap=${r.checks.maxGap}px fleet_empty=${r.checks.fleetEmpty}`);
|
|
223
|
+
if (r.notes.length) console.log(` notes: ${r.notes.join(' · ')}`);
|
|
224
|
+
}
|
|
225
|
+
const avg = report.reduce((s, r) => s + r.score, 0) / report.length;
|
|
226
|
+
console.log(`\noverall avg = ${avg.toFixed(1)}/10 across ${report.length} captures`);
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
module.exports=[50227,(a,b,c)=>{b.exports=a.x("node:path",()=>require("node:path"))},43515,a=>{"use strict";a.s(["formatUptime",0,function(a){let b=Math.floor(a/3600),c=Math.floor(a%3600/60);return b>0?`${b}h ${c}m`:`${c}m`},"timeAgo",0,function(a){if(!a)return"--";let b=Math.floor((Date.now()-new Date(a.replace(" ","T")+"Z").getTime())/1e3);return b<60?`${b}s ago`:b<3600?`${Math.floor(b/60)}m ago`:b<86400?`${Math.floor(b/3600)}h ago`:`${Math.floor(b/86400)}d ago`}])},53142,a=>{"use strict";var b=a.i(87924),c=a.i(38246);let d={nodes:{title:"No agents in this network",sub:"Agent sessions will appear here once they connect to the CommHub."},tasks:{title:"No tasks yet",sub:"Tasks will appear here when agents send them via CommHub."},messages:{title:"No messages",sub:"Messages between agents will appear here."},logs:{title:"No audit logs",sub:"Events will appear here when users register, login, or perform actions."},tokens:{title:"No API tokens",sub:"Create one to authenticate CLI tools and external integrations."},networks:{title:"No networks found",sub:"Create one or sign in with V3 auth to see your networks."},generic:{title:"Nothing here yet",sub:"Data will appear here once available."}};function e({variant:a,size:c}){let d={width:c,height:c},f={fill:"none",stroke:"currentColor",strokeWidth:1.25,strokeLinecap:"round",strokeLinejoin:"round"};switch(a){case"nodes":return(0,b.jsx)("svg",{viewBox:"0 0 64 64",...d,children:(0,b.jsxs)("g",{...f,children:[(0,b.jsx)("circle",{cx:"32",cy:"14",r:"4"}),(0,b.jsx)("circle",{cx:"14",cy:"44",r:"4"}),(0,b.jsx)("circle",{cx:"50",cy:"44",r:"4"}),(0,b.jsx)("line",{x1:"32",y1:"18",x2:"14",y2:"40",strokeDasharray:"3 3",opacity:"0.6"}),(0,b.jsx)("line",{x1:"32",y1:"18",x2:"50",y2:"40",strokeDasharray:"3 3",opacity:"0.6"}),(0,b.jsx)("line",{x1:"18",y1:"44",x2:"46",y2:"44",strokeDasharray:"3 3",opacity:"0.6"})]})});case"tasks":return(0,b.jsx)("svg",{viewBox:"0 0 64 64",...d,children:(0,b.jsxs)("g",{...f,children:[(0,b.jsx)("rect",{x:"14",y:"14",width:"36",height:"6",rx:"1.5"}),(0,b.jsx)("rect",{x:"14",y:"26",width:"36",height:"6",rx:"1.5",opacity:"0.6"}),(0,b.jsx)("rect",{x:"14",y:"38",width:"36",height:"6",rx:"1.5",opacity:"0.35"})]})});case"messages":return(0,b.jsx)("svg",{viewBox:"0 0 64 64",...d,children:(0,b.jsxs)("g",{...f,children:[(0,b.jsx)("path",{d:"M14 18 h36 a3 3 0 0 1 3 3 v18 a3 3 0 0 1 -3 3 h-18 l-8 6 v-6 h-10 a3 3 0 0 1 -3 -3 v-18 a3 3 0 0 1 3 -3 z"}),(0,b.jsx)("line",{x1:"22",y1:"28",x2:"42",y2:"28",opacity:"0.5"}),(0,b.jsx)("line",{x1:"22",y1:"34",x2:"36",y2:"34",opacity:"0.5"})]})});case"logs":return(0,b.jsx)("svg",{viewBox:"0 0 64 64",...d,children:(0,b.jsxs)("g",{...f,children:[(0,b.jsx)("path",{d:"M18 12 h22 l8 8 v32 a2 2 0 0 1 -2 2 h-28 a2 2 0 0 1 -2 -2 v-38 a2 2 0 0 1 2 -2 z"}),(0,b.jsx)("path",{d:"M40 12 v8 h8",opacity:"0.6"}),(0,b.jsx)("line",{x1:"24",y1:"32",x2:"40",y2:"32",opacity:"0.55"}),(0,b.jsx)("line",{x1:"24",y1:"38",x2:"40",y2:"38",opacity:"0.4"}),(0,b.jsx)("line",{x1:"24",y1:"44",x2:"34",y2:"44",opacity:"0.25"})]})});case"tokens":return(0,b.jsx)("svg",{viewBox:"0 0 64 64",...d,children:(0,b.jsxs)("g",{...f,children:[(0,b.jsx)("circle",{cx:"22",cy:"32",r:"8"}),(0,b.jsx)("line",{x1:"30",y1:"32",x2:"54",y2:"32"}),(0,b.jsx)("line",{x1:"44",y1:"32",x2:"44",y2:"38"}),(0,b.jsx)("line",{x1:"50",y1:"32",x2:"50",y2:"40"})]})});case"networks":return(0,b.jsx)("svg",{viewBox:"0 0 64 64",...d,children:(0,b.jsxs)("g",{...f,children:[(0,b.jsx)("circle",{cx:"32",cy:"32",r:"18"}),(0,b.jsx)("ellipse",{cx:"32",cy:"32",rx:"18",ry:"9",opacity:"0.55"}),(0,b.jsx)("line",{x1:"14",y1:"32",x2:"50",y2:"32",opacity:"0.55"}),(0,b.jsx)("line",{x1:"32",y1:"14",x2:"32",y2:"50",opacity:"0.55"})]})});default:return(0,b.jsx)("svg",{viewBox:"0 0 64 64",...d,children:(0,b.jsxs)("g",{...f,children:[(0,b.jsx)("circle",{cx:"32",cy:"32",r:"14",strokeDasharray:"3 3",opacity:"0.6"}),(0,b.jsx)("circle",{cx:"32",cy:"32",r:"3"})]})})}}function f({variant:a="generic",title:g,sub:h,cta:i,compact:j=!1}){let k=d[a],l=g??k.title,m=h??k.sub;return(0,b.jsxs)("div",{className:`text-center ${j?"py-8":"py-16"} px-4`,role:"status",children:[(0,b.jsx)("div",{className:"anet-empty-glyph inline-flex items-center justify-center mb-4 text-gray-500","aria-hidden":!0,children:(0,b.jsx)(e,{variant:a,size:j?40:56})}),(0,b.jsx)("h3",{className:`font-medium text-gray-300 ${j?"text-sm":"text-base"}`,children:l}),m&&(0,b.jsx)("p",{className:`text-gray-500 ${j?"text-xs mt-1.5":"text-sm mt-2"} max-w-md mx-auto leading-relaxed`,children:m}),i&&(0,b.jsx)("div",{className:"mt-4",children:i.href?(0,b.jsxs)(c.default,{href:i.href,className:"inline-flex items-center gap-1.5 text-sm font-medium text-cyan-400 hover:text-cyan-300",children:[i.label,(0,b.jsx)("span",{"aria-hidden":!0,children:"→"})]}):(0,b.jsxs)("button",{onClick:i.onClick,className:"inline-flex items-center gap-1.5 text-sm font-medium text-cyan-400 hover:text-cyan-300",children:[i.label,(0,b.jsx)("span",{"aria-hidden":!0,children:"→"})]})})]})}a.s(["EmptyState",0,f,"NodesEmptyState",0,function({hint:a}){return a?.global_count?(0,b.jsx)(f,{variant:"nodes",title:"No agents in this network",sub:`Server has ${a.global_count} nodes globally, but none are registered to the current network. Switch network or contact admin.`}):(0,b.jsx)(f,{variant:"nodes",cta:{label:"Run anet quickstart",href:"https://anet.sh"}})}])},44332,a=>{"use strict";var b=a.i(72596),c=a.i(22397);let d=async a=>{let b=await fetch(a);if(401===b.status)throw window.location.assign("/login"),Error("unauthorized");return b.json()},e={refreshInterval:5e3,dedupingInterval:3e3};function f(a,b){if(!b)return a;let c=a.includes("?")?"&":"?";return`${a}${c}network_id=${encodeURIComponent(b)}`}a.s(["useAnetConfig",0,function(){let{data:a}=(0,b.default)("/api/anet/config",d,{refreshInterval:3e4});return{config:a||null}},"useHealth",0,function(){let{data:a,error:c}=(0,b.default)("/api/hub/health",d,e);return{health:a||null,error:c}},"useLicense",0,function(){let{data:a,error:c}=(0,b.default)("/api/hub/license",d,{refreshInterval:6e4});return{license:a?.ok?a:null,error:c}},"useMessages",0,function(a=100){let{networkId:g}=(0,c.useNetworkId)(),{data:h,error:i,isLoading:j}=(0,b.default)(f(`/api/hub/messages?limit=${a}`,g),d,e);return{messages:h?.messages||[],error:i,isLoading:j}},"useSessions",0,function(){let{networkId:a}=(0,c.useNetworkId)(),{data:g,error:h,isLoading:i}=(0,b.default)(f("/api/hub/status",a),d,e);return{sessions:g?.sessions||[],hint:g?._hint,error:h,isLoading:i}},"useStats",0,function(){let{networkId:a}=(0,c.useNetworkId)(),{data:g,error:h}=(0,b.default)(f("/api/hub/stats",a),d,e);return{stats:g?.ok?g:null,error:h}},"useTasks",0,function(a){let{networkId:g}=(0,c.useNetworkId)(),h=new URLSearchParams({limit:"100",...a}).toString(),{data:i,error:j,isLoading:k}=(0,b.default)(f(`/api/hub/tasks?${h}`,g),d,e);return{tasks:i?.tasks||[],count:i?.count??0,source:i?.source,error:j,isLoading:k}}])},54826,(a,b,c)=>{},15299,(a,b,c)=>{a.r(54826);var d=a.r(72131),e=d&&"object"==typeof d&&"default"in d?d:{default:d},f="u">typeof process&&process.env&&!0,g=function(a){return"[object String]"===Object.prototype.toString.call(a)},h=function(){function a(a){var b=void 0===a?{}:a,c=b.name,d=void 0===c?"stylesheet":c,e=b.optimizeForSpeed,h=void 0===e?f:e;i(g(d),"`name` must be a string"),this._name=d,this._deletedRulePlaceholder="#"+d+"-deleted-rule____{}",i("boolean"==typeof h,"`optimizeForSpeed` must be a boolean"),this._optimizeForSpeed=h,this._serverSheet=void 0,this._tags=[],this._injected=!1,this._rulesCount=0,this._nonce=null}var b,c=a.prototype;return c.setOptimizeForSpeed=function(a){i("boolean"==typeof a,"`setOptimizeForSpeed` accepts a boolean"),i(0===this._rulesCount,"optimizeForSpeed cannot be when rules have already been inserted"),this.flush(),this._optimizeForSpeed=a,this.inject()},c.isOptimizeForSpeed=function(){return this._optimizeForSpeed},c.inject=function(){var a=this;i(!this._injected,"sheet already injected"),this._injected=!0,this._serverSheet={cssRules:[],insertRule:function(b,c){return"number"==typeof c?a._serverSheet.cssRules[c]={cssText:b}:a._serverSheet.cssRules.push({cssText:b}),c},deleteRule:function(b){a._serverSheet.cssRules[b]=null}}},c.getSheetForTag=function(a){if(a.sheet)return a.sheet;for(var b=0;b<document.styleSheets.length;b++)if(document.styleSheets[b].ownerNode===a)return document.styleSheets[b]},c.getSheet=function(){return this.getSheetForTag(this._tags[this._tags.length-1])},c.insertRule=function(a,b){return i(g(a),"`insertRule` accepts only strings"),"number"!=typeof b&&(b=this._serverSheet.cssRules.length),this._serverSheet.insertRule(a,b),this._rulesCount++},c.replaceRule=function(a,b){this._optimizeForSpeed;var c=this._serverSheet;if(b.trim()||(b=this._deletedRulePlaceholder),!c.cssRules[a])return a;c.deleteRule(a);try{c.insertRule(b,a)}catch(d){f||console.warn("StyleSheet: illegal rule: \n\n"+b+"\n\nSee https://stackoverflow.com/q/20007992 for more info"),c.insertRule(this._deletedRulePlaceholder,a)}return a},c.deleteRule=function(a){this._serverSheet.deleteRule(a)},c.flush=function(){this._injected=!1,this._rulesCount=0,this._serverSheet.cssRules=[]},c.cssRules=function(){return this._serverSheet.cssRules},c.makeStyleTag=function(a,b,c){b&&i(g(b),"makeStyleTag accepts only strings as second parameter");var d=document.createElement("style");this._nonce&&d.setAttribute("nonce",this._nonce),d.type="text/css",d.setAttribute("data-"+a,""),b&&d.appendChild(document.createTextNode(b));var e=document.head||document.getElementsByTagName("head")[0];return c?e.insertBefore(d,c):e.appendChild(d),d},b=[{key:"length",get:function(){return this._rulesCount}}],function(a,b){for(var c=0;c<b.length;c++){var d=b[c];d.enumerable=d.enumerable||!1,d.configurable=!0,"value"in d&&(d.writable=!0),Object.defineProperty(a,d.key,d)}}(a.prototype,b),a}();function i(a,b){if(!a)throw Error("StyleSheet: "+b+".")}var j=function(a){for(var b=5381,c=a.length;c;)b=33*b^a.charCodeAt(--c);return b>>>0},k={};function l(a,b){if(!b)return"jsx-"+a;var c=String(b),d=a+c;return k[d]||(k[d]="jsx-"+j(a+"-"+c)),k[d]}function m(a,b){var c=a+(b=b.replace(/\/style/gi,"\\/style"));return k[c]||(k[c]=b.replace(/__jsx-style-dynamic-selector/g,a)),k[c]}var n=function(){function a(a){var b=void 0===a?{}:a,c=b.styleSheet,d=void 0===c?null:c,e=b.optimizeForSpeed,f=void 0!==e&&e;this._sheet=d||new h({name:"styled-jsx",optimizeForSpeed:f}),this._sheet.inject(),d&&"boolean"==typeof f&&(this._sheet.setOptimizeForSpeed(f),this._optimizeForSpeed=this._sheet.isOptimizeForSpeed()),this._fromServer=void 0,this._indices={},this._instancesCounts={}}var b=a.prototype;return b.add=function(a){var b=this;void 0===this._optimizeForSpeed&&(this._optimizeForSpeed=Array.isArray(a.children),this._sheet.setOptimizeForSpeed(this._optimizeForSpeed),this._optimizeForSpeed=this._sheet.isOptimizeForSpeed());var c=this.getIdAndRules(a),d=c.styleId,e=c.rules;if(d in this._instancesCounts){this._instancesCounts[d]+=1;return}var f=e.map(function(a){return b._sheet.insertRule(a)}).filter(function(a){return -1!==a});this._indices[d]=f,this._instancesCounts[d]=1},b.remove=function(a){var b=this,c=this.getIdAndRules(a).styleId;if(function(a,b){if(!a)throw Error("StyleSheetRegistry: "+b+".")}(c in this._instancesCounts,"styleId: `"+c+"` not found"),this._instancesCounts[c]-=1,this._instancesCounts[c]<1){var d=this._fromServer&&this._fromServer[c];d?(d.parentNode.removeChild(d),delete this._fromServer[c]):(this._indices[c].forEach(function(a){return b._sheet.deleteRule(a)}),delete this._indices[c]),delete this._instancesCounts[c]}},b.update=function(a,b){this.add(b),this.remove(a)},b.flush=function(){this._sheet.flush(),this._sheet.inject(),this._fromServer=void 0,this._indices={},this._instancesCounts={}},b.cssRules=function(){var a=this,b=this._fromServer?Object.keys(this._fromServer).map(function(b){return[b,a._fromServer[b]]}):[],c=this._sheet.cssRules();return b.concat(Object.keys(this._indices).map(function(b){return[b,a._indices[b].map(function(a){return c[a].cssText}).join(a._optimizeForSpeed?"":"\n")]}).filter(function(a){return!!a[1]}))},b.styles=function(a){var b,c;return b=this.cssRules(),void 0===(c=a)&&(c={}),b.map(function(a){var b=a[0],d=a[1];return e.default.createElement("style",{id:"__"+b,key:"__"+b,nonce:c.nonce?c.nonce:void 0,dangerouslySetInnerHTML:{__html:d}})})},b.getIdAndRules=function(a){var b=a.children,c=a.dynamic,d=a.id;if(c){var e=l(d,c);return{styleId:e,rules:Array.isArray(b)?b.map(function(a){return m(e,a)}):[m(e,b)]}}return{styleId:l(d),rules:Array.isArray(b)?b:[b]}},b.selectFromServer=function(){return Array.prototype.slice.call(document.querySelectorAll('[id^="__jsx-"]')).reduce(function(a,b){return a[b.id.slice(2)]=b,a},{})},a}(),o=d.createContext(null);function p(){return new n}function q(){return d.useContext(o)}function r(a){var b=q();return b&&b.add(a),null}o.displayName="StyleSheetContext",e.default.useInsertionEffect||e.default.useLayoutEffect,r.dynamic=function(a){return a.map(function(a){return l(a[0],a[1])}).join(" ")},c.StyleRegistry=function(a){var b=a.registry,c=a.children,f=d.useContext(o),g=d.useState(function(){return f||b||p()})[0];return e.default.createElement(o.Provider,{value:g},c)},c.createStyleRegistry=p,c.style=r,c.useStyleRegistry=q},31626,(a,b,c)=>{b.exports=a.r(15299).style},1720,a=>{"use strict";var b=a.i(87924);let c=[180,200,220,270,300,330,30,90];a.s(["AliasAvatar",0,function({alias:a,size:d=28,className:e=""}){let f=function(a){let b=0;for(let c=0;c<a.length;c++)b=31*b+a.charCodeAt(c)>>>0;let d=c[b%c.length];return{bg:`hsl(${d} 55% 22%)`,ring:`hsl(${d} 60% 45%)`,text:`hsl(${d} 80% 78%)`}}(a),g=Math.max(9,Math.round(.42*d));return(0,b.jsx)("span",{className:`anet-alias-avatar inline-flex items-center justify-center rounded-full border shrink-0 font-semibold ${e}`,style:{width:d,height:d,fontSize:g,backgroundColor:f.bg,borderColor:f.ring,color:f.text},title:a,"aria-hidden":!0,children:a?(a.trim().match(/[\p{L}\p{N}]/u)?.[0]||a.trim()[0]||"·").toUpperCase():"·"})}])},96794,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(38246),e=a.i(43515),f=a.i(44332),g=a.i(15261),h=a.i(53142),i=a.i(1720);let j={working:"bg-green-500/10 text-green-300 border-green-500/20",idle:"bg-blue-500/10 text-blue-300 border-blue-500/20",blocked:"bg-yellow-500/10 text-yellow-300 border-yellow-500/20",error:"bg-red-500/10 text-red-300 border-red-500/20",offline:"bg-gray-500/10 text-gray-500 border-gray-500/20"};a.s(["default",0,function(){let a,k,l,m,{sessions:n,isLoading:o}=(0,f.useSessions)(),{health:p}=(0,f.useHealth)(),q=p?.sse_sessions||{},r=a=>(a.network_id?q[`${a.network_id}:${a.alias}`]:void 0)??q[a.alias],[s,t]=(0,c.useState)(""),[u,v]=(0,c.useState)(""),[w,x]=(0,c.useState)("list"),[y,z]=(0,c.useState)({}),[A,B]=(0,c.useState)(null),[C,D]=(0,c.useState)({}),[E,F]=(0,c.useState)(null),G=n.map(a=>({...a,online:!!r(a)})).filter(a=>"online"===s?a.online:"offline"===s?!a.online:!s||s===a.status).filter(a=>!u||a.alias.toLowerCase().includes(u.toLowerCase())||(a.agent||"").toLowerCase().includes(u.toLowerCase())).sort((a,b)=>!!b.online-!!a.online||("working"===b.status)-("working"===a.status)),H=n.filter(a=>r(a)).length,I=a=>{B(b=>b===a?null:a),D(b=>({...b,[a]:{}}))},J=(a,b)=>{z(c=>({...c,[a]:b}))},K=async a=>{let b=y[a]?.trim()||"";if(b){D(b=>({...b,[a]:{sending:!0}}));try{let c=await fetch("/api/hub/send",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({alias:a,task:b})}),d=await c.json();if(!c.ok||d?.ok===!1)throw Error(d?.error||"Send failed");z(b=>({...b,[a]:""})),D(b=>({...b,[a]:{success:"Task sent"}})),B(null)}catch(b){D(c=>({...c,[a]:{error:b instanceof Error?b.message:"Send failed"}}))}}};return(0,b.jsxs)("div",{className:"min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono",children:[(0,b.jsxs)("div",{className:"flex items-center gap-4 mb-6",children:[(0,b.jsx)("h1",{className:"text-2xl font-bold text-white lg:ml-0 ml-10",children:"Nodes"}),(0,b.jsxs)("span",{className:"text-xs bg-green-900/30 text-green-400 px-2 py-0.5 rounded-full border border-green-800/30",children:[H," online"]}),(0,b.jsxs)("span",{className:"text-xs bg-gray-900/30 text-gray-400 px-2 py-0.5 rounded-full border border-gray-800/30",children:[n.length," total"]})]}),n.length>0&&(a=G.filter(a=>a.online&&"working"===a.status).length,k=G.filter(a=>a.online&&"idle"===a.status).length,l=G.filter(a=>!a.online).length,m=G.length||1,(0,b.jsxs)("div",{className:"mb-6",children:[(0,b.jsxs)("div",{className:"flex h-2 rounded-full overflow-hidden bg-gray-800",children:[a>0&&(0,b.jsx)("div",{className:"bg-green-500",style:{width:`${a/m*100}%`}}),k>0&&(0,b.jsx)("div",{className:"bg-cyan-500",style:{width:`${k/m*100}%`}}),l>0&&(0,b.jsx)("div",{className:"bg-gray-600",style:{width:`${l/m*100}%`}})]}),(0,b.jsxs)("div",{className:"flex gap-4 mt-1.5 text-[10px] text-gray-500",children:[a>0&&(0,b.jsxs)("span",{children:[(0,b.jsx)("span",{className:"inline-block w-2 h-2 rounded-full bg-green-500 mr-1"}),a," working"]}),k>0&&(0,b.jsxs)("span",{children:[(0,b.jsx)("span",{className:"inline-block w-2 h-2 rounded-full bg-cyan-500 mr-1"}),k," idle"]}),l>0&&(0,b.jsxs)("span",{children:[(0,b.jsx)("span",{className:"inline-block w-2 h-2 rounded-full bg-gray-600 mr-1"}),l," offline"]})]})]})),(0,b.jsxs)("div",{className:"flex flex-wrap gap-3 mb-6",children:[(0,b.jsx)("input",{type:"text",value:u,onChange:a=>v(a.target.value),placeholder:"Search nodes...",className:"bg-[#111128] border border-[#2a2a4a] rounded-lg px-3 py-2 text-sm text-white placeholder-gray-600 focus:border-blue-500/50 focus:outline-none w-48"}),(0,b.jsxs)("select",{value:s,onChange:a=>t(a.target.value),className:"bg-[#111128] border border-[#2a2a4a] rounded-lg px-3 py-2 text-sm text-white focus:border-blue-500/50 focus:outline-none",children:[(0,b.jsx)("option",{value:"",children:"All"}),(0,b.jsx)("option",{value:"online",children:"Online"}),(0,b.jsx)("option",{value:"offline",children:"Offline"}),(0,b.jsx)("option",{value:"working",children:"Working"}),(0,b.jsx)("option",{value:"idle",children:"Idle"}),(0,b.jsx)("option",{value:"blocked",children:"Blocked"}),(0,b.jsx)("option",{value:"error",children:"Error"})]}),(0,b.jsx)("div",{className:"ml-auto flex rounded-lg border border-[#2a2a4a] bg-[#111128] p-1 text-sm",children:["list","grid"].map(a=>(0,b.jsx)("button",{type:"button",onClick:()=>x(a),className:`rounded-md px-3 py-1.5 transition-colors ${w===a?"bg-cyan-500/10 text-cyan-300":"text-gray-500 hover:text-gray-200"}`,children:"list"===a?"List":"Grid"},a))})]}),o?(0,b.jsx)("div",{className:"animate-pulse space-y-2",children:[1,2,3,4].map(a=>(0,b.jsx)("div",{className:"h-16 bg-gray-800/20 rounded-lg"},a))}):0===G.length?(0,b.jsx)(h.EmptyState,{variant:"nodes",title:"No nodes match your filters",sub:"Try clearing search or status filters, or wait for an agent to register."}):"grid"===w?(0,b.jsx)("div",{className:"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4",children:G.map(a=>{let c=a.online?a.status:"offline",f=C[a.alias]||{},g="number"==typeof a.progress?a.progress:0;return(0,b.jsxs)("div",{className:`relative overflow-hidden rounded-xl border border-[#2a2a4a] bg-[#111128] p-4 transition-colors ${!a.online?"opacity-60":""}`,children:[!a.online&&(0,b.jsx)("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:(0,b.jsx)("span",{className:"rotate-[-20deg] rounded-xl border border-white/10 bg-black/20 px-5 py-2 text-xl font-bold uppercase tracking-[0.35em] text-white/10",children:"Offline"})}),(0,b.jsxs)("div",{className:"flex items-start gap-3",children:[(0,b.jsx)(i.AliasAvatar,{alias:a.alias,size:36}),(0,b.jsxs)(d.default,{href:`/node?alias=${encodeURIComponent(a.alias)}`,className:"min-w-0 flex-1 hover:text-cyan-300",children:[(0,b.jsxs)("div",{className:"flex items-center gap-2",children:[(0,b.jsx)("span",{className:"truncate text-base font-semibold text-white",children:a.alias}),(0,b.jsx)("span",{className:`shrink-0 rounded-md border px-2 py-0.5 text-[10px] uppercase tracking-wide ${j[c]||j.offline}`,children:c})]}),(0,b.jsxs)("div",{className:"mt-0.5 truncate text-xs text-gray-500",children:[a.agent||"—",(0,b.jsx)("span",{className:"text-gray-700 mx-1.5",children:"·"}),a.server||"—"]})]}),(0,b.jsxs)("div",{className:"flex gap-1.5 shrink-0",children:[(0,b.jsx)("button",{type:"button",onClick:()=>F(a.alias),className:"rounded-lg border border-green-500/20 bg-green-500/10 px-3 py-1.5 text-xs text-green-300 transition-colors hover:bg-green-500/20",children:"Chat"}),(0,b.jsx)("button",{type:"button",onClick:()=>I(a.alias),className:"rounded-lg border border-cyan-500/20 bg-cyan-500/10 px-3 py-1.5 text-xs text-cyan-300 transition-colors hover:bg-cyan-500/20",children:"Task"})]})]}),(0,b.jsxs)("div",{className:"mt-3 rounded-lg border border-[#1a1a2a] bg-[#0a0a15] px-3 py-2 text-xs",children:[(0,b.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,b.jsx)("span",{className:"text-[10px] uppercase tracking-wide text-gray-600",children:"Current task"}),(0,b.jsx)("span",{className:"text-[10px] text-gray-600",children:(0,e.timeAgo)(a.last_seen_at||a.updated_at)})]}),(0,b.jsx)("div",{className:`mt-1 line-clamp-2 ${a.task?"text-gray-300":"text-gray-600 italic"}`,children:a.task||"No current task"})]}),g>0&&g<100&&(0,b.jsx)("div",{className:"mt-3 h-1.5 overflow-hidden rounded-full bg-gray-800",children:(0,b.jsx)("div",{className:"h-1.5 rounded-full bg-cyan-400 transition-all",style:{width:`${g}%`}})}),A===a.alias&&(0,b.jsxs)("div",{className:"mt-4 space-y-2 rounded-lg border border-[#2a2a4a] bg-[#0a0a15] p-3",children:[(0,b.jsx)("input",{type:"text",value:y[a.alias]||"",onChange:b=>J(a.alias,b.target.value),onKeyDown:b=>"Enter"===b.key&&K(a.alias),placeholder:`Send task to ${a.alias}...`,className:"w-full rounded-lg border border-[#2a2a4a] bg-[#050510] px-3 py-2 text-xs text-white placeholder-gray-600 focus:border-cyan-500 focus:outline-none"}),(0,b.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,b.jsx)("button",{type:"button",onClick:()=>B(null),className:"rounded-lg border border-gray-700 px-3 py-1.5 text-xs text-gray-400 hover:text-gray-200",children:"Cancel"}),(0,b.jsx)("button",{type:"button",onClick:()=>K(a.alias),disabled:f.sending||!(y[a.alias]||"").trim(),className:"rounded-lg bg-cyan-600 px-3 py-1.5 text-xs text-white hover:bg-cyan-500 disabled:cursor-not-allowed disabled:bg-gray-700",children:f.sending?"Sending...":"Send"})]})]}),f.error&&(0,b.jsx)("div",{className:"mt-2 text-xs text-red-400",children:f.error}),f.success&&A!==a.alias&&(0,b.jsx)("div",{className:"mt-2 text-xs text-green-400",children:f.success})]},a.alias)})}):(0,b.jsxs)("div",{className:"space-y-2",children:[(0,b.jsxs)("div",{className:"hidden sm:grid sm:grid-cols-12 gap-2 px-4 py-2 text-xs text-gray-600 uppercase",children:[(0,b.jsx)("div",{className:"col-span-1",children:"Status"}),(0,b.jsx)("div",{className:"col-span-2",children:"Alias"}),(0,b.jsx)("div",{className:"col-span-2",children:"Agent"}),(0,b.jsx)("div",{className:"col-span-2",children:"Server"}),(0,b.jsx)("div",{className:"col-span-2",children:"Current Task"}),(0,b.jsx)("div",{className:"col-span-1",children:"Updated"}),(0,b.jsx)("div",{className:"col-span-2 text-right",children:"Actions"})]}),G.map(a=>{let c=a.online?a.status:"offline",f=C[a.alias]||{};return(0,b.jsxs)("div",{className:`rounded-lg border border-[#2a2a4a] bg-[#111128] px-4 py-3 transition-colors hover:border-[#3a3a5a] ${!a.online?"opacity-50":""}`,children:[(0,b.jsxs)("div",{className:"hidden sm:grid sm:grid-cols-12 gap-2 items-center",children:[(0,b.jsx)("div",{className:"col-span-1",children:(0,b.jsx)("span",{className:`text-xs px-2 py-0.5 rounded-md border ${j[c]||j.offline}`,children:c})}),(0,b.jsx)("div",{className:"col-span-2 min-w-0",children:(0,b.jsxs)(d.default,{href:`/node?alias=${encodeURIComponent(a.alias)}`,className:"flex items-center gap-2 min-w-0 hover:text-cyan-300",children:[(0,b.jsx)(i.AliasAvatar,{alias:a.alias,size:20}),(0,b.jsx)("span",{className:"truncate text-sm font-medium text-white",children:a.alias})]})}),(0,b.jsx)("div",{className:"col-span-2 truncate text-xs text-gray-400",children:a.agent||"--"}),(0,b.jsx)("div",{className:"col-span-2 truncate text-xs text-gray-400",children:a.server||"--"}),(0,b.jsx)("div",{className:"col-span-2 truncate text-xs text-gray-500",children:a.task||"--"}),(0,b.jsx)("div",{className:"col-span-1 text-xs text-gray-500",children:(0,e.timeAgo)(a.last_seen_at||a.updated_at)}),(0,b.jsxs)("div",{className:"col-span-2 flex justify-end gap-1.5",children:[(0,b.jsx)("button",{type:"button",onClick:()=>F(a.alias),className:"rounded-lg border border-green-500/20 bg-green-500/10 px-2 py-1 text-xs text-green-300 hover:bg-green-500/20",children:"Chat"}),(0,b.jsx)("button",{type:"button",onClick:()=>I(a.alias),className:"rounded-lg border border-cyan-500/20 bg-cyan-500/10 px-2 py-1 text-xs text-cyan-300 hover:bg-cyan-500/20",children:"Task"})]})]}),(0,b.jsxs)("div",{className:"sm:hidden space-y-2",children:[(0,b.jsxs)("div",{className:"flex items-center gap-2.5",children:[(0,b.jsx)(i.AliasAvatar,{alias:a.alias,size:28}),(0,b.jsxs)(d.default,{href:`/node?alias=${encodeURIComponent(a.alias)}`,className:"min-w-0 flex-1 hover:text-cyan-300",children:[(0,b.jsx)("div",{className:"truncate text-sm font-medium text-white",children:a.alias}),(0,b.jsxs)("div",{className:"truncate text-[10px] text-gray-500",children:[a.agent||"—"," · ",(0,e.timeAgo)(a.last_seen_at||a.updated_at)]})]}),(0,b.jsx)("span",{className:`shrink-0 text-xs px-2 py-0.5 rounded-md border ${j[c]||j.offline}`,children:c})]}),a.task&&(0,b.jsx)("div",{className:"truncate text-xs text-gray-500",children:a.task}),(0,b.jsxs)("div",{className:"flex gap-2",children:[(0,b.jsx)("button",{type:"button",onClick:()=>F(a.alias),className:"flex-1 rounded-lg border border-green-500/20 bg-green-500/10 px-3 py-2 text-xs text-green-300 hover:bg-green-500/20",children:"Chat"}),(0,b.jsx)("button",{type:"button",onClick:()=>I(a.alias),className:"flex-1 rounded-lg border border-cyan-500/20 bg-cyan-500/10 px-3 py-2 text-xs text-cyan-300 hover:bg-cyan-500/20",children:"Send Task"})]})]}),A===a.alias&&(0,b.jsxs)("div",{className:"mt-3 space-y-2 border-t border-[#2a2a4a] pt-3",children:[(0,b.jsx)("input",{type:"text",value:y[a.alias]||"",onChange:b=>J(a.alias,b.target.value),onKeyDown:b=>"Enter"===b.key&&K(a.alias),placeholder:`Send task to ${a.alias}...`,className:"w-full rounded-lg border border-[#2a2a4a] bg-[#0a0a15] px-3 py-2 text-xs text-white placeholder-gray-600 focus:border-cyan-500 focus:outline-none"}),(0,b.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,b.jsx)("button",{type:"button",onClick:()=>B(null),className:"rounded-lg border border-gray-700 px-3 py-1.5 text-xs text-gray-400 hover:text-gray-200",children:"Cancel"}),(0,b.jsx)("button",{type:"button",onClick:()=>K(a.alias),disabled:f.sending||!(y[a.alias]||"").trim(),className:"rounded-lg bg-cyan-600 px-3 py-1.5 text-xs text-white hover:bg-cyan-500 disabled:cursor-not-allowed disabled:bg-gray-700",children:f.sending?"Sending...":"Send"})]})]}),f.error&&(0,b.jsx)("div",{className:"mt-2 text-xs text-red-400",children:f.error}),f.success&&A!==a.alias&&(0,b.jsx)("div",{className:"mt-2 text-xs text-green-400",children:f.success})]},a.alias)})]}),E&&(0,b.jsx)(g.TaskChatPanel,{alias:E,onClose:()=>F(null)})]})}])}];
|
|
2
|
-
|
|
3
|
-
//# sourceMappingURL=%5Broot-of-the-server%5D__06pu~4t._.js.map
|