Skip to content

Restore ability to mark task groups as success/failed in UI#60161

Draft
arjav1528 wants to merge 35 commits intoapache:mainfrom
arjav1528:dev-issue-56103
Draft

Restore ability to mark task groups as success/failed in UI#60161
arjav1528 wants to merge 35 commits intoapache:mainfrom
arjav1528:dev-issue-56103

Conversation

@arjav1528
Copy link
Copy Markdown
Contributor

@arjav1528 arjav1528 commented Jan 6, 2026

Description

This PR adds two new React components that restore the task group marking functionality:

  1. MarkGroupTaskInstanceAsButton - A dropdown button component that allows users to select a state (success/failed) and opens a dialog for confirmation
  2. MarkGroupTaskInstanceAsDialog - A dialog component that provides:
    • Options to include past/future/upstream/downstream task instances
    • Dry-run preview showing which task instances will be affected
    • Ability to add notes to the state change
    • Bulk update using the task instance bulk API for efficiency

The button is integrated into the Group Task Instance page header, alongside the existing Clear button.

Screenshots

image image

Solves #60121

Closes: #56103

@boring-cyborg boring-cyborg Bot added the area:UI Related to UI/UX. For Frontend Developers. label Jan 6, 2026
@bohdan-pd
Copy link
Copy Markdown

@arjav1528 Thank you for working on that! 👍

@arjav1528 arjav1528 force-pushed the main branch 2 times, most recently from 5db3cd8 to c9d177e Compare January 6, 2026 18:50
@arjav1528 arjav1528 marked this pull request as draft January 6, 2026 18:50
@arjav1528 arjav1528 marked this pull request as ready for review January 6, 2026 18:50
@arjav1528
Copy link
Copy Markdown
Contributor Author

@arjav1528 Thank you for working on that! 👍

is the UI ok or do you want me to refactor that

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.

Thanks for taking this on! Do you mind doing more manually testing to find where MarkAs isn't quite working? I think there are some issues with the API that we need to tackle before we can merge any UI changes.

Comment thread providers/snowflake/tests/unit/snowflake/hooks/test_snowflake_sql_api.py Outdated
@arjav1528 arjav1528 force-pushed the main branch 2 times, most recently from b068b63 to da03292 Compare January 7, 2026 16:39
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.

I tried using this locally and still had issues. Could you both manually test this out and also add fastapi test for dry runs?

@arjav1528
Copy link
Copy Markdown
Contributor Author

arjav1528 commented Jan 7, 2026

I tried using this locally and still had issues. Could you both manually test this out and also add fastapi test for dry runs?

Sorry about the trouble. I’ve tested this locally and couldn’t reproduce the issue. I have reproduced the issue, solved it, you can run it locally now

@arjav1528 arjav1528 force-pushed the main branch 3 times, most recently from d24fdae to 34153d8 Compare January 8, 2026 13:12
@arjav1528 arjav1528 requested a review from choo121600 as a code owner January 8, 2026 13:12
arjav1528 and others added 20 commits February 6, 2026 02:35
…ate update logic and removing listener triggers
…ion for improved clarity and reuse in task instance patching
… ID, including dry run functionality and improved state management
…sk_instances.py

Co-authored-by: Jason(Zhe-You) Liu <68415893+jason810496@users.noreply.github.com>
… affected instances and streamline updates for both single task instances and task groups
…points, enhancing dry run functionality and validation logic
…sk_instances.py

Co-authored-by: Jason(Zhe-You) Liu <68415893+jason810496@users.noreply.github.com>
…llection of unique task instances in patching logic
… based on test group and downgrade SQLAlchemy flag
…tances to ensure correct handling of failed states
…up_id over identifier, improving error handling and validation flow
…ce function to simplify code and improve readability
…fier for task group, enhancing clarity in API requests
… for task group, improving API request structure
…bulk update logic to remove dry_run parameter for improved clarity
@guan404ming
Copy link
Copy Markdown
Member

Feel free to let us know if this one is ready for next round review. Thanks!

@potiuk
Copy link
Copy Markdown
Member

potiuk commented Mar 11, 2026

@arjav1528 This PR has been converted to draft because it does not yet meet our Pull Request quality criteria.

Issues found:

  • Merge conflicts: This PR has merge conflicts with the main branch. Your branch is 884 commits behind main. Please rebase your branch (git fetch origin && git rebase origin/main), resolve the conflicts, and push again. See contributing quick start.
  • Pre-commit / static checks: Failing: CI image checks / Static checks. Run prek run --from-ref main locally to find and fix issues. See Pre-commit / static checks docs.
  • ⚠️ Unresolved review comments: This PR has 19 unresolved review threads from maintainers. Please review and resolve all inline review comments before requesting another review. You can resolve a conversation by clicking 'Resolve conversation' on each thread after addressing the feedback. See pull request guidelines.

