Skip to content

v1.3.36.4 -- Capture: host-row trigger fix

A bugfix on top of v1.3.36.3. The host-form modal still didn't capture correctly post-v1.3.36.3 because the spec was clicking a <tr> element with no onClick handler — the v1.3.36.3 modal-visibility wait worked perfectly but had nothing to wait for.

argosVersion and frontend/package.json deliberately stay at 1.3.35.4 (tooling-only). scripts/capture/package.json bumps 1.3.36.31.3.36.4.

Why

PHASE 0 source-code investigation of Hosts.tsx:

<tr key={h.id} className="border-t border-slate-800">
  ...cells...
  <td>
    <IconButton label="edit" onClick={() => openEdit(h)}>
      <Pencil className="w-4 h-4" />
    </IconButton>
  </td>
</tr>

The <tr> has no onClick. The modal opens via the <IconButton label="edit"> which renders as <button aria-label="edit" title="edit"> (per IconButton at Hosts.tsx:676-700). v1.3.36.x clicked the row → the click bubbled up unhandled → setModalOpen(true) never fired → waitForSelector('.fixed.inset-0.z-40') correctly timed out at 5 s because the modal genuinely was not in the DOM.

The v1.3.36.3 modal-visibility wait was correct in concept but irrelevant in practice — it was waiting for an element React never rendered.

  • Modal.tsx is a plain function component (no framer-motion, no React.createPortal, no opacity transitions).
  • if (!open) return null; — overlay isn't in the DOM until open flips to true; at that moment the entire subtree paints synchronously.
  • .fixed.inset-0.z-40 IS the correct overlay selector.
  • The 400 ms animation-settle in openModal() is harmless (no animation in practice) and remains for future-proofing in case the panel adds CSS transitions later.

Fix

Three call sites in capture.spec.js updated to scope the click to the IconButton instead of the row:

Line Test Before After
159 host-form table tbody tr:first-child table tbody tr:first-child button[aria-label="edit"]
175 host-form-dns-provider-dropdown (first openModal) table tbody tr:first-child table tbody tr:first-child button[aria-label="edit"]
235 host-form-true-detect table tbody tr:has(span:has-text("DETECT")) table tbody tr:has(span:has-text("DETECT")) button[aria-label="edit"]

The selector chains the row scope (first row, or the row with the DETECT badge) with the specific edit-trigger button via Playwright's :has-text and descendant combinator. aria-label is set programmatically by IconButton from its label prop (Hosts.tsx:691), so the selector is stable unless the IconButton component itself is refactored.

The DNS-01 radio click in test 6 (second openModal call) is unchanged — it's an in-modal form-state click, not a new modal-open.

The safeHover on the security-scenarios row (test 15) is unchanged — hovers don't depend on onClick handlers, and the row hover is what surfaces the description tooltip via React state.

The target-group-form selector (Add target group) is unchanged — that surface uses a direct button, not row delegation, and v1.3.36.3 already fixed it.

Smoke phase 11

scripts/smoke/capture-automation.sh gains two new asserts:

11. host-row triggers click button[aria-label="edit"]:
    - active-code 'tr ... button[aria-label="edit"]' occurrences: 3
    - PASS: 3 call sites click the edit-trigger button (not the row)
    - synthetic verify: Hosts.tsx IconButton renders aria-label={label}
      AND <IconButton label="edit"> exists -- so aria-label resolves
      to "edit" at runtime; selector is stable.

The synthetic verify reads frontend/src/pages/Hosts.tsx directly to confirm: 1. The IconButton component still has aria-label={label} in its <button> JSX. 2. The hosts list still has at least one <IconButton label="edit".

If either fails, the selector is broken and phase 11 fails loudly — saving an operator a 5s timeout per host capture.

Smoke result post-fix

phase 1:  run.sh refuses without .env...                     PASS
phase 2:  .env is git check-ignore'd...                      PASS
phase 3:  .env.example placeholders only...                  PASS
phase 4:  safeClick synthetic test...                        PASS (13/13)
phase 5:  working tree unchanged by smoke...                 PASS
phase 6:  storageState wiring (v1.3.36.1)...                 PASS (5/5)
phase 7:  banner output uses fs.readFileSync...              PASS
phase 8:  viewport 1440x1080 + shotFullScroll...             PASS
phase 9:  waitForSettled helper (timing fix)...              PASS (5/5)
phase 10: openModal modal-visibility wait + TG selector...   PASS (6/6)
phase 11: host-row triggers click button[aria-label=edit]... PASS (2/2)

scripts/check-no-personal-data.sh clean. mkdocs build --strict clean.

Files changed

  • scripts/capture/capture.spec.js — 3 trigger selectors scoped to button[aria-label="edit"]; comments document the v1.3.36.3 click-no-op failure mode.
  • scripts/capture/package.json1.3.36.31.3.36.4.
  • scripts/smoke/capture-automation.sh — phase 11 added.
  • docs/release-notes/v1.3.36.4.md — this file.
  • CHANGELOG.md, mkdocs.yml.

NOT changed: argosVersion stays at 1.3.35.4; frontend/package.json version stays at 1.3.35.4. No Go code; no frontend code; no panel binary change.

Operator workflow post-fix

cd ~/argos-edge && git pull
scripts/capture/run.sh

# Verify three things:
# 1. host-form.png shows the EDIT MODAL (form fields visible
#    with dark scrim) — NOT the hosts list table behind a
#    background.
# 2. host-form-dns-provider-dropdown.png shows the same modal
#    with DNS-01 radio selected and DNSProviderPicker rendered
#    below the radios.
# 3. No regression on other surfaces (target-group-form,
#    totp-setup, etc. unchanged from v1.3.36.3).

The mid-impl smoke fixed an overreach in the proposed phase 11b ("no bare 'tr:first-child' selectors anywhere") — the security-scenarios test legitimately uses bare row selectors for safeHover (the row hover surfaces the description tooltip and doesn't need a click trigger). Removed the overreach; the affirmative count + synthetic verify cover what matters.

Versioning

scripts/capture/package.json 1.3.36.31.3.36.4. Tag-without-rebuild precedent for tooling-only patches: v1.3.27.1, v1.3.34, v1.3.35.1, v1.3.35.5.