@sleep2agi/agent-network-dashboard 0.4.6-preview.21 → 0.4.6-preview.211
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/app-path-routes-manifest.json +1 -0
- package/.next/build-manifest.json +3 -3
- package/.next/diagnostics/route-bundle-stats.json +41 -41
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/routes-manifest.json +6 -0
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +2 -2
- package/.next/server/app/_not-found.rsc +12 -12
- package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
- package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
- package/.next/server/app/admin.html +2 -2
- package/.next/server/app/admin.rsc +14 -14
- package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
- package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
- package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
- package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
- package/.next/server/app/api/hub/servers/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/hub/servers/route/build-manifest.json +9 -0
- package/.next/server/app/api/hub/servers/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/hub/servers/route.js +7 -0
- package/.next/server/app/api/hub/servers/route.js.map +5 -0
- package/.next/server/app/api/hub/servers/route.js.nft.json +1 -0
- package/.next/server/app/api/hub/servers/route_client-reference-manifest.js +3 -0
- package/.next/server/app/index.html +2 -2
- package/.next/server/app/index.rsc +14 -14
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/server/app/index.segments/_index.segment.rsc +7 -7
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +2 -2
- package/.next/server/app/login.rsc +14 -14
- package/.next/server/app/login.segments/_full.segment.rsc +14 -14
- package/.next/server/app/login.segments/_head.segment.rsc +4 -4
- package/.next/server/app/login.segments/_index.segment.rsc +7 -7
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/login.segments/login.segment.rsc +3 -3
- package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/logs.html +2 -2
- package/.next/server/app/logs.rsc +14 -14
- package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
- package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
- package/.next/server/app/messages.html +2 -2
- package/.next/server/app/messages.rsc +14 -14
- package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
- package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
- package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
- package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
- package/.next/server/app/node/page_client-reference-manifest.js +1 -1
- package/.next/server/app/node.html +2 -2
- package/.next/server/app/node.rsc +14 -14
- package/.next/server/app/node.segments/_full.segment.rsc +14 -14
- package/.next/server/app/node.segments/_head.segment.rsc +4 -4
- package/.next/server/app/node.segments/_index.segment.rsc +7 -7
- package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/node.segments/node.segment.rsc +3 -3
- package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/nodes.html +2 -2
- package/.next/server/app/nodes.rsc +14 -14
- package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
- package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
- package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs.html +2 -2
- package/.next/server/app/server-logs.rsc +14 -14
- package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
- package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
- package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
- package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/networks.html +2 -2
- package/.next/server/app/settings/networks.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
- package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens.html +2 -2
- package/.next/server/app/settings/tokens.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
- package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
- package/.next/server/app/settings.html +2 -2
- package/.next/server/app/settings.rsc +14 -14
- package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
- package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
- package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
- package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
- package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tasks.html +2 -2
- package/.next/server/app/tasks.rsc +14 -14
- package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
- package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
- package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
- package/.next/server/app-paths-manifest.json +1 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_servers_route_actions_08-m-cs.js +3 -0
- package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_servers_route_actions_08-m-cs.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__03b.f76._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0fhoq8i._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0nw~zhp._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_057q.ne._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0_d45-d._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0i3759l._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_0xgney8._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_10hjgv4._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_1153xeb._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_12l4oto._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +2 -2
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/0-mpa_947ipeq.js +1 -0
- package/.next/static/chunks/01lmbsd37fybu.js +1 -0
- package/.next/static/chunks/03o.h6kvmw4l_.js +1 -0
- package/.next/static/chunks/03~~oirxz7~vc.js +1 -0
- package/.next/static/chunks/05uk96gc~9mni.js +1 -0
- package/.next/static/chunks/08kf-.bgs10ze.js +1 -0
- package/.next/static/chunks/09mo5s0d1t.rl.js +4 -0
- package/.next/static/chunks/0_tufsuno-ybu.js +1 -0
- package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
- package/.next/static/chunks/0glmrdj9112tc.js +7 -0
- package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
- package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
- package/.next/static/chunks/0yjst6n4eqy4c.js +1 -0
- package/.next/static/chunks/0~k1yvhakbob6.css +2 -0
- package/.next/static/chunks/174re5ar~kxne.js +1 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/.next/types/routes.d.ts +2 -1
- package/.next/types/validator.ts +9 -0
- package/app/api/hub/servers/route.ts +39 -0
- package/app/components/ChatPopover.tsx +38 -2
- package/app/components/CommandPalette.tsx +107 -0
- package/app/components/HelpOverlay.tsx +126 -0
- package/app/components/ServersDrawer.tsx +64 -27
- package/app/components/TopoGraph.tsx +4228 -255
- package/app/components/utils.ts +8 -7
- package/app/globals.css +110 -5
- package/app/lib/time.ts +36 -0
- package/package.json +1 -1
- package/scripts/help-overlay-topo-test.mjs +44 -0
- package/scripts/servers-drawer-live-test.mjs +96 -0
- package/scripts/topo-active-filter-pill-test.mjs +101 -0
- package/scripts/topo-active-links-chip-hover-test.mjs +103 -0
- package/scripts/topo-active-links-chip-nav-test.mjs +117 -0
- package/scripts/topo-active-links-chip-self-hover-test.mjs +171 -0
- package/scripts/topo-active-links-chip-test.mjs +73 -0
- package/scripts/topo-active-links-freshness-test.mjs +113 -0
- package/scripts/topo-active-links-tooltip-test.mjs +79 -0
- package/scripts/topo-arrival-ping-test.mjs +87 -0
- package/scripts/topo-arrow-tier-test.mjs +61 -0
- package/scripts/topo-auto-fit-test.mjs +73 -0
- package/scripts/topo-canvas-aria-test.mjs +108 -0
- package/scripts/topo-chat-target-breath-test.mjs +84 -0
- package/scripts/topo-chat-target-ring-fade-test.mjs +124 -0
- package/scripts/topo-chip-focus-test.mjs +95 -0
- package/scripts/topo-chip-pin-mirror-test.mjs +113 -0
- package/scripts/topo-chrome-a11y-test.mjs +107 -0
- package/scripts/topo-chrome-press-state-test.mjs +135 -0
- package/scripts/topo-chrome-zoom-level-pop-test.mjs +122 -0
- package/scripts/topo-chrome-zoom-pop-test.mjs +130 -0
- package/scripts/topo-click-ripple-test.mjs +66 -0
- package/scripts/topo-cmdk-edge-clear-test.mjs +109 -0
- package/scripts/topo-cmdk-layout-view-test.mjs +108 -0
- package/scripts/topo-cmdk-pin-test.mjs +123 -0
- package/scripts/topo-cmdk-vendor-clear-test.mjs +133 -0
- package/scripts/topo-cmdk-vendor-pin-test.mjs +103 -0
- package/scripts/topo-cwd-tooltip-test.mjs +64 -0
- package/scripts/topo-dblclick-reset-test.mjs +74 -0
- package/scripts/topo-discrete-zoom-smooth-test.mjs +125 -0
- package/scripts/topo-dispatch-pulse-test.mjs +83 -0
- package/scripts/topo-edge-badge-click-pin-test.mjs +94 -0
- package/scripts/topo-edge-badge-hot-test.mjs +115 -0
- package/scripts/topo-edge-badge-hover-test.mjs +85 -0
- package/scripts/topo-edge-badge-lift-test.mjs +150 -0
- package/scripts/topo-edge-badge-ripple-test.mjs +111 -0
- package/scripts/topo-edge-badge-stroke-transition-test.mjs +118 -0
- package/scripts/topo-edge-count-badge-test.mjs +86 -0
- package/scripts/topo-edge-endpoint-highlight-test.mjs +111 -0
- package/scripts/topo-edge-fadein-test.mjs +106 -0
- package/scripts/topo-edge-focus-test.mjs +113 -0
- package/scripts/topo-edge-hover-test.mjs +93 -0
- package/scripts/topo-edge-pill-hot-test.mjs +129 -0
- package/scripts/topo-edge-pill-test.mjs +105 -0
- package/scripts/topo-edge-stroke-transition-test.mjs +132 -0
- package/scripts/topo-edge-tooltip-test.mjs +70 -0
- package/scripts/topo-empty-state-breath-test.mjs +150 -0
- package/scripts/topo-endpoint-ring-fade-test.mjs +132 -0
- package/scripts/topo-endpoint-ring-test.mjs +93 -0
- package/scripts/topo-esc-clears-pin-test.mjs +98 -0
- package/scripts/topo-filter-pill-aliases-test.mjs +121 -0
- package/scripts/topo-filter-pill-body-click-test.mjs +112 -0
- package/scripts/topo-filter-pill-count-test.mjs +110 -0
- package/scripts/topo-filter-pill-mobile-test.mjs +90 -0
- package/scripts/topo-fit-key-test.mjs +106 -0
- package/scripts/topo-freshness-chip-test.mjs +74 -0
- package/scripts/topo-freshness-chip-transition-test.mjs +80 -0
- package/scripts/topo-fullscreen-active-test.mjs +115 -0
- package/scripts/topo-group-box-pinned-state-test.mjs +95 -0
- package/scripts/topo-group-count-test.mjs +68 -0
- package/scripts/topo-group-hover-test.mjs +82 -0
- package/scripts/topo-group-label-a11y-test.mjs +113 -0
- package/scripts/topo-group-label-hover-test.mjs +119 -0
- package/scripts/topo-group-label-tint-test.mjs +99 -0
- package/scripts/topo-group-label-title-test.mjs +83 -0
- package/scripts/topo-group-pin-test.mjs +119 -0
- package/scripts/topo-group-status-pips-test.mjs +103 -0
- package/scripts/topo-groupbox-fadein-test.mjs +95 -0
- package/scripts/topo-groupbox-hover-lift-test.mjs +127 -0
- package/scripts/topo-groupbox-live-test.mjs +100 -0
- package/scripts/topo-groupbox-march-busyness-test.mjs +155 -0
- package/scripts/topo-groupbox-test.mjs +4 -2
- package/scripts/topo-help-overlay-r109-test.mjs +67 -0
- package/scripts/topo-help-overlay-r118-test.mjs +69 -0
- package/scripts/topo-help-overlay-r123-test.mjs +69 -0
- package/scripts/topo-help-overlay-r134-test.mjs +74 -0
- package/scripts/topo-help-overlay-r137-test.mjs +81 -0
- package/scripts/topo-help-overlay-r141-test.mjs +86 -0
- package/scripts/topo-help-overlay-r153-test.mjs +85 -0
- package/scripts/topo-help-overlay-r59-test.mjs +67 -0
- package/scripts/topo-help-overlay-r65-test.mjs +64 -0
- package/scripts/topo-help-overlay-r70-test.mjs +63 -0
- package/scripts/topo-help-overlay-r78-test.mjs +59 -0
- package/scripts/topo-help-overlay-r81-test.mjs +58 -0
- package/scripts/topo-help-overlay-r87-test.mjs +64 -0
- package/scripts/topo-help-overlay-r91-test.mjs +65 -0
- package/scripts/topo-hub-a11y-test.mjs +112 -0
- package/scripts/topo-hub-busyness-test.mjs +100 -0
- package/scripts/topo-hub-click-fit-test.mjs +137 -0
- package/scripts/topo-hub-fadein-test.mjs +88 -0
- package/scripts/topo-hub-hover-lift-test.mjs +101 -0
- package/scripts/topo-hub-hover-ring-test.mjs +82 -0
- package/scripts/topo-hub-title-test.mjs +93 -0
- package/scripts/topo-hub-working-count-test.mjs +99 -0
- package/scripts/topo-ingroup-edge-test.mjs +103 -0
- package/scripts/topo-label-lift-test.mjs +119 -0
- package/scripts/topo-label-scale-test.mjs +78 -0
- package/scripts/topo-lastseen-tooltip-test.mjs +59 -0
- package/scripts/topo-layout-key-test.mjs +91 -0
- package/scripts/topo-layout-switch-crossfade-test.mjs +126 -0
- package/scripts/topo-layout-toggle-test.mjs +131 -0
- package/scripts/topo-legend-count-empty-test.mjs +126 -0
- package/scripts/topo-legend-count-test.mjs +88 -0
- package/scripts/topo-legend-hover-test.mjs +113 -0
- package/scripts/topo-legend-panel-header-test.mjs +83 -0
- package/scripts/topo-legend-pin-ring-fade-test.mjs +112 -0
- package/scripts/topo-legend-pin-test.mjs +128 -0
- package/scripts/topo-legend-row-hover-lift-test.mjs +109 -0
- package/scripts/topo-legend-row-tint-test.mjs +95 -0
- package/scripts/topo-legend-row-title-test.mjs +102 -0
- package/scripts/topo-legend-swatch-grow-test.mjs +116 -0
- package/scripts/topo-minimap-a11y-test.mjs +101 -0
- package/scripts/topo-minimap-dot-transition-test.mjs +113 -0
- package/scripts/topo-minimap-test.mjs +68 -0
- package/scripts/topo-minimap-viewport-smooth-test.mjs +124 -0
- package/scripts/topo-mobile-chips-test.mjs +103 -0
- package/scripts/topo-node-a11y-test.mjs +107 -0
- package/scripts/topo-node-hover-lift-test.mjs +85 -0
- package/scripts/topo-node-label-card-elevation-test.mjs +157 -0
- package/scripts/topo-node-stroke-transition-test.mjs +103 -0
- package/scripts/topo-node-title-peers-test.mjs +107 -0
- package/scripts/topo-node-title-test.mjs +101 -0
- package/scripts/topo-nodesize-active-hover-test.mjs +109 -0
- package/scripts/topo-nodesize-crossfade-test.mjs +141 -0
- package/scripts/topo-offline-dim-test.mjs +70 -0
- package/scripts/topo-online-chip-nav-test.mjs +143 -0
- package/scripts/topo-orbit-busyness-test.mjs +96 -0
- package/scripts/topo-overlap-test.mjs +32 -5
- package/scripts/topo-pan-cursor-test.mjs +62 -0
- package/scripts/topo-panel-elevation-test.mjs +76 -0
- package/scripts/topo-panel-fadein-test.mjs +102 -0
- package/scripts/topo-panel-hot-tail-fade-test.mjs +124 -0
- package/scripts/topo-panel-hover-elevation-test.mjs +118 -0
- package/scripts/topo-particle-stagger-test.mjs +82 -0
- package/scripts/topo-pin-intersection-empty-test.mjs +129 -0
- package/scripts/topo-pin-intersection-test.mjs +121 -0
- package/scripts/topo-pin-mirror-transition-test.mjs +101 -0
- package/scripts/topo-pin-persistence-test.mjs +105 -0
- package/scripts/topo-popover-meta-test.mjs +78 -0
- package/scripts/topo-pressure-bar-test.mjs +69 -0
- package/scripts/topo-pressure-hover-test.mjs +123 -0
- package/scripts/topo-pressure-pin-test.mjs +119 -0
- package/scripts/topo-pressure-seg-tooltip-test.mjs +98 -0
- package/scripts/topo-pressure-seg-transition-test.mjs +107 -0
- package/scripts/topo-pulse-rate-test.mjs +71 -0
- package/scripts/topo-recent-panel-count-freshness-test.mjs +109 -0
- package/scripts/topo-recent-panel-count-test.mjs +72 -0
- package/scripts/topo-recent-panel-hot-header-test.mjs +132 -0
- package/scripts/topo-recent-panel-more-cyan-hover-test.mjs +151 -0
- package/scripts/topo-recent-panel-more-nav-test.mjs +127 -0
- package/scripts/topo-recent-panel-more-test.mjs +106 -0
- package/scripts/topo-recent-row-count-fill-test.mjs +129 -0
- package/scripts/topo-recent-row-fadein-test.mjs +107 -0
- package/scripts/topo-recent-row-freshness-test.mjs +102 -0
- package/scripts/topo-recent-row-hot-test.mjs +110 -0
- package/scripts/topo-recent-row-hover-lift-test.mjs +128 -0
- package/scripts/topo-recent-row-hover-test.mjs +122 -0
- package/scripts/topo-recent-row-pin-test.mjs +126 -0
- package/scripts/topo-recent-row-tint-test.mjs +91 -0
- package/scripts/topo-recent-row-title-test.mjs +112 -0
- package/scripts/topo-recent-row-ts-alpha-test.mjs +100 -0
- package/scripts/topo-recent-row-ts-test.mjs +95 -0
- package/scripts/topo-recent-row-typography-test.mjs +119 -0
- package/scripts/topo-recent-signal-empty-hint-test.mjs +73 -0
- package/scripts/topo-recent-signal-empty-test.mjs +63 -0
- package/scripts/topo-reduced-motion-test.mjs +77 -0
- package/scripts/topo-reset-spin-test.mjs +120 -0
- package/scripts/topo-spoke-busyness-test.mjs +110 -0
- package/scripts/topo-status-chip-hover-test.mjs +101 -0
- package/scripts/topo-status-chip-tooltip-test.mjs +95 -0
- package/scripts/topo-statusbar-chips-self-hover-test.mjs +177 -0
- package/scripts/topo-svg-focus-test.mjs +112 -0
- package/scripts/topo-sweep-busyness-test.mjs +94 -0
- package/scripts/topo-tier-ring-fadein-test.mjs +107 -0
- package/scripts/topo-tier-ring-occupancy-test.mjs +87 -0
- package/scripts/topo-tier-ring-test.mjs +69 -0
- package/scripts/topo-tier-ring-tint-test.mjs +110 -0
- package/scripts/topo-tier-stagger-test.mjs +89 -0
- package/scripts/topo-tz-ghost-test.mjs +69 -0
- package/scripts/topo-vendor-chip-hover-test.mjs +111 -0
- package/scripts/topo-vendor-chip-self-hover-test.mjs +130 -0
- package/scripts/topo-vendor-letter-tooltip-test.mjs +92 -0
- package/scripts/topo-vendor-pill-test.mjs +125 -0
- package/scripts/topo-vendor-pin-test.mjs +125 -0
- package/scripts/topo-view-smooth-test.mjs +131 -0
- package/scripts/topo-wheel-zoom-test.mjs +79 -0
- package/scripts/topo-working-chip-pin-test.mjs +154 -0
- package/scripts/topo-working-halo-breath-test.mjs +86 -0
- package/scripts/topo-zoom-keys-test.mjs +89 -0
- package/.next/static/chunks/0-7iowzu4.798.js +0 -1
- package/.next/static/chunks/01j59m93~ijpq.js +0 -1
- package/.next/static/chunks/02t5jr4shh.hy.js +0 -1
- package/.next/static/chunks/09nd.t_hd.y6t.css +0 -2
- package/.next/static/chunks/0_qfg5s5uzs7..js +0 -7
- package/.next/static/chunks/0elalb9n_.~di.js +0 -1
- package/.next/static/chunks/0fqy_0wj_1xa7.js +0 -7
- package/.next/static/chunks/0j_q__o8p6g83.js +0 -1
- package/.next/static/chunks/0jl6_w50zh4l5.js +0 -1
- package/.next/static/chunks/0ms~5~zq93-vs.js +0 -1
- package/.next/static/chunks/0nh4tljy5z5ns.js +0 -1
- package/.next/static/chunks/0r4q73.-1bkyl.js +0 -1
- package/.next/static/chunks/0r_c8eccg3z2o.js +0 -1
- package/.next/static/chunks/10oi7l-tycgl9.js +0 -1
- package/.next/static/chunks/11uk1izuv3~0t.js +0 -1
- /package/.next/static/{XiA2VWgHsZvuY-5yWxSPj → FMKI0Nb4m8uK25F_8komz}/_buildManifest.js +0 -0
- /package/.next/static/{XiA2VWgHsZvuY-5yWxSPj → FMKI0Nb4m8uK25F_8komz}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{XiA2VWgHsZvuY-5yWxSPj → FMKI0Nb4m8uK25F_8komz}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/* Round 73 verification: clicking the pill body (not just the ×) clears
|
|
2
|
+
* the pin. Matches the Notion / Linear tag UX where the whole chip is
|
|
3
|
+
* the clear target. The × button keeps its dedicated <button> +
|
|
4
|
+
* aria-label so screen readers still get a proper "Clear filter" action.
|
|
5
|
+
*
|
|
6
|
+
* - Pre-seed pin via R66 sessionStorage so pill renders on first paint.
|
|
7
|
+
* - Click the pill body (text portion, NOT the × button).
|
|
8
|
+
* - Assert: pin clears + pill removed from DOM + node opacities
|
|
9
|
+
* restored.
|
|
10
|
+
* - Re-pin; click the × button → pin also clears.
|
|
11
|
+
* - title attr on the pill body reads "Click to clear filter".
|
|
12
|
+
* - cursor:pointer set on the pill body for affordance.
|
|
13
|
+
*/
|
|
14
|
+
import { chromium } from 'playwright';
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
|
|
17
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
18
|
+
const browser = await chromium.launch({ headless: true });
|
|
19
|
+
|
|
20
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
21
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
22
|
+
await ctx.addInitScript(() => {
|
|
23
|
+
try {
|
|
24
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
25
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
26
|
+
sessionStorage.setItem('anet-topo-pinned-status', 'working');
|
|
27
|
+
} catch {}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
31
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
32
|
+
const r = await route.fetch();
|
|
33
|
+
const b = await r.json();
|
|
34
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
35
|
+
const sessions = [
|
|
36
|
+
{ alias: 'wkr', status: 'working', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
37
|
+
{ alias: 'idl', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
38
|
+
];
|
|
39
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
40
|
+
});
|
|
41
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
42
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
43
|
+
const page = await ctx.newPage();
|
|
44
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
45
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
|
|
46
|
+
await page.waitForTimeout(500);
|
|
47
|
+
|
|
48
|
+
const readState = () => page.evaluate(() => {
|
|
49
|
+
const pill = document.querySelector('[data-active-filter="status"]');
|
|
50
|
+
return {
|
|
51
|
+
pillPresent: !!pill,
|
|
52
|
+
pillTitle: pill?.getAttribute('title') || null,
|
|
53
|
+
pillCursor: pill ? getComputedStyle(pill).cursor : null,
|
|
54
|
+
idlOpacity: +(document.querySelector('g[data-node="idl"]')?.style.opacity || '1'),
|
|
55
|
+
storageStatus: sessionStorage.getItem('anet-topo-pinned-status'),
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const before = await readState();
|
|
60
|
+
|
|
61
|
+
// Click on the pill body — pick a point in the text region, NOT the ×.
|
|
62
|
+
// The pill is a flex row; the first inner <span> holds the text. Click
|
|
63
|
+
// at its centre.
|
|
64
|
+
await page.evaluate(() => {
|
|
65
|
+
const pill = document.querySelector('[data-active-filter="status"]');
|
|
66
|
+
if (!pill) throw new Error('pill not found');
|
|
67
|
+
const text = pill.querySelector('span');
|
|
68
|
+
if (!text) throw new Error('pill text not found');
|
|
69
|
+
const r = text.getBoundingClientRect();
|
|
70
|
+
window.__bodyClickXY = { x: r.x + r.width / 2, y: r.y + r.height / 2 };
|
|
71
|
+
});
|
|
72
|
+
const xy = await page.evaluate(() => window.__bodyClickXY);
|
|
73
|
+
await page.mouse.click(xy.x, xy.y);
|
|
74
|
+
await page.waitForTimeout(250);
|
|
75
|
+
const afterBodyClick = await readState();
|
|
76
|
+
|
|
77
|
+
// Re-pin via sessionStorage + event.
|
|
78
|
+
await page.evaluate(() => {
|
|
79
|
+
sessionStorage.setItem('anet-topo-pinned-status', 'working');
|
|
80
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'status', value: 'working' } }));
|
|
81
|
+
});
|
|
82
|
+
await page.waitForTimeout(250);
|
|
83
|
+
const afterRepin = await readState();
|
|
84
|
+
|
|
85
|
+
// Click the × button.
|
|
86
|
+
await page.locator('[data-active-filter="status"] button').first().click();
|
|
87
|
+
await page.waitForTimeout(250);
|
|
88
|
+
const afterXClick = await readState();
|
|
89
|
+
|
|
90
|
+
await browser.close();
|
|
91
|
+
|
|
92
|
+
const bright = (v) => v != null && v >= 0.55;
|
|
93
|
+
const dim = (v) => v != null && v < 0.4;
|
|
94
|
+
const results = {
|
|
95
|
+
before_pillPresent: before.pillPresent === true,
|
|
96
|
+
before_titleHint: before.pillTitle === 'Click to clear filter',
|
|
97
|
+
before_cursorPointer: before.pillCursor === 'pointer',
|
|
98
|
+
before_idleDim: dim(before.idlOpacity),
|
|
99
|
+
bodyClick_pillGone: afterBodyClick.pillPresent === false,
|
|
100
|
+
bodyClick_storageGone: afterBodyClick.storageStatus === null,
|
|
101
|
+
bodyClick_idleRestored: bright(afterBodyClick.idlOpacity),
|
|
102
|
+
repin_pillBack: afterRepin.pillPresent === true,
|
|
103
|
+
xClick_pillGone: afterXClick.pillPresent === false,
|
|
104
|
+
xClick_storageGone: afterXClick.storageStatus === null,
|
|
105
|
+
};
|
|
106
|
+
const ok = Object.values(results).every(Boolean);
|
|
107
|
+
console.log(`${ok ? '✅' : '❌'} filter pill body click:`, JSON.stringify(results),
|
|
108
|
+
`\n before=`, before,
|
|
109
|
+
`\n afterBodyClick=`, afterBodyClick,
|
|
110
|
+
`\n afterRepin=`, afterRepin,
|
|
111
|
+
`\n afterXClick=`, afterXClick);
|
|
112
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/* Round 71 verification: each active-filter pill shows a "· N" match
|
|
2
|
+
* count tail and surfaces `data-filter-match-count` for tooling.
|
|
3
|
+
*
|
|
4
|
+
* Sessions: 1 working + 2 idle + 1 offline + 3-alpha cluster.
|
|
5
|
+
* Pin status=working → pill "filter: working · 1", count=1
|
|
6
|
+
* Pin status=idle → pill "filter: idle · 5", count=5 (idl + alpha1/2/3 all idle online)
|
|
7
|
+
* Pin status=offline → pill "filter: offline · 1", count=1
|
|
8
|
+
* Pin group=alpha → pill "filter: alpha · 3", count=3 (3 alphas)
|
|
9
|
+
*/
|
|
10
|
+
import { chromium } from 'playwright';
|
|
11
|
+
import { readFileSync } from 'node:fs';
|
|
12
|
+
|
|
13
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
14
|
+
const browser = await chromium.launch({ headless: true });
|
|
15
|
+
|
|
16
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
17
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
18
|
+
await ctx.addInitScript(() => {
|
|
19
|
+
try {
|
|
20
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
21
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
22
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
23
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
24
|
+
sessionStorage.removeItem('anet-topo-pinned-group');
|
|
25
|
+
} catch {}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
29
|
+
const stale = new Date(Date.now() - 30 * 60 * 1000).toISOString();
|
|
30
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
31
|
+
const r = await route.fetch();
|
|
32
|
+
const b = await r.json();
|
|
33
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
34
|
+
const sessions = [
|
|
35
|
+
{ alias: 'wkr', status: 'working', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
36
|
+
{ alias: 'idl', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
37
|
+
{ alias: 'idl2', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
38
|
+
{ alias: 'alpha1', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
39
|
+
{ alias: 'alpha2', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
40
|
+
{ alias: 'alpha3', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
41
|
+
{ alias: 'off', status: 'offline', network_id: nid, project_dir: null, created_at: stale, updated_at: stale, last_seen_at: stale },
|
|
42
|
+
];
|
|
43
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
44
|
+
});
|
|
45
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
46
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
47
|
+
const page = await ctx.newPage();
|
|
48
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
49
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 7, { timeout: 30000 });
|
|
50
|
+
await page.waitForTimeout(700);
|
|
51
|
+
|
|
52
|
+
async function pin({ status, group }) {
|
|
53
|
+
await page.evaluate(({ status, group }) => {
|
|
54
|
+
if (status === null) { sessionStorage.removeItem('anet-topo-pinned-status'); }
|
|
55
|
+
else { sessionStorage.setItem('anet-topo-pinned-status', status); }
|
|
56
|
+
if (group === null) { sessionStorage.removeItem('anet-topo-pinned-group'); }
|
|
57
|
+
else if (group) { sessionStorage.setItem('anet-topo-pinned-group', group); }
|
|
58
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin',
|
|
59
|
+
{ detail: status !== undefined ? { kind: 'status', value: status }
|
|
60
|
+
: group !== undefined ? { kind: 'group', value: group }
|
|
61
|
+
: { kind: 'clear' } }));
|
|
62
|
+
}, { status, group });
|
|
63
|
+
await page.waitForTimeout(250);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const readPill = (kind) => page.evaluate(k => {
|
|
67
|
+
const el = document.querySelector(`[data-active-filter="${k}"]`);
|
|
68
|
+
if (!el) return null;
|
|
69
|
+
return {
|
|
70
|
+
text: (el.innerText || el.textContent || '').trim(),
|
|
71
|
+
count: el.getAttribute('data-filter-match-count'),
|
|
72
|
+
};
|
|
73
|
+
}, kind);
|
|
74
|
+
|
|
75
|
+
// Pin working → 1 match.
|
|
76
|
+
await pin({ status: 'working' });
|
|
77
|
+
const w = await readPill('status');
|
|
78
|
+
|
|
79
|
+
// Pin idle → 5 (idl + idl2 + alpha1 + alpha2 + alpha3 — all idle online).
|
|
80
|
+
await pin({ status: 'idle' });
|
|
81
|
+
const i = await readPill('status');
|
|
82
|
+
|
|
83
|
+
// Pin offline → 1 match.
|
|
84
|
+
await pin({ status: 'offline' });
|
|
85
|
+
const o = await readPill('status');
|
|
86
|
+
|
|
87
|
+
// Pin group alpha → 3 match.
|
|
88
|
+
await pin({ status: null });
|
|
89
|
+
await pin({ group: 'alpha' });
|
|
90
|
+
const g = await readPill('group');
|
|
91
|
+
|
|
92
|
+
await browser.close();
|
|
93
|
+
|
|
94
|
+
const results = {
|
|
95
|
+
working_attrCount1: w && w.count === '1',
|
|
96
|
+
working_textHas1: w && /·\s*1\b/.test(w.text),
|
|
97
|
+
idle_attrCount5: i && i.count === '5',
|
|
98
|
+
idle_textHas5: i && /·\s*5\b/.test(i.text),
|
|
99
|
+
offline_attrCount1: o && o.count === '1',
|
|
100
|
+
offline_textHas1: o && /·\s*1\b/.test(o.text),
|
|
101
|
+
group_attrCount3: g && g.count === '3',
|
|
102
|
+
group_textHas3: g && /·\s*3\b/.test(g.text),
|
|
103
|
+
};
|
|
104
|
+
const ok = Object.values(results).every(Boolean);
|
|
105
|
+
console.log(`${ok ? '✅' : '❌'} filter pill count:`, JSON.stringify(results),
|
|
106
|
+
`\n working=`, w,
|
|
107
|
+
`\n idle=`, i,
|
|
108
|
+
`\n offline=`, o,
|
|
109
|
+
`\n group=`, g);
|
|
110
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/* Round 67 verification: filter pills shed the "filter:" prefix on
|
|
2
|
+
* narrow viewports and gain an anet-fade-in entrance.
|
|
3
|
+
* - At <sm (375 px) the prefix span has `display:none` via the
|
|
4
|
+
* `hidden sm:inline` class — visible pill text = "working×".
|
|
5
|
+
* - At sm+ (900 px) the prefix is visible — "filter: working ×".
|
|
6
|
+
* - The pill `<span>` carries `anet-fade-in` class so it eases in
|
|
7
|
+
* on mount (entrance polish).
|
|
8
|
+
*/
|
|
9
|
+
import { chromium } from 'playwright';
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
|
|
12
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
13
|
+
const browser = await chromium.launch({ headless: true });
|
|
14
|
+
|
|
15
|
+
async function probe(width) {
|
|
16
|
+
const ctx = await browser.newContext({ viewport: { width, height: 1500 } });
|
|
17
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
18
|
+
await ctx.addInitScript(() => {
|
|
19
|
+
try {
|
|
20
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
21
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
22
|
+
// Pre-seed the working pin via R66 persistence so the pill exists
|
|
23
|
+
// on first paint — keeps the test independent of click wiring.
|
|
24
|
+
sessionStorage.setItem('anet-topo-pinned-status', 'working');
|
|
25
|
+
} catch {}
|
|
26
|
+
});
|
|
27
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
28
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
29
|
+
const r = await route.fetch();
|
|
30
|
+
const b = await r.json();
|
|
31
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
32
|
+
const sessions = [
|
|
33
|
+
{ alias: 'wkr', status: 'working', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
34
|
+
{ alias: 'idl', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
35
|
+
];
|
|
36
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
37
|
+
});
|
|
38
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
39
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
40
|
+
const page = await ctx.newPage();
|
|
41
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
42
|
+
// Mobile viewport auto-hides the topology section; click "Show Topology"
|
|
43
|
+
// if the button surfaces. Otherwise the pill still renders in the chip
|
|
44
|
+
// row (chip row is independent of canvas visibility).
|
|
45
|
+
await page.waitForTimeout(1200);
|
|
46
|
+
const showBtn = page.locator('button', { hasText: /Show Topology/i });
|
|
47
|
+
if (await showBtn.count() > 0) await showBtn.first().click();
|
|
48
|
+
await page.waitForSelector('[data-active-filter="status"]', { timeout: 15000 });
|
|
49
|
+
|
|
50
|
+
const info = await page.evaluate(() => {
|
|
51
|
+
const pill = document.querySelector('[data-active-filter="status"]');
|
|
52
|
+
if (!pill) return null;
|
|
53
|
+
const prefix = pill.querySelector('[data-filter-prefix]');
|
|
54
|
+
// innerText respects display:none (vs textContent which includes
|
|
55
|
+
// all DOM text); that's the visible-to-the-user version.
|
|
56
|
+
return {
|
|
57
|
+
pillText: (pill.innerText || '').trim(),
|
|
58
|
+
pillFull: (pill.textContent || '').trim(),
|
|
59
|
+
pillClasses: pill.getAttribute('class') || '',
|
|
60
|
+
hasFadeIn: /\banet-fade-in\b/.test(pill.getAttribute('class') || ''),
|
|
61
|
+
prefixVisible: prefix
|
|
62
|
+
? (() => {
|
|
63
|
+
const r = prefix.getBoundingClientRect();
|
|
64
|
+
return r.width > 0 && r.height > 0;
|
|
65
|
+
})()
|
|
66
|
+
: false,
|
|
67
|
+
prefixDisplay: prefix ? getComputedStyle(prefix).display : null,
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
await ctx.close();
|
|
71
|
+
return info;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const mobile = await probe(375);
|
|
75
|
+
const desktop = await probe(900);
|
|
76
|
+
await browser.close();
|
|
77
|
+
|
|
78
|
+
const results = {
|
|
79
|
+
mobile_prefixHidden: mobile && mobile.prefixVisible === false && mobile.prefixDisplay === 'none',
|
|
80
|
+
mobile_textNoPrefix: mobile && /^working/.test(mobile.pillText.trim()),
|
|
81
|
+
mobile_hasFadeIn: mobile && mobile.hasFadeIn === true,
|
|
82
|
+
desktop_prefixVisible: desktop && desktop.prefixVisible === true,
|
|
83
|
+
desktop_textWithPrefix: desktop && /^filter:\s*working/.test(desktop.pillText.trim()),
|
|
84
|
+
desktop_hasFadeIn: desktop && desktop.hasFadeIn === true,
|
|
85
|
+
};
|
|
86
|
+
const ok = Object.values(results).every(Boolean);
|
|
87
|
+
console.log(`${ok ? '✅' : '❌'} filter pill mobile:`, JSON.stringify(results),
|
|
88
|
+
`\n mobile=`, mobile,
|
|
89
|
+
`\n desktop=`, desktop);
|
|
90
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/* Round 29 verification: `f` keyboard shortcut triggers fit-to-content.
|
|
2
|
+
* - on a fleet that overflows: f sets zoom < 100%
|
|
3
|
+
* - on a fleet that fits at 100%: f is a recenter (zoom stays/returns 100%)
|
|
4
|
+
* - input-focus suppression: typing `f` in Cmd+K palette must not fit
|
|
5
|
+
* - help overlay lists `f` */
|
|
6
|
+
import { chromium } from 'playwright';
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
|
|
9
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
10
|
+
const browser = await chromium.launch({ headless: true });
|
|
11
|
+
|
|
12
|
+
async function load({ fleetSize, persisted }) {
|
|
13
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 1600 } });
|
|
14
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
15
|
+
await ctx.addInitScript(([pers]) => {
|
|
16
|
+
try {
|
|
17
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
18
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
19
|
+
if (pers) localStorage.setItem('anet-topo-view', JSON.stringify(pers));
|
|
20
|
+
else localStorage.removeItem('anet-topo-view');
|
|
21
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
22
|
+
} catch {}
|
|
23
|
+
}, [persisted]);
|
|
24
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
25
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
26
|
+
const r = await route.fetch();
|
|
27
|
+
const b = await r.json();
|
|
28
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
29
|
+
const groups = ['A站', 'B站', 'C站', 'D站', 'E站', 'F站', 'G站'];
|
|
30
|
+
const aliases = Array.from({ length: fleetSize }, (_, i) =>
|
|
31
|
+
`${groups[Math.floor(i / 5) % groups.length]}n${i + 1}`);
|
|
32
|
+
const sessions = aliases.map(a => ({
|
|
33
|
+
alias: a, status: 'idle', network_id: nid, project_dir: null,
|
|
34
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
35
|
+
}));
|
|
36
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
37
|
+
});
|
|
38
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
39
|
+
const page = await ctx.newPage();
|
|
40
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
41
|
+
await page.waitForFunction((n) => document.querySelectorAll('g[data-node]').length === n, fleetSize, { timeout: 30000 }).catch(() => {});
|
|
42
|
+
await page.waitForTimeout(500);
|
|
43
|
+
return { ctx, page };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const readZoom = (page) => page.evaluate(() => {
|
|
47
|
+
const span = document.querySelector('button[aria-label="Zoom in"]').parentElement.querySelector('span[title*="zoom level"]');
|
|
48
|
+
return +span.textContent.replace('%', '');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// 1. Big fleet, persisted view at 100% → autoFit doesn't run (persisted respected);
|
|
52
|
+
// user presses `f` and gets fitted now.
|
|
53
|
+
const big = await load({ fleetSize: 35, persisted: { zoom: 1, x: 0, y: 0 } });
|
|
54
|
+
const bigBefore = await readZoom(big.page);
|
|
55
|
+
await big.page.keyboard.press('f');
|
|
56
|
+
await big.page.waitForTimeout(150);
|
|
57
|
+
const bigAfter = await readZoom(big.page);
|
|
58
|
+
await big.ctx.close();
|
|
59
|
+
|
|
60
|
+
// 2. Small fleet (no overflow), user manually zoomed in via `+` then presses `f` to recenter.
|
|
61
|
+
const small = await load({ fleetSize: 6, persisted: { zoom: 1, x: 0, y: 0 } });
|
|
62
|
+
await small.page.keyboard.press('=');
|
|
63
|
+
await small.page.keyboard.press('=');
|
|
64
|
+
await small.page.waitForTimeout(120);
|
|
65
|
+
const smallZoomedIn = await readZoom(small.page);
|
|
66
|
+
await small.page.keyboard.press('f');
|
|
67
|
+
await small.page.waitForTimeout(150);
|
|
68
|
+
const smallAfterFit = await readZoom(small.page);
|
|
69
|
+
await small.ctx.close();
|
|
70
|
+
|
|
71
|
+
// 3. Input-focus suppression: open Cmd+K, type `f`, expect no fit.
|
|
72
|
+
const focus = await load({ fleetSize: 35, persisted: { zoom: 1, x: 0, y: 0 } });
|
|
73
|
+
const focusBefore = await readZoom(focus.page);
|
|
74
|
+
await focus.page.keyboard.press('Meta+k');
|
|
75
|
+
await focus.page.waitForTimeout(200);
|
|
76
|
+
const paletteInput = focus.page.locator('input[placeholder*="Search"], input[type="search"], [role="dialog"] input').first();
|
|
77
|
+
await paletteInput.focus().catch(() => {});
|
|
78
|
+
await focus.page.keyboard.press('f');
|
|
79
|
+
await focus.page.waitForTimeout(150);
|
|
80
|
+
const focusAfter = await readZoom(focus.page);
|
|
81
|
+
await focus.page.keyboard.press('Escape');
|
|
82
|
+
await focus.ctx.close();
|
|
83
|
+
|
|
84
|
+
// 4. Help overlay lists `f`.
|
|
85
|
+
const help = await load({ fleetSize: 4 });
|
|
86
|
+
await help.page.keyboard.press('?');
|
|
87
|
+
await help.page.waitForTimeout(200);
|
|
88
|
+
const helpHasFit = await help.page.evaluate(() => {
|
|
89
|
+
const heading = [...document.querySelectorAll('[role="dialog"] div')].find(el => el.textContent === 'Topology canvas');
|
|
90
|
+
if (!heading) return false;
|
|
91
|
+
const txt = heading.parentElement?.textContent || '';
|
|
92
|
+
return /Fit topology/i.test(txt);
|
|
93
|
+
});
|
|
94
|
+
await help.ctx.close();
|
|
95
|
+
|
|
96
|
+
await browser.close();
|
|
97
|
+
const results = {
|
|
98
|
+
bigFleetFKeyFits: bigBefore === 100 && bigAfter < 100 && bigAfter >= 50,
|
|
99
|
+
smallFleetFKeyRecenters: smallZoomedIn > 100 && smallAfterFit === 100,
|
|
100
|
+
inputFocusSuppressed: focusAfter === focusBefore,
|
|
101
|
+
helpOverlayListsFit: helpHasFit,
|
|
102
|
+
};
|
|
103
|
+
const ok = Object.values(results).every(Boolean);
|
|
104
|
+
console.log(`${ok ? '✅' : '❌'} fit key:`, JSON.stringify(results),
|
|
105
|
+
`bigBefore=${bigBefore} bigAfter=${bigAfter} smallZoomedIn=${smallZoomedIn} smallAfterFit=${smallAfterFit} focusBefore=${focusBefore} focusAfter=${focusAfter}`);
|
|
106
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/* Round 46 verification: live · Ns freshness chip.
|
|
2
|
+
* - renders in the topology header with initial "live · 0s" or "live · 1s"
|
|
3
|
+
* - ticks up over time (>= 2s after a 2.5s wait)
|
|
4
|
+
* - resets near 0 when SWR delivers a new sessions payload (we trigger
|
|
5
|
+
* this by mutating the mocked /api/hub/status response — SWR's 5s
|
|
6
|
+
* refresh re-fetches and the chip should re-zero)
|
|
7
|
+
* - turns amber when stale (>10s since last sync; verified by blocking
|
|
8
|
+
* the second poll and waiting >12s) */
|
|
9
|
+
import { chromium } from 'playwright';
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
|
|
12
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
13
|
+
const browser = await chromium.launch({ headless: true });
|
|
14
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 900 } });
|
|
15
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
16
|
+
await ctx.addInitScript(() => {
|
|
17
|
+
try {
|
|
18
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
19
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
20
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
21
|
+
} catch {}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
let pollCount = 0;
|
|
25
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
26
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
27
|
+
pollCount++;
|
|
28
|
+
const r = await route.fetch();
|
|
29
|
+
const b = await r.json();
|
|
30
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
31
|
+
const sessions = [
|
|
32
|
+
{ alias: `a${pollCount}`, status: 'idle', network_id: nid, project_dir: null,
|
|
33
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
34
|
+
{ alias: 'b', status: 'idle', network_id: nid, project_dir: null,
|
|
35
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
36
|
+
];
|
|
37
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
38
|
+
});
|
|
39
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
40
|
+
const page = await ctx.newPage();
|
|
41
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
42
|
+
await page.waitForSelector('[data-freshness-chip]', { timeout: 30000 });
|
|
43
|
+
|
|
44
|
+
const readChip = () => page.evaluate(() => {
|
|
45
|
+
const el = document.querySelector('[data-freshness-chip]');
|
|
46
|
+
if (!el) return null;
|
|
47
|
+
return {
|
|
48
|
+
text: (el.textContent || '').trim(),
|
|
49
|
+
isAmber: /amber|warning/i.test(el.className) || el.className.includes('amber'),
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const initial = await readChip();
|
|
54
|
+
await page.waitForTimeout(2500);
|
|
55
|
+
const afterTick = await readChip();
|
|
56
|
+
|
|
57
|
+
// SWR refreshes every 5s — wait past one cycle and confirm the chip re-zeros.
|
|
58
|
+
// Initial chip might be 1s, after 2.5s should be 3s. After a ~5s sync,
|
|
59
|
+
// should drop to 0-1s.
|
|
60
|
+
await page.waitForTimeout(3500);
|
|
61
|
+
const afterSync = await readChip();
|
|
62
|
+
|
|
63
|
+
await browser.close();
|
|
64
|
+
const seconds = (s) => +(s.text.match(/(\d+)s/)?.[1] ?? -1);
|
|
65
|
+
const results = {
|
|
66
|
+
initialNearZero: initial !== null && seconds(initial) <= 2,
|
|
67
|
+
tickedUpAfter25s: afterTick !== null && seconds(afterTick) >= 2 && seconds(afterTick) <= 4,
|
|
68
|
+
reZeroedAfterSync: afterSync !== null && seconds(afterSync) <= 2,
|
|
69
|
+
pollsHappened: pollCount >= 2,
|
|
70
|
+
};
|
|
71
|
+
const ok = Object.values(results).every(Boolean);
|
|
72
|
+
console.log(`${ok ? '✅' : '❌'} freshness chip:`, JSON.stringify(results),
|
|
73
|
+
`\n initial=${JSON.stringify(initial)}\n afterTick=${JSON.stringify(afterTick)}\n afterSync=${JSON.stringify(afterSync)} polls=${pollCount}`);
|
|
74
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* Round 187 verification: FreshnessChip color transition.
|
|
2
|
+
*
|
|
3
|
+
* Pre-R187 the chip swapped between fresh (gray) and stale
|
|
4
|
+
* (amber) Tailwind classes — bg/text/border snapped every
|
|
5
|
+
* time the >10s boundary was crossed. R187 adds
|
|
6
|
+
* transition-colors duration-300 so the palette eases
|
|
7
|
+
* smoothly through the stale-onset and recovery.
|
|
8
|
+
*
|
|
9
|
+
* Test:
|
|
10
|
+
* 1. Mount: data-freshness-chip-stale='false' (just synced)
|
|
11
|
+
* 2. className includes transition-colors + duration-300
|
|
12
|
+
* 3. className includes gray fresh palette
|
|
13
|
+
* 4. computed transition string includes background-color,
|
|
14
|
+
* border-*, color properties
|
|
15
|
+
*/
|
|
16
|
+
import { chromium } from 'playwright';
|
|
17
|
+
import { readFileSync } from 'node:fs';
|
|
18
|
+
|
|
19
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
20
|
+
const browser = await chromium.launch({ headless: true });
|
|
21
|
+
|
|
22
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
23
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
24
|
+
await ctx.addInitScript(() => {
|
|
25
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
29
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
30
|
+
const r = await route.fetch();
|
|
31
|
+
const b = await r.json();
|
|
32
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
33
|
+
const mk = (alias) => ({
|
|
34
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
35
|
+
network_id: nid, project_dir: null,
|
|
36
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
37
|
+
});
|
|
38
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta')] } });
|
|
39
|
+
});
|
|
40
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
41
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
42
|
+
|
|
43
|
+
const page = await ctx.newPage();
|
|
44
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
45
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
|
|
46
|
+
await page.waitForSelector('[data-freshness-chip]', { timeout: 10000 });
|
|
47
|
+
await page.waitForTimeout(400);
|
|
48
|
+
|
|
49
|
+
const probe = await page.evaluate(() => {
|
|
50
|
+
const chip = document.querySelector('[data-freshness-chip]');
|
|
51
|
+
if (!chip) return null;
|
|
52
|
+
const computed = getComputedStyle(chip);
|
|
53
|
+
return {
|
|
54
|
+
staleAttr: chip.getAttribute('data-freshness-chip-stale'),
|
|
55
|
+
className: chip.getAttribute('class') || '',
|
|
56
|
+
transition: computed.transitionProperty + ' / ' + computed.transitionDuration,
|
|
57
|
+
text: chip.textContent,
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
await browser.close();
|
|
62
|
+
|
|
63
|
+
const results = {
|
|
64
|
+
chip_found: probe !== null,
|
|
65
|
+
initial_stale_false: probe?.staleAttr === 'false',
|
|
66
|
+
has_transition_colors: probe?.className.includes('transition-colors'),
|
|
67
|
+
has_duration_300: probe?.className.includes('duration-300'),
|
|
68
|
+
has_fresh_palette_bg: probe?.className.includes('bg-gray-500/10'),
|
|
69
|
+
has_fresh_palette_text: probe?.className.includes('text-gray-400'),
|
|
70
|
+
has_fresh_palette_border: probe?.className.includes('border-gray-500/20'),
|
|
71
|
+
no_stale_palette: !probe?.className.includes('bg-amber-500/10'),
|
|
72
|
+
transition_covers_bg: (probe?.transition || '').includes('background-color'),
|
|
73
|
+
transition_covers_border: (probe?.transition || '').includes('border'),
|
|
74
|
+
transition_covers_color: (probe?.transition || '').match(/(^|[\s,/])color\b/),
|
|
75
|
+
text_shows_live: /^live ·/.test(probe?.text || ''),
|
|
76
|
+
};
|
|
77
|
+
const ok = Object.values(results).every(Boolean);
|
|
78
|
+
console.log(`${ok ? '✅' : '❌'} freshness chip transition:`, JSON.stringify(Object.fromEntries(Object.entries(results).map(([k,v]) => [k, !!v]))),
|
|
79
|
+
`\n probe:`, probe);
|
|
80
|
+
process.exit(ok ? 0 : 1);
|