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,