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

vatsrahul1001 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 912bbe58050 Fix Dag list run badges and counters not refreshing after 
completion (#74734)
912bbe58050 is described below

commit 912bbe58050604b1d0080f0122fe27dc380724e1
Author: Anzin Mohammed <[email protected]>
AuthorDate: Sun Oct 18 13:18:46 2026 +0530

    Fix Dag list run badges and counters not refreshing after completion 
(#74734)
    
    * Fix Dag run state refresh
    
    * Fix MSW option in Dag refresh regression tests
---
 .../ui/src/queries/useDagRunStateCounts.tsx        |   2 +-
 .../src/airflow/ui/src/queries/useDags.test.tsx    | 101 +++++++++++++++++++++
 .../src/airflow/ui/src/queries/useDags.tsx         |   2 +-
 3 files changed, 103 insertions(+), 2 deletions(-)

diff --git a/airflow-core/src/airflow/ui/src/queries/useDagRunStateCounts.tsx 
b/airflow-core/src/airflow/ui/src/queries/useDagRunStateCounts.tsx
index 238f54cc563..c763d61918e 100644
--- a/airflow-core/src/airflow/ui/src/queries/useDagRunStateCounts.tsx
+++ b/airflow-core/src/airflow/ui/src/queries/useDagRunStateCounts.tsx
@@ -30,7 +30,7 @@ export const useDagRunStateCounts = ({
   // need to be loaded before it knows whether to poll — avoids a 
chicken-and-egg.
   readonly dags: ReadonlyArray<DAGWithLatestDagRunsResponse> | undefined;
 }) => {
-  const refetchInterval = useAutoRefresh({ checkPendingRuns: true });
+  const refetchInterval = useAutoRefresh({});
   const hasPendingRun =
     dags?.some((dag) => !dag.is_paused && dag.latest_dag_runs.some((run) => 
isStatePending(run.state))) ??
     false;
diff --git a/airflow-core/src/airflow/ui/src/queries/useDags.test.tsx 
b/airflow-core/src/airflow/ui/src/queries/useDags.test.tsx
new file mode 100644
index 00000000000..ed98797b8ed
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/queries/useDags.test.tsx
@@ -0,0 +1,101 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import type { PropsWithChildren } from "react";
+
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import { act, cleanup, renderHook, waitFor } from "@testing-library/react";
+import { http, HttpResponse } from "msw";
+import { setupServer } from "msw/node";
+import { afterAll, afterEach, beforeAll, expect, it, vi } from "vitest";
+
+import { successDag } from "src/mocks/handlers/dags";
+
+import { useDagRunStateCounts } from "./useDagRunStateCounts";
+import { useDags } from "./useDags";
+
+const server = setupServer();
+
+beforeAll(() => server.listen({ onUnhandledFrame: "error" }));
+afterEach(() => {
+  cleanup();
+  server.resetHandlers();
+  vi.useRealTimers();
+});
+afterAll(() => server.close());
+
+it.each(["latest run", "run counts"])("refreshes %s when no runs are pending", 
async (target) => {
+  vi.useFakeTimers({ shouldAdvanceTime: true });
+  let completed = false;
+  const client = new QueryClient({ defaultOptions: { queries: { retry: false } 
} });
+  const wrapper = ({ children }: PropsWithChildren) => (
+    <QueryClientProvider client={client}>{children}</QueryClientProvider>
+  );
+
+  server.use(
+    http.get("/ui/config", () => HttpResponse.json({ auto_refresh_interval: 1 
})),
+    http.get("/api/v2/dags/~/dagRuns", () => HttpResponse.json({ dag_runs: [], 
total_entries: 0 })),
+    http.get("/ui/dags", () =>
+      HttpResponse.json({
+        dags: [
+          {
+            ...successDag,
+            latest_dag_runs: successDag.latest_dag_runs.map((run) => ({
+              ...run,
+              state: completed ? "success" : "queued",
+            })),
+          },
+        ],
+        total_entries: 1,
+      }),
+    ),
+    http.get("/ui/dags/run_state_counts", () =>
+      HttpResponse.json({
+        dags: [{ dag_id: successDag.dag_id, state_counts: { success: completed 
? 1 : 0 } }],
+      }),
+    ),
+  );
+
+  const { result } = renderHook(
+    () => {
+      const dags = useDags({ dagRunsLimit: 1 });
+      const counts = useDagRunStateCounts({ dagIds: [successDag.dag_id], dags: 
dags.data?.dags });
+
+      return { counts, dags };
+    },
+    { wrapper },
+  );
+
+  await waitFor(() => {
+    
expect(result.current.dags.data?.dags[0]?.latest_dag_runs[0]?.state).toBe("queued");
+    expect(result.current.counts.data).toBeDefined();
+  });
+  completed = true;
+  await act(async () => {
+    await vi.advanceTimersByTimeAsync(12_000);
+  });
+
+  if (target === "latest run") {
+    
expect(result.current.dags.data?.dags[0]?.latest_dag_runs[0]?.state).toBe("success");
+  } else {
+    expect(result.current.counts.data).toEqual({
+      dags: [{ dag_id: successDag.dag_id, state_counts: { success: 1 } }],
+    });
+  }
+  client.clear();
+});
diff --git a/airflow-core/src/airflow/ui/src/queries/useDags.tsx 
b/airflow-core/src/airflow/ui/src/queries/useDags.tsx
index a9e6f283453..80c740f9ae0 100644
--- a/airflow-core/src/airflow/ui/src/queries/useDags.tsx
+++ b/airflow-core/src/airflow/ui/src/queries/useDags.tsx
@@ -68,7 +68,7 @@ export const useDags = ({
   teams?: Array<string>;
   timetableType?: Array<string>;
 }) => {
-  const refetchInterval = useAutoRefresh({ checkPendingRuns: true });
+  const refetchInterval = useAutoRefresh({});
 
   const { data, error, isLoading } = useDagServiceGetDagsUi(
     {

Reply via email to