@sleep2agi/agent-network-dashboard 0.4.6-preview.21 → 0.4.6-preview.210
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/0f0iq6304tw-p.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/0xtbt3szoyqsp.js +4 -0
- package/.next/static/chunks/0~k1yvhakbob6.css +2 -0
- package/.next/static/chunks/12m0az1fb1ovq.js +1 -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 +4212 -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-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 → Wt-rije1CRXoKiR80pqDA}/_buildManifest.js +0 -0
- /package/.next/static/{XiA2VWgHsZvuY-5yWxSPj → Wt-rije1CRXoKiR80pqDA}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{XiA2VWgHsZvuY-5yWxSPj → Wt-rije1CRXoKiR80pqDA}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/* Round 61 verification: legend rows also pin status filter on click.
|
|
2
|
+
* - Hovering still works (R55, transient release).
|
|
3
|
+
* - Clicking a row toggles pinnedStatus same as R60 pressure segments.
|
|
4
|
+
* - Pinned row's swatch gets an outer ring at r=8 (concentric, row colour).
|
|
5
|
+
* - Click same row again → release.
|
|
6
|
+
* - Sticky: pin survives mouse-move-away (vs R55 hover which clears).
|
|
7
|
+
* - The R60 pressure-segment pin and this share `pinnedStatus`, so
|
|
8
|
+
* clicking the legend then clicking the pressure-segment for a
|
|
9
|
+
* different status replaces (not stacks) the filter — verified by
|
|
10
|
+
* chain: legend.working → pressure.idle → only idle stays bright.
|
|
11
|
+
*/
|
|
12
|
+
import { chromium } from 'playwright';
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
|
|
15
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
16
|
+
const browser = await chromium.launch({ headless: true });
|
|
17
|
+
|
|
18
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
19
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
20
|
+
await ctx.addInitScript(() => {
|
|
21
|
+
try {
|
|
22
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
23
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
24
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
25
|
+
} 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 sessions = [
|
|
34
|
+
{ alias: 'wkr', status: 'working', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
35
|
+
{ alias: 'idl1', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
36
|
+
{ alias: 'idl2', status: 'idle', network_id: nid, project_dir: null, created_at: fresh, updated_at: fresh, last_seen_at: fresh },
|
|
37
|
+
];
|
|
38
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
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
|
+
const page = await ctx.newPage();
|
|
43
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
44
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
45
|
+
await page.waitForTimeout(500);
|
|
46
|
+
|
|
47
|
+
const opacities = () => page.evaluate(() => {
|
|
48
|
+
const o = {};
|
|
49
|
+
for (const a of ['wkr', 'idl1', 'idl2']) {
|
|
50
|
+
const g = document.querySelector(`g[data-node="${a}"]`);
|
|
51
|
+
o[a] = g ? +(g.style.opacity || '1') : null;
|
|
52
|
+
}
|
|
53
|
+
return o;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const before = await opacities();
|
|
57
|
+
|
|
58
|
+
// Click the WORKING legend row.
|
|
59
|
+
const workingLegend = page.locator('g[data-legend-status="working"]').first();
|
|
60
|
+
const workingExists = await workingLegend.count() > 0;
|
|
61
|
+
if (!workingExists) { console.log('❌ legend row[working] not found'); process.exit(1); }
|
|
62
|
+
await workingLegend.click({ force: true });
|
|
63
|
+
await page.waitForTimeout(250);
|
|
64
|
+
const afterPin = await opacities();
|
|
65
|
+
|
|
66
|
+
// Pin survives mouse move.
|
|
67
|
+
await page.mouse.move(10, 10);
|
|
68
|
+
await page.waitForTimeout(250);
|
|
69
|
+
const afterMouseMove = await opacities();
|
|
70
|
+
|
|
71
|
+
// Pinned row should carry an aria-pressed=true.
|
|
72
|
+
const pinnedAria = await page.evaluate(() => {
|
|
73
|
+
const g = document.querySelector('g[data-legend-status="working"]');
|
|
74
|
+
return g?.getAttribute('aria-pressed');
|
|
75
|
+
});
|
|
76
|
+
// And a concentric r=8 ring exists inside it.
|
|
77
|
+
const pinnedRingExists = await page.evaluate(() => {
|
|
78
|
+
const g = document.querySelector('g[data-legend-status="working"]');
|
|
79
|
+
if (!g) return false;
|
|
80
|
+
return [...g.querySelectorAll('circle')].some(c => c.getAttribute('r') === '8');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Switch pin via pressure segment (idle) — should REPLACE, not stack.
|
|
84
|
+
const idleSeg = page.locator('[data-pressure-seg="idle"]').first();
|
|
85
|
+
await idleSeg.click({ force: true });
|
|
86
|
+
await page.waitForTimeout(250);
|
|
87
|
+
const afterSwitch = await opacities();
|
|
88
|
+
|
|
89
|
+
// And the legend pin should release (concentric ring gone from working).
|
|
90
|
+
const workingRingGone = await page.evaluate(() => {
|
|
91
|
+
const g = document.querySelector('g[data-legend-status="working"]');
|
|
92
|
+
if (!g) return true;
|
|
93
|
+
return ![...g.querySelectorAll('circle')].some(c => c.getAttribute('r') === '8');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Click idle legend again to release pin. The click ALSO triggers a
|
|
97
|
+
// mouseenter that sets hoveredStatus='idle', which would keep the
|
|
98
|
+
// filter active (activeStatus = hoveredStatus ?? pinnedStatus). Move
|
|
99
|
+
// the mouse away to clear the hover so we observe the pin-only state.
|
|
100
|
+
await page.locator('g[data-legend-status="idle"]').first().click({ force: true });
|
|
101
|
+
await page.mouse.move(10, 10);
|
|
102
|
+
await page.waitForTimeout(250);
|
|
103
|
+
const afterRelease = await opacities();
|
|
104
|
+
|
|
105
|
+
await browser.close();
|
|
106
|
+
|
|
107
|
+
const bright = (v) => v != null && v >= 0.55;
|
|
108
|
+
const dim = (v) => v != null && v < 0.4;
|
|
109
|
+
const results = {
|
|
110
|
+
before_baseline: bright(before.wkr) && bright(before.idl1) && bright(before.idl2),
|
|
111
|
+
legendPin_keepsWorking: bright(afterPin.wkr),
|
|
112
|
+
legendPin_dimsIdle: dim(afterPin.idl1) && dim(afterPin.idl2),
|
|
113
|
+
legendPin_survivesMouse: bright(afterMouseMove.wkr) && dim(afterMouseMove.idl1),
|
|
114
|
+
legendPin_ariaPressed: pinnedAria === 'true',
|
|
115
|
+
legendPin_ringRendered: pinnedRingExists,
|
|
116
|
+
pressureSwitch_replaces: dim(afterSwitch.wkr) && bright(afterSwitch.idl1) && bright(afterSwitch.idl2),
|
|
117
|
+
pressureSwitch_clearsLegendRing: workingRingGone,
|
|
118
|
+
release_restoresAll: bright(afterRelease.wkr) && bright(afterRelease.idl1),
|
|
119
|
+
};
|
|
120
|
+
const ok = Object.values(results).every(Boolean);
|
|
121
|
+
console.log(`${ok ? '✅' : '❌'} legend pin:`, JSON.stringify(results),
|
|
122
|
+
`\n before=`, before,
|
|
123
|
+
`\n afterPin=`, afterPin,
|
|
124
|
+
`\n afterMouseMove=`, afterMouseMove,
|
|
125
|
+
`\n afterSwitch=`, afterSwitch,
|
|
126
|
+
`\n afterRelease=`, afterRelease,
|
|
127
|
+
`\n pinnedAria=${pinnedAria} ringRendered=${pinnedRingExists} workingRingGone=${workingRingGone}`);
|
|
128
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* Round 144 verification: legend panel rows lift 1px on hover or
|
|
2
|
+
* pin. Symmetric extension of R143 (recent-signal rows) to the
|
|
3
|
+
* sibling overlay panel.
|
|
4
|
+
*
|
|
5
|
+
* Now both side panels share matching row-level affordances:
|
|
6
|
+
* recent-signal row (R143): hover/pin → translateY(-1px)
|
|
7
|
+
* legend row (R144): hover/pin → translateY(-1px)
|
|
8
|
+
*
|
|
9
|
+
* Each row composes inside its panel's hover-shadow (R135) — two
|
|
10
|
+
* layers of feedback simultaneously when hovering a row.
|
|
11
|
+
*
|
|
12
|
+
* Path:
|
|
13
|
+
* 1. idle: working/idle/offline rows all flat
|
|
14
|
+
* 2. hover working row → that row lifts; others stay flat
|
|
15
|
+
* 3. leave hover → restored
|
|
16
|
+
* 4. click to pin idle row → idle lifted+pinned; working flat
|
|
17
|
+
* 5. Esc clears pin → idle flat again
|
|
18
|
+
*/
|
|
19
|
+
import { chromium } from 'playwright';
|
|
20
|
+
import { readFileSync } from 'node:fs';
|
|
21
|
+
|
|
22
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
23
|
+
const browser = await chromium.launch({ headless: true });
|
|
24
|
+
|
|
25
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
26
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
27
|
+
await ctx.addInitScript(() => {
|
|
28
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
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 mk = (alias, status) => ({
|
|
36
|
+
alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
37
|
+
network_id: nid, project_dir: null,
|
|
38
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
39
|
+
});
|
|
40
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
41
|
+
mk('alpha', 'working'), mk('beta', 'idle'), mk('gamma', 'working'),
|
|
42
|
+
] } });
|
|
43
|
+
});
|
|
44
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
45
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
46
|
+
|
|
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 === 3, { timeout: 30000 });
|
|
50
|
+
await page.waitForSelector('[data-legend-status="working"]', { timeout: 10000 });
|
|
51
|
+
await page.waitForTimeout(400);
|
|
52
|
+
|
|
53
|
+
const inspectAll = () => page.evaluate(() => {
|
|
54
|
+
const rows = [...document.querySelectorAll('[data-legend-status]')];
|
|
55
|
+
return rows.map(row => ({
|
|
56
|
+
key: row.getAttribute('data-legend-status'),
|
|
57
|
+
lifted: row.getAttribute('data-legend-row-lifted'),
|
|
58
|
+
pressed: row.getAttribute('aria-pressed'),
|
|
59
|
+
transform: row.getAttribute('style')?.match(/translateY\([^)]+\)/)?.[0],
|
|
60
|
+
}));
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const s1 = await inspectAll();
|
|
64
|
+
|
|
65
|
+
await page.locator('[data-legend-status="working"]').hover();
|
|
66
|
+
await page.waitForTimeout(250);
|
|
67
|
+
const s2 = await inspectAll();
|
|
68
|
+
const s2_working = s2.find(r => r.key === 'working');
|
|
69
|
+
const s2_idle = s2.find(r => r.key === 'idle');
|
|
70
|
+
|
|
71
|
+
await page.mouse.move(20, 20);
|
|
72
|
+
await page.waitForTimeout(250);
|
|
73
|
+
const s3 = await inspectAll();
|
|
74
|
+
const s3_working = s3.find(r => r.key === 'working');
|
|
75
|
+
|
|
76
|
+
await page.locator('[data-legend-status="idle"]').click();
|
|
77
|
+
await page.waitForTimeout(250);
|
|
78
|
+
await page.mouse.move(20, 20);
|
|
79
|
+
await page.waitForTimeout(250);
|
|
80
|
+
const s4 = await inspectAll();
|
|
81
|
+
const s4_idle = s4.find(r => r.key === 'idle');
|
|
82
|
+
const s4_working = s4.find(r => r.key === 'working');
|
|
83
|
+
|
|
84
|
+
await page.keyboard.press('Escape');
|
|
85
|
+
await page.waitForTimeout(250);
|
|
86
|
+
const s5 = await inspectAll();
|
|
87
|
+
const s5_idle = s5.find(r => r.key === 'idle');
|
|
88
|
+
|
|
89
|
+
await browser.close();
|
|
90
|
+
|
|
91
|
+
const liftStr = 'translateY(-1px)';
|
|
92
|
+
const results = {
|
|
93
|
+
s1_threeRows: s1.length === 3,
|
|
94
|
+
s1_allFlat: s1.every(r => r.lifted === 'false' && !r.transform),
|
|
95
|
+
|
|
96
|
+
s2_workingLifted: s2_working?.lifted === 'true' && s2_working?.transform === liftStr,
|
|
97
|
+
s2_idleStillFlat: s2_idle?.lifted === 'false' && !s2_idle?.transform,
|
|
98
|
+
|
|
99
|
+
s3_workingRestored: s3_working?.lifted === 'false' && !s3_working?.transform,
|
|
100
|
+
|
|
101
|
+
s4_idlePinned: s4_idle?.pressed === 'true' && s4_idle?.lifted === 'true' && s4_idle?.transform === liftStr,
|
|
102
|
+
s4_workingNotLifted: s4_working?.lifted === 'false' && !s4_working?.transform,
|
|
103
|
+
|
|
104
|
+
s5_idleCleared: s5_idle?.lifted === 'false' && !s5_idle?.transform && s5_idle?.pressed === 'false',
|
|
105
|
+
};
|
|
106
|
+
const ok = Object.values(results).every(Boolean);
|
|
107
|
+
console.log(`${ok ? '✅' : '❌'} legend-row hover lift:`, JSON.stringify(results),
|
|
108
|
+
`\n s1=`, s1, `\n s2=`, s2, `\n s3=`, s3, `\n s4=`, s4, `\n s5=`, s5);
|
|
109
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* Round 105 verification: legend rows in the SVG panel pick up a
|
|
2
|
+
* row-background tint on hover and pin, mirroring R104's treatment
|
|
3
|
+
* on the recent-signal panel. The tint uses the ROW'S OWN swatch
|
|
4
|
+
* colour (working=green, idle=teal, offline=slate) so the user's
|
|
5
|
+
* eye associates the highlight with its swatch instead of a generic
|
|
6
|
+
* accent.
|
|
7
|
+
*
|
|
8
|
+
* Verifies idle / hover / pinned states via the new data-legend-
|
|
9
|
+
* row-tinted attribute + actual fill/opacity. Pin is stronger than
|
|
10
|
+
* hover; idle is transparent.
|
|
11
|
+
*/
|
|
12
|
+
import { chromium } from 'playwright';
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
|
|
15
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
16
|
+
const browser = await chromium.launch({ headless: true });
|
|
17
|
+
|
|
18
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
19
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
20
|
+
await ctx.addInitScript(() => {
|
|
21
|
+
try {
|
|
22
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
23
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
24
|
+
sessionStorage.removeItem('anet-topo-pinned-status');
|
|
25
|
+
} 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, status) => ({
|
|
34
|
+
alias, status, 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: [
|
|
39
|
+
mk('wkr1', 'working'),
|
|
40
|
+
mk('idl1', 'idle'),
|
|
41
|
+
mk('off1', 'offline'),
|
|
42
|
+
] } });
|
|
43
|
+
});
|
|
44
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
45
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
46
|
+
const page = await ctx.newPage();
|
|
47
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
48
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
49
|
+
await page.waitForTimeout(400);
|
|
50
|
+
|
|
51
|
+
const readRow = (key) => page.evaluate((k) => {
|
|
52
|
+
const g = document.querySelector(`[data-legend-status="${k}"]`);
|
|
53
|
+
if (!g) return null;
|
|
54
|
+
const rect = g.querySelector('rect');
|
|
55
|
+
return {
|
|
56
|
+
tinted: rect?.getAttribute('data-legend-row-tinted') || '',
|
|
57
|
+
fill: rect?.getAttribute('fill') || '',
|
|
58
|
+
opacity: rect?.getAttribute('opacity') || '',
|
|
59
|
+
};
|
|
60
|
+
}, key);
|
|
61
|
+
|
|
62
|
+
const before = await Promise.all(['working', 'idle', 'offline'].map(readRow));
|
|
63
|
+
|
|
64
|
+
// Hover working.
|
|
65
|
+
await page.locator('[data-legend-status="working"]').hover();
|
|
66
|
+
await page.waitForTimeout(250);
|
|
67
|
+
const onHoverWorking = await Promise.all(['working', 'idle', 'offline'].map(readRow));
|
|
68
|
+
|
|
69
|
+
// Move away — clears hover.
|
|
70
|
+
await page.mouse.move(10, 10);
|
|
71
|
+
await page.waitForTimeout(250);
|
|
72
|
+
|
|
73
|
+
// Pin idle.
|
|
74
|
+
await page.locator('[data-legend-status="idle"]').click();
|
|
75
|
+
await page.waitForTimeout(250);
|
|
76
|
+
const onPinIdle = await Promise.all(['working', 'idle', 'offline'].map(readRow));
|
|
77
|
+
|
|
78
|
+
await browser.close();
|
|
79
|
+
|
|
80
|
+
const opacity = (s) => parseFloat(s) || 0;
|
|
81
|
+
const results = {
|
|
82
|
+
before_allTransparent: before.every(r => r?.tinted === 'none' && r?.fill === 'transparent'),
|
|
83
|
+
hoverWorking_workingTinted: onHoverWorking[0]?.tinted === 'hover' && onHoverWorking[0]?.fill !== 'transparent',
|
|
84
|
+
hoverWorking_othersUnchanged: onHoverWorking.slice(1).every(r => r?.tinted === 'none'),
|
|
85
|
+
hoverWorking_opacityLow: opacity(onHoverWorking[0]?.opacity || '') > 0 && opacity(onHoverWorking[0]?.opacity || '') < 0.2,
|
|
86
|
+
pinIdle_idlePinned: onPinIdle[1]?.tinted === 'pinned' && onPinIdle[1]?.fill !== 'transparent',
|
|
87
|
+
pinIdle_pinStrongerThanHover: opacity(onPinIdle[1]?.opacity || '') > opacity(onHoverWorking[0]?.opacity || ''),
|
|
88
|
+
pinIdle_otherRowsClean: onPinIdle.filter((_, i) => i !== 1).every(r => r?.tinted === 'none'),
|
|
89
|
+
};
|
|
90
|
+
const ok = Object.values(results).every(Boolean);
|
|
91
|
+
console.log(`${ok ? '✅' : '❌'} legend-row tint:`, JSON.stringify(results),
|
|
92
|
+
`\n before=`, before,
|
|
93
|
+
`\n onHoverWorking=`, onHoverWorking,
|
|
94
|
+
`\n onPinIdle=`, onPinIdle);
|
|
95
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* Round 149 verification: legend rows gain a <title> tooltip
|
|
2
|
+
* symmetric with R148's recent-signal row tooltip. Closes the
|
|
3
|
+
* R97 idiom on the panel side — anywhere the UI shows "N" should
|
|
4
|
+
* hover-explain WHICH N.
|
|
5
|
+
*
|
|
6
|
+
* Both side panels now have matching row-tooltip affordances:
|
|
7
|
+
* recent-signal row (R148): full from/to/timestamp/content + pin hint
|
|
8
|
+
* legend row (R149): status label + matched-aliases + pin hint
|
|
9
|
+
*
|
|
10
|
+
* Fleet: 3 working / 2 idle / 1 offline so all three bucket rows
|
|
11
|
+
* show non-zero. Verify each row's title contains:
|
|
12
|
+
* - status label + count
|
|
13
|
+
* - alias list of matching nodes
|
|
14
|
+
* - "click to pin" hint when not pinned
|
|
15
|
+
*
|
|
16
|
+
* Then click idle to pin → title flips to "click to release pin".
|
|
17
|
+
*/
|
|
18
|
+
import { chromium } from 'playwright';
|
|
19
|
+
import { readFileSync } from 'node:fs';
|
|
20
|
+
|
|
21
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
22
|
+
const browser = await chromium.launch({ headless: true });
|
|
23
|
+
|
|
24
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
25
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
26
|
+
await ctx.addInitScript(() => {
|
|
27
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } 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 mk = (alias, status) => ({
|
|
36
|
+
alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
37
|
+
network_id: nid, project_dir: null,
|
|
38
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
39
|
+
});
|
|
40
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
41
|
+
mk('worker-a', 'working'), mk('worker-b', 'working'), mk('worker-c', 'working'),
|
|
42
|
+
mk('idle-a', 'idle'), mk('idle-b', 'idle'),
|
|
43
|
+
mk('off-a', 'offline'),
|
|
44
|
+
] } });
|
|
45
|
+
});
|
|
46
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
47
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
48
|
+
|
|
49
|
+
const page = await ctx.newPage();
|
|
50
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
51
|
+
// 3 working + 2 idle + 1 offline = 6 sessions; offline nodes still
|
|
52
|
+
// render as g[data-node] (line ~2754 [...onlineNodes, ...offlineNodes]
|
|
53
|
+
// .map). Initial count check was off-by-one.
|
|
54
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 6, { timeout: 30000 });
|
|
55
|
+
await page.waitForSelector('[data-legend-status="working"]', { timeout: 10000 });
|
|
56
|
+
await page.waitForTimeout(400);
|
|
57
|
+
|
|
58
|
+
const readTitle = (key) => page.evaluate((k) => {
|
|
59
|
+
const row = document.querySelector(`[data-legend-status="${k}"]`);
|
|
60
|
+
return row?.querySelector('title')?.textContent || '';
|
|
61
|
+
}, key);
|
|
62
|
+
|
|
63
|
+
const wTitle = await readTitle('working');
|
|
64
|
+
const iTitle = await readTitle('idle');
|
|
65
|
+
const oTitle = await readTitle('offline');
|
|
66
|
+
|
|
67
|
+
// Pin idle → its title flips
|
|
68
|
+
await page.locator('[data-legend-status="idle"]').click();
|
|
69
|
+
await page.waitForTimeout(200);
|
|
70
|
+
const iPinnedTitle = await readTitle('idle');
|
|
71
|
+
|
|
72
|
+
await browser.close();
|
|
73
|
+
|
|
74
|
+
const results = {
|
|
75
|
+
// Working row: 3 working aliases
|
|
76
|
+
w_hasLabel: wTitle.includes('working node · 3'),
|
|
77
|
+
w_hasWorkerA: wTitle.includes('worker-a'),
|
|
78
|
+
w_hasWorkerB: wTitle.includes('worker-b'),
|
|
79
|
+
w_hasWorkerC: wTitle.includes('worker-c'),
|
|
80
|
+
w_pinHint: wTitle.includes('click to pin'),
|
|
81
|
+
|
|
82
|
+
// Idle row: 2 idle aliases
|
|
83
|
+
i_hasLabel: iTitle.includes('online idle · 2'),
|
|
84
|
+
i_hasIdleA: iTitle.includes('idle-a'),
|
|
85
|
+
i_hasIdleB: iTitle.includes('idle-b'),
|
|
86
|
+
i_pinHint: iTitle.includes('click to pin'),
|
|
87
|
+
|
|
88
|
+
// Offline row: 1 offline alias
|
|
89
|
+
o_hasLabel: oTitle.includes('offline / no SSE · 1'),
|
|
90
|
+
o_hasOffA: oTitle.includes('off-a'),
|
|
91
|
+
|
|
92
|
+
// After pin: title hint flipped
|
|
93
|
+
iPinned_releaseHint: iPinnedTitle.includes('click to release pin'),
|
|
94
|
+
iPinned_noPinHint: !iPinnedTitle.includes('click to pin · hover to preview'),
|
|
95
|
+
};
|
|
96
|
+
const ok = Object.values(results).every(Boolean);
|
|
97
|
+
console.log(`${ok ? '✅' : '❌'} legend-row title:`, JSON.stringify(results),
|
|
98
|
+
`\n workingTitle:\n${wTitle}`,
|
|
99
|
+
`\n idleTitle:\n${iTitle}`,
|
|
100
|
+
`\n offlineTitle:\n${oTitle}`,
|
|
101
|
+
`\n idlePinnedTitle:\n${iPinnedTitle}`);
|
|
102
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/* Round 197 verification: legend swatch dot scales r 5.5 → 7 when
|
|
2
|
+
* its row is hovered or pinned. Mirrors R177 hub hover-lift but at
|
|
3
|
+
* legend grain.
|
|
4
|
+
*
|
|
5
|
+
* Pre-R197 the swatch was a flat constant r=5.5 — every other piece
|
|
6
|
+
* of the row responded to hover/pin (R55 text brighten, R105 bg
|
|
7
|
+
* tint, R144 1px row lift, R181 pin ring) but the swatch dot
|
|
8
|
+
* itself stayed still. The dot is the row's visual-identity
|
|
9
|
+
* anchor; making it grow gives the gesture full row-wide reach.
|
|
10
|
+
*
|
|
11
|
+
* Test (cyber/dark theme, 4 working sessions):
|
|
12
|
+
* 1. Three swatches present: working / idle / offline.
|
|
13
|
+
* 2. Idle: data-legend-swatch-state='idle', r ~ 5.5.
|
|
14
|
+
* 3. Hover the "working" legend row, wait past 150ms transition.
|
|
15
|
+
* 4. Working swatch: state='hover', r ~ 7.
|
|
16
|
+
* 5. Other swatches (idle/offline) stay 'idle' + r ~ 5.5.
|
|
17
|
+
* 6. Move away, wait — working swatch back to 'idle' + r 5.5.
|
|
18
|
+
* 7. transition: r 150ms ease-out is in the inline style.
|
|
19
|
+
*/
|
|
20
|
+
import { chromium } from 'playwright';
|
|
21
|
+
import { readFileSync } from 'node:fs';
|
|
22
|
+
|
|
23
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
24
|
+
const browser = await chromium.launch({ headless: true });
|
|
25
|
+
|
|
26
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
27
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
28
|
+
await ctx.addInitScript(() => {
|
|
29
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
33
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
34
|
+
const r = await route.fetch();
|
|
35
|
+
const b = await r.json();
|
|
36
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
37
|
+
const mk = (alias, status = 'working') => ({
|
|
38
|
+
alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
39
|
+
network_id: nid, project_dir: null,
|
|
40
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
41
|
+
});
|
|
42
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
43
|
+
mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
44
|
+
] } });
|
|
45
|
+
});
|
|
46
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
47
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
48
|
+
|
|
49
|
+
const page = await ctx.newPage();
|
|
50
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
51
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
52
|
+
await page.waitForSelector('[data-legend-swatch]', { timeout: 10000 });
|
|
53
|
+
await page.waitForTimeout(300);
|
|
54
|
+
|
|
55
|
+
const probe = async () => page.evaluate(() => {
|
|
56
|
+
return [...document.querySelectorAll('[data-legend-swatch]')].map(el => ({
|
|
57
|
+
key: el.getAttribute('data-legend-swatch'),
|
|
58
|
+
state: el.getAttribute('data-legend-swatch-state'),
|
|
59
|
+
// Read both computed CSS r (the transitionable property) and the
|
|
60
|
+
// SVG attribute fallback. Chrome computes the CSS r as the live
|
|
61
|
+
// value, including mid-transition interpolated values.
|
|
62
|
+
cssR: parseFloat(getComputedStyle(el).r),
|
|
63
|
+
attrR: parseFloat(el.getAttribute('r') || ''),
|
|
64
|
+
transition: el.style.transition,
|
|
65
|
+
}));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const idle = await probe();
|
|
69
|
+
|
|
70
|
+
await page.hover('[data-legend-status="working"]');
|
|
71
|
+
await page.waitForTimeout(220); // past 150ms r transition + margin
|
|
72
|
+
const hovered = await probe();
|
|
73
|
+
|
|
74
|
+
await page.mouse.move(0, 0);
|
|
75
|
+
await page.waitForTimeout(220);
|
|
76
|
+
const settled = await probe();
|
|
77
|
+
|
|
78
|
+
await browser.close();
|
|
79
|
+
|
|
80
|
+
const idleWorking = idle.find(s => s.key === 'working');
|
|
81
|
+
const idleIdle = idle.find(s => s.key === 'idle');
|
|
82
|
+
const idleOffline = idle.find(s => s.key === 'offline');
|
|
83
|
+
|
|
84
|
+
const hovWorking = hovered.find(s => s.key === 'working');
|
|
85
|
+
const hovIdle = hovered.find(s => s.key === 'idle');
|
|
86
|
+
const hovOffline = hovered.find(s => s.key === 'offline');
|
|
87
|
+
|
|
88
|
+
const settledWorking = settled.find(s => s.key === 'working');
|
|
89
|
+
|
|
90
|
+
const results = {
|
|
91
|
+
three_swatches: idle.length === 3,
|
|
92
|
+
has_working_swatch: !!idleWorking,
|
|
93
|
+
has_idle_swatch: !!idleIdle,
|
|
94
|
+
has_offline_swatch: !!idleOffline,
|
|
95
|
+
|
|
96
|
+
idle_working_state_idle: idleWorking?.state === 'idle',
|
|
97
|
+
idle_working_r_small: Math.abs((idleWorking?.cssR ?? idleWorking?.attrR ?? 0) - 5.5) < 0.4,
|
|
98
|
+
transition_includes_r: (idleWorking?.transition || '').includes('r') &&
|
|
99
|
+
(idleWorking?.transition || '').includes('150ms'),
|
|
100
|
+
|
|
101
|
+
hov_working_state_hover: hovWorking?.state === 'hover',
|
|
102
|
+
hov_working_r_bigger: (hovWorking?.cssR ?? hovWorking?.attrR ?? 0) > 6.5,
|
|
103
|
+
hov_working_r_about_7: Math.abs((hovWorking?.cssR ?? hovWorking?.attrR ?? 0) - 7) < 0.4,
|
|
104
|
+
hov_idle_stays_idle: hovIdle?.state === 'idle',
|
|
105
|
+
hov_idle_r_unchanged: Math.abs((hovIdle?.cssR ?? hovIdle?.attrR ?? 0) - 5.5) < 0.4,
|
|
106
|
+
hov_offline_stays_idle: hovOffline?.state === 'idle',
|
|
107
|
+
|
|
108
|
+
settled_state_idle: settledWorking?.state === 'idle',
|
|
109
|
+
settled_r_back_small: Math.abs((settledWorking?.cssR ?? settledWorking?.attrR ?? 0) - 5.5) < 0.4,
|
|
110
|
+
};
|
|
111
|
+
const ok = Object.values(results).every(Boolean);
|
|
112
|
+
console.log(`${ok ? '✅' : '❌'} legend swatch grow:`, JSON.stringify(results),
|
|
113
|
+
`\n idle:`, idle,
|
|
114
|
+
`\n hovered:`, hovered,
|
|
115
|
+
`\n settled:`, settled);
|
|
116
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* Round 157 verification: minimap a11y completion.
|
|
2
|
+
*
|
|
3
|
+
* Pre-R157 the R30 minimap had role="img" (wrong — it's clickable)
|
|
4
|
+
* + aria-label but no tabIndex / onKeyDown. Mouse users could
|
|
5
|
+
* click to recenter; keyboard-only users couldn't reach or
|
|
6
|
+
* activate it.
|
|
7
|
+
*
|
|
8
|
+
* R157 closes the gap with the standard pattern (R116/R139/R140/
|
|
9
|
+
* R151/R152):
|
|
10
|
+
* role="button"
|
|
11
|
+
* tabIndex={0}
|
|
12
|
+
* aria-label="Topology minimap — click to recenter, Enter to reset view"
|
|
13
|
+
* onKeyDown(Enter/Space) → resetView()
|
|
14
|
+
* anet-topo-chip-focus className (R155 cyan outline)
|
|
15
|
+
*
|
|
16
|
+
* Test:
|
|
17
|
+
* 1. Force the canvas off-default via zoom (so minimap renders)
|
|
18
|
+
* 2. Verify role / tabIndex / aria-label / class on the minimap
|
|
19
|
+
* 3. Press Enter on focused minimap → view resets (zoom back to 100%)
|
|
20
|
+
*/
|
|
21
|
+
import { chromium } from 'playwright';
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
|
|
24
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
25
|
+
const browser = await chromium.launch({ headless: true });
|
|
26
|
+
|
|
27
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
28
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
29
|
+
await ctx.addInitScript(() => {
|
|
30
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
31
|
+
});
|
|
32
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
33
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
34
|
+
const r = await route.fetch();
|
|
35
|
+
const b = await r.json();
|
|
36
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
37
|
+
const mk = (alias) => ({
|
|
38
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
39
|
+
network_id: nid, project_dir: null,
|
|
40
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
41
|
+
});
|
|
42
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta')] } });
|
|
43
|
+
});
|
|
44
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
45
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
46
|
+
|
|
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 === 2, { timeout: 30000 });
|
|
50
|
+
await page.waitForTimeout(400);
|
|
51
|
+
|
|
52
|
+
// Initial: zoom is 100%, minimap not rendered (gated to non-default view)
|
|
53
|
+
const minimapBefore = await page.locator('[data-topo-minimap]').count();
|
|
54
|
+
|
|
55
|
+
// Press + (zoom in) twice to render the minimap
|
|
56
|
+
await page.keyboard.press('+');
|
|
57
|
+
await page.keyboard.press('+');
|
|
58
|
+
await page.waitForTimeout(250);
|
|
59
|
+
|
|
60
|
+
const probe = await page.evaluate(() => {
|
|
61
|
+
const el = document.querySelector('[data-topo-minimap]');
|
|
62
|
+
if (!el) return null;
|
|
63
|
+
return {
|
|
64
|
+
role: el.getAttribute('role'),
|
|
65
|
+
tabIndex: el.getAttribute('tabindex'),
|
|
66
|
+
ariaLabel: el.getAttribute('aria-label'),
|
|
67
|
+
title: el.getAttribute('title'),
|
|
68
|
+
className: el.getAttribute('class') || '',
|
|
69
|
+
zoomLevel: document.querySelector('[data-topo-chrome-zoom-level]')?.textContent?.trim(),
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Focus minimap + Enter → reset view (zoom back to 100%)
|
|
74
|
+
await page.locator('[data-topo-minimap]').focus();
|
|
75
|
+
await page.keyboard.press('Enter');
|
|
76
|
+
await page.waitForTimeout(250);
|
|
77
|
+
const afterEnter = await page.evaluate(() => ({
|
|
78
|
+
zoomLevel: document.querySelector('[data-topo-chrome-zoom-level]')?.textContent?.trim(),
|
|
79
|
+
minimapHidden: !document.querySelector('[data-topo-minimap]'),
|
|
80
|
+
}));
|
|
81
|
+
|
|
82
|
+
await browser.close();
|
|
83
|
+
|
|
84
|
+
const results = {
|
|
85
|
+
minimap_hiddenAtDefault: minimapBefore === 0,
|
|
86
|
+
minimap_renderedAfterZoom: probe !== null,
|
|
87
|
+
role_button: probe?.role === 'button',
|
|
88
|
+
tabIndex_0: probe?.tabIndex === '0',
|
|
89
|
+
ariaLabel_mentionsEnter: (probe?.ariaLabel || '').includes('Enter'),
|
|
90
|
+
title_mentionsEnter: (probe?.title || '').includes('Enter'),
|
|
91
|
+
hasFocusClass: (probe?.className || '').includes('anet-topo-chip-focus'),
|
|
92
|
+
zoomedBeforeReset: probe?.zoomLevel !== '100%',
|
|
93
|
+
enter_resetsZoom: afterEnter.zoomLevel === '100%',
|
|
94
|
+
enter_hidesMinimap: afterEnter.minimapHidden === true,
|
|
95
|
+
};
|
|
96
|
+
const ok = Object.values(results).every(Boolean);
|
|
97
|
+
console.log(`${ok ? '✅' : '❌'} minimap a11y:`, JSON.stringify(results),
|
|
98
|
+
`\n before count=${minimapBefore}`,
|
|
99
|
+
`\n probe=`, probe,
|
|
100
|
+
`\n afterEnter=`, afterEnter);
|
|
101
|
+
process.exit(ok ? 0 : 1);
|