@sleep2agi/agent-network-dashboard 0.5.2-preview.1 → 0.5.2-preview.11
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 +7 -7
- package/.next/fallback-build-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.html +1 -1
- package/.next/server/app/_not-found.rsc +1 -1
- package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- 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 +1 -1
- package/.next/server/app/admin.html +1 -1
- package/.next/server/app/admin.rsc +1 -1
- package/.next/server/app/admin.segments/_full.segment.rsc +1 -1
- package/.next/server/app/admin.segments/_head.segment.rsc +1 -1
- package/.next/server/app/admin.segments/_index.segment.rsc +1 -1
- package/.next/server/app/admin.segments/_tree.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +2 -2
- package/.next/server/app/login.rsc +2 -2
- package/.next/server/app/login.segments/_full.segment.rsc +2 -2
- package/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/.next/server/app/login.segments/_index.segment.rsc +1 -1
- package/.next/server/app/login.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/logs.rsc +1 -1
- package/.next/server/app/logs.segments/_full.segment.rsc +1 -1
- package/.next/server/app/logs.segments/_head.segment.rsc +1 -1
- package/.next/server/app/logs.segments/_index.segment.rsc +1 -1
- package/.next/server/app/logs.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/messages.rsc +1 -1
- package/.next/server/app/messages.segments/_full.segment.rsc +1 -1
- package/.next/server/app/messages.segments/_head.segment.rsc +1 -1
- package/.next/server/app/messages.segments/_index.segment.rsc +1 -1
- package/.next/server/app/messages.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/node.rsc +1 -1
- package/.next/server/app/node.segments/_full.segment.rsc +1 -1
- package/.next/server/app/node.segments/_head.segment.rsc +1 -1
- package/.next/server/app/node.segments/_index.segment.rsc +1 -1
- package/.next/server/app/node.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/nodes.rsc +1 -1
- package/.next/server/app/nodes.segments/_full.segment.rsc +1 -1
- package/.next/server/app/nodes.segments/_head.segment.rsc +1 -1
- package/.next/server/app/nodes.segments/_index.segment.rsc +1 -1
- package/.next/server/app/nodes.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/server-logs.rsc +1 -1
- package/.next/server/app/server-logs.segments/_full.segment.rsc +1 -1
- package/.next/server/app/server-logs.segments/_head.segment.rsc +1 -1
- package/.next/server/app/server-logs.segments/_index.segment.rsc +1 -1
- package/.next/server/app/server-logs.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/settings/networks.rsc +1 -1
- package/.next/server/app/settings/networks.segments/_full.segment.rsc +1 -1
- package/.next/server/app/settings/networks.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings/networks.segments/_index.segment.rsc +1 -1
- package/.next/server/app/settings/networks.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/settings/tokens.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/_full.segment.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/_index.segment.rsc +1 -1
- package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +1 -1
- 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 +2 -2
- package/.next/server/app/settings.segments/_full.segment.rsc +2 -2
- package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_index.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- 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.html +1 -1
- package/.next/server/app/tasks.rsc +1 -1
- package/.next/server/app/tasks.segments/_full.segment.rsc +1 -1
- package/.next/server/app/tasks.segments/_head.segment.rsc +1 -1
- package/.next/server/app/tasks.segments/_index.segment.rsc +1 -1
- package/.next/server/app/tasks.segments/_tree.segment.rsc +1 -1
- 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/[root-of-the-server]__0sv~g.o._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +1 -1
- package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +2 -2
- 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 +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/static/chunks/0h9xo63u79l9l.js +1 -0
- package/.next/static/chunks/0nrxcvtcs7x71.js +1 -0
- package/.next/static/chunks/{0pgnr.wdna.jv.js → 0rf5564pjvl7f.js} +1 -1
- package/.next/static/chunks/1841977._okm5.js +4 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/app/components/TopoGraph.tsx +243 -10
- package/package.json +1 -1
- package/scripts/topo-edge-badge-hot-glow-test.mjs +101 -0
- package/scripts/topo-group-label-glow-test.mjs +104 -0
- package/scripts/topo-hub-digit-glow-test.mjs +105 -0
- package/scripts/topo-layout-theme-attrs-test.mjs +91 -0
- package/scripts/topo-legend-pin-ring-glow-test.mjs +105 -0
- package/scripts/topo-legend-row-text-cadence-test.mjs +93 -0
- package/scripts/topo-legend-row-tint-cadence-test.mjs +92 -0
- package/scripts/topo-recent-row-freshness-glow-test.mjs +100 -0
- package/scripts/topo-recent-row-text-cadence-test.mjs +99 -0
- package/scripts/topo-recent-row-tint-cadence-test.mjs +96 -0
- package/.next/static/chunks/00047pvxj~z3x.js +0 -4
- package/.next/static/chunks/0ubkidns7e9dp.js +0 -1
- package/.next/static/chunks/0zpqg7iibb7fi.js +0 -1
- /package/.next/static/{1nsKFD4r1lqfWBZ-F7k3- → hG7R_jh4p1dno7frJBNCy}/_buildManifest.js +0 -0
- /package/.next/static/{1nsKFD4r1lqfWBZ-F7k3- → hG7R_jh4p1dno7frJBNCy}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{1nsKFD4r1lqfWBZ-F7k3- → hG7R_jh4p1dno7frJBNCy}/_ssgManifest.js +0 -0
package/.next/trace-build
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"name":"run-turbopack","duration":
|
|
1
|
+
[{"name":"run-turbopack","duration":5978558,"timestamp":180822290369,"id":14,"parentId":1,"tags":{},"startTime":1778988794537,"traceId":"3d0010a9212a1fa1"},{"name":"turbopack-build-events","duration":95,"timestamp":180822579535,"id":15,"parentId":1,"tags":{},"startTime":1778988794826,"traceId":"3d0010a9212a1fa1"},{"name":"run-typescript","duration":9740495,"timestamp":180828286955,"id":16,"parentId":1,"tags":{},"startTime":1778988800533,"traceId":"3d0010a9212a1fa1"},{"name":"static-check","duration":761394,"timestamp":180838220234,"id":19,"parentId":1,"tags":{},"startTime":1778988810467,"traceId":"3d0010a9212a1fa1"},{"name":"static-generation","duration":655125,"timestamp":180838997327,"id":109,"parentId":1,"tags":{},"startTime":1778988811244,"traceId":"3d0010a9212a1fa1"},{"name":"telemetry-flush","duration":34437,"timestamp":180839687385,"id":118,"parentId":1,"tags":{},"startTime":1778988811934,"traceId":"3d0010a9212a1fa1"},{"name":"next-build","duration":17661477,"timestamp":180822060373,"id":1,"tags":{"buildMode":"default","version":"16.2.3","bundler":"turbopack","has-custom-webpack-config":"false","use-build-worker":"true"},"startTime":1778988794307,"traceId":"3d0010a9212a1fa1"}]
|
|
@@ -3485,6 +3485,25 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
3485
3485
|
data-topo-working-count={workingCount}
|
|
3486
3486
|
data-topo-offline-count={offlineNodes.length}
|
|
3487
3487
|
data-topo-flow-count={flowLinks.length}
|
|
3488
|
+
/* Round 471 / Loop — surface 2 remaining canvas-level mode
|
|
3489
|
+
attrs alongside the R462/R466/R467/R469 set. Pre-R471 the
|
|
3490
|
+
root svg exposed 7 attrs but tests probing "what layout
|
|
3491
|
+
is active" had to query DOM internals (data-topo-chrome-
|
|
3492
|
+
layout-active on the chrome button row) or parse the URL
|
|
3493
|
+
for theme. R471 puts both modes on the root for one-stop
|
|
3494
|
+
snapshot reads:
|
|
3495
|
+
data-topo-layout — 'ring' | 'grid'
|
|
3496
|
+
data-topo-theme — 'cyber' | 'light'
|
|
3497
|
+
Together with R469 the canvas root now carries 9 cross-
|
|
3498
|
+
cutting attrs (1 build identity + 2 inspection mode + 4
|
|
3499
|
+
fleet split + 2 layout/theme). Test harness can read the
|
|
3500
|
+
FULL canvas state with 9 getAttribute calls; no traversal
|
|
3501
|
+
into chrome strip / theme provider / panel rows.
|
|
3502
|
+
Composed from existing `layout` (R138 ring↔grid toggle
|
|
3503
|
+
state) + `isLight` (R12 theme palette gate) — no new
|
|
3504
|
+
state, zero re-render cost. */
|
|
3505
|
+
data-topo-layout={layout}
|
|
3506
|
+
data-topo-theme={isLight ? 'light' : 'cyber'}
|
|
3488
3507
|
/* Round 466 / Loop — aggregate hover signal on the root SVG.
|
|
3489
3508
|
Exposes a single boolean `data-topo-any-hover` that
|
|
3490
3509
|
reflects whether ANY hover state in the topology is
|
|
@@ -4742,10 +4761,35 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
4742
4761
|
opacity={isPinned || isHovered ? 1 : 0.55}
|
|
4743
4762
|
data-group-label-hovered={isHovered && !isPinned ? 'true' : 'false'}
|
|
4744
4763
|
data-group-label-font-weight={isPinned ? '800' : '700'}
|
|
4764
|
+
/* Round 479 / Loop — extend drop-shadow visual-polish
|
|
4765
|
+
family to a 4th anchor: group-label parent text
|
|
4766
|
+
on isPinned. Continues the R476/R477/R478 arc:
|
|
4767
|
+
R476 hub digit hover-gated emerald
|
|
4768
|
+
R477 legend pin-ring pin-gated row.fill
|
|
4769
|
+
R478 recent-row pip freshness-gated cyan
|
|
4770
|
+
R479 group-label text pin-gated cyan
|
|
4771
|
+
Hue: pal.legendAccent at 0x80 alpha (≈50%) — same
|
|
4772
|
+
accent family R107/R477 use for tint surfaces. 3px
|
|
4773
|
+
blur reads as a soft cyan halo around the locked
|
|
4774
|
+
cluster name. Stacks with the R432 letter-spacing
|
|
4775
|
+
spread + R457 fw lift + R63 fill brighten + R142
|
|
4776
|
+
drop-shadow on the parent rect — pin signature on
|
|
4777
|
+
group label scope now spans typography + chroma +
|
|
4778
|
+
paint + container-lift + text-glow.
|
|
4779
|
+
Filter is paint-only; bbox unchanged; overlap-test
|
|
4780
|
+
invariants hold (R51 selector gated to g[data-node]
|
|
4781
|
+
descendants, this label is invisible to the probe).
|
|
4782
|
+
transition list extends to include 'filter 200ms
|
|
4783
|
+
ease-out' alongside the existing fill/ls/fw/opacity
|
|
4784
|
+
200ms tweens. */
|
|
4785
|
+
data-group-label-glow={isPinned ? 'true' : 'false'}
|
|
4745
4786
|
style={{
|
|
4746
|
-
transition: 'fill 200ms ease-out, letter-spacing 200ms ease-out, font-weight 200ms ease-out, opacity 200ms ease-out',
|
|
4787
|
+
transition: 'fill 200ms ease-out, letter-spacing 200ms ease-out, font-weight 200ms ease-out, opacity 200ms ease-out, filter 200ms ease-out',
|
|
4747
4788
|
letterSpacing: isPinned ? '0.5px' :
|
|
4748
4789
|
isHovered ? '0.25px' : '0px',
|
|
4790
|
+
filter: isPinned
|
|
4791
|
+
? `drop-shadow(0 0 3px ${pal.legendAccent}80)`
|
|
4792
|
+
: undefined,
|
|
4749
4793
|
}}
|
|
4750
4794
|
data-group-label={box.key}
|
|
4751
4795
|
data-group-label-pinned={isPinned ? 'true' : 'false'}
|
|
@@ -5771,6 +5815,34 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
5771
5815
|
via the new -opacity-active attr; the
|
|
5772
5816
|
legacy -opacity-hover attr kept for R395
|
|
5773
5817
|
test compatibility. */}
|
|
5818
|
+
{/* Round 480 / Loop — 5th anchor in the drop-shadow
|
|
5819
|
+
visual-polish family. Gates on isHot (link.
|
|
5820
|
+
count >= 10, R129 hot-lane threshold) so the
|
|
5821
|
+
badge gets a warm-amber halo when its edge
|
|
5822
|
+
crosses the high-traffic boundary.
|
|
5823
|
+
Drop-shadow family ledger now:
|
|
5824
|
+
R476 hub digit hover-gated emerald
|
|
5825
|
+
R477 legend pin-ring pin-gated row.fill
|
|
5826
|
+
R478 freshness pip freshness-gated cyan
|
|
5827
|
+
R479 group label pin-gated cyan
|
|
5828
|
+
R480 edge badge hot-lane-gated amber ← this round
|
|
5829
|
+
5th gate type — traffic volume — joins hover,
|
|
5830
|
+
pin, freshness, pin. Each polish anchor uses
|
|
5831
|
+
a distinct semantic gate but the same paint
|
|
5832
|
+
vocabulary. Hue: hotStroke (amber-tinted
|
|
5833
|
+
palette member) at 0x80 alpha — picks up the
|
|
5834
|
+
R126/R188 hot-edge accent colour family so
|
|
5835
|
+
the glow reads as a chromatic extension of
|
|
5836
|
+
the existing hot-lane stroke. 3-px blur
|
|
5837
|
+
radius reads as soft heat rather than
|
|
5838
|
+
emergency klaxon.
|
|
5839
|
+
R51 sentinel safety: badge sw=2 only matters
|
|
5840
|
+
when the overlap probe runs on g[data-node]
|
|
5841
|
+
descendants, which this edge-internal badge
|
|
5842
|
+
is not. Filter is paint-only, bbox unchanged.
|
|
5843
|
+
transition list extends to include 'filter
|
|
5844
|
+
200ms ease-out' so the heat halo eases on
|
|
5845
|
+
the count-crosses-threshold flip. */}
|
|
5774
5846
|
<circle
|
|
5775
5847
|
cx={badgeX} cy={badgeY}
|
|
5776
5848
|
r={isHoveredEdge || isPinned ? 10.5 : 9}
|
|
@@ -5785,7 +5857,13 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
5785
5857
|
data-edge-badge-opacity-rest={isLight ? 0.95 : 0.85}
|
|
5786
5858
|
data-edge-badge-opacity-hover="1"
|
|
5787
5859
|
data-edge-badge-opacity-active="1"
|
|
5788
|
-
|
|
5860
|
+
data-edge-badge-glow={isHot ? 'true' : 'false'}
|
|
5861
|
+
style={{
|
|
5862
|
+
filter: isHot
|
|
5863
|
+
? `drop-shadow(0 0 3px ${hotStroke}80)`
|
|
5864
|
+
: undefined,
|
|
5865
|
+
transition: 'r 180ms ease-out, stroke 300ms ease-out, stroke-width 300ms ease-out, fill 200ms ease-out, opacity 200ms ease-out, filter 200ms ease-out',
|
|
5866
|
+
}}
|
|
5789
5867
|
/>
|
|
5790
5868
|
{/* Round 224 / Loop: edge badge text gains the 4th
|
|
5791
5869
|
pin-signature typography. Pre-R224 the digit
|
|
@@ -6284,15 +6362,45 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
6284
6362
|
/* Round 253 / Loop: append fill 200ms to the hub
|
|
6285
6363
|
digit transition list — theme toggle (cyber #ecfdf5
|
|
6286
6364
|
↔ light #d1fae5) was the last hub-area snap. */
|
|
6365
|
+
/* Round 476 / Loop — hub working-count digit gains a
|
|
6366
|
+
filter: drop-shadow glow on hub-hover. Stacks with
|
|
6367
|
+
the existing 4-axis hub-hover gesture stack on this
|
|
6368
|
+
element:
|
|
6369
|
+
R209 transform: scale(1.08) geometry
|
|
6370
|
+
R425 fontWeight 700 → 800 typography
|
|
6371
|
+
R253 fill ease-out chroma (theme)
|
|
6372
|
+
R213 opacity gate fade (count cross)
|
|
6373
|
+
R476 filter drop-shadow glow paint (this round)
|
|
6374
|
+
The glow uses the cyber emerald-400 (#34d399) /
|
|
6375
|
+
light emerald-500 (#10b981) hue family so the
|
|
6376
|
+
chroma stays inside the hub-area palette. Subtle
|
|
6377
|
+
2-3 px blur radius at 0.6 opacity — visible but
|
|
6378
|
+
not loud, reads as "the focal digit lit up under
|
|
6379
|
+
attention".
|
|
6380
|
+
Reduced-motion users skip the filter via the
|
|
6381
|
+
!reducedMotion gate (R29 a11y blanket).
|
|
6382
|
+
Filter is a paint-only attribute — bbox stays
|
|
6383
|
+
the same, R51 overlap-test invariants hold.
|
|
6384
|
+
transition list extends to 'filter 200ms ease-out'
|
|
6385
|
+
so the glow eases under the same cadence as the
|
|
6386
|
+
scale + fw + fill axes. */
|
|
6387
|
+
data-topo-hub-working-count-glow={!reducedMotion && hoveredHub ? 'true' : 'false'}
|
|
6287
6388
|
style={{
|
|
6288
6389
|
pointerEvents: 'none',
|
|
6289
6390
|
transform: !reducedMotion && hoveredHub ? 'scale(1.08)' : 'scale(1)',
|
|
6290
6391
|
transformBox: 'fill-box',
|
|
6291
6392
|
transformOrigin: 'center',
|
|
6393
|
+
filter: !reducedMotion && hoveredHub
|
|
6394
|
+
? (isLight
|
|
6395
|
+
? 'drop-shadow(0 0 2px rgba(16, 185, 129, 0.6))'
|
|
6396
|
+
: 'drop-shadow(0 0 3px rgba(52, 211, 153, 0.6))')
|
|
6397
|
+
: undefined,
|
|
6292
6398
|
/* R425: font-weight 200ms appended so the hover fw
|
|
6293
6399
|
bump 700 → 800 eases under the same cadence as
|
|
6294
|
-
R209 scale + R253 fill + R213 opacity.
|
|
6295
|
-
|
|
6400
|
+
R209 scale + R253 fill + R213 opacity.
|
|
6401
|
+
R476: filter 200ms appended so the new drop-
|
|
6402
|
+
shadow glow eases at the same cadence. */
|
|
6403
|
+
transition: 'transform 200ms ease-out, opacity 300ms ease-out, fill 200ms ease-out, font-weight 200ms ease-out, filter 200ms ease-out',
|
|
6296
6404
|
fontVariantNumeric: 'tabular-nums',
|
|
6297
6405
|
}}
|
|
6298
6406
|
>
|
|
@@ -8806,6 +8914,22 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
8806
8914
|
the chip-row pills. R116: pinned rows tint
|
|
8807
8915
|
stronger than hovered ones so locked vs preview
|
|
8808
8916
|
is discriminable. */}
|
|
8917
|
+
{/* Round 472 / Loop — cadence-sync follow-on to the
|
|
8918
|
+
R459/R460/R461/R464/R465/R470 200ms uniform
|
|
8919
|
+
motion stack established at the cluster scope.
|
|
8920
|
+
This R104 recent-signal row tint rect was still
|
|
8921
|
+
at the legacy 150ms cadence — when a user
|
|
8922
|
+
hovers/pins a recent-signal row, the tint
|
|
8923
|
+
snapped in 50ms ahead of the rest of the row's
|
|
8924
|
+
state-change cascade (R143 translateY,
|
|
8925
|
+
R220+R434 letter-spacing, R434 fill tween).
|
|
8926
|
+
R472 lifts to 200ms ease-out to match. Same
|
|
8927
|
+
sibling idiom R459 closed at the group-label
|
|
8928
|
+
hitbox tier; now applied at the recent-signal
|
|
8929
|
+
row tier. data-recent-row-tint-transition attr
|
|
8930
|
+
exposes the cadence for tests.
|
|
8931
|
+
Geometry/paint logic unchanged — purely the
|
|
8932
|
+
transition timing. */}
|
|
8809
8933
|
<rect
|
|
8810
8934
|
x="6" y={38 + index * 16 - 10}
|
|
8811
8935
|
width="218" height="14" rx="3"
|
|
@@ -8813,7 +8937,9 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
8813
8937
|
opacity={isRowPinned ? (isLight ? 0.18 : 0.22)
|
|
8814
8938
|
: isRowHovered ? (isLight ? 0.10 : 0.14)
|
|
8815
8939
|
: 1}
|
|
8816
|
-
|
|
8940
|
+
data-recent-row-tint={link.key}
|
|
8941
|
+
data-recent-row-tint-transition="200ms"
|
|
8942
|
+
style={{ transition: 'fill 200ms ease-out, opacity 200ms ease-out' }}
|
|
8817
8943
|
/>
|
|
8818
8944
|
{/* Round 160 / Loop: recency pip. Canvas flow edges
|
|
8819
8945
|
fade by freshness (R10: full intensity ≤30s →
|
|
@@ -8915,16 +9041,47 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
8915
9041
|
to include 'r 200ms ease-out' matching the
|
|
8916
9042
|
opacity cadence. data-recent-row-freshness-
|
|
8917
9043
|
lifted attr exposes the gate for tests. */
|
|
9044
|
+
/* Round 478 / Loop — extend the R476/R477
|
|
9045
|
+
drop-shadow vocabulary to a third anchor:
|
|
9046
|
+
the recent-row freshness pip on `alpha
|
|
9047
|
+
> 0.7` (just-fired flow within ~30s per
|
|
9048
|
+
R10 freshness ramp). Gate is FRESHNESS-
|
|
9049
|
+
driven not pin/hover-driven, so the glow
|
|
9050
|
+
reads as "this signal is live" rather
|
|
9051
|
+
than "user is inspecting". As the alpha
|
|
9052
|
+
decays past 0.7 (≈45s after last fire),
|
|
9053
|
+
the glow eases off — natural breathing
|
|
9054
|
+
feel that tracks actual data freshness.
|
|
9055
|
+
Hue: pal.legendAccent at 0.5 alpha so
|
|
9056
|
+
the glow inherits the row's accent color
|
|
9057
|
+
family. 2.5-3px blur reads as soft
|
|
9058
|
+
radiance, not loud bloom.
|
|
9059
|
+
Drop-shadow visual-polish family now 3
|
|
9060
|
+
anchors:
|
|
9061
|
+
R476 hub digit hover-gated
|
|
9062
|
+
R477 legend pin-ring pin-gated
|
|
9063
|
+
R478 recent freshness freshness-gated
|
|
9064
|
+
Each anchor uses a different state gate
|
|
9065
|
+
but the same `filter: drop-shadow` paint
|
|
9066
|
+
vocabulary. Filter affects paint only —
|
|
9067
|
+
bbox unchanged, overlap-test invariants
|
|
9068
|
+
hold. Transition list extends to include
|
|
9069
|
+
'filter 200ms ease-out' alongside
|
|
9070
|
+
R10/R447 opacity + r tweens. */
|
|
8918
9071
|
fill={pal.legendAccent}
|
|
8919
9072
|
opacity={alpha}
|
|
8920
9073
|
data-recent-row-freshness={link.key}
|
|
8921
9074
|
data-recent-row-freshness-alpha={alpha.toFixed(2)}
|
|
8922
9075
|
data-recent-row-freshness-radius={(isRowHovered || isRowPinned) ? 2.5 : 2.0}
|
|
8923
9076
|
data-recent-row-freshness-lifted={(isRowHovered || isRowPinned) ? 'true' : 'false'}
|
|
9077
|
+
data-recent-row-freshness-glow={alpha > 0.7 ? 'true' : 'false'}
|
|
8924
9078
|
style={{
|
|
8925
9079
|
pointerEvents: 'none',
|
|
8926
9080
|
r: `${(isRowHovered || isRowPinned) ? 2.5 : 2.0}px`,
|
|
8927
|
-
|
|
9081
|
+
filter: alpha > 0.7
|
|
9082
|
+
? `drop-shadow(0 0 3px ${pal.legendAccent}80)`
|
|
9083
|
+
: undefined,
|
|
9084
|
+
transition: 'opacity 200ms ease-out, r 200ms ease-out, filter 200ms ease-out',
|
|
8928
9085
|
} as React.CSSProperties}
|
|
8929
9086
|
/>
|
|
8930
9087
|
);
|
|
@@ -9009,8 +9166,25 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
9009
9166
|
R427/R431/R432/R433/R434. R55 fill 150ms +
|
|
9010
9167
|
R220 letter-spacing 150ms transition kept
|
|
9011
9168
|
(additive conditional case, no new property). */
|
|
9169
|
+
/* Round 474 / Loop — cadence-sync follow-on to
|
|
9170
|
+
R472. R472 lifted the recent-row TINT RECT
|
|
9171
|
+
to 200ms but the row TEXT alongside still
|
|
9172
|
+
ran 150ms — same panel-row scope, two
|
|
9173
|
+
different rates. When a user hovered/pinned
|
|
9174
|
+
a row the rect background brightened in
|
|
9175
|
+
200ms while the text fill + letter-spacing
|
|
9176
|
+
finished in 150ms. R474 closes that internal
|
|
9177
|
+
desync by lifting the text transitions to
|
|
9178
|
+
match. Whole recent-row state-flip now
|
|
9179
|
+
eases at 200ms ease-out across rect AND
|
|
9180
|
+
text. data-recent-row-text-transition='200ms'
|
|
9181
|
+
attr exposed for tests. R434 3-tier letter-
|
|
9182
|
+
spacing values unchanged; R363 fw + R55 fill
|
|
9183
|
+
brighten unchanged — only the timing axis
|
|
9184
|
+
shifts. */
|
|
9185
|
+
data-recent-row-text-transition="200ms"
|
|
9012
9186
|
style={{
|
|
9013
|
-
transition: 'fill
|
|
9187
|
+
transition: 'fill 200ms ease-out, letter-spacing 200ms ease-out',
|
|
9014
9188
|
letterSpacing: isRowPinned ? '0.5px' :
|
|
9015
9189
|
isRowHovered ? '0.25px' : '0px',
|
|
9016
9190
|
}}
|
|
@@ -9666,6 +9840,20 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
9666
9840
|
now ~1.25px below hitbox center (vs ~2.25px pre).
|
|
9667
9841
|
No height change, no test ripple (other than this
|
|
9668
9842
|
one), no R260/R268/R270 chrome regressions. */}
|
|
9843
|
+
{/* Round 473 / Loop — final cadence-sync follow-on,
|
|
9844
|
+
closing the legacy 150ms transition at the
|
|
9845
|
+
LEGEND-ROW tint scope. R459 (group-label hitbox)
|
|
9846
|
+
+ R472 (recent-row hitbox) already lifted the
|
|
9847
|
+
two sibling panel-row hitboxes to 200ms; the
|
|
9848
|
+
legend-row was the last per-row tint still
|
|
9849
|
+
snapping at 150ms.
|
|
9850
|
+
After R473 the 200ms ease-out vocabulary is
|
|
9851
|
+
uniform across ALL three panel-row scopes —
|
|
9852
|
+
group-label, recent-signal, and legend — so
|
|
9853
|
+
hover/pin state-change cascades read coherently
|
|
9854
|
+
at every panel-tier surface. data-legend-row-
|
|
9855
|
+
tint-transition='200ms' attr exposed for tests.
|
|
9856
|
+
Geometry/paint unchanged. */}
|
|
9669
9857
|
<rect
|
|
9670
9858
|
x="6" y={row.y0 - 11}
|
|
9671
9859
|
width="170" height="22" rx="3"
|
|
@@ -9674,7 +9862,8 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
9674
9862
|
: hoveredStatus === row.key ? (isLight ? 0.08 : 0.12)
|
|
9675
9863
|
: 1}
|
|
9676
9864
|
data-legend-row-tinted={isPinned ? 'pinned' : hoveredStatus === row.key ? 'hover' : 'none'}
|
|
9677
|
-
|
|
9865
|
+
data-legend-row-tint-transition="200ms"
|
|
9866
|
+
style={{ transition: 'fill 200ms ease-out, opacity 200ms ease-out' }}
|
|
9678
9867
|
/>
|
|
9679
9868
|
{/* Round 197 / Loop: swatch dot scales r 5.5 → 7 when its
|
|
9680
9869
|
row is hovered or pinned. Pre-R197 the swatch was a
|
|
@@ -9759,6 +9948,30 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
9759
9948
|
+ pointerEvents:none all preserved. data-legend-
|
|
9760
9949
|
pin-ring-stroke-width attr exposes the value for
|
|
9761
9950
|
tests. */}
|
|
9951
|
+
{/* Round 477 / Loop — legend pin-ring gains a filter:
|
|
9952
|
+
drop-shadow glow on isPinned. Extends R476's
|
|
9953
|
+
drop-shadow idiom from hub-digit (focal scope)
|
|
9954
|
+
to the legend-row pin-ring (sibling pin-state
|
|
9955
|
+
surface). When a status row is pinned, the
|
|
9956
|
+
concentric ring around the swatch now lights
|
|
9957
|
+
up with a colour-matched halo using row.fill,
|
|
9958
|
+
reinforcing "this filter is locked" via a
|
|
9959
|
+
glow layer above the R402 sw bump + R181
|
|
9960
|
+
opacity fade-in.
|
|
9961
|
+
Hue: row.fill at 0.55 alpha — picks up each
|
|
9962
|
+
status tier's signature colour (working green /
|
|
9963
|
+
idle teal / offline slate). 3px blur stays
|
|
9964
|
+
subtle but unmistakable when the row is locked.
|
|
9965
|
+
Reduced-motion users skip the filter via R29
|
|
9966
|
+
a11y blanket (transition-duration → 0.001ms
|
|
9967
|
+
so the glow appears/disappears instantly with
|
|
9968
|
+
pin toggle).
|
|
9969
|
+
Filter is paint-only — bbox unchanged, R51
|
|
9970
|
+
overlap-test gated to g[data-node] descendants
|
|
9971
|
+
so this legend-internal ring is invisible to
|
|
9972
|
+
the probe anyway. Transition list extends to
|
|
9973
|
+
include 'filter 200ms ease-out' so the glow
|
|
9974
|
+
eases under the same cadence as opacity. */}
|
|
9762
9975
|
<circle
|
|
9763
9976
|
cx="16" cy={row.y0} r="8"
|
|
9764
9977
|
fill="none"
|
|
@@ -9768,9 +9981,13 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
9768
9981
|
data-legend-pin-ring={row.key}
|
|
9769
9982
|
data-legend-pin-ring-pinned={isPinned ? 'true' : 'false'}
|
|
9770
9983
|
data-legend-pin-ring-stroke-width="1.75"
|
|
9984
|
+
data-legend-pin-ring-glow={isPinned ? 'true' : 'false'}
|
|
9771
9985
|
style={{
|
|
9772
9986
|
pointerEvents: 'none',
|
|
9773
|
-
|
|
9987
|
+
filter: isPinned
|
|
9988
|
+
? `drop-shadow(0 0 3px ${row.fill}88)`
|
|
9989
|
+
: undefined,
|
|
9990
|
+
transition: 'opacity 150ms ease-out, filter 200ms ease-out',
|
|
9774
9991
|
}}
|
|
9775
9992
|
/>
|
|
9776
9993
|
{/* Round 219 / Loop: legend row text gains the same
|
|
@@ -9845,8 +10062,24 @@ export function TopoGraph({ sessions, sseSessions, renameSignal }: TopoGraphProp
|
|
|
9845
10062
|
group-label R432, legend-row R433). R55 fill
|
|
9846
10063
|
150ms + R219 letter-spacing 150ms transition
|
|
9847
10064
|
untouched — additive conditional case. */
|
|
10065
|
+
/* Round 475 / Loop — final closure of the panel-row
|
|
10066
|
+
text scope cadence-sync. R473 lifted the legend-
|
|
10067
|
+
row TINT RECT to 200ms; R474 lifted the recent-
|
|
10068
|
+
row TEXT to 200ms; R475 closes the matching
|
|
10069
|
+
legend-row text desync — fill + letter-spacing
|
|
10070
|
+
both 150 → 200ms ease-out. After R475 the 3-tier
|
|
10071
|
+
panel-row cadence family is fully 200ms across
|
|
10072
|
+
BOTH rect and text at every panel-row scope
|
|
10073
|
+
(group-label / recent-row / legend-row). Hover/
|
|
10074
|
+
pin state-flip at any panel-row tier reads as
|
|
10075
|
+
one motion-coherent unit. data-legend-row-
|
|
10076
|
+
label-transition='200ms' attr exposed for tests.
|
|
10077
|
+
R433 3-tier letter-spacing values (0/0.25/0.5)
|
|
10078
|
+
unchanged; R55 fill brighten unchanged — only
|
|
10079
|
+
the timing axis shifts. */
|
|
10080
|
+
data-legend-row-label-transition="200ms"
|
|
9848
10081
|
style={{
|
|
9849
|
-
transition: 'fill
|
|
10082
|
+
transition: 'fill 200ms ease-out, letter-spacing 200ms ease-out',
|
|
9850
10083
|
letterSpacing: isPinned ? '0.5px' :
|
|
9851
10084
|
hoveredStatus === row.key ? '0.25px' : '0px',
|
|
9852
10085
|
}}
|
package/package.json
CHANGED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* Round 480 verification: edge badge circle gains filter: drop-
|
|
2
|
+
* shadow glow on isHot (link.count >= 10). 5th anchor in the
|
|
3
|
+
* R476/R477/R478/R479 drop-shadow family — first traffic-volume-
|
|
4
|
+
* gated variant.
|
|
5
|
+
*
|
|
6
|
+
* Contract:
|
|
7
|
+
* - cold edge (count < 10): data-edge-badge-glow='false' AND
|
|
8
|
+
* computed filter === 'none'
|
|
9
|
+
* - hot edge (count >= 10): glow='true' AND computed filter
|
|
10
|
+
* starts with 'drop-shadow' using hotStroke @ 0x80 alpha
|
|
11
|
+
* - source-file conditional wired
|
|
12
|
+
*/
|
|
13
|
+
import { chromium } from 'playwright';
|
|
14
|
+
import { readFileSync } from 'node:fs';
|
|
15
|
+
|
|
16
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
17
|
+
const nowIso = () => new Date().toISOString();
|
|
18
|
+
const sessionFresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
19
|
+
|
|
20
|
+
const browser = await chromium.launch({ headless: true });
|
|
21
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
22
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
23
|
+
await ctx.addInitScript(() => {
|
|
24
|
+
try {
|
|
25
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
26
|
+
localStorage.setItem('anet-topo-layout', 'ring');
|
|
27
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
28
|
+
} catch {}
|
|
29
|
+
});
|
|
30
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
31
|
+
const r = await route.fetch();
|
|
32
|
+
const b = await r.json();
|
|
33
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
34
|
+
const mk = (alias, status) => ({
|
|
35
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
36
|
+
network_id: nid, project_dir: null,
|
|
37
|
+
created_at: sessionFresh, updated_at: sessionFresh, last_seen_at: sessionFresh,
|
|
38
|
+
});
|
|
39
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
40
|
+
mk('a·1', 'working'), mk('a·2', 'idle'), mk('b·1', 'working'),
|
|
41
|
+
] } });
|
|
42
|
+
});
|
|
43
|
+
// Build messages: 12 from a·1 → a·2 (HOT, count=12 >= 10)
|
|
44
|
+
// 2 from b·1 → a·1 (cold, count=2 < 10)
|
|
45
|
+
const hotMessages = [];
|
|
46
|
+
for (let i = 0; i < 12; i++) {
|
|
47
|
+
hotMessages.push({
|
|
48
|
+
id: `hot-${i}`, from_alias: 'a·1', to_alias: 'a·2',
|
|
49
|
+
content: `m${i}`, created_at: nowIso(),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const coldMessages = [
|
|
53
|
+
{ id: 'c1', from_alias: 'b·1', to_alias: 'a·1', content: 'c1', created_at: nowIso() },
|
|
54
|
+
{ id: 'c2', from_alias: 'b·1', to_alias: 'a·1', content: 'c2', created_at: nowIso() },
|
|
55
|
+
];
|
|
56
|
+
await ctx.route('**/api/hub/messages*', (route) => route.fulfill({ json: {
|
|
57
|
+
messages: [...hotMessages, ...coldMessages],
|
|
58
|
+
} }));
|
|
59
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
60
|
+
|
|
61
|
+
const page = await ctx.newPage();
|
|
62
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
63
|
+
await page.waitForSelector('[data-edge-badge-glow]', { timeout: 15000 });
|
|
64
|
+
await page.waitForTimeout(500);
|
|
65
|
+
|
|
66
|
+
const probe = await page.evaluate(() => {
|
|
67
|
+
const badges = [...document.querySelectorAll('[data-edge-badge-glow]')];
|
|
68
|
+
return badges.map(b => {
|
|
69
|
+
const cs = getComputedStyle(b);
|
|
70
|
+
return {
|
|
71
|
+
glow: b.getAttribute('data-edge-badge-glow'),
|
|
72
|
+
filter: cs.filter,
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
78
|
+
const sourceGlowAttr = /data-edge-badge-glow=\{isHot/.test(src);
|
|
79
|
+
const sourceDropShadow = /drop-shadow\(0 0 3px \$\{hotStroke\}80\)/.test(src);
|
|
80
|
+
const sourceFilterTween = /filter 200ms ease-out/.test(src);
|
|
81
|
+
|
|
82
|
+
await browser.close();
|
|
83
|
+
|
|
84
|
+
const hot = probe.find(b => b.glow === 'true');
|
|
85
|
+
const cold = probe.find(b => b.glow === 'false');
|
|
86
|
+
|
|
87
|
+
const results = {
|
|
88
|
+
badges_count_ge_2: probe.length >= 2,
|
|
89
|
+
hot_badge_found: !!hot,
|
|
90
|
+
hot_filter_has_drop: hot && /drop-shadow/.test(hot.filter),
|
|
91
|
+
cold_badge_found: !!cold,
|
|
92
|
+
cold_filter_none: cold?.filter === 'none',
|
|
93
|
+
source_glow_attr: sourceGlowAttr,
|
|
94
|
+
source_drop_shadow: sourceDropShadow,
|
|
95
|
+
source_filter_tween: sourceFilterTween,
|
|
96
|
+
};
|
|
97
|
+
const ok = Object.values(results).every(Boolean);
|
|
98
|
+
console.log(`${ok ? '✅' : '❌'} edge badge hot-lane drop-shadow:`, JSON.stringify(results),
|
|
99
|
+
'\n hot badge:', JSON.stringify(hot),
|
|
100
|
+
'\n cold badge:', JSON.stringify(cold));
|
|
101
|
+
process.exit(ok ? 0 : 1);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* Round 479 verification: group-label parent text gains filter:
|
|
2
|
+
* drop-shadow glow on isPinned. 4th anchor in the R476/R477/R478
|
|
3
|
+
* drop-shadow visual-polish family.
|
|
4
|
+
*
|
|
5
|
+
* Contract:
|
|
6
|
+
* - at rest (no group pinned): every group label has data-group-
|
|
7
|
+
* label-glow='false' AND computed filter === 'none'
|
|
8
|
+
* - click a group-label hitbox: that group's label flips to
|
|
9
|
+
* glow='true' + filter starts with 'drop-shadow' using
|
|
10
|
+
* pal.legendAccent at 0x80 alpha
|
|
11
|
+
* - sibling group labels stay rest (no spillover)
|
|
12
|
+
* - source-file conditional wired
|
|
13
|
+
*/
|
|
14
|
+
import { chromium } from 'playwright';
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
|
|
17
|
+
const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
|
|
18
|
+
const fresh = new Date(Date.now() - 60 * 1000).toISOString();
|
|
19
|
+
|
|
20
|
+
const browser = await chromium.launch({ headless: true });
|
|
21
|
+
const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
|
|
22
|
+
await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
|
|
23
|
+
await ctx.addInitScript(() => {
|
|
24
|
+
try {
|
|
25
|
+
localStorage.setItem('anet-theme', 'cyber');
|
|
26
|
+
localStorage.setItem('anet-topo-layout', 'grid');
|
|
27
|
+
sessionStorage.setItem('anet_v3_auth', '1');
|
|
28
|
+
} catch {}
|
|
29
|
+
});
|
|
30
|
+
await ctx.route('**/api/hub/status*', async (route) => {
|
|
31
|
+
const r = await route.fetch();
|
|
32
|
+
const b = await r.json();
|
|
33
|
+
const nid = (b.sessions || [])[0]?.network_id || 'default';
|
|
34
|
+
const mk = (alias, status) => ({
|
|
35
|
+
alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
|
|
36
|
+
network_id: nid, project_dir: null,
|
|
37
|
+
created_at: fresh, updated_at: fresh, last_seen_at: fresh,
|
|
38
|
+
});
|
|
39
|
+
await route.fulfill({ response: r, json: { ...b, sessions: [
|
|
40
|
+
mk('alpha·1', 'working'), mk('alpha·2', 'idle'),
|
|
41
|
+
mk('beta·1', 'working'), mk('beta·2', 'idle'),
|
|
42
|
+
] } });
|
|
43
|
+
});
|
|
44
|
+
await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
|
|
45
|
+
await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
|
|
46
|
+
|
|
47
|
+
const page = await ctx.newPage();
|
|
48
|
+
await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
|
|
49
|
+
await page.waitForSelector('[data-group-label-glow]', { timeout: 15000 });
|
|
50
|
+
await page.waitForTimeout(500);
|
|
51
|
+
|
|
52
|
+
const readAll = () => page.evaluate(() => {
|
|
53
|
+
const labels = [...document.querySelectorAll('[data-group-label-glow]')];
|
|
54
|
+
return labels.map(l => {
|
|
55
|
+
const cs = getComputedStyle(l);
|
|
56
|
+
return {
|
|
57
|
+
key: l.getAttribute('data-group-label'),
|
|
58
|
+
glow: l.getAttribute('data-group-label-glow'),
|
|
59
|
+
filter: cs.filter,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const rest = await readAll();
|
|
65
|
+
const firstKey = rest[0]?.key;
|
|
66
|
+
|
|
67
|
+
// Click hitbox to pin the first group
|
|
68
|
+
let pinned = null;
|
|
69
|
+
if (firstKey) {
|
|
70
|
+
const hit = await page.$(`[data-group-label-hit="${firstKey}"]`);
|
|
71
|
+
if (hit) {
|
|
72
|
+
await hit.click();
|
|
73
|
+
await page.waitForTimeout(400);
|
|
74
|
+
pinned = await readAll();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
|
|
79
|
+
const sourceGlowAttr = /data-group-label-glow=\{isPinned/.test(src);
|
|
80
|
+
const sourceDropShadow = /drop-shadow\(0 0 3px \$\{pal\.legendAccent\}80\)/.test(src);
|
|
81
|
+
|
|
82
|
+
await browser.close();
|
|
83
|
+
|
|
84
|
+
const restCount = rest.length;
|
|
85
|
+
const restAllFalse = rest.every(r => r.glow === 'false' && r.filter === 'none');
|
|
86
|
+
const pinnedTarget = pinned?.find(r => r.key === firstKey);
|
|
87
|
+
const pinTargetGlow = pinnedTarget?.glow === 'true';
|
|
88
|
+
const pinTargetHasShadow = pinnedTarget && /drop-shadow/.test(pinnedTarget.filter);
|
|
89
|
+
const pinSiblingsStill = pinned ? pinned.filter(r => r.key !== firstKey).every(r => r.glow === 'false') : false;
|
|
90
|
+
|
|
91
|
+
const results = {
|
|
92
|
+
rest_count_ge_2: restCount >= 2,
|
|
93
|
+
rest_all_false: restAllFalse,
|
|
94
|
+
pinned_target_glow: pinTargetGlow,
|
|
95
|
+
pinned_target_shadow: pinTargetHasShadow,
|
|
96
|
+
pinned_siblings_rest: pinSiblingsStill,
|
|
97
|
+
source_glow_attr: sourceGlowAttr,
|
|
98
|
+
source_drop_shadow: sourceDropShadow,
|
|
99
|
+
};
|
|
100
|
+
const ok = Object.values(results).every(Boolean);
|
|
101
|
+
console.log(`${ok ? '✅' : '❌'} group-label drop-shadow glow:`, JSON.stringify(results),
|
|
102
|
+
'\n rest:', JSON.stringify(rest),
|
|
103
|
+
'\n pinned target:', JSON.stringify(pinnedTarget));
|
|
104
|
+
process.exit(ok ? 0 : 1);
|