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 96988232c27 Fix dag list renders (#74426)
96988232c27 is described below

commit 96988232c27f8c2f502150722464e545a107059e
Author: Brent Bovenzi <[email protected]>
AuthorDate: Tue Oct 13 14:50:19 2026 -0400

    Fix dag list renders (#74426)
    
    * Fix dag card rerendering states
    
    * Drop isFetching from tables
    
    * UI: Fix Dags list error page from stale createColumns signature
    
    The rebase onto main kept a parameter the call site no longer passes, so
    the options object arrived in the wrong position and destructuring the
    third argument threw before the table could render. Reported in review
    and by the Chromium, WebKit and Firefox E2E jobs.
    
    Co-Authored-By: Claude <[email protected]>
    
    ---------
    
    Co-authored-by: Claude <[email protected]>
---
 .../ui/src/components/DataTable/DataTable.test.tsx |   8 -
 .../ui/src/components/DataTable/DataTable.tsx      |   6 +-
 .../src/airflow/ui/src/hooks/useNearViewport.ts    |  25 +-
 .../Asset/AssetStateStore/AssetStateStore.tsx      |   3 +-
 .../ui/src/pages/AssetsList/AssetsList.test.tsx    |   5 +-
 .../airflow/ui/src/pages/AssetsList/AssetsList.tsx |   3 +-
 .../ui/src/pages/Connections/Connections.tsx       |   3 +-
 .../pages/Dag/Backfills/BackfillDagRunsModal.tsx   |   3 +-
 .../ui/src/pages/Dag/Backfills/Backfills.tsx       |   3 +-
 .../src/airflow/ui/src/pages/Dag/Tasks/Tasks.tsx   |   2 -
 .../airflow/ui/src/pages/DagBundle/BundleFiles.tsx |   3 +-
 .../airflow/ui/src/pages/DagBundles/DagBundles.tsx |   3 +-
 .../src/airflow/ui/src/pages/DagsList/DagCard.tsx  |   7 +-
 .../ui/src/pages/DagsList/DagsList.test.tsx        |   5 +-
 .../src/airflow/ui/src/pages/DagsList/DagsList.tsx | 189 ++++++++--------
 .../ui/src/pages/DagsList/DagsListColumns.tsx      | 251 ++++++++++++---------
 .../src/pages/DagsList/DagsListCountsContext.tsx   |  73 ++++++
 .../src/pages/DagsList/PartitionScheduleModal.tsx  |   3 +-
 .../pages/DagsList/RecentTaskStateCountsColumn.tsx |  35 +--
 .../src/airflow/ui/src/pages/Deadlines/index.tsx   |   3 +-
 .../src/airflow/ui/src/pages/Events/Events.tsx     |   3 +-
 airflow-core/src/airflow/ui/src/pages/Jobs.tsx     |   3 +-
 .../ui/src/pages/TaskStateStore/TaskStateStore.tsx |   3 +-
 .../airflow/ui/src/pages/Variables/Variables.tsx   |   3 +-
 .../src/airflow/ui/src/pages/XCom/XCom.tsx         |   3 +-
 .../src/airflow/ui/src/queries/useDags.tsx         |   3 +-
 26 files changed, 388 insertions(+), 263 deletions(-)

diff --git 
a/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.test.tsx 
b/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.test.tsx
index ee6861afb31..55a0b69a7fb 100644
--- a/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.test.tsx
+++ b/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.test.tsx
@@ -264,14 +264,6 @@ describe("DataTable", () => {
     expect(screen.getByRole("heading")).toHaveTextContent(/^task_other$/u);
   });
 
-  it("keeps the row count heading while refetching", () => {
-    render(<DataTable columns={columns} data={data} isFetching 
modelName="task" total={2} />, {
-      wrapper: ChakraWrapper,
-    });
-
-    expect(screen.getByRole("heading")).toHaveTextContent("2 task");
-  });
-
   it("renders a capped row count heading when total reaches 
totalEntriesLimit", () => {
     render(
       <DataTable
diff --git a/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.tsx 
b/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.tsx
index 2759bfa7344..83151985ebd 100644
--- a/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.tsx
+++ b/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.tsx
@@ -32,7 +32,7 @@ import { useTranslation } from "react-i18next";
 import { HiChevronLeft, HiChevronRight } from "react-icons/hi2";
 import { useLocalStorage } from "usehooks-ts";
 
-import { IconButton, Pagination, ProgressBar, Toaster } from 
"src/system-components";
+import { IconButton, Pagination, Toaster } from "src/system-components";
 
 import { CardList } from "src/components/DataTable/CardList";
 import { FilterMenuButton } from "src/components/DataTable/FilterMenuButton";
@@ -64,7 +64,6 @@ type DataTableProps<TData extends RowData> = {
   readonly headingExtra?: ReactNode;
   readonly hideRowCountHeading?: boolean;
   readonly initialState?: TableState;
-  readonly isFetching?: boolean;
   readonly isLoading?: boolean;
   /**
    * i18n key naming the model this table lists — namespaced (`common:dagRun`) 
or bare for `common`.
@@ -120,7 +119,6 @@ export const DataTable = <TData extends RowData>({
   headingExtra,
   hideRowCountHeading,
   initialState,
-  isFetching,
   isLoading,
   modelName,
   nextCursor,
@@ -282,7 +280,6 @@ export const DataTable = <TData extends RowData>({
           gap={2}
           justifyContent="space-between"
           minH={10}
-          mt={2} // This offsets the spacing below created by the ProgressBar
         >
           <VStack alignItems="flex-start" flex="1" gap={2} minW={0} w="100%">
             {headingNode === undefined && headingExtra === undefined ? 
undefined : (
@@ -310,7 +307,6 @@ export const DataTable = <TData extends RowData>({
         </Flex>
       ) : undefined}
       {errorMessage}
-      <ProgressBar size="xs" visibility={Boolean(isFetching) && 
!Boolean(isLoading) ? "visible" : "hidden"} />
       <Box flex={1} minH={0} overflow="auto">
         {display === "card" && cardDef !== undefined ? (
           <CardList cardDef={cardDef} isLoading={isLoading} 
noRowsMessage={noRowsNode} rows={rows} />
diff --git a/airflow-core/src/airflow/ui/src/hooks/useNearViewport.ts 
b/airflow-core/src/airflow/ui/src/hooks/useNearViewport.ts
index 64785c6a1dd..fdf59eaa986 100644
--- a/airflow-core/src/airflow/ui/src/hooks/useNearViewport.ts
+++ b/airflow-core/src/airflow/ui/src/hooks/useNearViewport.ts
@@ -123,14 +123,33 @@ const observeNearViewport = (element: Element, listener: 
() => void) => {
   };
 };
 
-export const useNearViewport = <TElement extends Element>(): {
+export const useNearViewport = <TElement extends Element>({
+  revealedKeys,
+  revealKey,
+}: {
+  /**
+   * Keys already revealed, owned by whatever outlives the elements 
themselves. A list that
+   * remounts its rows — on pagination, a filter or a sort change — would 
otherwise re-latch from
+   * scratch and blank content that was already on screen until the observer 
fires again.
+   */
+  readonly revealedKeys?: Set<string>;
+  /** Identifies this element within `revealedKeys`. */
+  readonly revealKey?: string;
+} = {}): {
   readonly isNearViewport: boolean;
   readonly ref: RefObject<TElement | null>;
   readonly showContent: () => void;
 } => {
   const ref = useRef<TElement>(null);
-  const [isNearViewport, setIsNearViewport] = useState(false);
-  const showContent = useCallback(() => setIsNearViewport(true), []);
+  const [isNearViewport, setIsNearViewport] = useState(
+    () => revealKey !== undefined && revealedKeys?.has(revealKey) === true,
+  );
+  const showContent = useCallback(() => {
+    if (revealKey !== undefined) {
+      revealedKeys?.add(revealKey);
+    }
+    setIsNearViewport(true);
+  }, [revealKey, revealedKeys]);
 
   useEffect(() => {
     const element = ref.current;
diff --git 
a/airflow-core/src/airflow/ui/src/pages/Asset/AssetStateStore/AssetStateStore.tsx
 
b/airflow-core/src/airflow/ui/src/pages/Asset/AssetStateStore/AssetStateStore.tsx
index 4a2e1083a49..bf4649d69d8 100644
--- 
a/airflow-core/src/airflow/ui/src/pages/Asset/AssetStateStore/AssetStateStore.tsx
+++ 
b/airflow-core/src/airflow/ui/src/pages/Asset/AssetStateStore/AssetStateStore.tsx
@@ -145,7 +145,7 @@ export const AssetStateStore = () => {
   const { setTableURLState, tableURLState } = useTableURLState();
   const { pagination } = tableURLState;
 
-  const { data, error, isFetching, isLoading } = 
useAssetStateStoreServiceListAssetStateStore({
+  const { data, error, isLoading } = 
useAssetStateStoreServiceListAssetStateStore({
     assetId,
     limit: pagination.pageSize,
     offset: pagination.pageIndex * pagination.pageSize,
@@ -162,7 +162,6 @@ export const AssetStateStore = () => {
         displayMode="table"
         hideRowCountHeading
         initialState={tableURLState}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="assets:assetStateStore.entry"
         noRowsMessage={translate("assetStateStore.emptyState")}
diff --git 
a/airflow-core/src/airflow/ui/src/pages/AssetsList/AssetsList.test.tsx 
b/airflow-core/src/airflow/ui/src/pages/AssetsList/AssetsList.test.tsx
index e4389510483..77d693a1839 100644
--- a/airflow-core/src/airflow/ui/src/pages/AssetsList/AssetsList.test.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/AssetsList/AssetsList.test.tsx
@@ -120,8 +120,11 @@ describe("AssetsList filtering", () => {
 
     await waitFor(() => 
expect(screen.getByText("asset_with_dependencies")).toBeInTheDocument());
 
+    let refetchStarted = false;
+
     server.use(
       http.get("/ui/assets", async () => {
+        refetchStarted = true;
         await delay("infinite");
 
         return HttpResponse.json({ assets: [], total_entries: 0 });
@@ -130,7 +133,7 @@ describe("AssetsList filtering", () => {
 
     fireEvent.change(screen.getByTestId("search-dags"), { target: { value: 
"plain" } });
 
-    await waitFor(() => expect(screen.getByRole("progressbar")).toBeVisible());
+    await waitFor(() => expect(refetchStarted).toBe(true));
 
     expect(screen.getByText("asset_with_dependencies")).toBeInTheDocument();
     expect(screen.queryAllByTestId("skeleton")).toHaveLength(0);
diff --git a/airflow-core/src/airflow/ui/src/pages/AssetsList/AssetsList.tsx 
b/airflow-core/src/airflow/ui/src/pages/AssetsList/AssetsList.tsx
index d235bca75da..4123c8a0cae 100644
--- a/airflow-core/src/airflow/ui/src/pages/AssetsList/AssetsList.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/AssetsList/AssetsList.tsx
@@ -168,7 +168,7 @@ export const AssetsList = () => {
     value: searchParams.get(SearchParamsKeys.GROUP_PATTERN),
   });
 
-  const { data, error, isFetching, isLoading } = useAssetServiceGetAssetsUi(
+  const { data, error, isLoading } = useAssetServiceGetAssetsUi(
     {
       ...groupArg,
       dagIds: dagId === null || dagId === "" ? undefined : [dagId],
@@ -222,7 +222,6 @@ export const AssetsList = () => {
         </VStack>
       }
       initialState={tableURLState}
-      isFetching={isFetching}
       isLoading={isLoading}
       modelName="common:asset"
       onStateChange={setTableURLState}
diff --git a/airflow-core/src/airflow/ui/src/pages/Connections/Connections.tsx 
b/airflow-core/src/airflow/ui/src/pages/Connections/Connections.tsx
index 5b663124275..6279938f574 100644
--- a/airflow-core/src/airflow/ui/src/pages/Connections/Connections.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Connections/Connections.tsx
@@ -155,7 +155,7 @@ export const Connections = () => {
   const { pagination, sorting } = tableURLState;
   const [sort] = sorting;
   const orderBy = sort ? [`${sort.desc ? "-" : ""}${sort.id}`] : 
["connection_id"];
-  const { data, error, isFetching, isLoading } = 
useConnectionServiceGetConnections({
+  const { data, error, isLoading } = useConnectionServiceGetConnections({
     ...(advancedSearch.enabled
       ? { connectionIdPattern: connectionIdPattern ?? undefined }
       : { connectionIdPrefixPattern: connectionIdPattern ?? undefined }),
@@ -211,7 +211,6 @@ export const Connections = () => {
           />
         }
         initialState={tableURLState}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="admin:connections.connection"
         noRowsMessage={<NothingFoundInfo />}
diff --git 
a/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillDagRunsModal.tsx 
b/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillDagRunsModal.tsx
index 305986b9859..1666d0eadfe 100644
--- 
a/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillDagRunsModal.tsx
+++ 
b/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillDagRunsModal.tsx
@@ -165,7 +165,7 @@ export const BackfillDagRunsModal = ({ backfillId, dagId, 
onClose, open }: Backf
   });
   const shouldPoll = backfill?.completed_at === null;
 
-  const { data, error, isFetching, isLoading } = 
useBackfillServiceListBackfillDagRuns(
+  const { data, error, isLoading } = useBackfillServiceListBackfillDagRuns(
     {
       backfillId: backfillId ?? 0,
       limit: pageSize,
@@ -207,7 +207,6 @@ export const BackfillDagRunsModal = ({ backfillId, dagId, 
onClose, open }: Backf
         columns={getColumns(isPartitioned, translate)}
         data={data?.backfill_dag_runs ?? []}
         initialState={tableState}
-        isFetching={isFetching}
         isLoading={isBackfillLoading || isLoading}
         modelName="common:slot"
         onStateChange={(state) => setPageIndex(state.pagination.pageIndex)}
diff --git a/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/Backfills.tsx 
b/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/Backfills.tsx
index 7baacc01921..af18360831a 100644
--- a/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/Backfills.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/Backfills.tsx
@@ -181,7 +181,7 @@ export const Backfills = () => {
   const reprocessBehaviorParam = searchParams.get(REPROCESS_BEHAVIOR_PARAM);
   const reprocessBehavior = isReprocessBehavior(reprocessBehaviorParam) ? 
reprocessBehaviorParam : undefined;
 
-  const { data, error, isFetching, isLoading } = 
useBackfillServiceListBackfillsUi({
+  const { data, error, isLoading } = useBackfillServiceListBackfillsUi({
     completedAtGte: completedAtGte ?? undefined,
     completedAtLte: completedAtLte ?? undefined,
     createdAtGte: createdAtGte ?? undefined,
@@ -230,7 +230,6 @@ export const Backfills = () => {
       <DataTable
         columns={columns}
         data={data ? data.backfills : []}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="common:backfill"
         onStateChange={setTableURLState}
diff --git a/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/Tasks.tsx 
b/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/Tasks.tsx
index 87f2af4f49a..6b64835458b 100644
--- a/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/Tasks.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/Tasks.tsx
@@ -93,7 +93,6 @@ export const Tasks = () => {
   const {
     data,
     error: tasksError,
-    isFetching,
     isLoading,
   } = useTaskServiceGetTasks({
     dagId,
@@ -138,7 +137,6 @@ export const Tasks = () => {
         data={filteredTasks}
         displayMode="card"
         filterActions={<TaskFilters tasksData={data} />}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="common:task"
         total={data ? data.total_entries : 0}
diff --git a/airflow-core/src/airflow/ui/src/pages/DagBundle/BundleFiles.tsx 
b/airflow-core/src/airflow/ui/src/pages/DagBundle/BundleFiles.tsx
index 4da5e0cc671..f099ae2d92a 100644
--- a/airflow-core/src/airflow/ui/src/pages/DagBundle/BundleFiles.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/DagBundle/BundleFiles.tsx
@@ -113,7 +113,7 @@ export const BundleFiles = ({ bundleName }: { readonly 
bundleName: string }) =>
   const { pagination } = tableURLState;
   const [errorFileloc, setErrorFileloc] = useState<string | 
undefined>(undefined);
 
-  const { data, error, isFetching, isLoading } = 
useDagBundleServiceGetDagBundleFiles(
+  const { data, error, isLoading } = useDagBundleServiceGetDagBundleFiles(
     {
       bundleName,
       limit: pagination.pageSize,
@@ -137,7 +137,6 @@ export const BundleFiles = ({ bundleName }: { readonly 
bundleName: string }) =>
         data={data?.dag_bundle_files ?? []}
         errorMessage={<ErrorAlert error={error} />}
         initialState={tableURLState}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="browse:dagBundles.files.file"
         onStateChange={setTableURLState}
diff --git a/airflow-core/src/airflow/ui/src/pages/DagBundles/DagBundles.tsx 
b/airflow-core/src/airflow/ui/src/pages/DagBundles/DagBundles.tsx
index 4272ea33619..0b054b4af52 100644
--- a/airflow-core/src/airflow/ui/src/pages/DagBundles/DagBundles.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/DagBundles/DagBundles.tsx
@@ -122,7 +122,7 @@ export const DagBundles = () => {
 
   const refetchInterval = useDagBundleRefetchInterval();
 
-  const { data, error, isFetching, isLoading } = 
useDagBundleServiceGetDagBundles(
+  const { data, error, isLoading } = useDagBundleServiceGetDagBundles(
     {
       limit: pagination.pageSize,
       offset: pagination.pageIndex * pagination.pageSize,
@@ -143,7 +143,6 @@ export const DagBundles = () => {
         data={data?.dag_bundles ?? []}
         errorMessage={<ErrorAlert error={error} />}
         initialState={tableURLState}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="common:dagBundle"
         onStateChange={setTableURLState}
diff --git a/airflow-core/src/airflow/ui/src/pages/DagsList/DagCard.tsx 
b/airflow-core/src/airflow/ui/src/pages/DagsList/DagCard.tsx
index 887f66e8c5e..437e54ce081 100644
--- a/airflow-core/src/airflow/ui/src/pages/DagsList/DagCard.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/DagsList/DagCard.tsx
@@ -36,6 +36,7 @@ import { isStatePending, useAutoRefresh } from "src/utils";
 import { DagCardActions } from "./DagCardActions";
 import { DagRunStateCounts } from "./DagRunStateCounts";
 import { DagTags } from "./DagTags";
+import { useRevealedDagCards } from "./DagsListCountsContext";
 import { RecentRuns } from "./RecentRuns";
 import { RecentTaskStateCounts } from "./RecentTaskStateCounts";
 import { Schedule } from "./Schedule";
@@ -58,7 +59,11 @@ export const DagCard = ({
   const { t: translate } = useTranslation(["common", "dag"]);
   const [latestRun] = dag.latest_dag_runs;
   const multiTeamEnabled = Boolean(useConfig("multi_team"));
-  const { isNearViewport, ref, showContent } = 
useNearViewport<HTMLDivElement>();
+  const revealedKeys = useRevealedDagCards();
+  const { isNearViewport, ref, showContent } = 
useNearViewport<HTMLDivElement>({
+    revealedKeys,
+    revealKey: dag.dag_id,
+  });
 
   const refetchInterval = useAutoRefresh({});
 
diff --git a/airflow-core/src/airflow/ui/src/pages/DagsList/DagsList.test.tsx 
b/airflow-core/src/airflow/ui/src/pages/DagsList/DagsList.test.tsx
index 51dc04c8a2d..d41950df2d0 100644
--- a/airflow-core/src/airflow/ui/src/pages/DagsList/DagsList.test.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/DagsList/DagsList.test.tsx
@@ -106,8 +106,11 @@ describe("Dag Filters", () => {
 
     await waitFor(() => 
expect(screen.getByText("tutorial_taskflow_api_failed")).toBeInTheDocument());
 
+    let refetchStarted = false;
+
     server.use(
       http.get("/ui/dags", async () => {
+        refetchStarted = true;
         await delay("infinite");
 
         return HttpResponse.json({ dags: [], total_entries: 0 });
@@ -120,7 +123,7 @@ describe("Dag Filters", () => {
 
     await waitFor(() => {
       expect(screen.getByTestId("run_state-pill")).toBeInTheDocument();
-      expect(screen.getByRole("progressbar")).toBeVisible();
+      expect(refetchStarted).toBe(true);
     });
 
     
expect(screen.getByText("tutorial_taskflow_api_failed")).toBeInTheDocument();
diff --git a/airflow-core/src/airflow/ui/src/pages/DagsList/DagsList.tsx 
b/airflow-core/src/airflow/ui/src/pages/DagsList/DagsList.tsx
index 45fce36981a..e0d4572c4ee 100644
--- a/airflow-core/src/airflow/ui/src/pages/DagsList/DagsList.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/DagsList/DagsList.tsx
@@ -46,7 +46,7 @@ import { useConfig } from "src/queries/useConfig";
 import { useDagFolders } from "src/queries/useDagFolders";
 import { useDagRunStateCounts } from "src/queries/useDagRunStateCounts";
 import { useDags } from "src/queries/useDags";
-import { useRecentTaskStateCounts, type RecentTasks } from 
"src/queries/useRecentTaskStateCounts";
+import { useRecentTaskStateCounts } from 
"src/queries/useRecentTaskStateCounts";
 import { formatNumber, useDocumentTitle } from "src/utils";
 
 import { DagImportErrors } from "../Dashboard/Stats/DagImportErrors";
@@ -55,7 +55,8 @@ import BulkUnpauseDagsButton from "./BulkUnpauseDagsButton";
 import { DagCard } from "./DagCard";
 import { DagFolderTree, type FolderSelection } from "./DagFolderTree";
 import { DagsFilters } from "./DagsFilters";
-import { createColumns, getRowKey, type RunStateCountsContext } from 
"./DagsListColumns";
+import { createColumns, getRowKey } from "./DagsListColumns";
+import { DagsListCountsProvider, useDagsListCounts, type RunStateCounts } from 
"./DagsListCountsContext";
 import { SortSelect } from "./SortSelect";
 
 const {
@@ -77,23 +78,29 @@ const {
   TIMETABLE_TYPE,
 }: SearchParamsKeysType = SearchParamsKeys;
 
-const createCardDef = (
-  runStateContext: RunStateCountsContext,
-  recentTasks: RecentTasks,
-): CardDef<DAGWithLatestDagRunsResponse> => ({
-  card: ({ row }) => (
+// Both the component and the CardDef holding it are module-level constants: 
`flexRender` renders
+// `card` as a component type, so rebuilding either per render would remount 
every card on each
+// auto-refresh tick. The counts it needs come from context instead — see 
`DagsListCountsContext`.
+const DagCardCell = ({ row }: { readonly row: DAGWithLatestDagRunsResponse }) 
=> {
+  const { recentTasks, runStateCounts } = useDagsListCounts();
+
+  return (
     <DagCard
       dag={row}
       recentTasks={recentTasks}
-      runStateCounts={runStateContext.countsByDag[row.dag_id]}
-      runStateCountsLoading={runStateContext.isLoading}
-      stateCountLimit={runStateContext.stateCountLimit}
+      runStateCounts={runStateCounts.countsByDag[row.dag_id]}
+      runStateCountsLoading={runStateCounts.isLoading}
+      stateCountLimit={runStateCounts.stateCountLimit}
     />
-  ),
+  );
+};
+
+const CARD_DEF: CardDef<DAGWithLatestDagRunsResponse> = {
+  card: DagCardCell,
   meta: {
     customSkeleton: <Skeleton height="140px" width="100%" />,
   },
-});
+};
 
 export const DagsList = () => {
   const { i18n, t: translate } = useTranslation();
@@ -199,7 +206,7 @@ export const DagsList = () => {
     pendingHitl = false;
   }
 
-  const { data, error, isFetching, isLoading } = useDags({
+  const { data, error, isLoading } = useDags({
     advancedSearch: advancedSearch.enabled,
     bundleName: selectedBundle,
     dagDisplayNamePattern: Boolean(dagDisplayNamePattern) ? 
dagDisplayNamePattern : undefined,
@@ -226,7 +233,7 @@ export const DagsList = () => {
     dagIds: data?.dags.map((dag) => dag.dag_id) ?? [],
     dags: data?.dags,
   });
-  const runStateContext: RunStateCountsContext = {
+  const runStateCounts: RunStateCounts = {
     countsByDag: Object.fromEntries(
       (runStateCountsData?.dags ?? []).map((entry) => [entry.dag_id, 
entry.state_counts]),
     ),
@@ -236,11 +243,10 @@ export const DagsList = () => {
 
   const recentTasks = useRecentTaskStateCounts(data?.dags);
 
-  const columns = createColumns(translate, runStateContext, {
+  const columns = createColumns(translate, {
     multiTeam: multiTeamEnabled,
-    recentTasks,
+    showRecentTasks: recentTasks.show,
   });
-  const cardDef = createCardDef(runStateContext, recentTasks);
 
   const { allRowsSelected, clearSelections, deselectKeys, handleRowSelect, 
handleSelectAll, selectedRows } =
     useRowSelection({
@@ -286,81 +292,82 @@ export const DagsList = () => {
           </Box>
         ) : undefined}
         <Box flex={1} minWidth={0}>
-          <SelectionProvider
-            allRowsSelected={allRowsSelected}
-            onRowSelect={handleRowSelect}
-            onSelectAll={handleSelectAll}
-            selectedRows={selectedRows}
-          >
-            <DataTable
-              cardDef={cardDef}
-              columns={columns}
-              data={data?.dags ?? []}
-              displayMode={display}
-              enableMultiSort
-              errorMessage={<ErrorAlert error={error} />}
-              filterActions={
-                <VStack alignItems="flex-start" gap={2} w="100%">
-                  <SearchBar
-                    advancedSearch={advancedSearch}
-                    defaultValue={dagDisplayNamePattern}
-                    onChange={handleSearchChange}
-                    placeholder={translate("dags:search.dags")}
-                  />
-                  <DagsFilters />
-                </VStack>
-              }
-              headingExtra={<DagImportErrors iconOnly />}
-              initialState={tableURLState}
-              isFetching={isFetching}
-              isLoading={isLoading}
-              modelName="common:dag"
-              onDisplayToggleChange={handleDisplayToggleChange}
-              onStateChange={setTableURLState}
-              presentationActions={
-                hasFolderTree || display === "card" ? (
-                  <>
-                    {hasFolderTree ? (
-                      <Tooltip
-                        content={translate(showFolders ? "dags:folders.hide" : 
"dags:folders.show")}
-                        openDelay={200}
-                        portalled
-                      >
-                        <IconButton
-                          aria-label={translate(showFolders ? 
"dags:folders.hide" : "dags:folders.show")}
-                          onClick={() => setShowFolders(!showFolders)}
-                          size="sm"
-                          variant={showFolders ? "solid" : "outline"}
-                        >
-                          <FiSidebar />
-                        </IconButton>
-                      </Tooltip>
-                    ) : undefined}
-                    {display === "card" ? (
-                      <SortSelect handleSortChange={handleSortChange} 
orderBy={orderBy[0]} />
-                    ) : undefined}
-                  </>
-                ) : undefined
-              }
-              showDisplayToggle
-              skeletonCount={display === "card" ? 5 : undefined}
-              total={totalEntries}
-            />
-            <ActionBar.Root
-              closeOnInteractOutside={false}
-              open={display === "table" && selectedRows.size > 0}
+          <DagsListCountsProvider recentTasks={recentTasks} 
runStateCounts={runStateCounts}>
+            <SelectionProvider
+              allRowsSelected={allRowsSelected}
+              onRowSelect={handleRowSelect}
+              onSelectAll={handleSelectAll}
+              selectedRows={selectedRows}
             >
-              <ActionBar.Content>
-                <ActionBar.SelectionTrigger>
-                  {formatNumber(selectedRows.size, i18n.language)} 
{translate("selected")}
-                </ActionBar.SelectionTrigger>
-                <ActionBar.Separator />
-                <BulkPauseDrainDagsButton deselectKeys={deselectKeys} 
selectedDags={selectedDags} />
-                <BulkUnpauseDagsButton deselectKeys={deselectKeys} 
selectedDags={selectedDags} />
-                <ActionBar.CloseTrigger onClick={clearSelections} />
-              </ActionBar.Content>
-            </ActionBar.Root>
-          </SelectionProvider>
+              <DataTable
+                cardDef={CARD_DEF}
+                columns={columns}
+                data={data?.dags ?? []}
+                displayMode={display}
+                enableMultiSort
+                errorMessage={<ErrorAlert error={error} />}
+                filterActions={
+                  <VStack alignItems="flex-start" gap={2} w="100%">
+                    <SearchBar
+                      advancedSearch={advancedSearch}
+                      defaultValue={dagDisplayNamePattern}
+                      onChange={handleSearchChange}
+                      placeholder={translate("dags:search.dags")}
+                    />
+                    <DagsFilters />
+                  </VStack>
+                }
+                headingExtra={<DagImportErrors iconOnly />}
+                initialState={tableURLState}
+                isLoading={isLoading}
+                modelName="common:dag"
+                onDisplayToggleChange={handleDisplayToggleChange}
+                onStateChange={setTableURLState}
+                presentationActions={
+                  hasFolderTree || display === "card" ? (
+                    <>
+                      {hasFolderTree ? (
+                        <Tooltip
+                          content={translate(showFolders ? "dags:folders.hide" 
: "dags:folders.show")}
+                          openDelay={200}
+                          portalled
+                        >
+                          <IconButton
+                            aria-label={translate(showFolders ? 
"dags:folders.hide" : "dags:folders.show")}
+                            onClick={() => setShowFolders(!showFolders)}
+                            size="sm"
+                            variant={showFolders ? "solid" : "outline"}
+                          >
+                            <FiSidebar />
+                          </IconButton>
+                        </Tooltip>
+                      ) : undefined}
+                      {display === "card" ? (
+                        <SortSelect handleSortChange={handleSortChange} 
orderBy={orderBy[0]} />
+                      ) : undefined}
+                    </>
+                  ) : undefined
+                }
+                showDisplayToggle
+                skeletonCount={display === "card" ? 5 : undefined}
+                total={totalEntries}
+              />
+              <ActionBar.Root
+                closeOnInteractOutside={false}
+                open={display === "table" && selectedRows.size > 0}
+              >
+                <ActionBar.Content>
+                  <ActionBar.SelectionTrigger>
+                    {formatNumber(selectedRows.size, i18n.language)} 
{translate("selected")}
+                  </ActionBar.SelectionTrigger>
+                  <ActionBar.Separator />
+                  <BulkPauseDrainDagsButton deselectKeys={deselectKeys} 
selectedDags={selectedDags} />
+                  <BulkUnpauseDagsButton deselectKeys={deselectKeys} 
selectedDags={selectedDags} />
+                  <ActionBar.CloseTrigger onClick={clearSelections} />
+                </ActionBar.Content>
+              </ActionBar.Root>
+            </SelectionProvider>
+          </DagsListCountsProvider>
         </Box>
       </Flex>
     </DagsLayout>
diff --git a/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListColumns.tsx 
b/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListColumns.tsx
index ced285b4507..74bc5577ccc 100644
--- a/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListColumns.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListColumns.tsx
@@ -34,10 +34,9 @@ import { TeamName } from "src/components/TeamName";
 import { TogglePause } from "src/components/TogglePause";
 import { TriggerDAGButton } from "src/components/TriggerDag/TriggerDAGButton";
 
-import type { RecentTasks } from "src/queries/useRecentTaskStateCounts";
-
 import { DagRunStateCounts } from "./DagRunStateCounts";
 import { DagTags } from "./DagTags";
+import { useDagsListCounts } from "./DagsListCountsContext";
 import { buildRecentTaskStateCountsColumns } from 
"./RecentTaskStateCountsColumn";
 import { Schedule } from "./Schedule";
 
@@ -45,41 +44,146 @@ export const getRowKey = (dag: 
DAGWithLatestDagRunsResponse) => dag.dag_id;
 
 type GetColumnsParams = {
   readonly multiTeam: boolean;
-  readonly recentTasks: RecentTasks;
+  readonly showRecentTasks: boolean;
 };
 
-export type RunStateCountsContext = {
-  readonly countsByDag: Record<string, Record<string, number> | undefined>;
-  readonly isLoading: boolean;
-  readonly stateCountLimit: number | undefined;
+/**
+ * Every cell renderer below is a module-level component rather than an inline 
arrow.
+ * `flexRender` renders them as component types, so a new function identity 
each render would
+ * remount the cell instead of updating it — see `DagsListCountsContext`.
+ */
+type CellProps = { readonly row: { readonly original: 
DAGWithLatestDagRunsResponse } };
+
+const SelectHeader = () => <SelectionHeaderCheckbox colorPalette="brand" />;
+
+const SelectCell = ({ row }: CellProps) => (
+  <SelectionRowCheckbox colorPalette="brand" rowKey={getRowKey(row.original)} 
/>
+);
+
+const PauseCell = ({ row: { original } }: CellProps) => (
+  <TogglePause
+    dagDisplayName={original.dag_display_name}
+    dagId={original.dag_id}
+    hasUnfinishedRuns={original.has_unfinished_runs}
+    isPaused={original.is_paused}
+    schedulingState={original.scheduling_state}
+  />
+);
+
+const DagNameCell = ({ row: { original } }: CellProps) => (
+  <RouterLink fontWeight="bold" to={`/dags/${original.dag_id}`} 
whiteSpace="nowrap">
+    {original.dag_display_name}
+  </RouterLink>
+);
+
+const ScheduleCell = ({ row: { original } }: CellProps) => (
+  <Box whiteSpace="nowrap">
+    <Schedule
+      assetExpression={original.asset_expression}
+      dagId={original.dag_id}
+      timetableDescription={original.timetable_description}
+      timetablePartitioned={original.timetable_partitioned}
+      timetableSummary={original.timetable_summary}
+    />
+  </Box>
+);
+
+const NextRunCell = ({ row: { original } }: CellProps) =>
+  original.is_paused ? undefined : original.scheduling_state === "draining" ? (
+    <DrainingBadge />
+  ) : Boolean(original.next_dagrun_run_after) ? (
+    <Box whiteSpace="nowrap">
+      <DagRunInfo
+        logicalDate={original.next_dagrun_logical_date}
+        runAfter={original.next_dagrun_run_after as string}
+      />
+    </Box>
+  ) : undefined;
+
+const LatestRunCell = ({ row: { original } }: CellProps) =>
+  original.latest_dag_runs[0] ? (
+    <RouterLink
+      fontWeight="bold"
+      
to={`/dags/${original.dag_id}/runs/${original.latest_dag_runs[0].run_id}`}
+      whiteSpace="nowrap"
+    >
+      <DagRunInfo
+        endDate={original.latest_dag_runs[0].end_date}
+        logicalDate={original.latest_dag_runs[0].logical_date}
+        runAfter={original.latest_dag_runs[0].run_after}
+        startDate={original.latest_dag_runs[0].start_date}
+        state={original.latest_dag_runs[0].state}
+      />
+    </RouterLink>
+  ) : undefined;
+
+const RunStateCountsCell = ({ row: { original } }: CellProps) => {
+  const { runStateCounts } = useDagsListCounts();
+
+  return (
+    <DagRunStateCounts
+      compact
+      counts={runStateCounts.countsByDag[original.dag_id]}
+      dagId={original.dag_id}
+      isLoading={runStateCounts.isLoading}
+      stateCountLimit={runStateCounts.stateCountLimit}
+    />
+  );
 };
 
+const TagsCell = ({
+  row: {
+    original: { tags },
+  },
+}: CellProps) => (
+  <Box whiteSpace="nowrap">
+    <DagTags hideIcon tags={tags} />
+  </Box>
+);
+
+const TeamNameCell = ({ row: { original } }: CellProps) => (
+  <Box whiteSpace="nowrap">
+    <TeamName teamName={original.team_name} />
+  </Box>
+);
+
+const PendingActionsCell = ({ row: { original: dag } }: CellProps) => (
+  <NeedsReviewBadge pendingActions={dag.pending_actions} />
+);
+
+const TriggerCell = ({ row: { original } }: CellProps) => (
+  <TriggerDAGButton
+    allowedRunTypes={original.allowed_run_types}
+    dagDisplayName={original.dag_display_name}
+    dagId={original.dag_id}
+  />
+);
+
+const FavoriteCell = ({ row: { original } }: CellProps) => (
+  <FavoriteDagButton dagId={original.dag_id} isFavorite={original.is_favorite} 
/>
+);
+
+const DeleteCell = ({ row: { original } }: CellProps) => (
+  <DeleteDagButton dagDisplayName={original.dag_display_name} 
dagId={original.dag_id} />
+);
+
 export const createColumns = (
   translate: (key: string, options?: Record<string, unknown>) => string,
-  runStateContext: RunStateCountsContext,
-  { multiTeam, recentTasks }: GetColumnsParams,
+  { multiTeam, showRecentTasks }: GetColumnsParams,
 ): Array<ColumnDef<DataTableFeatures, DAGWithLatestDagRunsResponse>> => [
   {
     accessorKey: "select",
-    cell: ({ row }) => <SelectionRowCheckbox colorPalette="brand" 
rowKey={getRowKey(row.original)} />,
+    cell: SelectCell,
     enableHiding: false,
     enableSorting: false,
-    header: () => <SelectionHeaderCheckbox colorPalette="brand" />,
+    header: SelectHeader,
     meta: {
       skeletonWidth: 10,
     },
   },
   {
     accessorKey: "is_paused",
-    cell: ({ row: { original } }) => (
-      <TogglePause
-        dagDisplayName={original.dag_display_name}
-        dagId={original.dag_id}
-        hasUnfinishedRuns={original.has_unfinished_runs}
-        isPaused={original.is_paused}
-        schedulingState={original.scheduling_state}
-      />
-    ),
+    cell: PauseCell,
     enableSorting: false,
     header: "",
     meta: {
@@ -88,139 +192,70 @@ export const createColumns = (
   },
   {
     accessorKey: "dag_display_name",
-    cell: ({ row: { original } }) => (
-      <RouterLink fontWeight="bold" to={`/dags/${original.dag_id}`} 
whiteSpace="nowrap">
-        {original.dag_display_name}
-      </RouterLink>
-    ),
-    header: () => translate("dagId"),
+    cell: DagNameCell,
+    header: translate("dagId"),
   },
   {
     accessorKey: "timetable_description",
-    cell: ({ row: { original } }) => (
-      <Box whiteSpace="nowrap">
-        <Schedule
-          assetExpression={original.asset_expression}
-          dagId={original.dag_id}
-          timetableDescription={original.timetable_description}
-          timetablePartitioned={original.timetable_partitioned}
-          timetableSummary={original.timetable_summary}
-        />
-      </Box>
-    ),
+    cell: ScheduleCell,
     enableSorting: false,
-    header: () => translate("dagDetails.schedule"),
+    header: translate("dagDetails.schedule"),
   },
   {
     accessorKey: "next_dagrun",
-    cell: ({ row: { original } }) =>
-      original.is_paused ? undefined : original.scheduling_state === 
"draining" ? (
-        <DrainingBadge />
-      ) : Boolean(original.next_dagrun_run_after) ? (
-        <Box whiteSpace="nowrap">
-          <DagRunInfo
-            logicalDate={original.next_dagrun_logical_date}
-            runAfter={original.next_dagrun_run_after as string}
-          />
-        </Box>
-      ) : undefined,
-    header: () => translate("dagDetails.nextRun"),
+    cell: NextRunCell,
+    header: translate("dagDetails.nextRun"),
   },
   {
     accessorKey: "last_run_run_after",
-    cell: ({ row: { original } }) =>
-      original.latest_dag_runs[0] ? (
-        <RouterLink
-          fontWeight="bold"
-          
to={`/dags/${original.dag_id}/runs/${original.latest_dag_runs[0].run_id}`}
-          whiteSpace="nowrap"
-        >
-          <DagRunInfo
-            endDate={original.latest_dag_runs[0].end_date}
-            logicalDate={original.latest_dag_runs[0].logical_date}
-            runAfter={original.latest_dag_runs[0].run_after}
-            startDate={original.latest_dag_runs[0].start_date}
-            state={original.latest_dag_runs[0].state}
-          />
-        </RouterLink>
-      ) : undefined,
-    header: () => translate("dagDetails.latestRun"),
+    cell: LatestRunCell,
+    header: translate("dagDetails.latestRun"),
   },
   {
     accessorKey: "run_state_counts",
-    cell: ({ row: { original } }) => (
-      <DagRunStateCounts
-        compact
-        counts={runStateContext.countsByDag[original.dag_id]}
-        dagId={original.dag_id}
-        isLoading={runStateContext.isLoading}
-        stateCountLimit={runStateContext.stateCountLimit}
-      />
-    ),
+    cell: RunStateCountsCell,
     enableSorting: false,
-    header: () => translate("dags:runStateCounts.label"),
+    header: translate("dags:runStateCounts.label"),
   },
-  ...buildRecentTaskStateCountsColumns(recentTasks),
+  ...buildRecentTaskStateCountsColumns(showRecentTasks),
   {
     accessorKey: "tags",
-    cell: ({
-      row: {
-        original: { tags },
-      },
-    }) => (
-      <Box whiteSpace="nowrap">
-        <DagTags hideIcon tags={tags} />
-      </Box>
-    ),
+    cell: TagsCell,
     enableSorting: false,
-    header: () => translate("dagDetails.tags"),
+    header: translate("dagDetails.tags"),
   },
   ...(multiTeam
     ? [
         {
           accessorKey: "team_name",
-          cell: ({ row: { original } }: { row: { original: 
DAGWithLatestDagRunsResponse } }) => (
-            <Box whiteSpace="nowrap">
-              <TeamName teamName={original.team_name} />
-            </Box>
-          ),
+          cell: TeamNameCell,
           enableSorting: false,
-          header: () => translate("dagDetails.team"),
+          header: translate("dagDetails.team"),
         },
       ]
     : []),
   {
     accessorKey: "pending_actions",
-    cell: ({ row: { original: dag } }) => <NeedsReviewBadge 
pendingActions={dag.pending_actions} />,
+    cell: PendingActionsCell,
     enableSorting: false,
     header: "",
   },
   {
     accessorKey: "trigger",
-    cell: ({ row: { original } }) => (
-      <TriggerDAGButton
-        allowedRunTypes={original.allowed_run_types}
-        dagDisplayName={original.dag_display_name}
-        dagId={original.dag_id}
-      />
-    ),
+    cell: TriggerCell,
     enableSorting: false,
     header: "",
   },
   {
     accessorKey: "favourite",
-    cell: ({ row: { original } }) => (
-      <FavoriteDagButton dagId={original.dag_id} 
isFavorite={original.is_favorite} />
-    ),
+    cell: FavoriteCell,
     enableHiding: false,
     enableSorting: false,
     header: "",
   },
   {
     accessorKey: "delete",
-    cell: ({ row: { original } }) => (
-      <DeleteDagButton dagDisplayName={original.dag_display_name} 
dagId={original.dag_id} />
-    ),
+    cell: DeleteCell,
     enableSorting: false,
     header: "",
   },
diff --git 
a/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListCountsContext.tsx 
b/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListCountsContext.tsx
new file mode 100644
index 00000000000..3ab6a667dfe
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListCountsContext.tsx
@@ -0,0 +1,73 @@
+/*!
+ * 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 { createContext, useContext, useRef, type ReactNode } from "react";
+
+import type { RecentTasks } from "src/queries/useRecentTaskStateCounts";
+
+export type RunStateCounts = {
+  readonly countsByDag: Record<string, Record<string, number> | undefined>;
+  readonly isLoading: boolean;
+  readonly stateCountLimit: number | undefined;
+};
+
+type DagsListCountsValue = {
+  readonly recentTasks: RecentTasks;
+  /** Dag ids whose cards have already revealed their lazily-rendered content. 
*/
+  readonly revealedKeys: Set<string>;
+  readonly runStateCounts: RunStateCounts;
+};
+
+const DagsListCountsContext = createContext<DagsListCountsValue | 
undefined>(undefined);
+
+/**
+ * Carries the two polled count collections to the Dags list's cards and cells.
+ *
+ * They arrive from their own queries and change on every auto-refresh tick, 
so passing them
+ * through `createColumns`/`createCardDef` would rebuild those renderers and 
give React a new
+ * component type each tick — remounting every card and resetting their 
lazy-render latches.
+ * Reading them from context keeps the renderers module-level constants that 
update in place.
+ */
+export const DagsListCountsProvider = ({
+  children,
+  recentTasks,
+  runStateCounts,
+}: {
+  readonly children: ReactNode;
+  readonly recentTasks: RecentTasks;
+  readonly runStateCounts: RunStateCounts;
+}) => {
+  // Outlives the cards, so a card that remounts keeps whatever it had already 
revealed.
+  const revealedKeys = useRef(new Set<string>());
+  const value: DagsListCountsValue = { recentTasks, revealedKeys: 
revealedKeys.current, runStateCounts };
+
+  return <DagsListCountsContext.Provider 
value={value}>{children}</DagsListCountsContext.Provider>;
+};
+
+export const useDagsListCounts = () => {
+  const ctx = useContext(DagsListCountsContext);
+
+  if (ctx === undefined) {
+    throw new Error("Dags list cards and cells must be used inside 
<DagsListCountsProvider>");
+  }
+
+  return ctx;
+};
+
+/** The reveal cache when rendered inside the list, and `undefined` for a card 
rendered on its own. */
+export const useRevealedDagCards = () => 
useContext(DagsListCountsContext)?.revealedKeys;
diff --git 
a/airflow-core/src/airflow/ui/src/pages/DagsList/PartitionScheduleModal.tsx 
b/airflow-core/src/airflow/ui/src/pages/DagsList/PartitionScheduleModal.tsx
index b53769e10f3..2e9eaf9f498 100644
--- a/airflow-core/src/airflow/ui/src/pages/DagsList/PartitionScheduleModal.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/DagsList/PartitionScheduleModal.tsx
@@ -91,7 +91,7 @@ export const PartitionScheduleModal = ({ dagId, onClose, open 
}: PartitionSchedu
   } satisfies TableState;
   const { pagination } = tableState;
 
-  const { data, error, isFetching, isLoading } = 
usePartitionedDagRunServiceGetPartitionedDagRuns(
+  const { data, error, isLoading } = 
usePartitionedDagRunServiceGetPartitionedDagRuns(
     {
       dagId,
       hasCreatedDagRunId: false,
@@ -133,7 +133,6 @@ export const PartitionScheduleModal = ({ dagId, onClose, 
open }: PartitionSchedu
         data={partitionedDagRuns}
         hideRowCountHeading
         initialState={tableState}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="partitionedDagRun"
         onStateChange={(state) => setPageIndex(state.pagination.pageIndex)}
diff --git 
a/airflow-core/src/airflow/ui/src/pages/DagsList/RecentTaskStateCountsColumn.tsx
 
b/airflow-core/src/airflow/ui/src/pages/DagsList/RecentTaskStateCountsColumn.tsx
index c00b1b18c64..c9db7afea25 100644
--- 
a/airflow-core/src/airflow/ui/src/pages/DagsList/RecentTaskStateCountsColumn.tsx
+++ 
b/airflow-core/src/airflow/ui/src/pages/DagsList/RecentTaskStateCountsColumn.tsx
@@ -22,29 +22,38 @@ import type { DAGWithLatestDagRunsResponse } from 
"openapi/requests/types.gen";
 
 import type { DataTableFeatures } from "src/components/DataTable/features";
 
-import type { RecentTasks } from "src/queries/useRecentTaskStateCounts";
-
+import { useDagsListCounts } from "./DagsListCountsContext";
 import { RecentTaskStateCounts } from "./RecentTaskStateCounts";
 import { RecentTaskStateCountsHeader } from "./RecentTaskStateCountsHeader";
 
+const RecentTaskStateCountsCell = ({
+  row: { original },
+}: {
+  readonly row: { readonly original: DAGWithLatestDagRunsResponse };
+}) => {
+  const { recentTasks } = useDagsListCounts();
+
+  return (
+    <RecentTaskStateCounts
+      compact
+      dagId={original.dag_id}
+      entry={recentTasks.entriesByDag[original.dag_id]}
+      isLoading={recentTasks.isLoading}
+    />
+  );
+};
+
 /** The Dags table's "Recent tasks" column, or no column when the user turned 
it off. */
 export const buildRecentTaskStateCountsColumns = (
-  recentTasks: RecentTasks,
+  show: boolean,
 ): Array<ColumnDef<DataTableFeatures, DAGWithLatestDagRunsResponse>> =>
-  recentTasks.show
+  show
     ? [
         {
           accessorKey: "recent_task_state_counts",
-          cell: ({ row: { original } }) => (
-            <RecentTaskStateCounts
-              compact
-              dagId={original.dag_id}
-              entry={recentTasks.entriesByDag[original.dag_id]}
-              isLoading={recentTasks.isLoading}
-            />
-          ),
+          cell: RecentTaskStateCountsCell,
           enableSorting: false,
-          header: () => <RecentTaskStateCountsHeader />,
+          header: RecentTaskStateCountsHeader,
         },
       ]
     : [];
diff --git a/airflow-core/src/airflow/ui/src/pages/Deadlines/index.tsx 
b/airflow-core/src/airflow/ui/src/pages/Deadlines/index.tsx
index 77c01e78a7f..1fa0926e285 100644
--- a/airflow-core/src/airflow/ui/src/pages/Deadlines/index.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Deadlines/index.tsx
@@ -144,7 +144,7 @@ export const Deadlines = () => {
   const missedFilter =
     filteredMissed === "true" || filteredMissed === "false" ? filteredMissed 
=== "true" : undefined;
 
-  const { data, error, isFetching, isLoading } = 
useDeadlinesServiceGetDeadlines({
+  const { data, error, isLoading } = useDeadlinesServiceGetDeadlines({
     dagId: filteredDagId !== null && filteredDagId !== "" ? filteredDagId : 
"~",
     dagRunId: "~",
     deadlineTimeGte: deadlineTimeGte ?? undefined,
@@ -170,7 +170,6 @@ export const Deadlines = () => {
           />
         }
         initialState={tableURLState}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="browse:deadlines.deadline"
         onStateChange={setTableURLState}
diff --git a/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx 
b/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
index 865c99fc03b..d39995cec8e 100644
--- a/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
@@ -249,7 +249,7 @@ export const Events = () => {
     value: taskIdFilter,
   });
 
-  const { data, error, isFetching, isLoading } = 
useEventLogServiceGetEventLogs(
+  const { data, error, isLoading } = useEventLogServiceGetEventLogs(
     {
       after: afterDate,
       before: beforeDate,
@@ -288,7 +288,6 @@ export const Events = () => {
         displayMode="table"
         filterActions={<EventsFilters urlDagId={dagId} urlRunId={runId} 
urlTaskId={taskId} />}
         initialState={tableURLState}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="common:event"
         onStateChange={setTableURLState}
diff --git a/airflow-core/src/airflow/ui/src/pages/Jobs.tsx 
b/airflow-core/src/airflow/ui/src/pages/Jobs.tsx
index 4eb7513975b..1d2792e107c 100644
--- a/airflow-core/src/airflow/ui/src/pages/Jobs.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Jobs.tsx
@@ -146,7 +146,7 @@ export const Jobs = () => {
   const filteredEndDateLte = searchParams.get(SearchParamsKeys.END_DATE_LTE);
   const teams = searchParams.getAll(SearchParamsKeys.TEAMS);
 
-  const { data, error, isFetching, isLoading } = useJobServiceGetJobs({
+  const { data, error, isLoading } = useJobServiceGetJobs({
     endDateGte: filteredEndDateGte ?? undefined,
     endDateLte: filteredEndDateLte ?? undefined,
     executorClass: filteredExecutorClass ?? undefined,
@@ -175,7 +175,6 @@ export const Jobs = () => {
           />
         }
         initialState={tableURLState}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="admin:jobs.job"
         onStateChange={setTableURLState}
diff --git 
a/airflow-core/src/airflow/ui/src/pages/TaskStateStore/TaskStateStore.tsx 
b/airflow-core/src/airflow/ui/src/pages/TaskStateStore/TaskStateStore.tsx
index fb186f7243b..e81e679ab85 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskStateStore/TaskStateStore.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskStateStore/TaskStateStore.tsx
@@ -128,7 +128,7 @@ export const TaskStateStore = () => {
   const { setTableURLState, tableURLState } = useTableURLState();
   const { pagination } = tableURLState;
 
-  const { data, error, isFetching, isLoading } = 
useTaskStateStoreServiceListTaskStateStore(
+  const { data, error, isLoading } = 
useTaskStateStoreServiceListTaskStateStore(
     {
       ...coordinates,
       dagId,
@@ -153,7 +153,6 @@ export const TaskStateStore = () => {
         displayMode="table"
         hideRowCountHeading
         initialState={tableURLState}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="dag:taskStateStore.entry"
         noRowsMessage={translate("taskStateStore.emptyStore")}
diff --git a/airflow-core/src/airflow/ui/src/pages/Variables/Variables.tsx 
b/airflow-core/src/airflow/ui/src/pages/Variables/Variables.tsx
index 77f319ce303..2dd6c20fac8 100644
--- a/airflow-core/src/airflow/ui/src/pages/Variables/Variables.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Variables/Variables.tsx
@@ -164,7 +164,7 @@ export const Variables = () => {
   const orderBy = sort ? [`${sort.desc ? "-" : ""}${sort.id === "value" ? 
"_val" : sort.id}`] : ["-key"];
   const multiTeamEnabled = Boolean(useConfig("multi_team"));
 
-  const { data, error, isFetching, isLoading } = 
useVariableServiceGetVariables({
+  const { data, error, isLoading } = useVariableServiceGetVariables({
     limit: pagination.pageSize,
     offset: pagination.pageIndex * pagination.pageSize,
     orderBy,
@@ -222,7 +222,6 @@ export const Variables = () => {
           />
         }
         initialState={tableURLState}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="admin:variables.variable"
         noRowsMessage={translate("variables.noRowsMessage")}
diff --git a/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx 
b/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
index ecf0710cbb1..08a393a44f4 100644
--- a/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
@@ -259,7 +259,7 @@ export const XCom = () => {
     ...xcomKeyArg,
   };
 
-  const { data, error, isFetching, isLoading } = 
useXcomServiceGetXcomEntries(apiParams, undefined);
+  const { data, error, isLoading } = useXcomServiceGetXcomEntries(apiParams, 
undefined);
 
   const xcomEntries = data?.xcom_entries ?? [];
   const isTaskInstancePage = dagId !== "~" && runId !== "~" && taskId !== "~";
@@ -280,7 +280,6 @@ export const XCom = () => {
         displayMode="table"
         filterActions={<XComFilters />}
         initialState={tableURLState}
-        isFetching={isFetching}
         isLoading={isLoading}
         modelName="browse:xcom.entry"
         onStateChange={setTableURLState}
diff --git a/airflow-core/src/airflow/ui/src/queries/useDags.tsx 
b/airflow-core/src/airflow/ui/src/queries/useDags.tsx
index 4ccf18ca4df..a9e6f283453 100644
--- a/airflow-core/src/airflow/ui/src/queries/useDags.tsx
+++ b/airflow-core/src/airflow/ui/src/queries/useDags.tsx
@@ -70,7 +70,7 @@ export const useDags = ({
 }) => {
   const refetchInterval = useAutoRefresh({ checkPendingRuns: true });
 
-  const { data, error, isFetching, isLoading } = useDagServiceGetDagsUi(
+  const { data, error, isLoading } = useDagServiceGetDagsUi(
     {
       ...(advancedSearch
         ? { dagDisplayNamePattern, dagIdPattern }
@@ -114,7 +114,6 @@ export const useDags = ({
   return {
     data,
     error,
-    isFetching,
     isLoading,
   };
 };

Reply via email to