@sleep2agi/agent-network-dashboard 0.4.5-preview.9 → 0.4.5-preview.91
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/.mcp.json +11 -0
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +3 -3
- package/.next/diagnostics/route-bundle-stats.json +48 -48
- 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/next-font-manifest.json +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/next-font-manifest.json +1 -1
- 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 +15 -15
- package/.next/server/app/admin.segments/_full.segment.rsc +15 -15
- 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 +3 -3
- 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 +15 -15
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/index.segments/_full.segment.rsc +15 -15
- 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 +3 -3
- package/.next/server/app/login/page/next-font-manifest.json +1 -1
- 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 +15 -15
- package/.next/server/app/login.segments/_full.segment.rsc +15 -15
- 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 +3 -3
- 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/next-font-manifest.json +1 -1
- 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 +15 -15
- package/.next/server/app/logs.segments/_full.segment.rsc +15 -15
- 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 +3 -3
- 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/next-font-manifest.json +1 -1
- 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 +15 -15
- package/.next/server/app/messages.segments/_full.segment.rsc +15 -15
- 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 +3 -3
- 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/next-font-manifest.json +1 -1
- 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 +15 -15
- package/.next/server/app/node.segments/_full.segment.rsc +15 -15
- 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 +3 -3
- 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/next-font-manifest.json +1 -1
- 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 +15 -15
- package/.next/server/app/nodes.segments/_full.segment.rsc +15 -15
- 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 +3 -3
- 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/next-font-manifest.json +1 -1
- 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/next-font-manifest.json +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 +15 -15
- package/.next/server/app/server-logs.segments/_full.segment.rsc +15 -15
- 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 +3 -3
- 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/next-font-manifest.json +1 -1
- 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 +15 -15
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +15 -15
- 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 +3 -3
- 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/next-font-manifest.json +1 -1
- 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/next-font-manifest.json +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 +15 -15
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +15 -15
- 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 +3 -3
- 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 +15 -15
- package/.next/server/app/settings.segments/_full.segment.rsc +15 -15
- 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 +3 -3
- 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/next-font-manifest.json +1 -1
- 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/next-font-manifest.json +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 +15 -15
- package/.next/server/app/tasks.segments/_full.segment.rsc +15 -15
- 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 +3 -3
- 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]__0jl4ukn._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0jl4ukn._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0n46s~k._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0n46s~k._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0w2ay2h._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0w2ay2h._.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_0aenxef._.js +3 -0
- package/.next/server/chunks/ssr/app_0aenxef._.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_0emvkn2._.js +3 -0
- package/.next/server/chunks/ssr/app_0emvkn2._.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_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/next-font-manifest.js +1 -1
- package/.next/server/next-font-manifest.json +14 -14
- 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/0-hlcuoemhe7w.js +7 -0
- package/.next/static/chunks/02_zpo7taex9o.js +7 -0
- package/.next/static/chunks/03b6jkic-1r9u.css +2 -0
- package/.next/static/chunks/06fliypy0.f0r.js +1 -0
- package/.next/static/chunks/06n3d~fbbtagk.js +1 -0
- package/.next/static/chunks/07eba1lz2u3p4.js +1 -0
- package/.next/static/chunks/0av2~0.96~d~g.js +1 -0
- package/.next/static/chunks/{07okhs5561y5y.js → 0c1bp~g7.8ru..js} +1 -1
- package/.next/static/chunks/0g9aof0ob_fcj.js +1 -0
- package/.next/static/chunks/0gtbwcilfu6b7.js +1 -0
- package/.next/static/chunks/0s8jo6jypzkx5.js +1 -0
- package/.next/static/chunks/0ubqqhhpsaez4.js +1 -0
- package/.next/static/chunks/0vmfu_gz9tp4f.js +1 -0
- package/.next/static/chunks/0~qw9kxksr1v2.js +1 -0
- package/.next/static/chunks/12gprw3l0kvvf.js +1 -0
- package/.next/static/chunks/12mjtyh-j74~k.js +1 -0
- package/.next/static/chunks/12yuo353giomx.js +1 -0
- package/.next/static/media/4fa387ec64143e14-s.0.qu-9752pffj.woff2 +0 -0
- package/.next/static/media/5ce348bf30bf5439-s.0ee55_hj9qcer.woff2 +0 -0
- package/.next/static/media/6306c77e7c8268e4-s.0mao5jbfbduzp.woff2 +0 -0
- package/.next/static/media/797e433ab948586e-s.p.09zddjkbdep5a.woff2 +0 -0
- package/.next/static/media/7d817b4c03b0c5f1-s.0uzt.a6d44yda.woff2 +0 -0
- package/.next/static/media/bbc41e54d2fcbd21-s.0mvwgmnhv29no.woff2 +0 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/admin/page.tsx +97 -27
- 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 +127 -12
- 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 +81 -44
- 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 +527 -41
- package/app/components/utils.ts +13 -0
- package/app/globals.css +90 -0
- package/app/lib/status.ts +85 -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 +34 -9
- package/app/node/page.tsx +52 -27
- package/app/nodes/page.tsx +45 -21
- package/app/page.tsx +103 -32
- package/app/server-logs/page.tsx +104 -28
- package/app/settings/networks/page.tsx +40 -16
- 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/public/intern_avatar.png +0 -0
- package/scripts/empty-state-test.mjs +41 -0
- package/scripts/fold-only.mjs +47 -0
- package/scripts/intern-alias-test.mjs +46 -0
- package/scripts/loop-review.mjs +270 -0
- package/scripts/network-derive-shot.mjs +16 -0
- package/scripts/network-derive-test.mjs +28 -0
- package/scripts/topo-brand-shot.mjs +61 -0
- package/scripts/topo-cluster-test.mjs +41 -0
- package/scripts/topo-controls-shot.mjs +24 -0
- package/scripts/topo-group-test.mjs +37 -0
- package/scripts/topo-inspect.mjs +56 -0
- package/scripts/topo-interaction-test.mjs +80 -0
- package/scripts/topo-mock-large.mjs +58 -0
- package/scripts/topo-r104-test.mjs +54 -0
- package/scripts/topo-shot.mjs +31 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__06w_u7t._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__06w_u7t._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0ehu0jb._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0ehu0jb._.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/_13_v7-3._.js +0 -3
- package/.next/server/chunks/ssr/_13_v7-3._.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_10b5blc._.js +0 -9
- package/.next/server/chunks/ssr/app_10b5blc._.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/0-.hjh--kcdiy.js +0 -1
- package/.next/static/chunks/02afyxgpty3uf.js +0 -1
- package/.next/static/chunks/02flrewxlf_m_.js +0 -1
- package/.next/static/chunks/051gslfjka1kj.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/0h.ajsk_uxigl.js +0 -1
- package/.next/static/chunks/0msa~bub38ytf.css +0 -2
- package/.next/static/chunks/0ogeals5ufhho.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/12dcb86elsl-e.js +0 -7
- package/.next/static/chunks/13.dst7liziwo.js +0 -1
- package/.next/static/chunks/132e__998_q9r.js +0 -1
- package/.next/static/media/4fa387ec64143e14-s.0q3udbd2bu5yp.woff2 +0 -0
- package/.next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2 +0 -0
- package/.next/static/media/bbc41e54d2fcbd21-s.0gw~uztddq1df.woff2 +0 -0
- 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/{stSZtBF9uGYc3L399m0h1 → u-HIIfy-O0UVQ02APphkX}/_buildManifest.js +0 -0
- /package/.next/static/{stSZtBF9uGYc3L399m0h1 → u-HIIfy-O0UVQ02APphkX}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{stSZtBF9uGYc3L399m0h1 → u-HIIfy-O0UVQ02APphkX}/_ssgManifest.js +0 -0
package/app/components/utils.ts
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/** Round 82: strip the most common markdown markup from agent-to-agent
|
|
2
|
+
* task / message bodies so single-line table previews read cleanly.
|
|
3
|
+
* Full original content stays in the expanded row / drawer / title=. */
|
|
4
|
+
export function previewContent(raw: string | null | undefined): string {
|
|
5
|
+
if (!raw) return '--';
|
|
6
|
+
return raw
|
|
7
|
+
.replace(/!\[([^\]]*)\]\([^)]*\)/g, '$1') // images:  → alt
|
|
8
|
+
.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1') // links: [text](href) → text
|
|
9
|
+
.replace(/`([^`]+)`/g, '$1') // inline code: `x` → x
|
|
10
|
+
.replace(/\s+/g, ' ') // collapse whitespace
|
|
11
|
+
.trim() || '--';
|
|
12
|
+
}
|
|
13
|
+
|
|
1
14
|
export function timeAgo(dateStr: string): string {
|
|
2
15
|
if (!dateStr) return '--';
|
|
3
16
|
const diff = Date.now() - new Date(dateStr.replace(' ', 'T') + 'Z').getTime();
|
package/app/globals.css
CHANGED
|
@@ -811,3 +811,93 @@ body {
|
|
|
811
811
|
color: #92400e !important;
|
|
812
812
|
border-color: rgba(217, 119, 6, 0.28) !important;
|
|
813
813
|
}
|
|
814
|
+
|
|
815
|
+
/* Round 30 — global drawer entrance keyframes so TaskDrawer, TaskChatPanel,
|
|
816
|
+
and any future right-side panel share one source. Previously the
|
|
817
|
+
keyframe lived inside TaskChatPanel's <style jsx global>; if that
|
|
818
|
+
component never mounted, the keyframe was missing for TaskDrawer. */
|
|
819
|
+
@keyframes anet-slide-in {
|
|
820
|
+
from { transform: translateX(100%); }
|
|
821
|
+
to { transform: translateX(0); }
|
|
822
|
+
}
|
|
823
|
+
.animate-slide-in { animation: anet-slide-in 0.2s ease-out; }
|
|
824
|
+
|
|
825
|
+
@keyframes anet-fade-in {
|
|
826
|
+
from { opacity: 0; }
|
|
827
|
+
to { opacity: 1; }
|
|
828
|
+
}
|
|
829
|
+
.anet-fade-in { animation: anet-fade-in 0.15s ease-out; }
|
|
830
|
+
|
|
831
|
+
/* Round 36 — current-step ring pulse on TaskDrawer timeline. Halo gently
|
|
832
|
+
breathes around the active step's dot so users can spot "task is here". */
|
|
833
|
+
@keyframes anet-current-step-pulse-kf {
|
|
834
|
+
0%, 100% { transform: scale(1); opacity: 0.6; }
|
|
835
|
+
50% { transform: scale(1.25); opacity: 0.0; }
|
|
836
|
+
}
|
|
837
|
+
.anet-current-step-pulse {
|
|
838
|
+
animation: anet-current-step-pulse-kf 1.6s ease-in-out infinite;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
/* Round 45 — TopoGraph rotating radar sweep wedge. 6s slow rotation
|
|
842
|
+
gives the topology canvas a real "radar scan" feel without distracting
|
|
843
|
+
from the agent nodes. */
|
|
844
|
+
@keyframes anet-topo-sweep-kf {
|
|
845
|
+
0% { transform: rotate(0deg); }
|
|
846
|
+
100% { transform: rotate(360deg); }
|
|
847
|
+
}
|
|
848
|
+
.anet-topo-sweep {
|
|
849
|
+
animation: anet-topo-sweep-kf 6s linear infinite;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/* Round 46 — animated dashed spokes flowing from hub outward. Each spoke
|
|
853
|
+
gets a small animationDelay (set inline) so the dashes don't all flow
|
|
854
|
+
in sync — reads as "command relay" pulse rather than a metronome. */
|
|
855
|
+
@keyframes anet-topo-spoke-flow-kf {
|
|
856
|
+
from { stroke-dashoffset: 0; }
|
|
857
|
+
to { stroke-dashoffset: -40; }
|
|
858
|
+
}
|
|
859
|
+
.anet-topo-spoke-flow {
|
|
860
|
+
animation: anet-topo-spoke-flow-kf 2.4s linear infinite;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/* ─────────────────────────────────────────────────────────────────────
|
|
864
|
+
Round 29 — prefers-reduced-motion a11y sweep
|
|
865
|
+
|
|
866
|
+
Rounds 19~27 accumulated a lot of small animations: Tasks row 0fr↔1fr
|
|
867
|
+
expand, chevron rotate, hover bg shifts, Cmd+K popover, TaskChatPanel
|
|
868
|
+
slide-in, brand/skeleton pulses already had their own guards.
|
|
869
|
+
|
|
870
|
+
For users who set system "reduce motion": neutralise everything in one
|
|
871
|
+
pass. Don't kill state changes outright — only their durations and
|
|
872
|
+
keyframes. Hover and focus colours still apply, just instantly.
|
|
873
|
+
───────────────────────────────────────────────────────────────────── */
|
|
874
|
+
@media (prefers-reduced-motion: reduce) {
|
|
875
|
+
*,
|
|
876
|
+
*::before,
|
|
877
|
+
*::after {
|
|
878
|
+
animation-duration: 0.001ms !important;
|
|
879
|
+
animation-iteration-count: 1 !important;
|
|
880
|
+
transition-duration: 0.001ms !important;
|
|
881
|
+
scroll-behavior: auto !important;
|
|
882
|
+
}
|
|
883
|
+
/* Skeleton pulse already has its own guard; harden in case the bar
|
|
884
|
+
class is reused without anet-skeleton-pulse. */
|
|
885
|
+
.anet-skeleton-bar {
|
|
886
|
+
animation: none !important;
|
|
887
|
+
}
|
|
888
|
+
/* Brand pulse hidden — green/red dot still indicates state via color. */
|
|
889
|
+
.anet-brand-pulse {
|
|
890
|
+
animation: none !important;
|
|
891
|
+
}
|
|
892
|
+
/* Drawer entrance kills — keyframes promoted to globals in r30. */
|
|
893
|
+
.animate-slide-in,
|
|
894
|
+
.anet-fade-in,
|
|
895
|
+
.anet-current-step-pulse,
|
|
896
|
+
.anet-topo-sweep,
|
|
897
|
+
.anet-topo-spoke-flow {
|
|
898
|
+
animation: none !important;
|
|
899
|
+
}
|
|
900
|
+
/* Tasks row grid 0fr↔1fr keep working (it's the toggle mechanism),
|
|
901
|
+
but the smooth transition just snaps. Already handled via the
|
|
902
|
+
blanket transition-duration override above. */
|
|
903
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** Single source of truth for task status colors. Both `/tasks` (chip
|
|
2
|
+
* strip, badge, distribution bar) and the Overview Recent Activity row
|
|
3
|
+
* used to ship their own incomplete maps; round 66 consolidates them
|
|
4
|
+
* here so adding a new status updates every consumer at once.
|
|
5
|
+
*
|
|
6
|
+
* Order in `TASK_STATUSES` is chronological-ish: lifecycle progress on
|
|
7
|
+
* the left, terminal-good (`closed`) in the middle, terminal-bad
|
|
8
|
+
* (`failed`/`cancelled`/`expired`) on the right. */
|
|
9
|
+
|
|
10
|
+
export const TASK_STATUSES = [
|
|
11
|
+
'created',
|
|
12
|
+
'delivered',
|
|
13
|
+
'acked',
|
|
14
|
+
'running',
|
|
15
|
+
'replied',
|
|
16
|
+
'closed',
|
|
17
|
+
'failed',
|
|
18
|
+
'cancelled',
|
|
19
|
+
'expired',
|
|
20
|
+
] as const;
|
|
21
|
+
|
|
22
|
+
export type TaskStatus = typeof TASK_STATUSES[number];
|
|
23
|
+
|
|
24
|
+
/** Pill / chip background+text+border. Tailwind classes, not inlined hex,
|
|
25
|
+
* because chips are static class names safe from purge. */
|
|
26
|
+
export const STATUS_CHIP_CLASS: Record<string, string> = {
|
|
27
|
+
created: 'bg-gray-500/10 text-gray-400 border-gray-500/20',
|
|
28
|
+
delivered: 'bg-blue-500/10 text-blue-300 border-blue-500/20',
|
|
29
|
+
acked: 'bg-cyan-500/10 text-cyan-300 border-cyan-500/20',
|
|
30
|
+
running: 'bg-green-500/10 text-green-300 border-green-500/20',
|
|
31
|
+
replied: 'bg-purple-500/10 text-purple-300 border-purple-500/20',
|
|
32
|
+
closed: 'bg-gray-500/10 text-gray-500 border-gray-500/20',
|
|
33
|
+
failed: 'bg-red-500/10 text-red-300 border-red-500/20',
|
|
34
|
+
cancelled: 'bg-yellow-500/10 text-yellow-300 border-yellow-500/20',
|
|
35
|
+
expired: 'bg-orange-500/10 text-orange-300 border-orange-500/20',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** Inline hex dots — used wherever Tailwind would purge dynamic class
|
|
39
|
+
* names (`bg-${family}-400`). Style attribute carries the color. */
|
|
40
|
+
export const STATUS_DOT_HEX: Record<string, string> = {
|
|
41
|
+
created: '#9ca3af',
|
|
42
|
+
delivered: '#60a5fa',
|
|
43
|
+
acked: '#22d3ee',
|
|
44
|
+
running: '#4ade80',
|
|
45
|
+
replied: '#a78bfa',
|
|
46
|
+
closed: '#6b7280',
|
|
47
|
+
failed: '#f87171',
|
|
48
|
+
cancelled: '#facc15',
|
|
49
|
+
expired: '#fb923c',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** Session lifecycle (distinct from task lifecycle above). Shared by
|
|
53
|
+
* /nodes status pills and /admin Online Sessions row chips so an
|
|
54
|
+
* agent in `blocked` state reads the same color everywhere.
|
|
55
|
+
* Round 91 — extracted from app/nodes/page.tsx. */
|
|
56
|
+
export const SESSION_STATUS_CHIP_CLASS: Record<string, string> = {
|
|
57
|
+
working: 'bg-green-500/10 text-green-300 border-green-500/20',
|
|
58
|
+
idle: 'bg-blue-500/10 text-blue-300 border-blue-500/20',
|
|
59
|
+
blocked: 'bg-yellow-500/10 text-yellow-300 border-yellow-500/20',
|
|
60
|
+
error: 'bg-red-500/10 text-red-300 border-red-500/20',
|
|
61
|
+
offline: 'bg-gray-500/10 text-gray-500 border-gray-500/20',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** Text-only color for session status. Used where a chip background
|
|
65
|
+
* would be too heavy — e.g. /node detail header status label. */
|
|
66
|
+
export const SESSION_STATUS_TEXT_CLASS: Record<string, string> = {
|
|
67
|
+
working: 'text-green-400',
|
|
68
|
+
idle: 'text-blue-400',
|
|
69
|
+
blocked: 'text-yellow-400',
|
|
70
|
+
error: 'text-red-400',
|
|
71
|
+
offline: 'text-gray-500',
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** Solid bar segment background for the Tasks distribution bar. */
|
|
75
|
+
export const STATUS_BAR_CLASS: Record<string, string> = {
|
|
76
|
+
created: 'bg-gray-500',
|
|
77
|
+
delivered: 'bg-blue-500',
|
|
78
|
+
acked: 'bg-cyan-500',
|
|
79
|
+
running: 'bg-green-500',
|
|
80
|
+
replied: 'bg-purple-500',
|
|
81
|
+
closed: 'bg-gray-600',
|
|
82
|
+
failed: 'bg-red-500',
|
|
83
|
+
cancelled: 'bg-yellow-500',
|
|
84
|
+
expired: 'bg-orange-500',
|
|
85
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Dashboard package version sourced from package.json at build time.
|
|
2
|
+
* Importing JSON requires `resolveJsonModule: true` in tsconfig, which
|
|
3
|
+
* Next sets by default. Bumping is automated by the publish flow, so this
|
|
4
|
+
* surfaces the real preview number in Settings → Dashboard. */
|
|
5
|
+
import pkg from '../../package.json' assert { type: 'json' };
|
|
6
|
+
|
|
7
|
+
export const DASHBOARD_VERSION: string = pkg.version;
|
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
|
|
|
@@ -107,8 +107,16 @@ export default function MessagesPage() {
|
|
|
107
107
|
<div className="min-h-screen bg-[#0a0a1a] text-gray-100 p-4 sm:p-6 font-mono">
|
|
108
108
|
<div className="flex items-center gap-4 mb-6">
|
|
109
109
|
<h1 className="text-2xl font-bold text-white lg:ml-0 ml-10">Messages</h1>
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
{/* Round 89: filter-aware chip. When search/type filter is active
|
|
111
|
+
the visible rows are filtered.length; the total loaded is
|
|
112
|
+
messages.length (capped at 200 by useMessages). Show
|
|
113
|
+
`filtered / total` so users notice how much the filter is
|
|
114
|
+
hiding. Same pattern as r88 /tasks chip. */}
|
|
115
|
+
<span
|
|
116
|
+
className="text-xs bg-blue-900/30 text-blue-400 px-2 py-0.5 rounded-full border border-blue-800/30 tabular-nums"
|
|
117
|
+
title={filtered.length < messages.length ? `Showing ${filtered.length} of ${messages.length} messages` : undefined}
|
|
118
|
+
>
|
|
119
|
+
{filtered.length < messages.length ? `${filtered.length} / ${messages.length}` : messages.length}
|
|
112
120
|
</span>
|
|
113
121
|
{filtered.length > 0 && (
|
|
114
122
|
<button
|
|
@@ -129,6 +137,11 @@ export default function MessagesPage() {
|
|
|
129
137
|
)}
|
|
130
138
|
</div>
|
|
131
139
|
|
|
140
|
+
{/* Round 76: hide search + type filter + view toggle + Debug button
|
|
141
|
+
when there are no messages at all. Same r70-class fix carried
|
|
142
|
+
across /nodes (r74) and /tasks (r75). When at least one message
|
|
143
|
+
exists, the chrome reappears so users can still clear filters. */}
|
|
144
|
+
{messages.length > 0 && (
|
|
132
145
|
<div className="flex flex-wrap gap-3 mb-3">
|
|
133
146
|
<input
|
|
134
147
|
type="text"
|
|
@@ -165,6 +178,7 @@ export default function MessagesPage() {
|
|
|
165
178
|
{debug ? 'Debug ON' : 'Debug'}
|
|
166
179
|
</button>
|
|
167
180
|
</div>
|
|
181
|
+
)}
|
|
168
182
|
|
|
169
183
|
{quickFromChips.length > 0 && (
|
|
170
184
|
<div className="mb-6 flex flex-wrap gap-2">
|
|
@@ -206,17 +220,20 @@ export default function MessagesPage() {
|
|
|
206
220
|
<div key={ci} className="bg-[#111128] border border-[#2a2a4a] rounded-xl overflow-hidden">
|
|
207
221
|
<div className="px-4 py-2.5 border-b border-[#2a2a4a] flex items-center justify-between">
|
|
208
222
|
<div className="flex items-center gap-2">
|
|
209
|
-
<
|
|
223
|
+
<AliasAvatar alias={conv.participants[0]} size={16} />
|
|
224
|
+
<span className="text-sm text-gray-200 font-medium">{conv.participants[0]}</span>
|
|
210
225
|
<span className="text-gray-600 text-xs">↔</span>
|
|
211
|
-
<
|
|
226
|
+
<AliasAvatar alias={conv.participants[1]} size={16} />
|
|
227
|
+
<span className="text-sm text-gray-200 font-medium">{conv.participants[1]}</span>
|
|
212
228
|
</div>
|
|
213
229
|
<span className="text-[10px] text-gray-600">{conv.messages.length} messages</span>
|
|
214
230
|
</div>
|
|
215
231
|
<div className="px-4 py-2 space-y-2 max-h-64 overflow-y-auto">
|
|
216
232
|
{conv.messages.map(m => (
|
|
217
233
|
<div key={m.id} className="flex items-start gap-2 text-xs py-1">
|
|
218
|
-
|
|
219
|
-
<span className="text-gray-
|
|
234
|
+
{m.from_alias && <AliasAvatar alias={m.from_alias} size={14} />}
|
|
235
|
+
<span className="shrink-0 font-medium text-gray-200">{m.from_alias}</span>
|
|
236
|
+
<span className="text-gray-400 flex-1 truncate" title={m.content || ''}>{previewContent(m.content).slice(0, 120)}</span>
|
|
220
237
|
<span className="text-[9px] text-gray-600 shrink-0">{timeAgo(m.created_at || '')}</span>
|
|
221
238
|
</div>
|
|
222
239
|
))}
|
|
@@ -264,7 +281,11 @@ export default function MessagesPage() {
|
|
|
264
281
|
{message.priority === 'high' && <span className="text-xs text-red-400">HIGH</span>}
|
|
265
282
|
<span className="ml-auto text-xs text-gray-500">{message.created_at ? timeAgo(message.created_at) : '--'}</span>
|
|
266
283
|
</div>
|
|
267
|
-
|
|
284
|
+
{/* Round 79: break-words + overflow-wrap:anywhere so
|
|
285
|
+
long unbroken runs (URLs, ASCII rules like
|
|
286
|
+
`═══════════════`) wrap instead of pushing the
|
|
287
|
+
chat bubble past the mobile viewport. */}
|
|
288
|
+
<div className="whitespace-pre-wrap break-words [overflow-wrap:anywhere] text-sm leading-relaxed text-gray-200">
|
|
268
289
|
{renderHighlighted(message.content, search)}
|
|
269
290
|
</div>
|
|
270
291
|
</div>
|
|
@@ -295,7 +316,11 @@ export default function MessagesPage() {
|
|
|
295
316
|
</div>
|
|
296
317
|
)}
|
|
297
318
|
|
|
298
|
-
|
|
319
|
+
{/* Round 79: break-words + overflow-wrap:anywhere so
|
|
320
|
+
long unbroken runs (URLs, ASCII rules like
|
|
321
|
+
`═══════════════`) wrap instead of pushing the
|
|
322
|
+
chat bubble past the mobile viewport. */}
|
|
323
|
+
<div className="whitespace-pre-wrap break-words [overflow-wrap:anywhere] text-sm leading-relaxed text-gray-200">
|
|
299
324
|
{renderHighlighted(message.content, search)}
|
|
300
325
|
</div>
|
|
301
326
|
|