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

kaxilnaik pushed a commit to branch v3-0-test
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit 2fe9f018a9cd3879c6dcab83d2dce03476a8592b
Author: LI,JHE-CHEN <[email protected]>
AuthorDate: Tue May 13 06:12:00 2025 +0800

    UI: Implement navigation on bar click (#50416)
    
    * UI: implement navigation on bar click
    
    * use default tooltip
    
    * fix: remove unnecessary type assertion and add TI overview 
click-to-navigate function
    
    * refactor: optimize hover handling in DurationChart
    
    * nit:Use switch statement and extract common path
    
    (cherry picked from commit 21ca3ce024f27e200be0864644000b77a6374a7c)
---
 .../airflow/ui/src/components/DurationChart.tsx    | 31 +++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/airflow-core/src/airflow/ui/src/components/DurationChart.tsx 
b/airflow-core/src/airflow/ui/src/components/DurationChart.tsx
index 6a4e86ff1bd..a10af96f417 100644
--- a/airflow-core/src/airflow/ui/src/components/DurationChart.tsx
+++ b/airflow-core/src/airflow/ui/src/components/DurationChart.tsx
@@ -31,6 +31,7 @@ import type { PartialEventContext } from 
"chartjs-plugin-annotation";
 import annotationPlugin from "chartjs-plugin-annotation";
 import dayjs from "dayjs";
 import { Bar } from "react-chartjs-2";
+import { useNavigate } from "react-router-dom";
 
 import type { TaskInstanceResponse, DAGRunResponse } from 
"openapi/requests/types.gen";
 import { system } from "src/theme";
@@ -64,6 +65,8 @@ export const DurationChart = ({
   readonly entries: Array<RunResponse> | undefined;
   readonly kind: "Dag Run" | "Task Instance";
 }) => {
+  const navigate = useNavigate();
+
   if (!entries) {
     return undefined;
   }
@@ -141,6 +144,33 @@ export const DurationChart = ({
         }}
         datasetIdKey="id"
         options={{
+          onClick: (_event, elements) => {
+            const [element] = elements;
+
+            if (!element) {
+              return;
+            }
+
+            const entry = entries[element.index];
+            const baseUrl = `/dags/${entry?.dag_id}/runs/${entry?.dag_run_id}`;
+
+            switch (kind) {
+              case "Dag Run": {
+                navigate(baseUrl);
+                break;
+              }
+              case "Task Instance": {
+                const taskInstance = entry as TaskInstanceResponse;
+
+                navigate(`${baseUrl}/tasks/${taskInstance.task_id}`);
+                break;
+              }
+              default:
+            }
+          },
+          onHover: (_event, elements, chart) => {
+            chart.canvas.style.cursor = elements.length > 0 ? "pointer" : 
"default";
+          },
           plugins: {
             annotation: {
               annotations: {
@@ -158,7 +188,6 @@ export const DurationChart = ({
               },
               title: { align: "end", display: true, text: "Run After" },
             },
-
             y: {
               title: { align: "end", display: true, text: "Duration (seconds)" 
},
             },

Reply via email to