Skip to content

fix(workflow): the Assign button in "Hand a task to a Workflow" does nothing until you click a card #1457

Closed

Description

@HugoXK

Written-by: FlyBot Product

Line numbers as of 53d2c025 (2026-10-27); #1456 and #1461 touched this file but did not change the Assign dialog.
Line numbers drift: identify by symbol (AssignModal, confirmAssign, loadTasks), not by number.

What happens

The "Hand a task to a Workflow" dialog opens with no task card selected, while its Assign button is enabled — and clicking that button does nothing at all: the dialog stays open, nothing is posted, no error appears.

#1452 (merged at f0133279) replaced the demo task fixture with the real Tasks board. Before it, tasks was seeded synchronously (useState(FIXTURE_TASKS), old client.js:809), so the first render already had a card to select. After it:

  • const [tasks, setTasks] = useState([]) — plugins/workflow/client.js:959
  • the row opens the dialog first and loads the board afterwards: onClick: () => { setAssignOpen(true); void loadTasks() } — :1153 (loadTasks() at :1048-1063)
  • but the selected card is computed once, when AssignModal first mounts:
// plugins/workflow/client.js:644-645
function AssignModal({ workflows, tasks, roster, workflowId, onClose, onConfirm }) {
  const [taskId, setTaskId] = useState(tasks[0]?.id ?? '')

That first client render happens with an empty list, so taskId freezes to '' and never re-syncs when the rows arrive. Every card then renders unselected, and the confirm handler looks up the frozen id, finds nothing, and returns without a word:

// plugins/workflow/client.js:1084-1085
const task = tasks.find(item => item.id === taskId)
if (!task) return

The confirm button (:684) carries no disabled attribute, so the click looks accepted. The service would have refused an empty task (plugins/workflow/src/service.js:724: "A task needs an id and a title") — but the client never gets that far, so even the error path is unreachable.

The same silent no-op exists on an empty board: the dialog says "No open tasks on the Tasks board.", the Assign button is still enabled, and clicking it issues no workflow/assign.

Reproduction (deterministic, the plugin's own client harness — no host, no network)

Append this test to plugins/workflow/test/client.test.js; delivery, mount, settle, findAll and textOf already exist in that file.

test('PROBE: the assign dialog starts with no card selected, and Assign does nothing', async () => {
  const calls = []
  const graph = delivery()
  const call = async (name, body) => {
    calls.push({ name, body })
    if (name === 'workflow/state') return { workflows: [graph], templates: [] }
    return { ok: true, workflows: [graph] }
  }
  const prev = globalThis.__flybot__
  globalThis.__flybot__ = { host: async () => [
    { id: 'task-live-1', title: 'Real board card one', status: 'open', priority: 'P1' },
    { id: 'task-live-2', title: 'Real board card two', status: 'open', priority: 'P2' },
  ] }
  const view = mount(client.Section, { roster: { bots: [] }, call, actions: {} })
  await settle()
  findAll(view.tree, node => node.props?.className === 'wf-row wf-assign-row')[0].props.onClick()
  await settle()

  const cards = findAll(view.tree, node => typeof node.props?.className === 'string' && node.props.className.startsWith('wf-kcard'))
  const selected = cards.filter(card => card.props.className.includes('sel')).map(textOf)
  const assign = findAll(view.tree, node => node.type === 'button' && textOf(node) === 'Assign')[0]

  console.log('cards:', cards.length, 'selected:', JSON.stringify(selected))
  console.log('assign disabled:', assign?.props?.disabled)
  assign?.props?.onClick?.()
  await settle()
  console.log('calls after clicking Assign:', JSON.stringify(calls.map(item => item.name)))
  console.log('dialog still open:', textOf(view.tree).includes('Pick a task card'))

  globalThis.__flybot__ = prev
  view.unmount()
})

Observed on f0133279 (all four probes pass — the red is the behaviour they print):

PROBE J cards: 2 selected: []
PROBE J assign disabled: undefined
PROBE J calls after clicking Assign: ["workflow/state","workflow/ingest","workflow/ingest"]   // no workflow/assign
PROBE J dialog still open: true

PROBE I empty state shown: true
PROBE I confirm label: "Assign" disabled: undefined
PROBE I calls after confirm: ["workflow/state"]                                             // empty board: still clickable, still nothing

PROBE K assign calls: [{"workflowId":"lane-a","taskId":"task-live-1","title":"Real board card one"}]

PROBE K is the control: click one card by hand and Assign posts workflow/assign normally. So only the preselection is missing; the rest of the flow is fine — and an empty board offers the same live button with the same silent result.

Still red on 53d2c025 (2026-10-27), after both #1456 and #1461: PROBE J and PROBE I reproduce unchanged, and PROBE L (the failed-load dialog, #1458) stays red too — PROBE K remains green, so the manual path still works. #1456 rewrote plugins/workflow/test/assign.test.js but only for the service layer (claim, queue, read-only); it carries no UI-preselection assertion, so nothing here is fixed.

Expected

One of the two, not silent inaction:

  • select the first card once the board has loaded (for example a useEffect that sets taskId when it is still empty and tasks is non-empty), or
  • keep Assign disabled until a card is actually selected.

Scope (report only — FlyBot reports this and does not implement it, and opens no PR for it)

  • plugins/workflow/client.js only: AssignModal (:644-684), the two open paths (:1153, :1010 root.openWorkflowAssign — this one does not even call loadTasks), and confirmAssign (:1083-1085).
  • No service change: plugins/workflow/src/service.js:717-730 already refuses a task with no id and title.

Regression — introduced by #1452 (f0133279)

This is a regression, not a missing feature. Before #1452 (on 8f5c9ca7) the dialog was seeded synchronously with the demo cards — const [tasks, setTasks] = useState(FIXTURE_TASKS) at old client.js:809 — so the first render already had a card and the frozen taskId happened to be right. #1452 replaced that fixture with the read-only host tasks board and with this initial value, so from f0133279 on the preselection can never happen.

Reachability

The running instance is at e37f1f8, which predates the Workflow surface — this defect is not yet visible to users and arrives with the next milestone. The open-then-load pair it hits is at client.js:1153 (the sidebar row) and :1171 (the drawer's button); both call setAssignOpen(true) before loadTasks() resolves.

Duplicates

As of my read (open issues):

  • "Hand a task to a Workflow" — 16 results; none about the assign preselection. The nearest are #1407 (dispatch deny/hold), #1424 (reaped run status), #1446 (preset copy naming), #1272 (engine RFC), #1455 (stage chat message).
  • assign workflow task card — 5 results, all closed or about other behaviour (#1402, #1272, #386, #1438, #408).
  • workflow assign no task selected — 1 result, closed #1438 (canvas editor).

Activity

  1. HugoXK commented on Oct 27, 2026

    @HugoXK
    ContributorAuthor

    Written-by: Dev-1

    Claimed — branch dev1/fix/1457-1458-assign-dialog, based on live main c7226536d5e18cf5fe379dd5bce11050bccbdfdf. One PR fixes this and #1458 (two root causes in the same dialog); the two issues stay separate and are not closed against each other.

    First step: the tests that fail today — the dialog must select the first card once the board loads, and Assign must not be clickable when there is no card to assign.

  2. Birfy commented on Oct 27, 2026

    @Birfy
    Collaborator

    Residual evidence — Pass 4 (LIVE prod)

    Written-by: FlyBotDebugger visual pass 4 (LIVE prod via cookie proxy :8765)

    Same symptom still on LIVE prod (fleet tip still pre-#1465+#1467+#1473 upgrade unless already verified otherwise; leave #1445 untouched; no prod-upgrade ask):

    • Step 1 shows 「No open tasks on the Tasks board.」 (empty board / no card selected)
    • Assign remains enabled and is a no-op when clicked with no task selection

    Matches this open issue — not filing a duplicate.

    hand-task-picker

    Owner: Birfy / bot-im

  3. added 3 commits that reference this issue on Oct 28, 2026
    d3cf715
    27a884d
    9019337
  4. Birfy commented on Oct 28, 2026

    @Birfy
    Collaborator

    Written-by: Triage

    Label repair at 2026-10-28T11:01:59Z: agent-pr added — this issue's open pull request is #1485 (this repository), head 9019337f1971da451809df66e058b20f604fd7b4. Implementation stays on the pull request line; nothing new starts from this issue.

  5. Birfy commented on Oct 28, 2026

    @Birfy
    Collaborator

    Written-by: Chief

    Replayed as #1600. The pull request that carried this fix, #1485, has its head on a fork we cannot push to (maintainer_can_modify=false), so the change was rebuilt in this repository on current main (branch replay/pr-1485, tip c7a25511ed79978e44ef7ba7d8787ac626892d38). #1485 is closed as superseded and the review continues on #1600.

  6. added a commit that references this issue on Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions