From 92df28a569db4ebfd56b3bfad4aa1ae083da5650 Mon Sep 17 00:00:00 2001 From: Kpa-clawbot Date: Sat, 23 May 2026 20:54:03 -0700 Subject: [PATCH] fix(touch-gestures): stamp data-hash on Trace and Filter buttons (#1305) (#1332) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Row-overlay Trace and Filter buttons silently did nothing on touch swipes. `ensureRowOverlay` stamped `data-hash` only on the Copy button, while `onClickAction` gates both `trace` and `filter` navigation on `hash && ...` — so the click handler short-circuited before `location.hash` was set. Users saw the buttons but tapping them was a no-op. ## Fix `public/touch-gestures.js` — in `ensureRowOverlay`, stamp `data-hash` on all three buttons (Trace, Filter, Copy) from the same source the Copy button already used (`row.getAttribute('data-hash') || row.getAttribute('data-id')`). One-line factoring of the attribute fragment to avoid duplicating the escape logic. Behavior after fix: - Trace → `#/packets/` - Filter → `#/packets?hash=` - Copy → clipboard (unchanged) All three match the existing branches in `onClickAction`. ## TDD - **RED commit** (`dd90f72c`): removes the cov1/cov2 workaround in `test-touch-gestures-coverage-e2e.js` that artificially stamped `data-hash` on trace/filter buttons from the test harness. With this commit alone, cov1/cov2 fail their `location.hash` assertions because `onClickAction`'s guard short-circuits. - **GREEN commit** (`a526c30f`): production fix in `ensureRowOverlay`. cov1/cov2 now pass natively against the real production code path with no harness-side stamping. ## Browser verified Coverage E2E (`test-touch-gestures-coverage-e2e.js`) exercises the real swipe → overlay → button-click → navigation path in headless Chromium against the running server. cov1 asserts `location.hash === #/packets/`, cov2 asserts `location.hash === #/packets?hash=` — these assertions are the regression gate. E2E assertion added: test-touch-gestures-coverage-e2e.js:227 (cov1 trace) and test-touch-gestures-coverage-e2e.js:259 (cov2 filter). ## Preflight All hard gates and warnings pass. Fixes #1305 --------- Co-authored-by: openclaw --- public/touch-gestures.js | 8 ++++---- test-touch-gestures-coverage-e2e.js | 22 +++++++++------------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/public/touch-gestures.js b/public/touch-gestures.js index 96d0b3e6..a61ad64f 100644 --- a/public/touch-gestures.js +++ b/public/touch-gestures.js @@ -157,11 +157,11 @@ o.setAttribute('role', 'group'); o.setAttribute('aria-label', 'Row actions'); var hash = row.getAttribute('data-hash') || row.getAttribute('data-id') || ''; + var hashAttr = ' data-hash="' + String(hash).replace(/"/g, '"') + '"'; o.innerHTML = - '' + - '' + - ''; + '' + + '' + + ''; document.body.appendChild(o); rowOverlay = o; return o; diff --git a/test-touch-gestures-coverage-e2e.js b/test-touch-gestures-coverage-e2e.js index c36a01e3..763d8660 100644 --- a/test-touch-gestures-coverage-e2e.js +++ b/test-touch-gestures-coverage-e2e.js @@ -208,14 +208,12 @@ async function main() { if (!overlayPresent) { fail('(cov1) precondition — overlay did not appear after left swipe'); } else { - await page.evaluate((h) => { + await page.evaluate(() => { + // Production stamps data-hash on trace/filter/copy buttons natively + // (issue #1305). Just click — no test-side workaround needed. const btn = document.querySelector('.row-action-overlay [data-row-action="trace"]'); - // Production only sets data-hash on the copy button; for the - // trace/filter branch in onClickAction to navigate, the button - // must carry data-hash. Stamp it here from the row's hash so - // the coverage test exercises the real navigation path. - if (btn) { btn.setAttribute('data-hash', h); btn.click(); } - }, r.hash); + if (btn) { btn.click(); } + }); await page.waitForTimeout(120); const state = await page.evaluate(() => ({ hash: location.hash, @@ -241,13 +239,11 @@ async function main() { if (!ok) { fail('(cov2) precondition — filter button not in overlay'); } else { - await page.evaluate((h) => { + await page.evaluate(() => { + // Production stamps data-hash on filter button natively (#1305). const btn = document.querySelector('.row-action-overlay [data-row-action="filter"]'); - // Same as cov1: production stamps data-hash only on the copy - // button. Stamp it on filter here so onClickAction's hash - // guard passes and we exercise the real navigation branch. - if (btn) { btn.setAttribute('data-hash', h); btn.click(); } - }, r2.hash); + if (btn) { btn.click(); } + }); await page.waitForTimeout(120); const state = await page.evaluate(() => ({ hash: location.hash,