Automations and webhooks for the AT Protocol airglow.run

fix(form): show the watched repos block before a lexicon is picked #87

Closed tyb.there-hugo.dev
Closed opened by tyb.there-hugo.dev

Follow-up to #22.

Problem #

#22 asked to always show the Watched repos block. The branch shows it for every valid lexicon NSID, so on a new automation the block is still hidden until an NSID is typed in full. Users who scan the form before picking a lexicon still don't know it exists, which was the problem #22 set out to fix.

Evidence #

  • app/islands/AutomationForm.tsx:3210: the Watched repos fieldset is wrapped in {isValidNsid(lexicon) && (…)}.
  • The same gate hides the "Fires when anyone writes a record…" hint at AutomationForm.tsx:3192.
  • Seen on the New automation page: an empty Lexicon NSID shows only Trigger events under it; typing site.standard.document makes the hint, the Watched repos block and its alert appear at once, pushing the rest of the form down.

Expected #

  • The Watched repos block is always in the form, empty NSID included, as "(optional)" with the "all repos" default.
  • Before a valid NSID, the wording that names the NSID falls back to something generic (e.g. "Watching all repos: a matching record written by anyone triggers this automation."). The "(required)" state and its NSID-specific line still switch on once the NSID is known to need watched repos.
  • The layout doesn't jump when the NSID becomes valid: only text inside the block changes.
  • Watched repos entered before the NSID are kept when it is picked or changed.

Acceptance criteria #

Out of scope #

Whether the "Fires when anyone writes a record…" hint should also show before an NSID: leave it as it is unless it needs to move for the layout to stay stable.

Queued: the loop will work on this version of the issue.

loop:queued cid=bafyreiehdgt27ww3lqqw6uno6tswwx4dkvfe27uqjzyfazi42vcok55fwq

Working on this, attempt 1.

loop:claim run=contribute-20261102-213520-87 branch=loop/87 attempt=1 issue=87

fix(form): show the watched repos block before a lexicon is picked

The Watched repos fieldset on the automation form is no longer gated on a valid Lexicon NSID, so a blank New automation form shows it with its {{self}} explanation, the "+ Watch my DID" / "+ Add DID" buttons and the "all repos" default. Until the NSID is valid, the all-repos notice reads "a matching record" instead of naming the NSID, and the "(required)" state only switches on for a complete NSID that matches a gated glob, so a half-typed prefix like app.bsky can't flip it.

Verified #

  • pnpm run check and pnpm run test pass (185 files, 2852 tests).
  • New tests in AutomationForm.test.tsx ("AutomationForm watched repos"): blank form with a gated glob configured; typing a prefix (app.bsky), then a gated NSID (app.bsky.feed.post); the notice naming a valid, ungated NSID; watched repos entered before the NSID kept across picking and then changing it. With the component change stashed, the blank-form test and the kept-repos test fail.

Acceptance criteria #

What each state shows #

  • Empty or invalid NSID: "Watched repos (optional)", the {{self}} explanation, the low-volume event.did hint, the info notice "Watching all repos: a matching record written by anyone triggers this automation. Add a repo to react to those accounts only.", and the two add buttons. No NSID text anywhere in the block.
  • Valid, ungated NSID: the same, but the notice names the NSID ("a at.example.thing record written by anyone...").
  • Valid, gated NSID: "(required)", "This NSID (...) requires at least one watched repo on this instance.", and no all-repos notice.
  • Watched repos entered: the all-repos notice goes away and the rows show in every state. Picking or changing the NSID doesn't clear them. The conflict warning works as before.

No new controls, so keyboard use and focus are unchanged.

Decisions you can reverse #

  • The "Fires when anyone writes a record in this collection..." hint under the Lexicon field is still shown only for a valid NSID, as the issue's out-of-scope note asks. When it appears it still pushes the block down by one hint. Everything else that changes on validation is text inside the block. If you want no shift at all, showing that hint always (it doesn't name the NSID) would do it.
  • "(required)" now also needs isValidNsid(lexicon), not just a glob match. Before, the block was hidden for any invalid NSID, so the visible result is the same.

Review: https://tangled.org/exosphere.site/airglow/compare/main...loop/87

loop:pushed run=contribute-20261102-213520-87 sha=26fbfc31f962b7559922193aa38e7511040ddcbc

Verdict: merge. The branch takes the isValidNsid(lexicon) gate off the Watched repos fieldset, so a blank New automation form shows the block with "(optional)", the {{self}} explanation and both add buttons. Until the NSID is valid, the all-repos notice says "a matching record". "(required)" now turns on only for a complete NSID that matches a gated glob. This covers every acceptance criterion and follows the "Conditional sections" rule in docs/design.md.

What I checked:

  • I read the whole diff against the issue. wantedDidsRequired is read only in this block's render. Adding the isValidNsid guard changes nothing visible on the edit or duplicate pages, where the lexicon is always valid. The server still enforces the gate on its own (lib/actions/validation.ts, resolveWantedDids). Nothing in the form clears wantedDids when the lexicon changes, so repos entered before the NSID are kept, and the new test confirms it.
  • Every other isValidNsid( and "Watched repos" place in app/ and lib/: the only remaining gate in the form is the "Fires when anyone writes..." hint under the Lexicon field, which the issue leaves out of scope. The detail page's "Watched repos" <dt> is not part of this issue.
  • With no valid NSID, nothing in the block shows the NSID. The only places that print {lexicon} are the gated line, which needs a valid NSID now, and the notice, which has its own isValidNsid check.
  • pnpm run check passes. pnpm run test passes: 185 files, 2852 tests. The new tests in "AutomationForm watched repos" cover the blank form, a gated prefix (app.bsky) staying optional, the full gated NSID turning it required, a valid ungated NSID being named, and repos kept across picking and then changing the NSID.
  • I added a throwaway test, since deleted, that server-renders a blank New form (no initial, nsidRequireDids: ["app.bsky.*"]). The SSR markup includes the Watched repos fieldset with "(optional)" and "+ Watch my DID", so the block is there before hydration too.
  • The branch adds no new controls and no new styles. The existing buttons keep their names and keyboard behaviour. The alertInfo style is listed as known debt in design.md and isn't this branch's to clear.

loop:verdict run=review-20261102-214248-87 sha=26fbfc31f962b7559922193aa38e7511040ddcbc verdict=merge

Merged onto main as 75d3c9ed963b73158b034edfb57b879e38c54ee0.

loop:merged sha=75d3c9ed963b73158b034edfb57b879e38c54ee0 head=26fbfc31f962b7559922193aa38e7511040ddcbc

Sign up or Sign in to add to the discussion.