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 4dae472e41a Respect the limit search param in the task overview 
duration chart (#72147)
4dae472e41a is described below

commit 4dae472e41a619e529f26885d596b9d03416776a
Author: warreee <[email protected]>
AuthorDate: Mon Aug 31 21:05:01 2026 +0200

    Respect the limit search param in the task overview duration chart (#72147)
    
    The duration chart on the task overview always requested the last 14 task
    instances, ignoring the number of dag runs the user picked. The dag details
    layout already writes that choice to the limit search param, and the dag
    overview page reads a value of its own, so the task page was the only view
    that could not be widened.
    
    Read the same limit search param the details layout writes, falling back to
    the same default of 10, so the chart follows the selector and can be shared
    through the URL.
    
    The remaining limit on the failed task instance query is left alone: that
    query only reads total_entries and never renders the rows it fetches.
---
 .../ui/src/pages/Task/Overview/Overview.test.tsx   | 54 +++++++++++++++++++---
 .../ui/src/pages/Task/Overview/Overview.tsx        |  7 ++-
 2 files changed, 53 insertions(+), 8 deletions(-)

diff --git 
a/airflow-core/src/airflow/ui/src/pages/Task/Overview/Overview.test.tsx 
b/airflow-core/src/airflow/ui/src/pages/Task/Overview/Overview.test.tsx
index 90c39ec41eb..add9a7796a2 100644
--- a/airflow-core/src/airflow/ui/src/pages/Task/Overview/Overview.test.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Task/Overview/Overview.test.tsx
@@ -18,13 +18,32 @@
  */
 import "@testing-library/jest-dom";
 import { render, screen } from "@testing-library/react";
-import { describe, expect, it, vi } from "vitest";
+import type { PropsWithChildren } from "react";
+import { MemoryRouter } from "react-router-dom";
+import { beforeEach, describe, expect, it, vi } from "vitest";
 
 import type { ReactAppResponse } from "openapi/requests/types.gen";
-import { Wrapper } from "src/utils/Wrapper";
+import { BaseWrapper, Wrapper } from "src/utils/Wrapper";
 
 import { Overview } from "./Overview";
 
+const { mockUseTaskInstanceServiceGetTaskInstances } = vi.hoisted(() => ({
+  mockUseTaskInstanceServiceGetTaskInstances: vi.fn(() => ({
+    data: { task_instances: [], total_entries: 0 },
+    isLoading: false,
+  })),
+}));
+
+const wrapperWithSearch = (search: string) => {
+  const RouterWrapper = ({ children }: PropsWithChildren) => (
+    <BaseWrapper>
+      <MemoryRouter 
initialEntries={[`/dags/my_dag/tasks/my_task${search}`]}>{children}</MemoryRouter>
+    </BaseWrapper>
+  );
+
+  return RouterWrapper;
+};
+
 vi.mock("openapi/queries", () => ({
   usePluginServiceGetPlugins: () => ({
     data: {
@@ -44,10 +63,7 @@ vi.mock("openapi/queries", () => ({
       ],
     },
   }),
-  useTaskInstanceServiceGetTaskInstances: () => ({
-    data: { task_instances: [], total_entries: 0 },
-    isLoading: false,
-  }),
+  useTaskInstanceServiceGetTaskInstances: 
mockUseTaskInstanceServiceGetTaskInstances,
 }));
 
 vi.mock("src/components/DurationChart", () => ({ DurationChart: () => null }));
@@ -79,3 +95,29 @@ describe("Task overview plugins", () => {
     expect(screen.queryByText("Scoped overview 
plugin")).not.toBeInTheDocument();
   });
 });
+
+describe("Task overview duration chart limit", () => {
+  beforeEach(() => {
+    mockUseTaskInstanceServiceGetTaskInstances.mockClear();
+  });
+
+  it("requests the default number of task instances when no limit is set", () 
=> {
+    render(<Overview />, { wrapper: wrapperWithSearch("") });
+
+    expect(mockUseTaskInstanceServiceGetTaskInstances).toHaveBeenCalledWith(
+      expect.objectContaining({ limit: 10, orderBy: ["-run_after"] }),
+      undefined,
+      expect.anything(),
+    );
+  });
+
+  it("requests the number of task instances given by the limit search param", 
() => {
+    render(<Overview />, { wrapper: wrapperWithSearch("?limit=50") });
+
+    expect(mockUseTaskInstanceServiceGetTaskInstances).toHaveBeenCalledWith(
+      expect.objectContaining({ limit: 50, orderBy: ["-run_after"] }),
+      undefined,
+      expect.anything(),
+    );
+  });
+});
diff --git a/airflow-core/src/airflow/ui/src/pages/Task/Overview/Overview.tsx 
b/airflow-core/src/airflow/ui/src/pages/Task/Overview/Overview.tsx
index 470877d1742..377a674f368 100644
--- a/airflow-core/src/airflow/ui/src/pages/Task/Overview/Overview.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Task/Overview/Overview.tsx
@@ -20,7 +20,7 @@ import { Box, HStack, Skeleton, VStack } from 
"@chakra-ui/react";
 import dayjs from "dayjs";
 import { useState } from "react";
 import { useTranslation } from "react-i18next";
-import { useParams } from "react-router-dom";
+import { useParams, useSearchParams } from "react-router-dom";
 
 import { usePluginServiceGetPlugins, useTaskInstanceServiceGetTaskInstances } 
from "openapi/queries";
 import { DurationChart } from "src/components/DurationChart";
@@ -38,6 +38,9 @@ export const Overview = () => {
   const { dagId = "", groupId, taskId } = useParams();
   const { t: translate } = useTranslation("dag");
 
+  const [searchParams] = useSearchParams();
+  const limit = Number(searchParams.get(SearchParamsKeys.LIMIT) ?? "10");
+
   const now = dayjs();
   const [startDate, setStartDate] = useState(now.subtract(Number(defaultHour), 
"hour").toISOString());
   const [endDate, setEndDate] = useState(now.toISOString());
@@ -62,7 +65,7 @@ export const Overview = () => {
     {
       dagId,
       dagRunId: "~",
-      limit: 14,
+      limit,
       orderBy: ["-run_after"],
       taskGroupId: groupId ?? undefined,
       taskId: Boolean(groupId) ? undefined : taskId,

Reply via email to