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

jscheffl 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 9ce71fd2270 Add additional task instance attributes to task instance's 
details section (#68378)
9ce71fd2270 is described below

commit 9ce71fd2270f634760b150324360bf2ee6bfa812
Author: Jayachandra Kasarla <[email protected]>
AuthorDate: Mon Jun 15 03:02:46 2026 +0530

    Add additional task instance attributes to task instance's details section 
(#68378)
    
    * Add additional task instance attributes to Airflow 3 UI task instance 
details page
    
    * Add task instance attributes to task details page
    
    * added task instance id and filtered out kwargs from trigger
    
    * renamed Task Instance ID to ID in common.json
    
    * Added RenderedJsonField component to render JSON in the details page
    
    ---------
    
    Co-authored-by: Jayachandra Kasarla <[email protected]>
---
 .../airflow/ui/public/i18n/locales/en/common.json  |  4 ++
 .../airflow/ui/src/pages/TaskInstance/Details.tsx  | 63 +++++++++++++++++++++-
 2 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/en/common.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/en/common.json
index c949d619b6c..cc27c1faf54 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/en/common.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/en/common.json
@@ -285,10 +285,12 @@
   "taskGroup_other": "Task Groups",
   "taskId": "Task ID",
   "taskInstance": {
+    "additionalAttributes": "Additional Task Instance Attributes",
     "dagVersion": "Dag Version",
     "executor": "Executor",
     "executorConfig": "Executor Config",
     "hostname": "Hostname",
+    "id": "ID",
     "maxTries": "Max Tries",
     "pid": "PID",
     "pool": "Pool",
@@ -298,11 +300,13 @@
     "queuedWhen": "Queued At",
     "renderedMapIndex": "Rendered Map Index",
     "scheduledWhen": "Scheduled At",
+    "trigger": "Trigger",
     "triggerer": {
       "assigned": "Assigned triggerer",
       "class": "Trigger class",
       "createdAt": "Trigger creation time",
       "id": "Trigger ID",
+      "job": "Triggerer Job",
       "latestHeartbeat": "Latest triggerer heartbeat",
       "title": "Triggerer Info"
     },
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 646fc36cdd9..6b5eccf7f5d 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
@@ -16,7 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { Box, Flex, HStack, Table } from "@chakra-ui/react";
+import { Box, Flex, Heading, HStack, Table } from "@chakra-ui/react";
+import type { ReactNode } from "react";
 import { useTranslation } from "react-i18next";
 import { useParams, useSearchParams } from "react-router-dom";
 
@@ -25,6 +26,7 @@ import {
   useTaskInstanceServiceGetTaskInstanceTryDetails,
 } from "openapi/queries";
 import { DagVersionDetails } from "src/components/DagVersionDetails";
+import RenderedJsonField from "src/components/RenderedJsonField";
 import { StateBadge } from "src/components/StateBadge";
 import { TaskTrySelect } from "src/components/TaskTrySelect";
 import Time from "src/components/Time";
@@ -84,6 +86,40 @@ export const Details = () => {
     },
   );
 
+  const renderValue = (value: unknown): ReactNode => {
+    if (value === null || value === undefined || value === "") {
+      return translate("common:none", { defaultValue: "None" });
+    }
+
+    if (typeof value === "object") {
+      return <RenderedJsonField content={value} />;
+    }
+
+    if (typeof value === "string") {
+      return value;
+    }
+
+    if (typeof value === "number" || typeof value === "boolean" || typeof 
value === "bigint") {
+      return value.toString();
+    }
+
+    return translate("common:none", { defaultValue: "None" });
+  };
+
+  // omit kwargs from trigger
+  const triggerWithoutKwargs = taskInstance?.trigger
+    ? (({ kwargs, ...rest }) => rest)(taskInstance.trigger)
+    : undefined;
+
+  const rawTaskInstanceDetails: Array<{ label: string; value: unknown }> = [
+    { label: translate("taskInstance.id"), value: taskInstance?.id },
+    { label: translate("tryNumber"), value: tryInstance?.try_number },
+    { label: translate("taskInstance.maxTries"), value: tryInstance?.max_tries 
},
+    { label: translate("dagId"), value: tryInstance?.dag_id },
+    { label: translate("taskInstance.trigger"), value: triggerWithoutKwargs },
+    { label: translate("taskInstance.triggerer.job"), value: 
taskInstance?.triggerer_job },
+  ];
+
   return (
     <Box p={2}>
       {taskInstance === undefined || tryNumber === undefined || 
taskInstance.try_number <= 1 ? (
@@ -225,6 +261,31 @@ export const Details = () => {
           </Table.Row>
         </Table.Body>
       </Table.Root>
+      <Box mt={6}>
+        <Heading as="h3" mb={3} size="sm">
+          {translate("taskInstance.additionalAttributes")}
+        </Heading>
+
+        <Table.Root striped>
+          <Table.Body>
+            {rawTaskInstanceDetails.map(({ label, value }) => {
+              const isObject = typeof value === "object" && value !== null;
+
+              return (
+                <Table.Row key={label}>
+                  <Table.Cell>{label}</Table.Cell>
+                  <Table.Cell
+                    fontFamily={isObject ? undefined : "mono"}
+                    whiteSpace={isObject ? undefined : "pre-wrap"}
+                  >
+                    {renderValue(value)}
+                  </Table.Cell>
+                </Table.Row>
+              );
+            })}
+          </Table.Body>
+        </Table.Root>
+      </Box>
     </Box>
   );
 };

Reply via email to