@sleep2agi/agent-network-dashboard 0.4.6-preview.20 → 0.4.6-preview.201
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/01b6zl3rabau1.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/0fzk-axksemic.css +2 -0
- package/.next/static/chunks/0ggj5ummw2a84.js +7 -0
- package/.next/static/chunks/0glmrdj9112tc.js +7 -0
- package/.next/static/chunks/0n7ow3nu-_bsk.js +4 -0
- package/.next/static/chunks/0rxrez_cjn.eh.js +1 -0
- package/.next/static/chunks/0x8x.29hkju5a.js +1 -0
- package/.next/static/chunks/0zx.24yobat5o.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 +3984 -264
- 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-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-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-minimap-a11y-test.mjs +101 -0
- package/scripts/topo-minimap-test.mjs +68 -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-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-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-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-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/02t5jr4shh.hy.js +0 -1
- package/.next/static/chunks/076u9wjiilxzg.js +0 -1
- package/.next/static/chunks/07hlou5cndq1b.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/0lw~4lr23sl-r.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/{kZOwEPGbIfBUUE4MFGvHz → IZ83xXmRRznWkvPwyxx-z}/_buildManifest.js +0 -0
- /package/.next/static/{kZOwEPGbIfBUUE4MFGvHz → IZ83xXmRRznWkvPwyxx-z}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{kZOwEPGbIfBUUE4MFGvHz → IZ83xXmRRznWkvPwyxx-z}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/* Round 131 verification: outer-ring orbit period buckets on
|
|
2
|
+
* workingCount, mirroring R84's hub-breath cadence. Idle fleet
|
|
3
|
+
* keeps the original 16s "calm sweep"; as work piles up the
|
|
4
|
+
* orbit accelerates to 14 / 12 / 10s. Both motion layers now
|
|
5
|
+
* read the same underlying "is the network busy" signal.
|
|
6
|
+
*
|
|
7
|
+
* Bucket boundaries identical to R84 (line ~2702):
|
|
8
|
+
* workingCount === 0 → bucket 0, dur 16s
|
|
9
|
+
* workingCount in [1, 2] → bucket 1, dur 14s
|
|
10
|
+
* workingCount in [3, 5] → bucket 2, dur 12s
|
|
11
|
+
* workingCount >= 6 → bucket 3, dur 10s
|
|
12
|
+
*
|
|
13
|
+
* R50 only renders on cyber theme (light is skipped to keep the
|
|
14
|
+
* white surface clean). All probes use cyber.
|
|
15
|
+
*
|
|
16
|
+
* Probe fleet sizes pick one representative per bucket.
|
|
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
|
+
|
|
23
|
+
async function probe(workingCount, totalCount) {
|
|
24
|
+
const browser = await chromium.launch({ headless: true });
|
|
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 sessions = [];
|
|
36
|
+
for (let i = 0; i < totalCount; i++) {
|
|
37
|
+
sessions.push({
|
|
38
|
+
alias: `node${i}`,
|
|
39
|
+
status: i < workingCount ? 'working' : 'idle',
|
|
40
|
+
model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
41
|
+
network_id: nid, project_dir: null,
|
|
42
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
46
|
+
});
|
|
47
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
48
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
49
|
+
|
|
50
|
+
const page = await ctx.newPage();
|
|
51
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
52
|
+
await page.waitForFunction((n) => document.querySelectorAll('g[data-node]').length === n, totalCount, { timeout: 30000 });
|
|
53
|
+
await page.waitForTimeout(400);
|
|
54
|
+
|
|
55
|
+
const out = await page.evaluate(() => {
|
|
56
|
+
const orbits = [...document.querySelectorAll('[data-topo-orbit-bucket]')];
|
|
57
|
+
return orbits.map(g => ({
|
|
58
|
+
bucket: g.getAttribute('data-topo-orbit-bucket'),
|
|
59
|
+
dur: g.getAttribute('data-topo-orbit-dur'),
|
|
60
|
+
animDur: g.querySelector('animateTransform')?.getAttribute('dur'),
|
|
61
|
+
}));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
await browser.close();
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Pick one from each bucket
|
|
69
|
+
const b0 = await probe(0, 4); // workingCount=0 → bucket 0, dur 16
|
|
70
|
+
const b1 = await probe(2, 4); // workingCount=2 → bucket 1, dur 14
|
|
71
|
+
const b2 = await probe(4, 5); // workingCount=4 → bucket 2, dur 12
|
|
72
|
+
const b3 = await probe(7, 8); // workingCount=7 → bucket 3, dur 10
|
|
73
|
+
|
|
74
|
+
const allConsistent = (orbits, bucket, dur) =>
|
|
75
|
+
orbits.length === 4 &&
|
|
76
|
+
orbits.every(o => o.bucket === String(bucket) && o.dur === String(dur) && o.animDur === `${dur}s`);
|
|
77
|
+
|
|
78
|
+
const results = {
|
|
79
|
+
b0_fourOrbits: b0.length === 4,
|
|
80
|
+
b0_bucket0_16s: allConsistent(b0, 0, 16),
|
|
81
|
+
b1_bucket1_14s: allConsistent(b1, 1, 14),
|
|
82
|
+
b2_bucket2_12s: allConsistent(b2, 2, 12),
|
|
83
|
+
b3_bucket3_10s: allConsistent(b3, 3, 10),
|
|
84
|
+
// dur strictly decreases as busy increases
|
|
85
|
+
dur_monotonic:
|
|
86
|
+
Number(b0[0]?.dur) > Number(b1[0]?.dur) &&
|
|
87
|
+
Number(b1[0]?.dur) > Number(b2[0]?.dur) &&
|
|
88
|
+
Number(b2[0]?.dur) > Number(b3[0]?.dur),
|
|
89
|
+
};
|
|
90
|
+
const ok = Object.values(results).every(Boolean);
|
|
91
|
+
console.log(`${ok ? '✅' : '❌'} orbit busyness:`, JSON.stringify(results),
|
|
92
|
+
`\n b0(0w/4)=`, b0,
|
|
93
|
+
`\n b1(2w/4)=`, b1,
|
|
94
|
+
`\n b2(4w/5)=`, b2,
|
|
95
|
+
`\n b3(7w/8)=`, b3);
|
|
96
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
* - node ↔ node — status rings don't intersect
|
|
4
4
|
* - node ↔ panel — no node circle intersects an overlay panel rect
|
|
5
5
|
* - node ↔ group-label — no group-box label text covers a node
|
|
6
|
-
* - group-box ↔ box — no two group boxes overlap
|
|
6
|
+
* - group-box ↔ box — no two group boxes overlap
|
|
7
|
+
* - label ↔ label — no two text labels overlap (Round 27 — caught
|
|
8
|
+
* the dense-node-label vs group-label collision
|
|
9
|
+
* Vincent reported in preview.29) */
|
|
7
10
|
import { chromium } from 'playwright';
|
|
8
11
|
import { readFileSync, mkdirSync } from 'node:fs';
|
|
9
12
|
|
|
@@ -80,11 +83,24 @@ async function check(layout) {
|
|
|
80
83
|
label: { x: bb.x, y: bb.y, w: bb.width, h: bb.height },
|
|
81
84
|
};
|
|
82
85
|
});
|
|
83
|
-
|
|
86
|
+
// Round 27 / P0: every visible label bbox (node alias text + group
|
|
87
|
+
// headings) so we can assert label↔label clearance. Skip elements
|
|
88
|
+
// with empty bboxes (e.g., text inside an unrendered <g>).
|
|
89
|
+
const allLabels = [];
|
|
90
|
+
for (const t of svg.querySelectorAll('g[data-node] text, g[data-group] text')) {
|
|
91
|
+
const bb = t.getBBox();
|
|
92
|
+
if (bb.width === 0 || bb.height === 0) continue;
|
|
93
|
+
allLabels.push({
|
|
94
|
+
kind: t.closest('g[data-group]') ? 'group' : 'node',
|
|
95
|
+
owner: (t.closest('g[data-group]')?.getAttribute('data-group')) || (t.closest('g[data-node]')?.getAttribute('data-node')) || '?',
|
|
96
|
+
x: bb.x, y: bb.y, w: bb.width, h: bb.height,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return { nodes, panels, groups, allLabels };
|
|
84
100
|
});
|
|
85
101
|
|
|
86
102
|
const TOL = 2; // px slack — touching edges is fine, real overlap is not
|
|
87
|
-
let nodeNode = 0, nodePanel = 0, nodeLabel = 0, boxBox = 0;
|
|
103
|
+
let nodeNode = 0, nodePanel = 0, nodeLabel = 0, boxBox = 0, labelLabel = 0;
|
|
88
104
|
|
|
89
105
|
// node ↔ node
|
|
90
106
|
for (let i = 0; i < data.nodes.length; i++) {
|
|
@@ -119,12 +135,23 @@ async function check(layout) {
|
|
|
119
135
|
overlaps1D(a.y, a.y + a.h, b.y, b.y + b.h, TOL)) boxBox++;
|
|
120
136
|
}
|
|
121
137
|
}
|
|
138
|
+
// label ↔ label (Round 27)
|
|
139
|
+
// Same-node node-labels (e.g. alias + sub-status in the full card) are
|
|
140
|
+
// intentionally close and adjacent — skip pairs that share an owner.
|
|
141
|
+
for (let i = 0; i < data.allLabels.length; i++) {
|
|
142
|
+
for (let j = i + 1; j < data.allLabels.length; j++) {
|
|
143
|
+
const a = data.allLabels[i], b = data.allLabels[j];
|
|
144
|
+
if (a.owner === b.owner) continue;
|
|
145
|
+
if (overlaps1D(a.x, a.x + a.w, b.x, b.x + b.w, TOL) &&
|
|
146
|
+
overlaps1D(a.y, a.y + a.h, b.y, b.y + b.h, TOL)) labelLabel++;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
122
149
|
|
|
123
150
|
await page.screenshot({ path: `/tmp/anet-issue-112/overlap-${layout}.png` });
|
|
124
151
|
await ctx.close();
|
|
125
|
-
const ok = nodeNode === 0 && nodePanel === 0 && nodeLabel === 0 && boxBox === 0;
|
|
152
|
+
const ok = nodeNode === 0 && nodePanel === 0 && nodeLabel === 0 && boxBox === 0 && labelLabel === 0;
|
|
126
153
|
console.log(`${ok ? '✅' : '❌'} [${layout}] nodes=${data.nodes.length} groups=${data.groups.length} — ` +
|
|
127
|
-
`node↔node:${nodeNode} node↔panel:${nodePanel} node↔label:${nodeLabel} box↔box:${boxBox}`);
|
|
154
|
+
`node↔node:${nodeNode} node↔panel:${nodePanel} node↔label:${nodeLabel} box↔box:${boxBox} label↔label:${labelLabel}`);
|
|
128
155
|
return ok;
|
|
129
156
|
}
|
|
130
157
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/* Round 21 verification: SVG cursor flips from grab → grabbing during
|
|
2
|
+
* a pan drag and back to grab on release. */
|
|
3
|
+
import { chromium } from 'playwright';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
7
|
+
const browser = await chromium.launch({ headless: true });
|
|
8
|
+
// Need a tall enough viewport to keep the SVG ABOVE the fold so real
|
|
9
|
+
// pointer events land — at 1280×900 the canvas starts at ~y=815 (the
|
|
10
|
+
// /admin hero + StatsBar above push it below the viewport bottom).
|
|
11
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 1600 } });
|
|
12
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
13
|
+
await ctx.addInitScript(() => {
|
|
14
|
+
try {
|
|
15
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
16
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
17
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
18
|
+
} catch {}
|
|
19
|
+
});
|
|
20
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
21
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
22
|
+
const r = await route.fetch();
|
|
23
|
+
const b = await r.json();
|
|
24
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
25
|
+
const sessions = ['a', 'b'].map(a => ({
|
|
26
|
+
alias: a, status: 'idle', network_id: nid, project_dir: null,
|
|
27
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
28
|
+
}));
|
|
29
|
+
await route.fulfill({ response: r, json: { ...b, sessions } });
|
|
30
|
+
});
|
|
31
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
32
|
+
const page = await ctx.newPage();
|
|
33
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
34
|
+
await page.waitForSelector('svg[viewBox="0 0 1000 680"]', { timeout: 30000 });
|
|
35
|
+
await page.waitForTimeout(400);
|
|
36
|
+
|
|
37
|
+
const cursorAt = () => page.$eval('svg[viewBox="0 0 1000 680"]', el => el.style.cursor);
|
|
38
|
+
const rest = await cursorAt();
|
|
39
|
+
|
|
40
|
+
// pick a pan-safe target far from any node — top-left empty canvas region
|
|
41
|
+
const box = await page.$eval('svg[viewBox="0 0 1000 680"]', el => el.getBoundingClientRect());
|
|
42
|
+
const sx = box.x + box.width * 0.08;
|
|
43
|
+
const sy = box.y + box.height * 0.40;
|
|
44
|
+
|
|
45
|
+
await page.mouse.move(sx, sy);
|
|
46
|
+
await page.mouse.down();
|
|
47
|
+
await page.mouse.move(sx + 40, sy + 30);
|
|
48
|
+
await page.waitForTimeout(50);
|
|
49
|
+
const during = await cursorAt();
|
|
50
|
+
await page.mouse.up();
|
|
51
|
+
await page.waitForTimeout(50);
|
|
52
|
+
const after = await cursorAt();
|
|
53
|
+
|
|
54
|
+
await browser.close();
|
|
55
|
+
const results = {
|
|
56
|
+
restIsGrab: rest === 'grab',
|
|
57
|
+
duringIsGrabbing: during === 'grabbing',
|
|
58
|
+
afterIsGrab: after === 'grab',
|
|
59
|
+
};
|
|
60
|
+
const ok = Object.values(results).every(Boolean);
|
|
61
|
+
console.log(`${ok ? '✅' : '❌'} pan cursor:`, JSON.stringify(results), `rest=${rest} during=${during} after=${after}`);
|
|
62
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* Round 57 verification: recent-signal + legend panels carry a drop-
|
|
2
|
+
* shadow filter so they read as floating cards instead of pasted-on
|
|
3
|
+
* graphics — especially important on light theme where panel fill is
|
|
4
|
+
* near-white on a near-white canvas.
|
|
5
|
+
*
|
|
6
|
+
* - Both panels render a <rect> with `data-topo-panel-elevation`.
|
|
7
|
+
* - The rect's `style.filter` contains "drop-shadow(".
|
|
8
|
+
* - Light vs cyber themes use different shadow alpha (light tuned for
|
|
9
|
+
* contrast against white canvas; cyber for subtle depth on dark).
|
|
10
|
+
* Verify the strings differ so the theme switch isn't a no-op.
|
|
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
|
+
async function probe(theme) {
|
|
19
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 1500 } });
|
|
20
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
21
|
+
await ctx.addInitScript((t) => {
|
|
22
|
+
try {
|
|
23
|
+
localStorage.setItem('anet-theme', t);
|
|
24
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
25
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
26
|
+
} catch {}
|
|
27
|
+
}, theme);
|
|
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 = ['alpha', 'beta'].map(a => ({
|
|
34
|
+
alias: a, 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/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
40
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
41
|
+
const page = await ctx.newPage();
|
|
42
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
43
|
+
await page.waitForSelector('rect[data-topo-panel-elevation="recent"]', { timeout: 30000 });
|
|
44
|
+
await page.waitForTimeout(400);
|
|
45
|
+
const filters = await page.evaluate(() => {
|
|
46
|
+
const recent = document.querySelector('rect[data-topo-panel-elevation="recent"]');
|
|
47
|
+
const legend = document.querySelector('rect[data-topo-panel-elevation="legend"]');
|
|
48
|
+
return {
|
|
49
|
+
recent: recent?.getAttribute('style') || '',
|
|
50
|
+
legend: legend?.getAttribute('style') || '',
|
|
51
|
+
recentComputed: recent ? getComputedStyle(recent).filter : null,
|
|
52
|
+
legendComputed: legend ? getComputedStyle(legend).filter : null,
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
await ctx.close();
|
|
56
|
+
return filters;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const light = await probe('light');
|
|
60
|
+
const cyber = await probe('cyber');
|
|
61
|
+
await browser.close();
|
|
62
|
+
|
|
63
|
+
const hasShadow = (s) => /drop-shadow\(/.test(s || '');
|
|
64
|
+
const results = {
|
|
65
|
+
light_recent_hasShadow: hasShadow(light.recent),
|
|
66
|
+
light_legend_hasShadow: hasShadow(light.legend),
|
|
67
|
+
cyber_recent_hasShadow: hasShadow(cyber.recent),
|
|
68
|
+
cyber_legend_hasShadow: hasShadow(cyber.legend),
|
|
69
|
+
themes_differ: light.recent !== cyber.recent,
|
|
70
|
+
computed_resolves: hasShadow(light.recentComputed) && hasShadow(cyber.recentComputed),
|
|
71
|
+
};
|
|
72
|
+
const ok = Object.values(results).every(Boolean);
|
|
73
|
+
console.log(`${ok ? '✅' : '❌'} panel elevation:`, JSON.stringify(results),
|
|
74
|
+
`\n light.recent=${JSON.stringify(light.recent)}`,
|
|
75
|
+
`\n cyber.recent=${JSON.stringify(cyber.recent)}`);
|
|
76
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* Round 175 verification: corner panels fade-in after the
|
|
2
|
+
* canvas content reveal.
|
|
3
|
+
*
|
|
4
|
+
* Pre-R175 the recent-signal (top-left) + legend (top-right)
|
|
5
|
+
* panels appeared instantly while nodes/edges/group boxes/tier
|
|
6
|
+
* rings staggered in around them. The panels felt like 'already
|
|
7
|
+
* there' before the content showed up.
|
|
8
|
+
*
|
|
9
|
+
* R175 adds .anet-fade-in + 700ms / 800ms animation-delay on
|
|
10
|
+
* the two panel <g> wrappers — fifth surface in the first-paint
|
|
11
|
+
* reveal family (after R9 nodes / R172 edges / R173 group boxes
|
|
12
|
+
* / R174 tier rings).
|
|
13
|
+
*
|
|
14
|
+
* Test:
|
|
15
|
+
* 1. Mock 3 sessions in ring layout
|
|
16
|
+
* 2. Probe [data-topo-panel="recent"] and [="legend"]
|
|
17
|
+
* 3. Both have .anet-fade-in className
|
|
18
|
+
* 4. recent panel animationDelay = 700ms
|
|
19
|
+
* 5. legend panel animationDelay = 800ms
|
|
20
|
+
* 6. data-topo-panel-fade-delay attributes match
|
|
21
|
+
*/
|
|
22
|
+
import { chromium } from 'playwright';
|
|
23
|
+
import { readFileSync } from 'node:fs';
|
|
24
|
+
|
|
25
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
26
|
+
const browser = await chromium.launch({ headless: true });
|
|
27
|
+
|
|
28
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1500 } });
|
|
29
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
30
|
+
await ctx.addInitScript(() => {
|
|
31
|
+
try {
|
|
32
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
33
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
34
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
35
|
+
} catch {}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
39
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
40
|
+
const r = await route.fetch();
|
|
41
|
+
const b = await r.json();
|
|
42
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
43
|
+
const mk = (alias) => ({
|
|
44
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
45
|
+
network_id: nid, project_dir: null,
|
|
46
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
47
|
+
});
|
|
48
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [mk('alpha'), mk('beta'), mk('gamma')] } });
|
|
49
|
+
});
|
|
50
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
51
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
52
|
+
|
|
53
|
+
const page = await ctx.newPage();
|
|
54
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
55
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
56
|
+
await page.waitForSelector('[data-topo-panel="recent"]', { timeout: 10000 });
|
|
57
|
+
await page.waitForSelector('[data-topo-panel="legend"]', { timeout: 10000 });
|
|
58
|
+
await page.waitForTimeout(400);
|
|
59
|
+
|
|
60
|
+
const probe = await page.evaluate(() => {
|
|
61
|
+
const grab = (sel) => {
|
|
62
|
+
const el = document.querySelector(sel);
|
|
63
|
+
if (!el) return null;
|
|
64
|
+
return {
|
|
65
|
+
hasFadeClass: (el.getAttribute('class') || '').includes('anet-fade-in'),
|
|
66
|
+
fadeDelayAttr: parseFloat(el.getAttribute('data-topo-panel-fade-delay') || ''),
|
|
67
|
+
animationDelay: el.style.animationDelay || getComputedStyle(el).animationDelay,
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
71
|
+
recent: grab('[data-topo-panel="recent"]'),
|
|
72
|
+
legend: grab('[data-topo-panel="legend"]'),
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await browser.close();
|
|
77
|
+
|
|
78
|
+
const parseDelay = (s) => {
|
|
79
|
+
if (!s) return null;
|
|
80
|
+
if (s.endsWith('ms')) return parseFloat(s);
|
|
81
|
+
if (s.endsWith('s')) return parseFloat(s) * 1000;
|
|
82
|
+
return parseFloat(s);
|
|
83
|
+
};
|
|
84
|
+
const recentDelay = parseDelay(probe.recent?.animationDelay);
|
|
85
|
+
const legendDelay = parseDelay(probe.legend?.animationDelay);
|
|
86
|
+
|
|
87
|
+
const results = {
|
|
88
|
+
recent_panel_found: probe.recent !== null,
|
|
89
|
+
legend_panel_found: probe.legend !== null,
|
|
90
|
+
recent_has_fade_class: probe.recent?.hasFadeClass === true,
|
|
91
|
+
legend_has_fade_class: probe.legend?.hasFadeClass === true,
|
|
92
|
+
recent_delay_attr_700: probe.recent?.fadeDelayAttr === 700,
|
|
93
|
+
legend_delay_attr_800: probe.legend?.fadeDelayAttr === 800,
|
|
94
|
+
recent_anim_delay_700ms: recentDelay === 700,
|
|
95
|
+
legend_anim_delay_800ms: legendDelay === 800,
|
|
96
|
+
legend_lags_recent_100ms: legendDelay - recentDelay === 100,
|
|
97
|
+
};
|
|
98
|
+
const ok = Object.values(results).every(Boolean);
|
|
99
|
+
console.log(`${ok ? '✅' : '❌'} panel fade-in:`, JSON.stringify(results),
|
|
100
|
+
`\n recent =`, probe.recent, `delay=${recentDelay}`,
|
|
101
|
+
`\n legend =`, probe.legend, `delay=${legendDelay}`);
|
|
102
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/* Round 190 verification: R129 hot-tail tspan in recent-signal
|
|
2
|
+
* panel header gets anet-fade-in for smooth entrance.
|
|
3
|
+
*
|
|
4
|
+
* Pre-R190 the tspan mounted/unmounted on hotFlowCount > 0 —
|
|
5
|
+
* snap. R190 keeps the conditional render (so the tspan
|
|
6
|
+
* doesn't consume layout when no hot flows) but adds the R3
|
|
7
|
+
* .anet-fade-in CSS animation that plays once on mount.
|
|
8
|
+
*
|
|
9
|
+
* Test scenarios:
|
|
10
|
+
* A. 0 hot flows (just a few cold ones):
|
|
11
|
+
* [data-recent-panel-hot-count] NOT present
|
|
12
|
+
* B. 1 hot flow (count=12):
|
|
13
|
+
* tspan present with text '· 1 hot', className contains
|
|
14
|
+
* 'anet-fade-in', data-recent-panel-hot-count='1'
|
|
15
|
+
* C. 2 hot flows (count=15 + count=20):
|
|
16
|
+
* data-recent-panel-hot-count='2', text '· 2 hot'
|
|
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: 1500, 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
|
+
async function run(scenario) {
|
|
31
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
32
|
+
await ctx.unroute('**/api/hub/status*').catch(() => {});
|
|
33
|
+
await ctx.unroute('**/api/hub/messages*').catch(() => {});
|
|
34
|
+
await ctx.unroute('**/api/hub/tasks*').catch(() => {});
|
|
35
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
36
|
+
const r = await route.fetch();
|
|
37
|
+
const b = await r.json();
|
|
38
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
39
|
+
const mk = (alias) => ({
|
|
40
|
+
alias, status: 'working', model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
41
|
+
network_id: nid, project_dir: null,
|
|
42
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
43
|
+
});
|
|
44
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
45
|
+
mk('alpha'), mk('beta'), mk('gamma'), mk('delta'),
|
|
46
|
+
] } });
|
|
47
|
+
});
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
const msgs = scenario(now);
|
|
50
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
|
|
51
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
52
|
+
|
|
53
|
+
const page = await ctx.newPage();
|
|
54
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
55
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 4, { timeout: 30000 });
|
|
56
|
+
await page.waitForSelector('[data-recent-panel-count]', { timeout: 10000 });
|
|
57
|
+
await page.waitForTimeout(400);
|
|
58
|
+
|
|
59
|
+
const out = await page.evaluate(() => {
|
|
60
|
+
const tail = document.querySelector('[data-recent-panel-hot-count]');
|
|
61
|
+
return {
|
|
62
|
+
tailPresent: !!tail,
|
|
63
|
+
tailText: tail?.textContent || null,
|
|
64
|
+
tailCount: tail?.getAttribute('data-recent-panel-hot-count'),
|
|
65
|
+
tailClassName: tail?.getAttribute('class') || '',
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
await page.close();
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Scenario A: 0 hot — 1 cold flow
|
|
73
|
+
const a = await run((now) => {
|
|
74
|
+
const m = [];
|
|
75
|
+
for (let i = 0; i < 4; i++) {
|
|
76
|
+
m.push({ id: `cold${i}`, from_alias: 'alpha', to_alias: 'beta', content: 'hi',
|
|
77
|
+
network_id: 'default', created_at: new Date(now - (1000 + i * 50)).toISOString() });
|
|
78
|
+
}
|
|
79
|
+
return m;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Scenario B: 1 hot flow alpha→beta count=12
|
|
83
|
+
const b = await run((now) => {
|
|
84
|
+
const m = [];
|
|
85
|
+
for (let i = 0; i < 12; i++) {
|
|
86
|
+
m.push({ id: `hot${i}`, from_alias: 'alpha', to_alias: 'beta', content: 'hi',
|
|
87
|
+
network_id: 'default', created_at: new Date(now - (1000 + i * 50)).toISOString() });
|
|
88
|
+
}
|
|
89
|
+
return m;
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Scenario C: 2 hot flows
|
|
93
|
+
const c = await run((now) => {
|
|
94
|
+
const m = [];
|
|
95
|
+
for (let i = 0; i < 15; i++) {
|
|
96
|
+
m.push({ id: `h1-${i}`, from_alias: 'alpha', to_alias: 'beta', content: 'hi',
|
|
97
|
+
network_id: 'default', created_at: new Date(now - (5000 + i * 50)).toISOString() });
|
|
98
|
+
}
|
|
99
|
+
for (let i = 0; i < 20; i++) {
|
|
100
|
+
m.push({ id: `h2-${i}`, from_alias: 'gamma', to_alias: 'delta', content: 'hi',
|
|
101
|
+
network_id: 'default', created_at: new Date(now - (15000 + i * 50)).toISOString() });
|
|
102
|
+
}
|
|
103
|
+
return m;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
await browser.close();
|
|
107
|
+
|
|
108
|
+
const results = {
|
|
109
|
+
a_no_tail: a.tailPresent === false,
|
|
110
|
+
b_tail_present: b.tailPresent === true,
|
|
111
|
+
b_tail_text: /·\s*1\s*hot/.test(b.tailText || ''),
|
|
112
|
+
b_tail_count_1: b.tailCount === '1',
|
|
113
|
+
b_has_fade_class: b.tailClassName.includes('anet-fade-in'),
|
|
114
|
+
c_tail_present: c.tailPresent === true,
|
|
115
|
+
c_tail_text: /·\s*2\s*hot/.test(c.tailText || ''),
|
|
116
|
+
c_tail_count_2: c.tailCount === '2',
|
|
117
|
+
c_has_fade_class: c.tailClassName.includes('anet-fade-in'),
|
|
118
|
+
};
|
|
119
|
+
const ok = Object.values(results).every(Boolean);
|
|
120
|
+
console.log(`${ok ? '✅' : '❌'} panel hot-tail fade:`, JSON.stringify(results),
|
|
121
|
+
`\n A (0 hot):`, a,
|
|
122
|
+
`\n B (1 hot):`, b,
|
|
123
|
+
`\n C (2 hot):`, c);
|
|
124
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/* Round 135 verification: both overlay panels (recent-signal +
|
|
2
|
+
* legend) drop-shadow boosts on mouseenter, restores on leave.
|
|
3
|
+
* Mirrors R18's KPI-card hover-elevation from the Overview page.
|
|
4
|
+
*
|
|
5
|
+
* Why both panels: each panel chrome already hosts interactive
|
|
6
|
+
* rows (R56/R116 recent rows, R55/R61 legend rows) and footer
|
|
7
|
+
* nav (R133). Hover-lift signals "this whole panel is alive"
|
|
8
|
+
* without misleading users that the panel itself is clickable —
|
|
9
|
+
* the underlying click affordances are still the rows + footer.
|
|
10
|
+
*
|
|
11
|
+
* State transitions tested:
|
|
12
|
+
* 1. Neither panel hovered → both data-topo-panel-hovered="false",
|
|
13
|
+
* both rect filters = baseline (2px/6px blur)
|
|
14
|
+
* 2. Hover recent → that panel hovered=true, filter boosted
|
|
15
|
+
* (4px/12px blur); legend still baseline
|
|
16
|
+
* 3. Leave recent (move far away) → recent restored
|
|
17
|
+
* 4. Hover legend → legend hovered=true, filter boosted
|
|
18
|
+
* 5. Leave legend → legend restored
|
|
19
|
+
*
|
|
20
|
+
* Filter inline-string detection: the boosted variant carries the
|
|
21
|
+
* `4px 12px` magic numbers in its drop-shadow argument.
|
|
22
|
+
*/
|
|
23
|
+
import { chromium } from 'playwright';
|
|
24
|
+
import { readFileSync } from 'node:fs';
|
|
25
|
+
|
|
26
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
27
|
+
const browser = await chromium.launch({ headless: true });
|
|
28
|
+
|
|
29
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
30
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
31
|
+
await ctx.addInitScript(() => {
|
|
32
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
36
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
37
|
+
const r = await route.fetch();
|
|
38
|
+
const b = await r.json();
|
|
39
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
40
|
+
const mk = (alias, status) => ({
|
|
41
|
+
alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
42
|
+
network_id: nid, project_dir: null,
|
|
43
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
44
|
+
});
|
|
45
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
46
|
+
mk('alpha', 'working'), mk('beta', 'idle'), mk('gamma', 'working'),
|
|
47
|
+
] } });
|
|
48
|
+
});
|
|
49
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [] } }));
|
|
50
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
51
|
+
const page = await ctx.newPage();
|
|
52
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
53
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
54
|
+
await page.waitForSelector('[data-topo-panel="recent"]', { timeout: 10000 });
|
|
55
|
+
await page.waitForTimeout(400);
|
|
56
|
+
|
|
57
|
+
const inspect = () => page.evaluate(() => {
|
|
58
|
+
const get = (key) => {
|
|
59
|
+
const g = document.querySelector(`[data-topo-panel="${key}"]`);
|
|
60
|
+
const rect = g?.querySelector('rect[data-topo-panel-elevation]');
|
|
61
|
+
return {
|
|
62
|
+
hovered: g?.getAttribute('data-topo-panel-hovered'),
|
|
63
|
+
filter: (rect?.getAttribute('style') || ''),
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
return { recent: get('recent'), legend: get('legend') };
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// State 1 — neither hovered
|
|
70
|
+
const s1 = await inspect();
|
|
71
|
+
|
|
72
|
+
// State 2 — hover recent
|
|
73
|
+
await page.locator('[data-topo-panel="recent"]').hover();
|
|
74
|
+
await page.waitForTimeout(300);
|
|
75
|
+
const s2 = await inspect();
|
|
76
|
+
|
|
77
|
+
// State 3 — leave recent (move far away from both panels)
|
|
78
|
+
await page.mouse.move(700, 350);
|
|
79
|
+
await page.waitForTimeout(300);
|
|
80
|
+
const s3 = await inspect();
|
|
81
|
+
|
|
82
|
+
// State 4 — hover legend
|
|
83
|
+
await page.locator('[data-topo-panel="legend"]').hover();
|
|
84
|
+
await page.waitForTimeout(300);
|
|
85
|
+
const s4 = await inspect();
|
|
86
|
+
|
|
87
|
+
// State 5 — leave legend
|
|
88
|
+
await page.mouse.move(500, 350);
|
|
89
|
+
await page.waitForTimeout(300);
|
|
90
|
+
const s5 = await inspect();
|
|
91
|
+
|
|
92
|
+
await browser.close();
|
|
93
|
+
|
|
94
|
+
const isBoosted = (style) => /4px\s+12px/.test(style);
|
|
95
|
+
const isBase = (style) => /2px\s+6px/.test(style) && !/4px\s+12px/.test(style);
|
|
96
|
+
|
|
97
|
+
const results = {
|
|
98
|
+
s1_recent_notHovered: s1.recent.hovered === 'false',
|
|
99
|
+
s1_legend_notHovered: s1.legend.hovered === 'false',
|
|
100
|
+
s1_recent_baseShadow: isBase(s1.recent.filter),
|
|
101
|
+
s1_legend_baseShadow: isBase(s1.legend.filter),
|
|
102
|
+
|
|
103
|
+
s2_recent_hovered: s2.recent.hovered === 'true',
|
|
104
|
+
s2_recent_boosted: isBoosted(s2.recent.filter),
|
|
105
|
+
s2_legend_stillBase: s2.legend.hovered === 'false' && isBase(s2.legend.filter),
|
|
106
|
+
|
|
107
|
+
s3_recent_restored: s3.recent.hovered === 'false' && isBase(s3.recent.filter),
|
|
108
|
+
|
|
109
|
+
s4_legend_hovered: s4.legend.hovered === 'true',
|
|
110
|
+
s4_legend_boosted: isBoosted(s4.legend.filter),
|
|
111
|
+
s4_recent_stillBase: s4.recent.hovered === 'false' && isBase(s4.recent.filter),
|
|
112
|
+
|
|
113
|
+
s5_legend_restored: s5.legend.hovered === 'false' && isBase(s5.legend.filter),
|
|
114
|
+
};
|
|
115
|
+
const ok = Object.values(results).every(Boolean);
|
|
116
|
+
console.log(`${ok ? '✅' : '❌'} panel hover elevation:`, JSON.stringify(results),
|
|
117
|
+
`\n s1=`, s1, `\n s2=`, s2, `\n s3=`, s3, `\n s4=`, s4, `\n s5=`, s5);
|
|
118
|
+
process.exit(ok ? 0 : 1);
|