Skip to content

Add Clear All Mapped Tasks button for mapped task instances#60591

Open
VedantMadane wants to merge 1 commit intoapache:mainfrom
VedantMadane:ui-clear-all-mapped-ti
Open

Add Clear All Mapped Tasks button for mapped task instances#60591
VedantMadane wants to merge 1 commit intoapache:mainfrom
VedantMadane:ui-clear-all-mapped-ti

Conversation

@VedantMadane
Copy link
Copy Markdown

Summary

This PR adds a "Clear All Mapped Tasks" button to the mapped task instance header, allowing users to clear all mapped task instances at once.

Closes #60460

Problem

Currently, there is no way to clear all mapped task instances at once for a specific task. Users have to clear each individual mapped task instance separately, which is tedious when dealing with many mapped instances.

Solution

Added a "Clear All Mapped Tasks" button to the mapped task instance header that clears all map indices for a given task. The backend already supports this functionality - when only the task_id is provided (without map_index), all map indices are targeted for clearing.

Changes

  • ClearAllMappedTaskInstancesButton.tsx: New button component that triggers the dialog
  • ClearAllMappedTaskInstancesDialog.tsx: New dialog component similar to ClearTaskInstanceDialog, but uses task_ids: [taskId] instead of [[taskId, mapIndex]] to clear all mapped instances
  • Header.tsx: Updated to accept dagId and dagRunId props and render the new button
  • MappedTaskInstance.tsx: Updated to pass dagId and dagRunId to the Header component
  • dags.json: Added translation keys for the new feature

Screenshot Location

The button appears in the header of the mapped task instance page (e.g., /dags/{dag_id}/runs/{run_id}/tasks/{task_id}/mapped), next to the task name and statistics.

Testing

  • TypeScript compilation passes
  • The feature uses existing backend functionality that already supports clearing all mapped instances
  • The dialog follows the same patterns as the existing ClearTaskInstanceDialog

@rachanadutta
Copy link
Copy Markdown
Contributor

rachanadutta commented Jan 15, 2026

Screenshot 2026-01-15 at 11 09 14 PM

Hi @VedantMadane , thanks for the PR — the implementation looks solid 👍

I was actually working on this issue as well (I’m the assignee), and my approach was slightly different on the UI side.

Instead of placing the button in the mapped task header, I was adding the “Clear all mapped task instances” button next to the Filter button in the Task Instances section, to keep it consistent with other bulk actions on that page.

I’ve attached a screenshot below showing the placement I was testing locally.

Functionality-wise, your approach of passing only task_id (without map_index) matches what I had in mind, and we could reuse the same dialog logic.

@maintainers — would you prefer the button in the header (as in this PR), or alongside the filter in the Task Instances section?

Based on your guidance, I’m happy to either:

follow up with a small PR adjusting the placement, or

help refine this PR instead.

Thanks!

@VedantMadane
Copy link
Copy Markdown
Author

Sorry about that Rachana, feel free to modify this PR or reuse code from it.

@rachanadutta
Copy link
Copy Markdown
Contributor

rachanadutta commented Jan 16, 2026

Screenshot 2026-01-15 at 10 47 28 PM Hi @VedantMadane — quick check while testing this locally 🙂

On my side, when I open the “Clear All Mapped Task Instances” dialog, the mapped task instances are not appearing in the dialog (the ActionAccordion looks empty).

Could you please share a quick screenshot from your local setup showing whether the mapped task instances are listed correctly in the dialog? That would really help confirm whether this is environment-specific or something we need to adjust in the PR.

Thanks!

@VedantMadane
Copy link
Copy Markdown
Author

Hi @rachanadutta, thanks for catching this! I found the bug.

The ActionAccordion component requires note and setNote props, but I was only passing affectedTasks. This caused the accordion to render incorrectly and not display the task instances.

I've pushed a fix that adds the missing props. Could you try pulling the latest changes and testing again?

The accordion should now show the list of mapped task instances that will be affected by the clear operation.

@rachanadutta
Copy link
Copy Markdown
Contributor

@VedantMadane I reviewed and tested the changes locally.
The “Clear all mapped task instances” action is now available in the UI and the mapped task instances are now appearing correctly in the clear dialog, which addresses the original issue. 👍

I tested the clear task instance behavior both locally and on released Airflow (3.1.3) using airflow standalone:

the confirmation dialog shows the affected tasks with No Status,

but the Task Instances list and the individual task instance page still show the previous state (e.g. Success).

This makes it difficult for users to tell from the main page that the clear action actually took effect as there is no success message like delete instance.
That said, this seems like a separate UI refresh / state update issue, and not directly related to the changes in this PR, so I’ll open a follow-up issue to track it separately.