Note: Your branch is 884 commits behind main. Some check failures may be caused by changes in the base branch rather than by your PR. Please rebase your branch and push again to get up-to-date CI results.

What to do next:

  • The comment informs you what you need to do.
  • Fix each issue, then mark the PR as "Ready for review" in the GitHub UI - but only after making sure that all the issues are fixed.
  • Maintainers will then proceed with a normal review.

Converting a PR to draft is not a rejection — it is an invitation to bring the PR up to the project's standards so that maintainer review time is spent productively. If you have questions, feel free to ask on the Airflow Slack.

@vatsrahul1001 vatsrahul1001 removed this from the Airflow 3.2.0 milestone Mar 27, 2026
@bbovenzi
Copy link
Copy Markdown
Contributor

bbovenzi commented Apr 7, 2026

@arjav1528 Any progress on Pierre's review? We definitely will need to rebase this.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Restores “mark task group as success/failed” in the UI by adding task-group mark-as components and extending the Task Instance API to support task-group targeting and dry-run previews.

Changes:

  • Added UI components/hooks for marking task groups and bulk/dry-run updates.
  • Extended FastAPI Task Instance patch/dry-run routes to accept task_group_id and added a new bulk dry-run endpoint.
  • Updated OpenAPI generated client/types and added unit tests (Python + UI) around the new behavior.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_task_instances.py Adds coverage for task_group_id patch/dry-run and bulk dry-run behavior; updates existing expectations.
airflow-core/src/airflow/ui/src/queries/usePatchTaskInstanceDryRun.ts Passes new identifier field required by updated OpenAPI path.
airflow-core/src/airflow/ui/src/queries/usePatchTaskInstance.ts Updates mutation variable typing to align with new OpenAPI request shape.
airflow-core/src/airflow/ui/src/queries/usePatchTaskGroupDryRun.ts Introduces hook for task-group dry-run via Task Instance dry-run endpoint.
airflow-core/src/airflow/ui/src/queries/usePatchTaskGroup.ts Adds mutation hook to patch task-group instances and invalidate relevant caches.
airflow-core/src/airflow/ui/src/queries/useBulkUpdateTaskInstancesDryRun.ts Adds UI hook intended to call new bulk dry-run behavior.
airflow-core/src/airflow/ui/src/queries/useBulkUpdateTaskInstancesDryRun.test.ts Tests the dry-run hook request shape and caching behavior.
airflow-core/src/airflow/ui/src/queries/useBulkUpdateTaskInstances.ts Adds wrapper hook for the bulk TI update API plus cache invalidations/toasts.
airflow-core/src/airflow/ui/src/queries/useBulkUpdateTaskInstances.test.ts Adds unit tests for bulk update hook behavior (success + error).
airflow-core/src/airflow/ui/src/pages/TaskInstance/Header.tsx Updates patch calls to include identifier.
airflow-core/src/airflow/ui/src/pages/GroupTaskInstance/Header.tsx Adds the new “Mark as” dropdown into the group TI header actions.
airflow-core/src/airflow/ui/src/components/MarkAs/TaskInstance/MarkTaskInstanceAsDialog.tsx Updates patch calls to include identifier.
airflow-core/src/airflow/ui/src/components/MarkAs/TaskInstance/MarkGroupTaskInstanceAsDialog.tsx Adds the new dialog UX for task-group mark-as with options + dry-run preview + notes.
airflow-core/src/airflow/ui/src/components/MarkAs/TaskInstance/MarkGroupTaskInstanceAsDialog.test.tsx Adds unit tests for the new dialog behavior and hook call wiring.
airflow-core/src/airflow/ui/src/components/MarkAs/TaskInstance/MarkGroupTaskInstanceAsButton.tsx Adds the dropdown button + hotkeys to open the dialog with selected state.
airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx Updates patch calls to include identifier.
airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts Regenerates types for updated TI endpoints and adds bulk dry-run types.
airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts Regenerates service methods/paths including TI identifier and bulk dry-run endpoint.
airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts Regenerates query/mutation hooks for updated TI endpoints and adds bulk dry-run mutation.
airflow-core/src/airflow/ui/openapi-gen/queries/common.ts Adds the generated result type for bulk TI dry-run.
airflow-core/src/airflow/api_fastapi/core_api/services/public/task_instances.py Implements task-group TI selection, unique-TI collection helper, and bulk dry-run handling.
airflow-core/src/airflow/api_fastapi/core_api/routes/public/task_instances.py Extends TI patch/dry-run routes for task groups and adds /taskInstances/dry_run endpoint.
airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml Updates OpenAPI paths/params for identifier-based endpoints and adds bulk dry-run path.
.github/workflows/run-unit-tests.yml Tweaks comment around TOTAL_TEST_TIMEOUT.

