@sleep2agi/agent-network-dashboard 0.4.6-preview.161 → 0.4.6-preview.163
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +3 -3
- package/.next/diagnostics/route-bundle-stats.json +4 -4
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +2 -2
- package/.next/server/app/_not-found.rsc +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/admin.segments/_full.segment.rsc +2 -2
- package/.next/server/app/admin.segments/_head.segment.rsc +1 -1
- package/.next/server/app/admin.segments/_index.segment.rsc +2 -2
- package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/admin.segments/admin.segment.rsc +1 -1
- package/.next/server/app/index.html +2 -2
- package/.next/server/app/index.rsc +3 -3
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/server/app/index.segments/_index.segment.rsc +2 -2
- 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 +3 -3
- package/.next/server/app/login.segments/_full.segment.rsc +3 -3
- package/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/.next/server/app/login.segments/_index.segment.rsc +2 -2
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/login.segments/login.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/logs.segments/_full.segment.rsc +2 -2
- package/.next/server/app/logs.segments/_head.segment.rsc +1 -1
- package/.next/server/app/logs.segments/_index.segment.rsc +2 -2
- package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/logs.segments/logs.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/messages.segments/_full.segment.rsc +2 -2
- package/.next/server/app/messages.segments/_head.segment.rsc +1 -1
- package/.next/server/app/messages.segments/_index.segment.rsc +2 -2
- package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/messages.segments/messages.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/node.segments/_full.segment.rsc +2 -2
- package/.next/server/app/node.segments/_head.segment.rsc +1 -1
- package/.next/server/app/node.segments/_index.segment.rsc +2 -2
- package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/node.segments/node.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/nodes.segments/_full.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/_head.segment.rsc +1 -1
- package/.next/server/app/nodes.segments/_index.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/nodes.segments/nodes.segment.rsc +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/server-logs.html +2 -2
- package/.next/server/app/server-logs.rsc +2 -2
- package/.next/server/app/server-logs.segments/_full.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/_head.segment.rsc +1 -1
- package/.next/server/app/server-logs.segments/_index.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/server-logs.segments/server-logs.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings/networks.segments/_index.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +1 -1
- package/.next/server/app/settings/networks.segments/settings.segment.rsc +1 -1
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/tokens.html +2 -2
- package/.next/server/app/settings/tokens.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/_index.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/settings.segment.rsc +1 -1
- package/.next/server/app/settings.html +2 -2
- package/.next/server/app/settings.rsc +3 -3
- package/.next/server/app/settings.segments/_full.segment.rsc +3 -3
- package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_index.segment.rsc +2 -2
- package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/tasks.segments/_full.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/_head.segment.rsc +1 -1
- package/.next/server/app/tasks.segments/_index.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/tasks.segments/tasks.segment.rsc +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +3 -3
- 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_09d29my._.js +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.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/{10z.kc0g0jj8p.js → 0l1bmg_n.dezi.js} +1 -1
- package/.next/static/chunks/{032~4k7il7hnk.css → 0m7e_hszjk30d.css} +1 -1
- package/.next/static/chunks/{0oehx47rte9ek.js → 0zq~jtyqwejzx.js} +1 -1
- package/.next/static/chunks/11t1ercs8j0x1.js +4 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/TopoGraph.tsx +16 -10
- package/app/globals.css +29 -0
- package/package.json +1 -1
- package/scripts/topo-chip-focus-test.mjs +95 -0
- package/scripts/topo-svg-focus-test.mjs +112 -0
- package/.next/static/chunks/06fy8p2g0jbz1.js +0 -4
- /package/.next/static/{IJ5nEFbzhj38AtfV6zg14 → wpeRwhWZ_hD3osxjp5P7e}/_buildManifest.js +0 -0
- /package/.next/static/{IJ5nEFbzhj38AtfV6zg14 → wpeRwhWZ_hD3osxjp5P7e}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{IJ5nEFbzhj38AtfV6zg14 → wpeRwhWZ_hD3osxjp5P7e}/_ssgManifest.js +0 -0
|
@@ -1363,7 +1363,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1363
1363
|
return (
|
|
1364
1364
|
<>
|
|
1365
1365
|
<span
|
|
1366
|
-
className="px-2.5 py-1 rounded-md bg-green-500/10 text-green-300 border border-green-500/20"
|
|
1366
|
+
className="px-2.5 py-1 rounded-md bg-green-500/10 text-green-300 border border-green-500/20 anet-topo-chip-focus"
|
|
1367
1367
|
data-working-chip
|
|
1368
1368
|
data-working-chip-aliases={workingAliases.join(',')}
|
|
1369
1369
|
data-pin-mirror={pinnedStatus === 'working' ? 'true' : 'false'}
|
|
@@ -1401,7 +1401,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1401
1401
|
{workingCount} working
|
|
1402
1402
|
</span>
|
|
1403
1403
|
<span
|
|
1404
|
-
className="px-2.5 py-1 rounded-md bg-cyan-500/10 text-cyan-300 border border-cyan-500/20"
|
|
1404
|
+
className="px-2.5 py-1 rounded-md bg-cyan-500/10 text-cyan-300 border border-cyan-500/20 anet-topo-chip-focus"
|
|
1405
1405
|
data-online-chip
|
|
1406
1406
|
data-online-chip-aliases={onlineAliases.join(',')}
|
|
1407
1407
|
data-pin-mirror={pinnedStatus === 'idle' ? 'true' : 'false'}
|
|
@@ -1485,6 +1485,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1485
1485
|
role="button"
|
|
1486
1486
|
tabIndex={0}
|
|
1487
1487
|
aria-pressed={isPinned}
|
|
1488
|
+
className="anet-topo-chip-focus"
|
|
1488
1489
|
title={`${n} ${label}\n${previewList}${suffix}\n${titleAction}`}
|
|
1489
1490
|
style={{
|
|
1490
1491
|
width: `${(n / total) * 100}%`,
|
|
@@ -1586,7 +1587,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1586
1587
|
data-active-filter="status"
|
|
1587
1588
|
data-filter-match-count={matchCount}
|
|
1588
1589
|
data-filter-match-aliases={matchAliases.join(',')}
|
|
1589
|
-
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md font-mono text-xs border anet-fade-in"
|
|
1590
|
+
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md font-mono text-xs border anet-fade-in anet-topo-chip-focus"
|
|
1590
1591
|
title={matchCount > 0 ? `${matchPreview}${matchSuffix} — click to clear` : 'Click to clear filter'}
|
|
1591
1592
|
onClick={() => setPinnedStatus(null)}
|
|
1592
1593
|
style={{
|
|
@@ -1624,7 +1625,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1624
1625
|
data-active-filter="group"
|
|
1625
1626
|
data-filter-match-count={matchCount}
|
|
1626
1627
|
data-filter-match-aliases={matchAliases.join(',')}
|
|
1627
|
-
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md font-mono text-xs border anet-fade-in"
|
|
1628
|
+
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md font-mono text-xs border anet-fade-in anet-topo-chip-focus"
|
|
1628
1629
|
title={matchCount > 0 ? `${matchPreview}${matchSuffix} — click to clear` : 'Click to clear filter'}
|
|
1629
1630
|
onClick={() => setPinnedGroup(null)}
|
|
1630
1631
|
style={{
|
|
@@ -1674,7 +1675,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1674
1675
|
data-active-filter="vendor"
|
|
1675
1676
|
data-filter-match-count={matchCount}
|
|
1676
1677
|
data-filter-match-aliases={matchAliases.join(',')}
|
|
1677
|
-
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md font-mono text-xs border anet-fade-in"
|
|
1678
|
+
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md font-mono text-xs border anet-fade-in anet-topo-chip-focus"
|
|
1678
1679
|
title={matchCount > 0 ? `${matchPreview}${matchSuffix} — click to clear` : 'Click to clear vendor filter'}
|
|
1679
1680
|
onClick={() => setPinnedVendor(null)}
|
|
1680
1681
|
style={{
|
|
@@ -1722,7 +1723,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1722
1723
|
data-filter-match-count={link.count}
|
|
1723
1724
|
data-filter-match-aliases={`${link.from},${link.to}`}
|
|
1724
1725
|
data-active-filter-edge-hot={isHot ? 'true' : 'false'}
|
|
1725
|
-
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md font-mono text-xs border anet-fade-in"
|
|
1726
|
+
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md font-mono text-xs border anet-fade-in anet-topo-chip-focus"
|
|
1726
1727
|
title={`${link.from} → ${link.to} (${link.count} msg${link.count === 1 ? '' : 's'}${isHot ? ', hot lane · ≥ 10' : ''}) — click to clear`}
|
|
1727
1728
|
onClick={() => setPinnedEdgeKey(null)}
|
|
1728
1729
|
style={{
|
|
@@ -1836,7 +1837,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1836
1837
|
data-pin-intersection-count={matchAliases.length}
|
|
1837
1838
|
data-pin-intersection-empty={isEmpty ? 'true' : 'false'}
|
|
1838
1839
|
data-pin-intersection-aliases={matchAliases.join(',')}
|
|
1839
|
-
className="hidden sm:inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md font-mono text-xs border anet-fade-in"
|
|
1840
|
+
className="hidden sm:inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md font-mono text-xs border anet-fade-in anet-topo-chip-focus"
|
|
1840
1841
|
title={tooltip}
|
|
1841
1842
|
style={{
|
|
1842
1843
|
background: isEmpty
|
|
@@ -1889,7 +1890,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1889
1890
|
role="button"
|
|
1890
1891
|
tabIndex={0}
|
|
1891
1892
|
aria-pressed={isPinned}
|
|
1892
|
-
className="inline-flex items-baseline gap-0.5 px-1 rounded"
|
|
1893
|
+
className="inline-flex items-baseline gap-0.5 px-1 rounded anet-topo-chip-focus"
|
|
1893
1894
|
data-vendor-letter={v.initial}
|
|
1894
1895
|
data-vendor-pinned={isPinned ? 'true' : 'false'}
|
|
1895
1896
|
data-vendor-aliases={aliases.join(',')}
|
|
@@ -1959,7 +1960,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
1959
1960
|
: `${flowList}${flowSuffix} — hover brightens all · click to open /messages`;
|
|
1960
1961
|
return (
|
|
1961
1962
|
<span
|
|
1962
|
-
className="hidden sm:inline px-2.5 py-1 rounded-md bg-gray-500/10 text-gray-400 border border-gray-500/20"
|
|
1963
|
+
className="hidden sm:inline px-2.5 py-1 rounded-md bg-gray-500/10 text-gray-400 border border-gray-500/20 anet-topo-chip-focus"
|
|
1963
1964
|
data-active-links-chip
|
|
1964
1965
|
data-active-links-flow-count={flowLinks.length}
|
|
1965
1966
|
data-active-links-clickable={isInteractive ? 'true' : 'false'}
|
|
@@ -2475,6 +2476,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
2475
2476
|
tabIndex={0}
|
|
2476
2477
|
aria-pressed={pinnedGroup === box.key}
|
|
2477
2478
|
data-group-label-hit={box.key}
|
|
2479
|
+
className="anet-topo-svg-focus"
|
|
2478
2480
|
style={{ pointerEvents: 'all', cursor: 'pointer' }}
|
|
2479
2481
|
onPointerDown={(e) => e.stopPropagation()}
|
|
2480
2482
|
onClick={() => setPinnedGroup(prev => prev === box.key ? null : box.key)}
|
|
@@ -2856,6 +2858,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
2856
2858
|
role="button"
|
|
2857
2859
|
tabIndex={0}
|
|
2858
2860
|
aria-pressed={isPinned}
|
|
2861
|
+
className="anet-topo-svg-focus"
|
|
2859
2862
|
style={{ pointerEvents: 'all', cursor: 'pointer' }}
|
|
2860
2863
|
opacity={badgeOpacity}
|
|
2861
2864
|
onPointerDown={(e) => e.stopPropagation()}
|
|
@@ -3133,7 +3136,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
3133
3136
|
// an existing node don't re-trigger (React preserves the <g>
|
|
3134
3137
|
// via the alias key), so status changes don't flicker. The
|
|
3135
3138
|
// global prefers-reduced-motion sweep already neutralises it.
|
|
3136
|
-
className="group transition-opacity anet-fade-in"
|
|
3139
|
+
className="group transition-opacity anet-fade-in anet-topo-svg-focus"
|
|
3137
3140
|
style={{
|
|
3138
3141
|
cursor: 'pointer',
|
|
3139
3142
|
// Round 17 / Loop: offline nodes drop to 0.6 at rest so
|
|
@@ -3805,6 +3808,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
3805
3808
|
data-recent-row-pinned={isRowPinned ? 'true' : 'false'}
|
|
3806
3809
|
data-recent-row-hot={isHot ? 'true' : 'false'}
|
|
3807
3810
|
data-recent-row-lifted={(isRowHovered || isRowPinned) ? 'true' : 'false'}
|
|
3811
|
+
className="anet-topo-svg-focus"
|
|
3808
3812
|
role="button"
|
|
3809
3813
|
tabIndex={0}
|
|
3810
3814
|
aria-pressed={isRowPinned}
|
|
@@ -3951,6 +3955,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
3951
3955
|
data-recent-panel-more-nav
|
|
3952
3956
|
role="link"
|
|
3953
3957
|
tabIndex={0}
|
|
3958
|
+
className="anet-topo-svg-focus"
|
|
3954
3959
|
style={{ cursor: 'pointer', pointerEvents: 'all' }}
|
|
3955
3960
|
onPointerDown={(e) => e.stopPropagation()}
|
|
3956
3961
|
onMouseEnter={() => setHoveredRecentMore(true)}
|
|
@@ -4051,6 +4056,7 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
4051
4056
|
key={row.key}
|
|
4052
4057
|
data-legend-status={row.key}
|
|
4053
4058
|
data-legend-row-lifted={isLifted ? 'true' : 'false'}
|
|
4059
|
+
className="anet-topo-svg-focus"
|
|
4054
4060
|
role="button"
|
|
4055
4061
|
tabIndex={0}
|
|
4056
4062
|
aria-pressed={isPinned}
|
package/app/globals.css
CHANGED
|
@@ -856,6 +856,35 @@ body {
|
|
|
856
856
|
animation-iteration-count: infinite;
|
|
857
857
|
}
|
|
858
858
|
|
|
859
|
+
/* R155 — focus-visible outline for TopoGraph chip-row interactives.
|
|
860
|
+
Cyber theme's dark canvas often swallows the browser default focus
|
|
861
|
+
ring; R154 fixed it for chrome buttons via Tailwind's focus-visible:
|
|
862
|
+
ring (box-shadow). Chip-row chips reuse `box-shadow` for the R88 /
|
|
863
|
+
R139 / R140 pin-mirror inset — so a focus box-shadow would conflict
|
|
864
|
+
with the pinned-state shadow. `outline` is a separate CSS property
|
|
865
|
+
and doesn't fight box-shadow, so we use it here. `currentColor`
|
|
866
|
+
inherits the chip's own accent (green for working, cyan for online,
|
|
867
|
+
per-vendor for letters, etc.). Only fires on :focus-visible
|
|
868
|
+
(keyboard) — mouse focus stays unstyled. */
|
|
869
|
+
.anet-topo-chip-focus:focus-visible {
|
|
870
|
+
outline: 2px solid currentColor;
|
|
871
|
+
outline-offset: 1px;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/* R156 — focus-visible outline for SVG-side TopoGraph interactives.
|
|
875
|
+
Same idiom as R155's chip-row class but for SVG <g> elements
|
|
876
|
+
(recent-signal rows, legend rows, group labels, edge badges,
|
|
877
|
+
node bodies, "+N more" footer). Each <g> already has role=
|
|
878
|
+
"button"/"link" + tabIndex=0 + onKeyDown (R116/R121/R133/R143/
|
|
879
|
+
R144/R151/R152). Browser default focus outline on SVG is hard
|
|
880
|
+
to spot against the canvas; explicit cyan-300 ring matches the
|
|
881
|
+
dashboard's legendAccent. 2-px outline-offset gives breathing
|
|
882
|
+
room around the painted bounding box. */
|
|
883
|
+
.anet-topo-svg-focus:focus-visible {
|
|
884
|
+
outline: 2px solid #67e8f9;
|
|
885
|
+
outline-offset: 2px;
|
|
886
|
+
}
|
|
887
|
+
|
|
859
888
|
/* Round 46 — animated dashed spokes flowing from hub outward. Each spoke
|
|
860
889
|
gets a small animationDelay (set inline) so the dashes don't all flow
|
|
861
890
|
in sync — reads as "command relay" pulse rather than a metronome.
|
package/package.json
CHANGED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* Round 155 verification: chip-row interactives gain
|
|
2
|
+
* `.anet-topo-chip-focus` for keyboard focus-visible outline,
|
|
3
|
+
* matching R154's chrome-button treatment.
|
|
4
|
+
*
|
|
5
|
+
* Why `outline` not `box-shadow`: the R88 vendor letter / R139
|
|
6
|
+
* working chip / R140 online chip already use inline boxShadow
|
|
7
|
+
* for the pin-mirror inset. Adding focus-visible:ring (which
|
|
8
|
+
* Tailwind paints via box-shadow) would conflict — inline style
|
|
9
|
+
* wins specificity. `outline: 2px solid currentColor` is on a
|
|
10
|
+
* separate CSS property, no conflict; `currentColor` inherits
|
|
11
|
+
* the chip's own accent (green / cyan / per-vendor / etc.).
|
|
12
|
+
*
|
|
13
|
+
* Test: every chip-row interactive surface carries the class.
|
|
14
|
+
*/
|
|
15
|
+
import { chromium } from 'playwright';
|
|
16
|
+
import { readFileSync } from 'node:fs';
|
|
17
|
+
|
|
18
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
19
|
+
const browser = await chromium.launch({ headless: true });
|
|
20
|
+
|
|
21
|
+
const ctx = await browser.newContext({ viewport: { width: 1400, height: 1500 } });
|
|
22
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
23
|
+
await ctx.addInitScript(() => {
|
|
24
|
+
try { localStorage.setItem('anet-theme', 'cyber'); sessionStorage.setItem('anet_v3_auth', '1'); } catch {}
|
|
25
|
+
});
|
|
26
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
27
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
28
|
+
const r = await route.fetch();
|
|
29
|
+
const b = await r.json();
|
|
30
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
31
|
+
const mk = (alias, status, model) => ({
|
|
32
|
+
alias, status, model, runtime: 'cli-claude-code',
|
|
33
|
+
network_id: nid, project_dir: null,
|
|
34
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
35
|
+
});
|
|
36
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
37
|
+
mk('alpha', 'working', 'claude-opus-4'),
|
|
38
|
+
mk('beta', 'idle', 'gpt-4o'),
|
|
39
|
+
] } });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
// 1 message to populate flowLinks → active-links chip is interactive
|
|
44
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: [
|
|
45
|
+
{ id: 'm0', from_alias: 'alpha', to_alias: 'beta', content: 'hi',
|
|
46
|
+
network_id: 'default', created_at: new Date(now - 10000).toISOString() },
|
|
47
|
+
] } }));
|
|
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(() => document.querySelectorAll('g[data-node]').length === 2, { timeout: 30000 });
|
|
53
|
+
await page.waitForTimeout(400);
|
|
54
|
+
|
|
55
|
+
// Pin status + vendor to surface filter pills + intersection chip
|
|
56
|
+
await page.evaluate(() => {
|
|
57
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'status', value: 'working' } }));
|
|
58
|
+
window.dispatchEvent(new CustomEvent('anet:topo-pin', { detail: { kind: 'vendor', value: 'A' } }));
|
|
59
|
+
});
|
|
60
|
+
await page.waitForTimeout(300);
|
|
61
|
+
|
|
62
|
+
const inspect = () => page.evaluate(() => {
|
|
63
|
+
const has = (sel) => {
|
|
64
|
+
const el = document.querySelector(sel);
|
|
65
|
+
return el && (el.className || '').includes('anet-topo-chip-focus');
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
pressureSeg_working: has('[data-pressure-seg="working"]'),
|
|
69
|
+
workingChip: has('[data-working-chip]'),
|
|
70
|
+
onlineChip: has('[data-online-chip]'),
|
|
71
|
+
vendorLetter_A: has('[data-vendor-letter="A"]'),
|
|
72
|
+
activeLinks: has('[data-active-links-chip]'),
|
|
73
|
+
filterPill_status: has('[data-active-filter="status"]'),
|
|
74
|
+
filterPill_vendor: has('[data-active-filter="vendor"]'),
|
|
75
|
+
intersectionChip: has('[data-pin-intersection]'),
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const result = await inspect();
|
|
80
|
+
await browser.close();
|
|
81
|
+
|
|
82
|
+
const results = {
|
|
83
|
+
pressureSeg_focusClass: result.pressureSeg_working === true,
|
|
84
|
+
workingChip_focusClass: result.workingChip === true,
|
|
85
|
+
onlineChip_focusClass: result.onlineChip === true,
|
|
86
|
+
vendorLetter_focusClass: result.vendorLetter_A === true,
|
|
87
|
+
activeLinks_focusClass: result.activeLinks === true,
|
|
88
|
+
filterPillStatus_focusClass: result.filterPill_status === true,
|
|
89
|
+
filterPillVendor_focusClass: result.filterPill_vendor === true,
|
|
90
|
+
intersectionChip_focusClass: result.intersectionChip === true,
|
|
91
|
+
};
|
|
92
|
+
const ok = Object.values(results).every(Boolean);
|
|
93
|
+
console.log(`${ok ? '✅' : '❌'} chip focus class:`, JSON.stringify(results),
|
|
94
|
+
`\n raw=`, result);
|
|
95
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/* Round 156 verification: SVG <g> interactives gain
|
|
2
|
+
* `.anet-topo-svg-focus` for keyboard focus outline.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors R155's chip-row treatment at the SVG scope. 6 surfaces:
|
|
5
|
+
* data-node (R151 node body)
|
|
6
|
+
* data-group-label-hit (R63 group label)
|
|
7
|
+
* data-edge-count-badge (R121 edge badge)
|
|
8
|
+
* data-recent-row (R116 recent-signal row)
|
|
9
|
+
* data-recent-panel-more-nav (R133 "+N more" footer)
|
|
10
|
+
* data-legend-status (R61 legend row)
|
|
11
|
+
*
|
|
12
|
+
* Class `.anet-topo-svg-focus:focus-visible` paints outline 2px
|
|
13
|
+
* cyan-300 (#67e8f9) with 2px outline-offset. Browser default
|
|
14
|
+
* focus ring on SVG is hard to spot against the dashboard
|
|
15
|
+
* canvas; explicit cyan matches the legendAccent palette.
|
|
16
|
+
*
|
|
17
|
+
* Test: every SVG interactive surface carries the class.
|
|
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: 1600, 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 {
|
|
29
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
30
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
31
|
+
// grid layout to surface group labels
|
|
32
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
33
|
+
} catch {}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
37
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
38
|
+
const r = await route.fetch();
|
|
39
|
+
const b = await r.json();
|
|
40
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
41
|
+
const mk = (alias, status) => ({
|
|
42
|
+
alias, status, model: 'claude-opus-4', runtime: 'cli-claude-code',
|
|
43
|
+
network_id: nid, project_dir: null,
|
|
44
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
45
|
+
});
|
|
46
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
47
|
+
mk('agents-a1', 'working'), mk('agents-a2', 'working'),
|
|
48
|
+
mk('infra-b1', 'working'),
|
|
49
|
+
] } });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
// Edge midpoint count badge (R100) only renders when link.count >= 3.
|
|
54
|
+
// Pair agents-a1 → agents-a2 gets 4 msgs to clear the threshold; add 4
|
|
55
|
+
// other singletons so flowLinks.length = 5 → R128 "+ 2 more flows"
|
|
56
|
+
// footer also renders.
|
|
57
|
+
const msgs = [];
|
|
58
|
+
for (let i = 0; i < 4; i++) {
|
|
59
|
+
msgs.push({
|
|
60
|
+
id: `a2a${i}`, from_alias: 'agents-a1', to_alias: 'agents-a2', content: 'hi',
|
|
61
|
+
network_id: 'default', created_at: new Date(now - (10000 + i * 500)).toISOString(),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
msgs.push({ id: 'm1', from_alias: 'agents-a2', to_alias: 'infra-b1', content: 'hi',
|
|
65
|
+
network_id: 'default', created_at: new Date(now - 11000).toISOString() });
|
|
66
|
+
msgs.push({ id: 'm2', from_alias: 'infra-b1', to_alias: 'agents-a1', content: 'hi',
|
|
67
|
+
network_id: 'default', created_at: new Date(now - 12000).toISOString() });
|
|
68
|
+
msgs.push({ id: 'm3', from_alias: 'agents-a1', to_alias: 'infra-b1', content: 'hi',
|
|
69
|
+
network_id: 'default', created_at: new Date(now - 13000).toISOString() });
|
|
70
|
+
msgs.push({ id: 'm4', from_alias: 'agents-a2', to_alias: 'agents-a1', content: 'hi',
|
|
71
|
+
network_id: 'default', created_at: new Date(now - 14000).toISOString() });
|
|
72
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: { messages: msgs } }));
|
|
73
|
+
await ctx.route('**/api/hub/tasks*', (route) => route.fulfill({ json: { tasks: [] } }));
|
|
74
|
+
|
|
75
|
+
const page = await ctx.newPage();
|
|
76
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'domcontentloaded' });
|
|
77
|
+
await page.waitForFunction(() => document.querySelectorAll('g[data-node]').length === 3, { timeout: 30000 });
|
|
78
|
+
await page.waitForSelector('[data-recent-row]', { timeout: 10000 });
|
|
79
|
+
await page.waitForSelector('[data-recent-panel-more-nav]', { timeout: 10000 });
|
|
80
|
+
await page.waitForSelector('[data-edge-count-badge]', { timeout: 10000 });
|
|
81
|
+
await page.waitForSelector('[data-group-label-hit]', { timeout: 10000 });
|
|
82
|
+
await page.waitForTimeout(400);
|
|
83
|
+
|
|
84
|
+
const out = await page.evaluate(() => {
|
|
85
|
+
const has = (sel) => {
|
|
86
|
+
const el = document.querySelector(sel);
|
|
87
|
+
return el && (el.getAttribute('class') || '').includes('anet-topo-svg-focus');
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
nodeBody: has('g[data-node]'),
|
|
91
|
+
groupLabel: has('[data-group-label-hit]'),
|
|
92
|
+
edgeCountBadge: has('[data-edge-count-badge]'),
|
|
93
|
+
recentRow: has('[data-recent-row]'),
|
|
94
|
+
recentPanelMoreNav: has('[data-recent-panel-more-nav]'),
|
|
95
|
+
legendStatusRow: has('[data-legend-status="working"]'),
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await browser.close();
|
|
100
|
+
|
|
101
|
+
const results = {
|
|
102
|
+
nodeBody_focus: out.nodeBody === true,
|
|
103
|
+
groupLabel_focus: out.groupLabel === true,
|
|
104
|
+
edgeCountBadge_focus: out.edgeCountBadge === true,
|
|
105
|
+
recentRow_focus: out.recentRow === true,
|
|
106
|
+
recentPanelMoreNav_focus: out.recentPanelMoreNav === true,
|
|
107
|
+
legendStatusRow_focus: out.legendStatusRow === true,
|
|
108
|
+
};
|
|
109
|
+
const ok = Object.values(results).every(Boolean);
|
|
110
|
+
console.log(`${ok ? '✅' : '❌'} SVG focus class:`, JSON.stringify(results),
|
|
111
|
+
`\n raw=`, out);
|
|
112
|
+
process.exit(ok ? 0 : 1);
|