@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/login/page.tsx
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { FormEvent, useState } from 'react';
|
|
4
|
+
import { DASHBOARD_VERSION } from '../lib/version';
|
|
4
5
|
|
|
5
6
|
export default function LoginPage() {
|
|
6
7
|
const [mode, setMode] = useState<'login' | 'register'>('login');
|
|
7
8
|
const [username, setUsername] = useState('');
|
|
8
9
|
const [password, setPassword] = useState('');
|
|
10
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
9
11
|
const [error, setError] = useState('');
|
|
10
12
|
const [pending, setPending] = useState(false);
|
|
11
13
|
|
|
@@ -68,7 +70,9 @@ export default function LoginPage() {
|
|
|
68
70
|
</div>
|
|
69
71
|
<h1 className="text-[22px] sm:text-2xl font-semibold text-white tracking-tight">Agent Network</h1>
|
|
70
72
|
<p className="text-[13px] text-gray-500 mt-1.5 leading-snug">
|
|
71
|
-
|
|
73
|
+
{mode === 'login'
|
|
74
|
+
? <>Welcome back ยท <span className="text-gray-600">Tasks ยท Mesh ยท Messages</span></>
|
|
75
|
+
: <>Create your account ยท <span className="text-gray-600">Free preview ยท no credit card</span></>}
|
|
72
76
|
</p>
|
|
73
77
|
</div>
|
|
74
78
|
|
|
@@ -93,22 +97,51 @@ export default function LoginPage() {
|
|
|
93
97
|
<label htmlFor="password" className="block text-xs text-gray-500 mb-2 uppercase tracking-wider">
|
|
94
98
|
Password
|
|
95
99
|
</label>
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
100
|
+
<div className="relative">
|
|
101
|
+
<input id="password" type={showPassword ? 'text' : 'password'} value={password} onChange={e => setPassword(e.target.value)}
|
|
102
|
+
placeholder="Enter password"
|
|
103
|
+
className="w-full bg-[#0a0a15] border border-[#2a2a4a] rounded-lg px-4 pr-11 py-3 text-sm text-white placeholder-gray-600 focus:border-cyan-500/50 focus:ring-1 focus:ring-cyan-500/20 focus:outline-none transition-all" />
|
|
104
|
+
<button
|
|
105
|
+
type="button"
|
|
106
|
+
onClick={() => setShowPassword(s => !s)}
|
|
107
|
+
tabIndex={-1}
|
|
108
|
+
aria-label={showPassword ? 'Hide password' : 'Show password'}
|
|
109
|
+
className="absolute inset-y-0 right-0 flex items-center px-3 text-gray-600 hover:text-gray-300 transition-colors"
|
|
110
|
+
>
|
|
111
|
+
{showPassword ? (
|
|
112
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
113
|
+
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" />
|
|
114
|
+
<line x1="1" y1="1" x2="23" y2="23" />
|
|
115
|
+
</svg>
|
|
116
|
+
) : (
|
|
117
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
118
|
+
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
|
|
119
|
+
<circle cx="12" cy="12" r="3" />
|
|
120
|
+
</svg>
|
|
121
|
+
)}
|
|
122
|
+
</button>
|
|
123
|
+
</div>
|
|
99
124
|
|
|
100
125
|
{error && (
|
|
101
126
|
<div className="mt-3 text-sm text-red-300 bg-red-500/5 border border-red-500/10 rounded-lg px-3 py-2">{error}</div>
|
|
102
127
|
)}
|
|
103
128
|
|
|
104
|
-
<button type="submit" disabled={pending || !password}
|
|
105
|
-
className="mt-5 w-full px-4 py-3 bg-gradient-to-r from-cyan-600 to-blue-600 hover:from-cyan-500 hover:to-blue-500 disabled:from-gray-800 disabled:to-gray-800 disabled:text-gray-600 text-white text-sm font-medium rounded-lg transition-all shadow-lg shadow-cyan-500/10 hover:shadow-cyan-500/20 disabled:shadow-none">
|
|
106
|
-
{pending
|
|
129
|
+
<button type="submit" disabled={pending || !password || !username.trim()}
|
|
130
|
+
className="mt-5 w-full flex items-center justify-center gap-2 px-4 py-3 bg-gradient-to-r from-cyan-600 to-blue-600 hover:from-cyan-500 hover:to-blue-500 disabled:from-gray-800 disabled:to-gray-800 disabled:text-gray-600 text-white text-sm font-medium rounded-lg transition-all shadow-lg shadow-cyan-500/10 hover:shadow-cyan-500/20 disabled:shadow-none">
|
|
131
|
+
{pending && (
|
|
132
|
+
<svg aria-hidden className="w-4 h-4 animate-spin" viewBox="0 0 24 24" fill="none">
|
|
133
|
+
<circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="3" opacity="0.25" />
|
|
134
|
+
<path d="M4 12a8 8 0 018-8" stroke="currentColor" strokeWidth="3" strokeLinecap="round" />
|
|
135
|
+
</svg>
|
|
136
|
+
)}
|
|
137
|
+
<span>{pending ? (mode === 'login' ? 'Signing inโฆ' : 'Registeringโฆ') : (mode === 'login' ? 'Sign in' : 'Create account')}</span>
|
|
107
138
|
</button>
|
|
108
139
|
</form>
|
|
109
140
|
|
|
110
141
|
<p className="text-center text-[11px] text-gray-700 mt-6">
|
|
111
142
|
Sleep2AGI ยท Apache-2.0 ยท <a href="https://anet.sh" className="hover:text-gray-500 transition-colors">anet.sh</a>
|
|
143
|
+
<span className="mx-1 text-gray-800">ยท</span>
|
|
144
|
+
<span className="font-mono" title="@sleep2agi/agent-network-dashboard">v{DASHBOARD_VERSION}</span>
|
|
112
145
|
</p>
|
|
113
146
|
</div>
|
|
114
147
|
</main>
|
package/app/logs/page.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import Link from 'next/link';
|
|
|
5
5
|
import { timeAgo } from '../components/utils';
|
|
6
6
|
import { useNetworkId } from '../lib/network-context';
|
|
7
7
|
import { EmptyState } from '../components/EmptyState';
|
|
8
|
+
import { AliasAvatar } from '../components/AliasAvatar';
|
|
8
9
|
|
|
9
10
|
interface AuditLog {
|
|
10
11
|
id: string;
|
|
@@ -26,6 +27,18 @@ const ACTION_COLORS: Record<string, string> = {
|
|
|
26
27
|
send_task: 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20',
|
|
27
28
|
};
|
|
28
29
|
|
|
30
|
+
/** 2px left-rail stripe color per audit action โ reuses the r32 server-logs
|
|
31
|
+
* pattern so failed logins / token rotations spike out of a wall of
|
|
32
|
+
* registers and logins without users reading every chip. Inline hex
|
|
33
|
+
* prevents Tailwind v4 from purging dynamic class names. */
|
|
34
|
+
const ACTION_STRIPE: Record<string, string> = {
|
|
35
|
+
register: '#4ade80',
|
|
36
|
+
login: '#60a5fa',
|
|
37
|
+
login_failed: '#ef4444',
|
|
38
|
+
create_network: '#a78bfa',
|
|
39
|
+
send_task: '#22d3ee',
|
|
40
|
+
};
|
|
41
|
+
|
|
29
42
|
export default function LogsPage() {
|
|
30
43
|
const { networkId } = useNetworkId();
|
|
31
44
|
const [logs, setLogs] = useState<AuditLog[]>([]);
|
|
@@ -64,25 +77,50 @@ export default function LogsPage() {
|
|
|
64
77
|
return (
|
|
65
78
|
<div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono">
|
|
66
79
|
<div className="flex items-center gap-4 mb-6">
|
|
67
|
-
<h1 className="text-2xl font-bold text-white lg:ml-0 ml-10">
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
80
|
+
<h1 className="text-2xl font-bold text-white lg:ml-0 ml-10">Audit Log</h1>
|
|
81
|
+
{/* Round 87: dropped {logs.length} header chip โ r43 added
|
|
82
|
+
`All <count>` to the action-filter strip below, which
|
|
83
|
+
duplicated this value 40px away. Matches r86 /server-logs. */}
|
|
71
84
|
</div>
|
|
72
85
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
{/* Action filter chips (round 43) โ same chip pattern as Tasks
|
|
87
|
+
status tabs / Overview agent filter. Each chip carries its
|
|
88
|
+
ACTION_STRIPE dot so the visual key matches the per-row left
|
|
89
|
+
rail. Counts come from the currently loaded log set. */}
|
|
90
|
+
<div className="mb-6 flex flex-wrap items-center gap-1 anet-tabstrip-wrap overflow-x-auto sm:overflow-x-visible">
|
|
91
|
+
{(() => {
|
|
92
|
+
const counts: Record<string, number> = {};
|
|
93
|
+
logs.forEach(l => { counts[l.action] = (counts[l.action] || 0) + 1; });
|
|
94
|
+
const chips: { key: string; label: string; dot?: string }[] = [
|
|
95
|
+
{ key: '', label: 'All' },
|
|
96
|
+
{ key: 'login', label: 'login', dot: ACTION_STRIPE.login },
|
|
97
|
+
{ key: 'login_failed', label: 'login_failed', dot: ACTION_STRIPE.login_failed },
|
|
98
|
+
{ key: 'register', label: 'register', dot: ACTION_STRIPE.register },
|
|
99
|
+
{ key: 'create_network', label: 'create_network', dot: ACTION_STRIPE.create_network },
|
|
100
|
+
{ key: 'send_task', label: 'send_task', dot: ACTION_STRIPE.send_task },
|
|
101
|
+
];
|
|
102
|
+
return chips.map(c => {
|
|
103
|
+
const count = c.key === '' ? logs.length : counts[c.key] || 0;
|
|
104
|
+
const isActive = filterAction === c.key;
|
|
105
|
+
return (
|
|
106
|
+
<button
|
|
107
|
+
key={c.key || 'all'}
|
|
108
|
+
type="button"
|
|
109
|
+
onClick={() => setFilterAction(c.key)}
|
|
110
|
+
disabled={count === 0 && c.key !== ''}
|
|
111
|
+
className={`flex items-center gap-1.5 rounded-md px-2.5 py-1 text-xs transition-colors disabled:opacity-30 disabled:cursor-not-allowed shrink-0 whitespace-nowrap ${
|
|
112
|
+
isActive
|
|
113
|
+
? 'bg-cyan-500/10 text-cyan-300 border border-cyan-500/30'
|
|
114
|
+
: 'text-gray-500 hover:text-gray-200 hover:bg-[#1a1a2a] border border-transparent'
|
|
115
|
+
}`}
|
|
116
|
+
>
|
|
117
|
+
{c.dot && <span aria-hidden className="inline-block w-1.5 h-1.5 rounded-full" style={{ backgroundColor: c.dot }} />}
|
|
118
|
+
<span>{c.label}</span>
|
|
119
|
+
<span className={`text-[10px] tabular-nums ${isActive ? 'text-cyan-400' : 'text-gray-600'}`}>{count}</span>
|
|
120
|
+
</button>
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
})()}
|
|
86
124
|
</div>
|
|
87
125
|
|
|
88
126
|
{error && (() => {
|
|
@@ -125,13 +163,23 @@ export default function LogsPage() {
|
|
|
125
163
|
<EmptyState variant="logs" />
|
|
126
164
|
) : (
|
|
127
165
|
<div className="space-y-2">
|
|
128
|
-
{logs.map(log =>
|
|
129
|
-
|
|
166
|
+
{logs.map(log => {
|
|
167
|
+
const userName = log.username || log.user_id;
|
|
168
|
+
return (
|
|
169
|
+
<div key={log.id} className="relative bg-[#111128] border border-[#2a2a4a] rounded-lg pl-4 pr-4 py-3 hover:border-[#3a3a5a] transition-colors overflow-hidden">
|
|
170
|
+
{/* 2px left rail per action (round 33) โ failed logins, token
|
|
171
|
+
rotations spike out of a wall of register/login rows. */}
|
|
172
|
+
<span
|
|
173
|
+
aria-hidden
|
|
174
|
+
className="absolute left-0 top-0 bottom-0 w-0.5"
|
|
175
|
+
style={{ backgroundColor: ACTION_STRIPE[log.action] || 'transparent' }}
|
|
176
|
+
/>
|
|
130
177
|
<div className="flex flex-wrap items-center gap-2 mb-1">
|
|
131
178
|
<span className={`text-xs px-2 py-0.5 rounded-md border ${ACTION_COLORS[log.action] || 'bg-gray-500/10 text-gray-400 border-gray-500/20'}`}>
|
|
132
179
|
{log.action}
|
|
133
180
|
</span>
|
|
134
|
-
<
|
|
181
|
+
{userName && <AliasAvatar alias={userName} size={16} />}
|
|
182
|
+
<span className="text-sm text-gray-200 font-medium">{userName}</span>
|
|
135
183
|
{log.target_type && (
|
|
136
184
|
<>
|
|
137
185
|
<span className="text-xs text-gray-600">→</span>
|
|
@@ -143,7 +191,8 @@ export default function LogsPage() {
|
|
|
143
191
|
{log.detail && <div className="text-xs text-gray-500">{log.detail}</div>}
|
|
144
192
|
{log.ip && log.ip !== 'unknown' && <div className="text-[10px] text-gray-700">IP: {log.ip}</div>}
|
|
145
193
|
</div>
|
|
146
|
-
|
|
194
|
+
);
|
|
195
|
+
})}
|
|
147
196
|
</div>
|
|
148
197
|
)}
|
|
149
198
|
</div>
|
package/app/messages/page.tsx
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useMemo, useState } from 'react';
|
|
4
4
|
import { useMessages } from '../lib/hooks';
|
|
5
|
-
import { timeAgo } from '../components/utils';
|
|
5
|
+
import { timeAgo, previewContent } from '../components/utils';
|
|
6
6
|
import { EmptyState } from '../components/EmptyState';
|
|
7
7
|
import { AliasAvatar } from '../components/AliasAvatar';
|
|
8
8
|
|
|
@@ -129,6 +129,11 @@ export default function MessagesPage() {
|
|
|
129
129
|
)}
|
|
130
130
|
</div>
|
|
131
131
|
|
|
132
|
+
{/* Round 76: hide search + type filter + view toggle + Debug button
|
|
133
|
+
when there are no messages at all. Same r70-class fix carried
|
|
134
|
+
across /nodes (r74) and /tasks (r75). When at least one message
|
|
135
|
+
exists, the chrome reappears so users can still clear filters. */}
|
|
136
|
+
{messages.length > 0 && (
|
|
132
137
|
<div className="flex flex-wrap gap-3 mb-3">
|
|
133
138
|
<input
|
|
134
139
|
type="text"
|
|
@@ -165,6 +170,7 @@ export default function MessagesPage() {
|
|
|
165
170
|
{debug ? 'Debug ON' : 'Debug'}
|
|
166
171
|
</button>
|
|
167
172
|
</div>
|
|
173
|
+
)}
|
|
168
174
|
|
|
169
175
|
{quickFromChips.length > 0 && (
|
|
170
176
|
<div className="mb-6 flex flex-wrap gap-2">
|
|
@@ -206,17 +212,20 @@ export default function MessagesPage() {
|
|
|
206
212
|
<div key={ci} className="bg-[#111128] border border-[#2a2a4a] rounded-xl overflow-hidden">
|
|
207
213
|
<div className="px-4 py-2.5 border-b border-[#2a2a4a] flex items-center justify-between">
|
|
208
214
|
<div className="flex items-center gap-2">
|
|
209
|
-
<
|
|
215
|
+
<AliasAvatar alias={conv.participants[0]} size={16} />
|
|
216
|
+
<span className="text-sm text-gray-200 font-medium">{conv.participants[0]}</span>
|
|
210
217
|
<span className="text-gray-600 text-xs">โ</span>
|
|
211
|
-
<
|
|
218
|
+
<AliasAvatar alias={conv.participants[1]} size={16} />
|
|
219
|
+
<span className="text-sm text-gray-200 font-medium">{conv.participants[1]}</span>
|
|
212
220
|
</div>
|
|
213
221
|
<span className="text-[10px] text-gray-600">{conv.messages.length} messages</span>
|
|
214
222
|
</div>
|
|
215
223
|
<div className="px-4 py-2 space-y-2 max-h-64 overflow-y-auto">
|
|
216
224
|
{conv.messages.map(m => (
|
|
217
225
|
<div key={m.id} className="flex items-start gap-2 text-xs py-1">
|
|
218
|
-
|
|
219
|
-
<span className="text-gray-
|
|
226
|
+
{m.from_alias && <AliasAvatar alias={m.from_alias} size={14} />}
|
|
227
|
+
<span className="shrink-0 font-medium text-gray-200">{m.from_alias}</span>
|
|
228
|
+
<span className="text-gray-400 flex-1 truncate" title={m.content || ''}>{previewContent(m.content).slice(0, 120)}</span>
|
|
220
229
|
<span className="text-[9px] text-gray-600 shrink-0">{timeAgo(m.created_at || '')}</span>
|
|
221
230
|
</div>
|
|
222
231
|
))}
|
|
@@ -264,7 +273,11 @@ export default function MessagesPage() {
|
|
|
264
273
|
{message.priority === 'high' && <span className="text-xs text-red-400">HIGH</span>}
|
|
265
274
|
<span className="ml-auto text-xs text-gray-500">{message.created_at ? timeAgo(message.created_at) : '--'}</span>
|
|
266
275
|
</div>
|
|
267
|
-
|
|
276
|
+
{/* Round 79: break-words + overflow-wrap:anywhere so
|
|
277
|
+
long unbroken runs (URLs, ASCII rules like
|
|
278
|
+
`โโโโโโโโโโโโโโโ`) wrap instead of pushing the
|
|
279
|
+
chat bubble past the mobile viewport. */}
|
|
280
|
+
<div className="whitespace-pre-wrap break-words [overflow-wrap:anywhere] text-sm leading-relaxed text-gray-200">
|
|
268
281
|
{renderHighlighted(message.content, search)}
|
|
269
282
|
</div>
|
|
270
283
|
</div>
|
|
@@ -295,7 +308,11 @@ export default function MessagesPage() {
|
|
|
295
308
|
</div>
|
|
296
309
|
)}
|
|
297
310
|
|
|
298
|
-
|
|
311
|
+
{/* Round 79: break-words + overflow-wrap:anywhere so
|
|
312
|
+
long unbroken runs (URLs, ASCII rules like
|
|
313
|
+
`โโโโโโโโโโโโโโโ`) wrap instead of pushing the
|
|
314
|
+
chat bubble past the mobile viewport. */}
|
|
315
|
+
<div className="whitespace-pre-wrap break-words [overflow-wrap:anywhere] text-sm leading-relaxed text-gray-200">
|
|
299
316
|
{renderHighlighted(message.content, search)}
|
|
300
317
|
</div>
|
|
301
318
|
|
package/app/node/page.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import Link from 'next/link';
|
|
|
6
6
|
import { Suspense } from 'react';
|
|
7
7
|
import { TaskChatPanel } from '../components/TaskChatPanel';
|
|
8
8
|
import { timeAgo } from '../components/utils';
|
|
9
|
+
import { AliasAvatar } from '../components/AliasAvatar';
|
|
9
10
|
|
|
10
11
|
interface SessionDetail {
|
|
11
12
|
resume_id: string;
|
|
@@ -150,15 +151,23 @@ function NodeDetailContent() {
|
|
|
150
151
|
|
|
151
152
|
return (
|
|
152
153
|
<div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono">
|
|
153
|
-
{/* Header
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
<
|
|
161
|
-
|
|
154
|
+
{/* Header โ round 40: avatar joins the alias for cross-page hue
|
|
155
|
+
consistency; agent type lives in a subtitle so users know what
|
|
156
|
+
kind of node they're looking at. */}
|
|
157
|
+
<div className="flex items-center gap-3 mb-6 lg:ml-0 ml-10">
|
|
158
|
+
<Link href="/nodes" className="text-gray-500 hover:text-gray-300 text-sm shrink-0">← Nodes</Link>
|
|
159
|
+
<AliasAvatar alias={alias} size={32} />
|
|
160
|
+
<div className="min-w-0 flex-1">
|
|
161
|
+
<div className="flex items-center gap-2">
|
|
162
|
+
<h1 className="text-xl sm:text-2xl font-bold text-white truncate">{alias}</h1>
|
|
163
|
+
<span className={`inline-block w-1.5 h-1.5 rounded-full shrink-0 ${
|
|
164
|
+
sse > 0 ? (session?.status === 'working' ? 'bg-green-500 animate-pulse' : 'bg-emerald-400') : 'bg-gray-500'
|
|
165
|
+
}`} />
|
|
166
|
+
<span className={`text-[10px] uppercase tracking-wide font-semibold ${statusColor}`}>{session?.status || 'unknown'}</span>
|
|
167
|
+
</div>
|
|
168
|
+
{session?.agent && (
|
|
169
|
+
<div className="text-xs text-gray-500 truncate">{session.agent}{session.server ? <> <span className="text-gray-700 mx-1">ยท</span> {session.server}</> : null}</div>
|
|
170
|
+
)}
|
|
162
171
|
</div>
|
|
163
172
|
</div>
|
|
164
173
|
|
|
@@ -190,14 +199,22 @@ function NodeFullPanel({ alias, session, sse, sendMsg, setSendMsg, sending, send
|
|
|
190
199
|
|
|
191
200
|
return (
|
|
192
201
|
<div className="bg-[#0d0d1a] border border-[#2a2a4a] rounded-xl overflow-hidden h-[calc(100vh-140px)] flex flex-col">
|
|
193
|
-
{/* Tab bar
|
|
202
|
+
{/* Tab bar โ round 40: emoji icons (๐ฌ ๐ ๐) replaced with stroke
|
|
203
|
+
SVG to drop the "AI generated" tell. */}
|
|
194
204
|
<div className="flex border-b border-[#2a2a4a] bg-[#0a0a15] shrink-0">
|
|
195
|
-
{([
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
205
|
+
{([
|
|
206
|
+
{ id: 'chat', label: 'Chat', icon: 'M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z' },
|
|
207
|
+
{ id: 'events', label: 'Events', icon: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6 M16 13H8 M16 17H8 M10 9H8' },
|
|
208
|
+
{ id: 'info', label: 'Info', icon: 'M12 21a9 9 0 100-18 9 9 0 000 18z M12 8h.01 M11 12h1v4h1' },
|
|
209
|
+
] as const).map(t => (
|
|
210
|
+
<button key={t.id} onClick={() => setTab(t.id)}
|
|
211
|
+
className={`flex items-center gap-2 px-5 py-3 text-sm font-medium border-b-2 transition-colors ${
|
|
212
|
+
tab === t.id ? 'border-cyan-400 text-cyan-300' : 'border-transparent text-gray-500 hover:text-gray-300'
|
|
199
213
|
}`}>
|
|
200
|
-
|
|
214
|
+
<svg className="w-4 h-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
|
|
215
|
+
<path d={t.icon} />
|
|
216
|
+
</svg>
|
|
217
|
+
<span>{t.label}</span>
|
|
201
218
|
</button>
|
|
202
219
|
))}
|
|
203
220
|
</div>
|
|
@@ -299,13 +316,16 @@ function NodeFullPanel({ alias, session, sse, sendMsg, setSendMsg, sending, send
|
|
|
299
316
|
);
|
|
300
317
|
}
|
|
301
318
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
319
|
+
/** Round 59: emoji icons replaced with stroke SVG paths to drop the
|
|
320
|
+
* "AI generated" tell. Each path is sized to fit inside the 18px
|
|
321
|
+
* colored event dot. */
|
|
322
|
+
const EVENT_COLORS: Record<string, { dot: string; line: string; path: string }> = {
|
|
323
|
+
delivered: { dot: 'bg-blue-400', line: 'bg-blue-500/30', path: 'M12 5v14 M5 12l7 7 7-7' }, // down arrow
|
|
324
|
+
acked: { dot: 'bg-yellow-400', line: 'bg-yellow-500/30', path: 'M20 6 9 17l-5-5' }, // check
|
|
325
|
+
running: { dot: 'bg-green-400', line: 'bg-green-500/30', path: 'M13 2L4 14h6l-1 8 10-12h-6l1-8z' }, // bolt
|
|
326
|
+
replied: { dot: 'bg-purple-400', line: 'bg-purple-500/30', path: 'M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z' }, // chat bubble
|
|
327
|
+
failed: { dot: 'bg-red-400', line: 'bg-red-500/30', path: 'M18 6 6 18 M6 6l12 12' }, // X
|
|
328
|
+
created: { dot: 'bg-gray-400', line: 'bg-gray-500/30', path: 'M12 5v14 M5 12h14' }, // plus
|
|
309
329
|
};
|
|
310
330
|
|
|
311
331
|
function EventsTimeline({ events, loading }: { events: Array<{ id: number; event_type: string; from_status: string; to_status: string; detail: string; created_at: string; task_id?: string }>; loading: boolean }) {
|
|
@@ -334,9 +354,12 @@ function EventsTimeline({ events, loading }: { events: Array<{ id: number; event
|
|
|
334
354
|
const cfg = EVENT_COLORS[e.to_status] || EVENT_COLORS.created;
|
|
335
355
|
return (
|
|
336
356
|
<div key={e.id} className="relative pb-4 last:pb-0">
|
|
337
|
-
{/* Dot on line
|
|
338
|
-
|
|
339
|
-
|
|
357
|
+
{/* Dot on line โ round 59: emoji icons replaced with
|
|
358
|
+
a 10px stroke SVG path matching event type. */}
|
|
359
|
+
<div className={`absolute -left-6 top-0.5 w-[18px] h-[18px] rounded-full ${cfg.dot} flex items-center justify-center z-10 border-2 border-[#111128]`}>
|
|
360
|
+
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="#0a0a15" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
|
|
361
|
+
<path d={cfg.path} />
|
|
362
|
+
</svg>
|
|
340
363
|
</div>
|
|
341
364
|
{/* Content */}
|
|
342
365
|
<div className="ml-2">
|
package/app/nodes/page.tsx
CHANGED
|
@@ -5,10 +5,18 @@ import Link from 'next/link';
|
|
|
5
5
|
import { timeAgo } from '../components/utils';
|
|
6
6
|
import { useSessions, useHealth } from '../lib/hooks';
|
|
7
7
|
import { TaskChatPanel } from '../components/TaskChatPanel';
|
|
8
|
-
import { EmptyState } from '../components/EmptyState';
|
|
8
|
+
import { EmptyState, NodesEmptyState } from '../components/EmptyState';
|
|
9
9
|
import { AliasAvatar } from '../components/AliasAvatar';
|
|
10
10
|
import type { Session } from '../components/types';
|
|
11
11
|
|
|
12
|
+
/** Round 81: shorten long server hostnames (Alibaba `iZโฆoyZ` style)
|
|
13
|
+
* for table display. Returns the original string unchanged when โค12
|
|
14
|
+
* chars. Full value should stay in `title=` for hover + screen-readers. */
|
|
15
|
+
function shortServer(server: string | null | undefined): string {
|
|
16
|
+
if (!server) return 'โ';
|
|
17
|
+
return server.length > 12 ? `${server.slice(0, 8)}โฆ` : server;
|
|
18
|
+
}
|
|
19
|
+
|
|
12
20
|
const STATUS_COLORS: Record<string, string> = {
|
|
13
21
|
working: 'bg-green-500/10 text-green-300 border-green-500/20',
|
|
14
22
|
idle: 'bg-blue-500/10 text-blue-300 border-blue-500/20',
|
|
@@ -121,6 +129,12 @@ export default function NodesPage() {
|
|
|
121
129
|
);
|
|
122
130
|
})()}
|
|
123
131
|
|
|
132
|
+
{/* Round 74: hide the filter+view chrome when there are no nodes
|
|
133
|
+
anywhere โ these controls have nothing to act on, and they only
|
|
134
|
+
push the onboarding CTA further down. When at least one session
|
|
135
|
+
exists, the chrome is back even if the current filter happens
|
|
136
|
+
to hide everything (so users can clear filters). */}
|
|
137
|
+
{sessions.length > 0 && (
|
|
124
138
|
<div className="flex flex-wrap gap-3 mb-6">
|
|
125
139
|
<input
|
|
126
140
|
type="text"
|
|
@@ -142,7 +156,11 @@ export default function NodesPage() {
|
|
|
142
156
|
<option value="blocked">Blocked</option>
|
|
143
157
|
<option value="error">Error</option>
|
|
144
158
|
</select>
|
|
145
|
-
|
|
159
|
+
{/* Round 80: List/Grid toggle hidden on mobile โ Grid uses
|
|
160
|
+
grid-cols-1 below `md` and List degrades to the same single
|
|
161
|
+
column, so the toggle has no visual effect under sm and only
|
|
162
|
+
steals a row of vertical space. */}
|
|
163
|
+
<div className="hidden sm:flex ml-auto rounded-lg border border-[#2a2a4a] bg-[#111128] p-1 text-sm">
|
|
146
164
|
{(['list', 'grid'] as const).map(mode => (
|
|
147
165
|
<button
|
|
148
166
|
key={mode}
|
|
@@ -159,17 +177,27 @@ export default function NodesPage() {
|
|
|
159
177
|
))}
|
|
160
178
|
</div>
|
|
161
179
|
</div>
|
|
180
|
+
)}
|
|
162
181
|
|
|
163
182
|
{loading ? (
|
|
164
183
|
<div className="animate-pulse space-y-2">
|
|
165
184
|
{[1,2,3,4].map(i => <div key={i} className="h-16 bg-gray-800/20 rounded-lg" />)}
|
|
166
185
|
</div>
|
|
167
186
|
) : filtered.length === 0 ? (
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
187
|
+
sessions.length === 0 ? (
|
|
188
|
+
/* Round 73: first-run case โ no agents anywhere. Use the same
|
|
189
|
+
onboarding empty state as the Overview (NodesEmptyState
|
|
190
|
+
includes the `npx โฆ init` quickstart command). Previously this
|
|
191
|
+
was the "No nodes match your filters" copy, which was wrong
|
|
192
|
+
for new users who have no filters applied. */
|
|
193
|
+
<NodesEmptyState />
|
|
194
|
+
) : (
|
|
195
|
+
<EmptyState
|
|
196
|
+
variant="nodes"
|
|
197
|
+
title="No nodes match your filters"
|
|
198
|
+
sub="Try clearing search or status filters, or wait for an agent to register."
|
|
199
|
+
/>
|
|
200
|
+
)
|
|
173
201
|
) : viewMode === 'grid' ? (
|
|
174
202
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
|
175
203
|
{filtered.map(s => {
|
|
@@ -199,7 +227,7 @@ export default function NodesPage() {
|
|
|
199
227
|
</span>
|
|
200
228
|
</div>
|
|
201
229
|
<div className="mt-0.5 truncate text-xs text-gray-500">
|
|
202
|
-
{(s.agent || 'โ')}<span className="text-gray-700 mx-1.5">ยท</span
|
|
230
|
+
{(s.agent || 'โ')}<span className="text-gray-700 mx-1.5">ยท</span><span title={s.server || ''}>{shortServer(s.server)}</span>
|
|
203
231
|
</div>
|
|
204
232
|
</Link>
|
|
205
233
|
<div className="flex gap-1.5 shrink-0">
|
|
@@ -299,7 +327,7 @@ export default function NodesPage() {
|
|
|
299
327
|
</Link>
|
|
300
328
|
</div>
|
|
301
329
|
<div className="col-span-2 truncate text-xs text-gray-400">{s.agent || '--'}</div>
|
|
302
|
-
<div className="col-span-2 truncate text-xs text-gray-400"
|
|
330
|
+
<div className="col-span-2 truncate text-xs text-gray-400" title={s.server || ''}>{shortServer(s.server)}</div>
|
|
303
331
|
<div className="col-span-2 truncate text-xs text-gray-500">{s.task || '--'}</div>
|
|
304
332
|
<div className="col-span-1 text-xs text-gray-500">{timeAgo(s.last_seen_at || s.updated_at)}</div>
|
|
305
333
|
<div className="col-span-2 flex justify-end gap-1.5">
|