mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-07-13 03:18:58 +00:00
fb6bb085a5
Fixes #1657
## Bug
On `/analytics` → **Channels** tab, the "Channel Activity" table's
group-header rows ("My Channels", "Network", "Encrypted") rendered
literal HTML source text:
```
<SVG CLASS="PH-ICON" ARIA-HIDDEN="TRUE"><USE HREF="/ICONS/PHOSPHOR-SPRITE.SVG#PH-KEY"/></SVG> My Channels
```
instead of the actual Phosphor sprites. Per-row encrypted/lock icons
rendered fine — the bug was isolated to the group-header render path.
## Root cause
`public/analytics.js` `channelTbodyHtml` builds each group-section
header by wrapping the section label in `esc()`:
```js
esc(sections[si].label) + ' <span class="text-muted">(' + rows.length + ')</span>'
```
But the labels (`sections[].label`) are hardcoded sprite-bearing
strings:
```js
{ key: 'mine', label: '<svg class="ph-icon" aria-hidden="true"><use href="…#ph-key"/></svg> My Channels' },
```
`esc()` HTML-encoded the `<` / `>` so the browser displayed the source
text rather than rendering the sprite. Affects all 3 groups (and any
future group with a sprite).
## Fix
Drop the `esc()` wrap on the hardcoded label (single line change, same
pattern as M3 commit 4ca73ced for mobile channel avatars). The
`(<count>)` suffix is numeric and was always safe.
## Tests
New `test-issue-1657-analytics-channels-group-sprites-e2e.js` (mobile
375 viewport, matching the bug report):
- (1) at least one group-header row renders
- (2) every header row contains a real `<svg.ph-icon>` child
- (3) per-group sprite refs resolve (My Channels → `#ph-key`, Network →
`#ph-radio`, Encrypted → `#ph-lock`)
- (4) the Channel Activity table's `innerText` contains no literal
`<svg` substring (escape-leak gate)
Wired into the CI E2E lane (`.github/workflows/deploy.yml`) immediately
after the M4 icons E2E.
## TDD evidence
- Red commit: `8f8781c1` — test + CI wiring only, no production change.
Test asserts behavior that did not exist on master → CI fails on this
commit.
- Green commit: `8385fa54` — 1-line fix to `public/analytics.js`. Test
passes.
## Anti-tautology proof
Hot-patched staging with the `analytics.js` from the red commit
(pre-fix), reloaded `/analytics?tab=channels` at 375 viewport, and the
in-browser DOM probe returned:
```
headers[0].text = "<svg class=\"ph-icon\" aria-hidden=\"true\"><use href=\"/icons/phosphor-sprite.svg#ph…"
headers[0].svgs = 0 // (2) would fail
headers[1].svgs = 0 // (2) would fail
literalSvg = true // (4) would fail
```
Restored the fixed file; same probe returned `svgs=1`, correct `uses[]`
refs, `literalSvg=false`.
## Staging verification
Hot-patched `corescope-staging-go:/app/public/analytics.js` (no restart
needed — static file). Mobile dark @ 375 viewport shows Network → radio
sprite and Encrypted → lock sprite rendering correctly. (My Channels
group not present because the e2e fixture has no `mine`-tagged channels
— expected; the test skips that assertion when the row is absent.)
## Scope discipline
Touched only:
- `public/analytics.js` (1-line `esc()` removal + comment)
- `test-issue-1657-…-e2e.js` (new)
- `.github/workflows/deploy.yml` (1-line E2E wire)
No broadening, no helper renames, no related-but-different
escape-removal opportunism.
---------
Co-authored-by: openclaw-bot <bot@openclaw.local>