This is an automated email from the ASF dual-hosted git repository.

bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new b11895dcd39 Add TIs tab to mapped task details (#50085)
b11895dcd39 is described below

commit b11895dcd39d0f33a91c4294d31665e0a862b60a
Author: Brent Bovenzi <[email protected]>
AuthorDate: Fri May 2 17:25:23 2025 -0400

    Add TIs tab to mapped task details (#50085)
    
    * Add TIs tab to mapped task details
    
    * Adjust Tab title to total mapped count
---
 .../MappedTaskInstance/MappedTaskInstance.tsx      |  6 ++-
 .../ui/src/pages/TaskInstance/TaskInstance.tsx     | 43 ++++++++++++++++++++--
 2 files changed, 44 insertions(+), 5 deletions(-)

diff --git 
a/airflow-core/src/airflow/ui/src/pages/MappedTaskInstance/MappedTaskInstance.tsx
 
b/airflow-core/src/airflow/ui/src/pages/MappedTaskInstance/MappedTaskInstance.tsx
index 770c6e9348d..9225610bc24 100644
--- 
a/airflow-core/src/airflow/ui/src/pages/MappedTaskInstance/MappedTaskInstance.tsx
+++ 
b/airflow-core/src/airflow/ui/src/pages/MappedTaskInstance/MappedTaskInstance.tsx
@@ -30,8 +30,6 @@ import { isStatePending, useAutoRefresh } from "src/utils";
 
 import { Header } from "./Header";
 
-const tabs = [{ icon: <MdOutlineTask />, label: "Task Instances", value: "" }];
-
 export const MappedTaskInstance = () => {
   const { dagId = "", runId = "", taskId = "" } = useParams();
   const refetchInterval = useAutoRefresh({ dagId });
@@ -74,6 +72,10 @@ export const MappedTaskInstance = () => {
     .find((dr) => dr.dag_run_id === runId)
     ?.task_instances.find((ti) => ti.task_id === taskId);
 
+  const tabs = [
+    { icon: <MdOutlineTask />, label: `Task Instances 
[${taskInstance?.task_count}]`, value: "" },
+  ];
+
   return (
     <ReactFlowProvider>
       <DetailsLayout dag={dag} error={error ?? dagError} isLoading={isLoading 
|| isDagLoading} tabs={tabs}>
diff --git 
a/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx 
b/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
index f6993b87b27..8e19e7dbec2 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
@@ -18,11 +18,15 @@
  */
 import { ReactFlowProvider } from "@xyflow/react";
 import { FiCode } from "react-icons/fi";
-import { MdDetails, MdOutlineEventNote, MdReorder, MdSyncAlt } from 
"react-icons/md";
+import { MdDetails, MdOutlineEventNote, MdOutlineTask, MdReorder, MdSyncAlt } 
from "react-icons/md";
 import { PiBracketsCurlyBold } from "react-icons/pi";
 import { useParams } from "react-router-dom";
 
-import { useDagServiceGetDagDetails, 
useTaskInstanceServiceGetMappedTaskInstance } from "openapi/queries";
+import {
+  useDagServiceGetDagDetails,
+  useGridServiceGridData,
+  useTaskInstanceServiceGetMappedTaskInstance,
+} from "openapi/queries";
 import { DetailsLayout } from "src/layouts/Details/DetailsLayout";
 import { isStatePending, useAutoRefresh } from "src/utils";
 
@@ -67,9 +71,42 @@ export const TaskInstance = () => {
     },
   );
 
+  // Filter grid data to get only a single dag run
+  const { data } = useGridServiceGridData(
+    {
+      dagId,
+      limit: 1,
+      offset: 0,
+      runAfterGte: taskInstance?.run_after,
+      runAfterLte: taskInstance?.run_after,
+    },
+    undefined,
+    {
+      enabled: taskInstance !== undefined,
+    },
+  );
+
+  const mappedTaskInstance = data?.dag_runs
+    .find((dr) => dr.dag_run_id === runId)
+    ?.task_instances.find((ti) => ti.task_id === taskId);
+
+  let newTabs = tabs;
+
+  if (taskInstance && taskInstance.map_index > -1) {
+    newTabs = [
+      ...tabs.slice(0, 1),
+      {
+        icon: <MdOutlineTask />,
+        label: `Task Instances [${mappedTaskInstance?.task_count ?? ""}]`,
+        value: "task_instances",
+      },
+      ...tabs.slice(1),
+    ];
+  }
+
   return (
     <ReactFlowProvider>
-      <DetailsLayout dag={dag} error={error ?? dagError} isLoading={isLoading 
|| isDagLoading} tabs={tabs}>
+      <DetailsLayout dag={dag} error={error ?? dagError} isLoading={isLoading 
|| isDagLoading} tabs={newTabs}>
         {taskInstance === undefined ? undefined : (
           <Header
             isRefreshing={Boolean(isStatePending(taskInstance.state) && 
Boolean(refetchInterval))}

Reply via email to