Comment on lines +59 to +62
query: {
dry_run: true,
},
url: "/api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances",
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

The backend route added in this PR is PATCH /api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/dry_run (path suffix), but this hook calls /taskInstances with dry_run=true query param. This mismatch will cause 404s and break the UI dry-run. Update the hook to call the new /taskInstances/dry_run endpoint (or switch to the generated TaskInstanceService.bulkTaskInstancesDryRun / useTaskInstanceServiceBulkTaskInstancesDryRun).

Suggested change
query: {
dry_run: true,
},
url: "/api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances",
url: "/api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/taskInstances/dry_run",

Copilot uses AI. Check for mistakes.
Comment on lines +93 to +105
expect(mockRequest).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
method: "PATCH",
path: {
dag_id: "test-dag",
dag_run_id: "test-run",
},
query: {
dry_run: true,
},
}),
);
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

This test locks in the (now incorrect) client contract of calling /taskInstances with dry_run=true. If the hook is updated to use the new /taskInstances/dry_run endpoint, update this assertion to validate the correct URL and remove the dry_run query expectation. This is required to prevent the test suite from passing while the UI remains incompatible with the API.

Copilot uses AI. Check for mistakes.
Comment on lines 1028 to 1040
def patch_task_instance(
dag_id: str,
dag_run_id: str,
task_id: str,
dag_bag: DagBagDep,
body: PatchTaskInstanceBody,
user: GetUserDep,
session: SessionDep,
identifier: str | None = None,
task_id: str | None = None,
map_index: int | None = None,
task_group_id: str | None = Query(None, description="Task group id to update task instances for"),
update_mask: list[str] | None = Query(None),
) -> TaskInstanceCollectionResponse:
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

This endpoint’s path is .../taskInstances/{identifier}, but identifier is declared optional and there is also a task_id query parameter that can override which task is actually patched. That allows requests like /taskInstances/foo?task_id=bar, where the modified resource doesn’t match the URL path, and it also generates an OpenAPI schema with nullable path params (invalid for required path segments). Make identifier: str (no default) and remove the task_id query parameter from this route; keep task_group_id as the selector for group updates.

Copilot uses AI. Check for mistakes.
Comment on lines +7329 to +7331
anyOf:
- type: string
- type: 'null'
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

The generated OpenAPI marks the identifier path parameter as nullable (string | null). Path params cannot be null when the segment is required. This comes from the FastAPI signature using identifier: str | None = None. Update the route signatures so required path params are non-optional (str with no default), then regenerate the OpenAPI spec/client.

Suggested change
anyOf:
- type: string
- type: 'null'
type: string

Copilot uses AI. Check for mistakes.
toaster.create({
description: error.message,
title: translate("toaster.update.error", {
resourceName: translate("taskGroup"),
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

This hook is for bulk updating task instances, but the error toast uses resourceName: translate(\"taskGroup\"), which will produce a misleading error title in non-task-group contexts. Use the task-instance translation key (consistent with other TI toasts, e.g. taskInstance_one) or make the resource name configurable via props.

Suggested change
resourceName: translate("taskGroup"),
resourceName: translate("taskInstance_one"),

Copilot uses AI. Check for mistakes.
include_past: past,
include_upstream: upstream,
new_state: state,
note,
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

The dry-run request includes note, but notes don’t affect which task instances are selected; including it increases request churn (and if the dry-run hook’s cache key doesn’t include note, it can lead to confusing cache behavior while typing). Prefer omitting note from dry-run requests, or (if the API intentionally echoes note-related data) include note in the dry-run queryKey so caching stays consistent.

Suggested change
note,

Copilot uses AI. Check for mistakes.
Comment on lines +660 to +669
for ti in affected_tis:
ti_key = (
ti.dag_id,
ti.run_id,
ti.task_id,
ti.map_index if ti.map_index is not None else -1,
)
if ti_key not in seen_ti_keys:
seen_ti_keys.add(ti_key)
all_affected_tis.append(ti)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

This manually re-implements unique task instance collection logic. Since _collect_unique_tis(...) is introduced in the same module and already encapsulates this behavior, reuse it here (and in the other loop below) to avoid duplication and ensure keying stays consistent across endpoints.

Suggested change
for ti in affected_tis:
ti_key = (
ti.dag_id,
ti.run_id,
ti.task_id,
ti.map_index if ti.map_index is not None else -1,
)
if ti_key not in seen_ti_keys:
seen_ti_keys.add(ti_key)
all_affected_tis.append(ti)
_collect_unique_tis(affected_tis, seen_ti_keys, all_affected_tis)

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:UI Related to UI/UX. For Frontend Developers.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing the ability to mark all tasks in a Task Group Success/Failed in AF3