One minor UX thought (happy to defer to maintainers): placing the action closer to the existing +Filter button (instead of the header) might better align with the overall UI patterns, but I understand this is a design choice and should be maintainer-driven.

@pierrejeambrun pierrejeambrun added this to the Airflow 3.2.0 milestone Jan 21, 2026
Copy link
Copy Markdown
Member

@pierrejeambrun pierrejeambrun left a comment

Choose a reason for hiding this comment

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

Nice!

Tested locally and working as expected.

A few suggestions before we can merge.

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.

We only call mapIndex in a handful of places in our existing ClearTaskInstanceDialog. I wonder if we can add a allMapped boolean param to it to handle this condition instead of making an entire parallel set of components.

@VedantMadane VedantMadane force-pushed the ui-clear-all-mapped-ti branch from 50b548d to fba7b51 Compare January 31, 2026 06:18
VedantMadane added a commit to VedantMadane/airflow that referenced this pull request Jan 31, 2026
- Add allMapped boolean prop to ClearTaskInstanceButton and ClearTaskInstanceDialog
- Eliminate need for parallel ClearAllMapped* components
- Fix tooltip ternary to use different translation keys based on allMapped and isHotkeyEnabled
- Conditionally handle mapIndex in 6 places (taskIds, patch hook, confirmation dialog, note patching, title, tooltips)

Addresses review feedback from @bbovenzi in PR apache#60591
VedantMadane added a commit to VedantMadane/airflow that referenced this pull request Jan 31, 2026
- Add allMapped boolean prop to ClearTaskInstanceButton and ClearTaskInstanceDialog
- Eliminate need for parallel ClearAllMapped* components
- Fix tooltip ternary to use different translation keys based on allMapped and isHotkeyEnabled
- Conditionally handle mapIndex in 6 places (taskIds, patch hook, confirmation dialog, note patching, title, tooltips)

Addresses review feedback from @bbovenzi in PR apache#60591
@VedantMadane
Copy link
Copy Markdown
Author

VedantMadane commented Jan 31, 2026

Added allMapped?: boolean prop to existing components instead of creating parallel ClearAllMapped* components. Commit 5e53ef7

VedantMadane added a commit to VedantMadane/airflow that referenced this pull request Jan 31, 2026
- Delete ClearAllMappedTaskInstancesButton.tsx and ClearAllMappedTaskInstancesDialog.tsx
- Update Header.tsx to use ClearTaskInstanceButton with allMapped=true
- All functionality now consolidated into existing components with allMapped boolean param

Addresses @bbovenzi review feedback in PR apache#60591:
1. Eliminated parallel component set - now using single allMapped param
2. Fixed tooltip ternary to use different translation keys
3. Translation keys already exist in dags.json (clearAllMapped.button, clearAllMapped.buttonTooltip, clearAllMapped.title)
VedantMadane added a commit to VedantMadane/airflow that referenced this pull request Jan 31, 2026
- Keep ClearAllMappedTaskInstancesButton with explicit props (dagId, dagRunId, taskId)
- Delete redundant ClearAllMappedTaskInstancesDialog (200 lines)
- Enhance ClearTaskInstanceDialog to accept both TaskInstanceResponse OR explicit props
- Add allMapped parameter to ClearTaskInstanceDialog for conditional logic
- Fix task_ids API format: [taskId] for all mapped vs [[taskId, mapIndex]] for single
- Fix tooltip ternary to show different text when hotkey disabled
- Handle optional taskInstance fields gracefully (note, dag_version, task_display_name, start_date, logical_date)

Addresses @bbovenzi review feedback in PR apache#60591:
1. Consolidate dialog logic with allMapped param instead of parallel components
2. Fix tooltip ternary dead code (lines 53-55)
3. Properly handle mapIndex in handful of places with conditional logic

Net change: -173 lines of code
@VedantMadane VedantMadane force-pushed the ui-clear-all-mapped-ti branch from ce26f2f to 1db8d12 Compare January 31, 2026 07:17
Copy link
Copy Markdown
Member

@pierrejeambrun pierrejeambrun left a comment

Choose a reason for hiding this comment

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

Thanks,

That's looking better.

A few things to address

@VedantMadane VedantMadane force-pushed the ui-clear-all-mapped-ti branch from a60feb1 to 7d071ad Compare February 10, 2026 09:19
VedantMadane added a commit to VedantMadane/airflow that referenced this pull request Feb 10, 2026
- Keep ClearAllMappedTaskInstancesButton with explicit props (dagId, dagRunId, taskId)
- Delete redundant ClearAllMappedTaskInstancesDialog (200 lines)
- Enhance ClearTaskInstanceDialog to accept both TaskInstanceResponse OR explicit props
- Add allMapped parameter to ClearTaskInstanceDialog for conditional logic
- Fix task_ids API format: [taskId] for all mapped vs [[taskId, mapIndex]] for single
- Fix tooltip ternary to show different text when hotkey disabled
- Handle optional taskInstance fields gracefully (note, dag_version, task_display_name, start_date, logical_date)

