pierrejeambrun commented on code in PR #67242:
URL: https://github.com/apache/airflow/pull/67242#discussion_r3453369902


##########
airflow-core/newsfragments/67242.feature.rst:
##########
@@ -0,0 +1 @@
+Restore per-Dag run state counts on the Dag list page; click a count to jump 
to that Dag's runs filtered by state.

Review Comment:
   To delete. We don't use feature newsfreagmen



##########
airflow-core/src/airflow/ui/src/pages/DagsList/DagsList.tsx:
##########
@@ -299,9 +356,19 @@ export const DagsList = () => {
             </Heading>
             <DagImportErrors iconOnly />
           </HStack>
-          {display === "card" ? (
-            <SortSelect handleSortChange={handleSortChange} orderBy={orderBy} 
/>
-          ) : undefined}
+          <HStack>
+            <TimeRangeSelector
+              defaultValue={DEFAULT_HOURS}
+              endDate={endDate}
+              setEndDate={setEndDate}
+              setStartDate={setStartDate}
+              showDateRange={false}
+              startDate={startDate}

Review Comment:
   This only seems to apply to the `run_state_count`, I would remove it it's 
confusing



##########
airflow-core/src/airflow/ui/src/pages/DagsList/DagsList.tsx:
##########
@@ -270,6 +307,26 @@ export const DagsList = () => {
     tagsMatchMode: selectedMatchMode,
   });
 
+  const visibleDagIds = useMemo(() => data?.dags.map((dag) => dag.dag_id) ?? 
[], [data?.dags]);
+  const { data: runStateCountsData, isLoading: runStateCountsLoading } = 
useDagRunStateCounts({
+    dagIds: visibleDagIds,
+    dags: data?.dags,
+    startDate,
+  });
+  const runStateContext: RunStateCountsContext = useMemo(
+    () => ({
+      countsByDag: Object.fromEntries(
+        (runStateCountsData?.dags ?? []).map((entry) => [entry.dag_id, 
entry.state_counts]),
+      ),
+      isLoading: runStateCountsLoading,
+      stateCountLimit: runStateCountsData?.state_count_limit,
+    }),
+    [runStateCountsData, runStateCountsLoading],
+  );
+
+  const columns = useMemo(() => createColumns(translate, runStateContext), 
[translate, runStateContext]);
+  const cardDef = useMemo(() => createCardDef(runStateContext), 
[runStateContext]);
+

Review Comment:
   That's a lot of use memo which were not there before, is all that necessary ?



##########
airflow-core/src/airflow/api_fastapi/core_api/routes/ui/dags.py:
##########
@@ -284,3 +288,59 @@ def get_latest_run_info(dag_id: str, session: SessionDep) 
-> DAGRunLightResponse
     latest_run_info = session.execute(latest_run_info_select).one_or_none()
 
     return DAGRunLightResponse(**latest_run_info._mapping) if latest_run_info 
else None
+
+
+@dags_router.get(
+    "/run_state_counts",
+    dependencies=[
+        Depends(requires_access_dag(method="GET")),
+        Depends(requires_access_dag(method="GET", 
access_entity=DagAccessEntity.RUN)),
+    ],
+    operation_id="get_dag_run_state_counts_ui",
+)
+def get_dag_run_state_counts(
+    session: SessionDep,
+    readable_dags_filter: ReadableDagsFilterDep,
+    dag_ids: Annotated[list[str], Query(min_length=1)],
+    run_after_gte: datetime | None = None,
+) -> DAGsRunStateCountsCollectionResponse:
+    """Return per-Dag DagRun state counts (zero-filled) for the Dag list 
page."""
+    permitted_dag_ids = readable_dags_filter.value or set()
+    requested_dag_ids = list(set(dag_ids) & permitted_dag_ids)
+    counts_by_dag: dict[str, dict[DagRunState, int]] = {
+        dag_id: {state: 0 for state in DagRunState} for dag_id in 
requested_dag_ids
+    }
+
+    if requested_dag_ids:
+        # One capped union per state, not a single (dag, state) union: keeping 
every
+        # branch on the same state lets the planner pick a uniform, efficient 
per-branch
+        # plan. A mixed-state union misplans and scans whole partitions 
(orders of
+        # magnitude slower). Each branch reads at most STATE_COUNT_CAP rows; 
the UI
+        # shows "N+" once a count reaches the cap.
+        for state in DagRunState:
+            branches = []
+            for dag_id in requested_dag_ids:
+                filters = [DagRun.dag_id == dag_id, DagRun.state == state]
+                if run_after_gte is not None:
+                    filters.append(DagRun.run_after >= run_after_gte)
+                capped = (
+                    select(literal(dag_id).label("dag_id"))
+                    .select_from(DagRun)
+                    .where(*filters)
+                    .limit(STATE_COUNT_CAP)
+                    .subquery()
+                )
+                branches.append(select(capped.c.dag_id))
+            counts = union_all(*branches).subquery()
+            for row in session.execute(

Review Comment:
   Number of requests scales with the number of passed dag_id. Maybe there's a 
better way to achieve this.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to