Automations and webhooks for the AT Protocol airglow.run

New steps always append, and reordering is drag-only #19

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

Problem #

  • addStep (AutomationForm.tsx:866) always appends, so a condition added after an action lands below it.
  • Reordering is drag-only.
  • The left/right arrows are indent/outdent and are greyed out at the top level, so they look like broken move buttons (AutomationForm.tsx:2510-2561).

Seen in the session #

In https://www.youtube.com/watch?v=5MnT-ZgbBIc:

  • 0:35 and 0:40: the condition ends up after the action.
  • 1:23:30: "Condition first, please."

Fix direction #

Add move up/down controls, allow inserting a step between existing ones, and make the indent arrows read as indent controls.

Details: docs/brainstorms/2026-10-17-graze-conference-automation-feedback.md (U3).

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

loop:queued cid=bafyreia3tv34hjv2ecuiginemds6afzmg2dneygds2nhznptjwcliymabu

Working on this, attempt 1.

loop:claim run=contribute-20261026-152048-3my32g62syv22 branch=loop/3my32g62syv22 attempt=1 issue=19

feat(automations): move steps up/down, insert between steps, clearer indent controls

Each step card in the automation form now has Move up and Move down buttons, so you no longer have to drag to reorder. A muted "Insert step here" control sits above every step and opens the usual step picker, so a condition can go in front of an action instead of always landing at the end. The indent and outdent buttons now use list-indent icons, and they only show up where they can do something (indent after a branch or loop, outdent inside one), so they no longer look like broken move buttons that are greyed out at the top level.

What changed #

  • app/islands/step-drafts/tree.ts: new insertIntoContainer(drafts, key, index, draft), which clamps the index to the list's ends. Up/down reuse the existing moveWithinContainer.
  • app/islands/AutomationForm.tsx: addStep/addActionStep take an optional insert index. renderAddControl takes an optional insertAt: closed, it is a slim button, and open, it is the same picker. Its open state is keyed "<container>@<index>", so only one picker is open at a time. renderStep gets the step's siblings for the up/down limits and to decide whether to show indent.
  • app/icons.ts: ArrowUp, ArrowDown, ListIndentDecrease, ListIndentIncrease (lucide).
  • AutomationForm.css.ts: an insertStepBtn style.

Verification #

  • pnpm run check passes.
  • pnpm run test passes: 167 files, 2605 tests.
  • New tests:
    • step-drafts/tree.test.ts: insert at an index, insert clamped, insert nested, move up/down, a move past the ends is a no-op.
    • AutomationForm.test.tsx:
      • up/down reorder the payload, and the first/last buttons are disabled;
      • "Insert step here" above the only step puts a new Condition first;
      • two top-level steps show no indent/outdent buttons.
  • The existing indent/outdent test still passes. The buttons keep the Indent step/Outdent step aria-labels, and the title explains what each one does.
  • I did not check this in a browser: the run has no dev server or PDS. Please look at the spacing of the insert controls in a long list.

Acceptance criteria #

Decisions the owner can reverse #

  • Insert controls show above every step, including the first, and are always visible but muted. The other option was to show them only on hover or focus, which is harder to discover.
  • Indent/outdent buttons are hidden, not disabled, where they can never apply. Indent still shows disabled, with the reason in its title, when the step above is a branch or loop but the depth cap blocks it.
  • Up/down move a step only within its own list, like drag does. Moving between levels is still done with indent/outdent.
  • When the step cap is reached, the insert controls are hidden. The cap hint on the end-of-list "Add step" box still explains why.

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

loop:pushed run=contribute-20261026-152048-3my32g62syv22 sha=a57656b651cd6133153086bc3c2ea4dbd99a2300

Merge. The branch covers all three parts of issue #19. Each step now has Move up and Move down buttons. An "Insert step here" control above every step opens the same picker and places the new step at that index, so a condition can go before an action. The indent and outdent controls now use list-indent icons and only show where they can apply, so they no longer look like greyed-out move buttons. pnpm run check and pnpm run test (167 files, 2605 tests) both pass on a57656b.

What I checked:

  • Insert: insertIntoContainer in tree.ts clamps the index and goes through updateContainer, so it also works inside nested lists. addStep and addActionStep pass the optional index through all three picker tile paths (structural, data, actions). Each picker slot has its own key (container@index), so only one is open at a time, and addStep closes it. Insert controls are hidden at the step cap. The depth block uses the depth of the list being inserted into.
  • Move up/down: these reuse moveWithinContainer, which ignores moves past either end. The buttons are disabled at the ends of the list. Step cards stay keyed by d.id, so mixing the insert buttons into the list does not remount them.
  • Indent visibility: showIndent uses the same rule as indentTarget (the step above is a loop, or a condition with then/else). So the button only shows when an indent target exists, and it is disabled with the reason in its title when the depth cap blocks it. Outdent shows only when canOutdent is true. The Indent step/Outdent step aria-labels are unchanged, and the existing indent test still passes.
  • Tests: there are new unit tests for insert and move in tree.test.ts, and new component tests for reordering, disabled buttons at the ends, inserting a condition first, and hidden indent buttons. Nothing changed outside the issue's scope, and there is no migration.
  • Not checked: I could not look at it in a browser, because there is no dev server or PDS here. The contributor asks the owner to check the spacing of the insert controls in a long list. That is cosmetic and does not block the merge.

loop:verdict run=review-20261026-153107-3my32g62syv22 sha=a57656b651cd6133153086bc3c2ea4dbd99a2300 verdict=merge

Merged main into the branch: c02d66afdd7232e6db0f338a762976dcd62679d5.

loop:carry from=a57656b651cd6133153086bc3c2ea4dbd99a2300 sha=c02d66afdd7232e6db0f338a762976dcd62679d5

Merged onto main as 8a07212dc52c17056f471a757f00ef9952540ec5.

loop:merged sha=8a07212dc52c17056f471a757f00ef9952540ec5 head=c02d66afdd7232e6db0f338a762976dcd62679d5

Sign up or Sign in to add to the discussion.