Addresses @bbovenzi review feedback in PR apache#60591:
1. Consolidate dialog logic with allMapped param instead of parallel components
2. Fix tooltip ternary dead code (lines 53-55)
3. Properly handle mapIndex in handful of places with conditional logic

Net change: -173 lines of code
Copy link
Copy Markdown
Member

@pierrejeambrun pierrejeambrun 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 updating the PR.

A few more suggestions.

@eladkal
Copy link
Copy Markdown
Contributor

eladkal commented Mar 13, 2026

@VedantMadane can you address the open items?

VedantMadane added a commit to VedantMadane/airflow that referenced this pull request Mar 25, 2026
- Simplify Props: remove discriminated union, use explicit dagId,
  dagRunId, taskId, mapIndex props only (no taskInstance object)
- Explicit prop destructuring instead of ...rest spread
- Fix note updating for allMapped: patch all affected TIs
- Remove eslint-disable in ClearTaskInstanceConfirmationDialog
- Revert testsSetup.ts changes (unrelated to this feature)
- Update all ClearTaskInstanceButton callers to pass explicit IDs

Addresses @pierrejeambrun review feedback in PR apache#60591
@vatsrahul1001 vatsrahul1001 removed this from the Airflow 3.2.0 milestone Mar 27, 2026
@eladkal eladkal requested a review from pierrejeambrun March 27, 2026 07:48
@VedantMadane VedantMadane force-pushed the ui-clear-all-mapped-ti branch from ff3c6ff to 0dcf8f5 Compare March 28, 2026 09:22
@VedantMadane
Copy link
Copy Markdown
Author

Rebased onto latest main (squashed to a single clean commit) and all open review items from @pierrejeambrun have been addressed:

  • Simplified Props (no discriminated union, explicit dagId/dagRunId/taskId/mapIndex)
  • No ...rest\ spread, explicit props throughout
  • Note patching for allMapped iterates affected TIs
  • Removed eslint-disable in ClearTaskInstanceConfirmationDialog
  • Reverted testsSetup.ts changes
  • Updated all callers to pass explicit IDs

Ready for re-review.

Copy link
Copy Markdown
Member

@pierrejeambrun pierrejeambrun left a comment

Choose a reason for hiding this comment

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

A couple of things don't seem right and probably need fixing

Comment on lines +249 to +256
mutatePatchTaskInstance({
dagId,
dagRunId,
mapIndex: ti.map_index,
requestBody: { note },
taskId,
});
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You don't need to call it for each map_index. The API offers the possibility to patch all of the mapped index at once. (with map_index = None)

Comment on lines +13 to +14
"lint": "eslint --quiet",
"typecheck": "tsc --p tsconfig.app.json",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This seems unrelated.

Comment on lines +30 to +38
const successLabel = i18n.t("common:states.success");
const failedLabel = i18n.t("common:states.failed");

await waitFor(() => expect(screen.getByText(successLabel)).toBeInTheDocument());
await waitFor(() => screen.getByText(successLabel).click());
await waitFor(() => expect(screen.getByText("tutorial_taskflow_api_success")).toBeInTheDocument());

await waitFor(() => expect(screen.getByText("states.failed")).toBeInTheDocument());
await waitFor(() => screen.getByText("states.failed").click());
await waitFor(() => expect(screen.getByText(failedLabel)).toBeInTheDocument());
await waitFor(() => screen.getByText(failedLabel).click());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Unrelated change.

<Flex alignItems="center" justifyContent="space-between">
<TaskInstancesFilter />
{Boolean(dagId) && Boolean(runId) && Boolean(taskId) ? (
<ClearTaskInstanceButton allMapped dagId={dagId as string} dagRunId={runId as string} taskId={taskId as string} />
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this type casting necessary? Type narrowing above instead of using Boolean. (!== undefined !== null)

<Box>
<HeaderCard
actions={<ClearTaskInstanceButton groupTaskInstance={taskInstance} isHotkeyEnabled />}
actions={<ClearTaskInstanceButton dagId={dagId} dagRunId={runId} isHotkeyEnabled taskId={taskInstance.task_id} />}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Doesn't this break the task group clearing pattern?

@potiuk potiuk added the ready for maintainer review Set after triaging when all criteria pass. label Apr 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:translations area:UI Related to UI/UX. For Frontend Developers. ready for maintainer review Set after triaging when all criteria pass. translation:default

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UI - Clear all mapped index for a mapped TI

7 participants