This is an automated email from the ASF dual-hosted git repository.
bbovenzi pushed a commit to branch v3-1-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-1-test by this push:
new 28415802c57 [v3-1-test] fix: Enable real-time extra links updates for
TriggerDagRunOperator (#59507) (#60225)
28415802c57 is described below
commit 28415802c571442813d81d07345926192a48a01f
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Wed Jan 7 11:47:47 2026 -0500
[v3-1-test] fix: Enable real-time extra links updates for
TriggerDagRunOperator (#59507) (#60225)
* fix: Enable real-time extra links updates for TriggerDagRunOperator
- Add smart polling to ExtraLinks component using useAutoRefresh hook
- Poll automatically when DAG is active and links are not yet available
- Stop polling once extra links appear to reduce server load
- Respects global auto_refresh_interval config and DAG paused state
- Fixes issue where Triggered DAG button only appeared after manual refresh
Closes #58928
* fix: prevent infinite polling for tasks without extra links
- Add task metadata check using useTaskServiceGetTask
- Only poll if task.extra_links.length > 0
- Conditionally render ExtraLinks component in Details.tsx
- Prevents unnecessary API calls for tasks without extra links
Addresses review feedback from @bbovenzi
* refactor: reuse parent refetchInterval pattern in child components
- Pass parent's refetchInterval to ExtraLinks and BlockingDeps components
- Remove duplicate useAutoRefresh and useTaskServiceGetTask calls
- Eliminate invalid taskInstance.extra_links property access (doesn't exist
on TaskInstanceResponse)
- Polling now tied to try instance pending state - stops automatically when
task completes
- Simplifies architecture by centralizing refresh logic in parent component
Addresses review feedback from @pierrejeambrun and @bbovenzi
* style: apply pre-commit hook formatting fixes
- Reorder type union to alphabetical order (number | false)
- Format ExtraLinks component to single line
(cherry picked from commit 2768fba69549cb4030af8ce97c675ef893433017)
Co-authored-by: subhash-0000
<[email protected]>
---
.../ui/src/pages/TaskInstance/BlockingDeps.tsx | 25 ++++++++++++++++------
.../airflow/ui/src/pages/TaskInstance/Details.tsx | 7 ++++--
.../ui/src/pages/TaskInstance/ExtraLinks.tsx | 24 +++++++++++++++------
3 files changed, 40 insertions(+), 16 deletions(-)
diff --git
a/airflow-core/src/airflow/ui/src/pages/TaskInstance/BlockingDeps.tsx
b/airflow-core/src/airflow/ui/src/pages/TaskInstance/BlockingDeps.tsx
index 2ed76613df7..fed7908b6ab 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/BlockingDeps.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/BlockingDeps.tsx
@@ -22,14 +22,25 @@ import { useTranslation } from "react-i18next";
import { useTaskInstanceServiceGetTaskInstanceDependencies } from
"openapi/queries";
import type { TaskInstanceResponse } from "openapi/requests/types.gen";
-export const BlockingDeps = ({ taskInstance }: { readonly taskInstance:
TaskInstanceResponse }) => {
+type BlockingDepsProps = {
+ readonly refetchInterval: number | false;
+ readonly taskInstance: TaskInstanceResponse;
+};
+
+export const BlockingDeps = ({ refetchInterval, taskInstance }:
BlockingDepsProps) => {
const { t: translate } = useTranslation();
- const { data } = useTaskInstanceServiceGetTaskInstanceDependencies({
- dagId: taskInstance.dag_id,
- dagRunId: taskInstance.dag_run_id,
- mapIndex: taskInstance.map_index,
- taskId: taskInstance.task_id,
- });
+ const { data } = useTaskInstanceServiceGetTaskInstanceDependencies(
+ {
+ dagId: taskInstance.dag_id,
+ dagRunId: taskInstance.dag_run_id,
+ mapIndex: taskInstance.map_index,
+ taskId: taskInstance.task_id,
+ },
+ undefined,
+ {
+ refetchInterval,
+ },
+ );
if (data === undefined || data.dependencies.length < 1) {
return undefined;
diff --git a/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
b/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
index a769498f6d0..5e7b66c7a5e 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
@@ -95,11 +95,14 @@ export const Details = () => {
taskInstance={taskInstance}
/>
)}
- <ExtraLinks />
+ <ExtraLinks refetchInterval={isStatePending(tryInstance?.state) ?
refetchInterval : false} />
{taskInstance === undefined ||
// eslint-disable-next-line unicorn/no-null
![null, "queued", "scheduled"].includes(taskInstance.state) ? undefined
: (
- <BlockingDeps taskInstance={taskInstance} />
+ <BlockingDeps
+ refetchInterval={isStatePending(tryInstance?.state) ?
refetchInterval : false}
+ taskInstance={taskInstance}
+ />
)}
{taskInstance !== undefined && (taskInstance.trigger ??
taskInstance.triggerer_job) ? (
<TriggererInfo taskInstance={taskInstance} />
diff --git a/airflow-core/src/airflow/ui/src/pages/TaskInstance/ExtraLinks.tsx
b/airflow-core/src/airflow/ui/src/pages/TaskInstance/ExtraLinks.tsx
index 3559d48065b..2ff7876dfc0 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/ExtraLinks.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/ExtraLinks.tsx
@@ -22,16 +22,26 @@ import { useParams } from "react-router-dom";
import { useTaskInstanceServiceGetExtraLinks } from "openapi/queries";
-export const ExtraLinks = () => {
+type ExtraLinksProps = {
+ readonly refetchInterval: number | false;
+};
+
+export const ExtraLinks = ({ refetchInterval }: ExtraLinksProps) => {
const { t: translate } = useTranslation("dag");
const { dagId = "", mapIndex = "-1", runId = "", taskId = "" } = useParams();
- const { data } = useTaskInstanceServiceGetExtraLinks({
- dagId,
- dagRunId: runId,
- mapIndex: parseInt(mapIndex, 10),
- taskId,
- });
+ const { data } = useTaskInstanceServiceGetExtraLinks(
+ {
+ dagId,
+ dagRunId: runId,
+ mapIndex: parseInt(mapIndex, 10),
+ taskId,
+ },
+ undefined,
+ {
+ refetchInterval,
+ },
+ );
return data && Object.keys(data.extra_links).length > 0 ? (
<Box py={1}>