Skip to content

UI: Use react-query native error state for bulk action hooks#67284

Open
pierrejeambrun wants to merge 3 commits into
apache:mainfrom
astronomer:fix/bulk-action-error-handling
Open

UI: Use react-query native error state for bulk action hooks#67284
pierrejeambrun wants to merge 3 commits into
apache:mainfrom
astronomer:fix/bulk-action-error-handling

Conversation

@pierrejeambrun
Copy link
Copy Markdown
Member

Stacked on #67095. The diff here includes the 7 commits from #67095 — the only commit relevant to this PR is the top one, UI: Use react-query native error state for bulk action hooks. Once #67095 merges, GitHub will auto-clean the diff down to that single commit.

useBulkTaskInstances and useBulkDeleteDagRuns both kept the same anti-pattern @bbovenzi flagged on #67095: a useState<unknown> for the error, an onError callback that just forwarded the network error to setError, and a tiny helper that grabbed errors[0] from the response body and re-shaped it into {body:{detail:...}} so ErrorAlert could render the first per-entity failure. That hid every error past the first and duplicated mutation state into React state for no reason.

Both hooks now return { bulkAction, data, error, isPending, reset } straight from useMutation:

  • error covers HTTP-level failures (4xx/5xx, network).
  • data.delete.errors / data.update.errors carries the per-entity failures the backend returns on a 200 response (partial success). Consumers render every entry, not just the first.
  • reset replaces the consumer-side setError(undefined) calls.

onSuccess still invalidates queries unconditionally, fires the toaster + clears selection when success.length > 0, and only closes the dialog when errors.length === 0 — partial-success keeps the dialog open so the user can read what failed.


Was generative AI tooling used to co-author this PR?
  • Yes — Claude Code (Opus 4.7)

Generated-by: Claude Code (Opus 4.7) following the guidelines

@boring-cyborg boring-cyborg Bot added area:airflow-ctl area:API Airflow's REST/HTTP API area:UI Related to UI/UX. For Frontend Developers. backport-to-airflow-ctl/v0-1-test labels May 21, 2026
@pierrejeambrun pierrejeambrun mentioned this pull request May 21, 2026
1 task
@pierrejeambrun
Copy link
Copy Markdown
Member Author

Only the last commit is relevant.

@pierrejeambrun pierrejeambrun force-pushed the fix/bulk-action-error-handling branch from 0f52d79 to c0952b0 Compare May 22, 2026 11:35
Comment thread airflow-core/src/airflow/ui/src/pages/DagRuns/BulkDeleteDagRunsButton.tsx Outdated
Copy link
Copy Markdown
Contributor

@bbovenzi bbovenzi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a screenshot of the modal with many errors at once? Let's make sure the modal displays correctly

Both ``useBulkTaskInstances`` and ``useBulkDeleteDagRuns`` mirrored
the same anti-pattern: a ``useState<unknown>`` field, an ``onError``
callback that just forwarded to ``setError``, and a tiny helper that
grabbed ``errors[0]`` from the response body and re-shaped it into
``{body:{detail:...}}`` so ``ErrorAlert`` could render the first
per-entity failure. That hid every error past the first and
duplicated mutation state into React state for no reason.

Both hooks now return ``{ bulkAction, data, error, isPending, reset }``
straight from ``useMutation``:

- ``error`` covers HTTP-level failures (4xx/5xx, network).
- ``data.delete.errors`` / ``data.update.errors`` carries the
  per-entity failures the backend returns on a 200 response (partial
  success). Consumers render every entry, not just the first.
- ``reset`` replaces the consumer-side ``setError(undefined)`` calls.

``onSuccess`` still invalidates queries unconditionally, fires the
toaster + clears selection when ``success.length > 0``, and only
closes the dialog when ``errors.length === 0`` — partial-success
keeps the dialog open so the user can read what failed.

The three consumers (``BulkMarkTaskInstancesAsButton``,
``BulkDeleteTaskInstancesButton``, ``BulkDeleteDagRunsButton``) now
render network errors via ``ErrorAlert`` and per-entity errors as a
``Stack`` of ``Alert`` rows below it.
@pierrejeambrun pierrejeambrun force-pushed the fix/bulk-action-error-handling branch from c0952b0 to d44e815 Compare May 26, 2026 10:39
On a partial success the dialog now stays mounted so the user can read
the per-entity errors, and only the successful rows are removed from
the selection — clicking confirm again retries just the failed ones.

The previous behaviour cleared the whole selection on any success,
which collapsed the ActionBar (its open state is bound to
``selectedRows.size``) and unmounted the dialog along with it, hiding
the errors the user was meant to see.

UI row keys now use the same identifier format the bulk API echoes
back in ``success`` / ``errors`` (``{dag_id}.{run_id}`` and
``{dag_id}.{run_id}.{task_id}[{map_index}]``), so the bulk hooks can
pass the response's ``success`` array straight to a new
``deselectKeys`` on ``useRowSelection``.
@pierrejeambrun
Copy link
Copy Markdown
Member Author

pierrejeambrun commented May 26, 2026

it handles multiple errors

Partial success, delete dag runs.

Screen.Recording.2026-05-26.at.15.08.59.mov

Partial success, delete task instances:

Screen.Recording.2026-05-26.at.15.30.00.mov

Partial success, mark task instances as:
https://github.com/user-attachments/assets/45bb6d7d-3054-4995-8ebd-2ce3a94b8085

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:airflow-ctl area:API Airflow's REST/HTTP API area:UI Related to UI/UX. For Frontend Developers. backport-to-airflow-ctl/v0-1-test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants