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 dc2ee911151 UI: Add duration filter to DAG Backfills tab (#74202)
dc2ee911151 is described below

commit dc2ee91115169502a1dc1953ff9c0d7b277fabcd
Author: Sakshi Yadav <[email protected]>
AuthorDate: Wed Oct 7 00:20:04 2026 +0530

    UI: Add duration filter to DAG Backfills tab (#74202)
    
    * core file changes
    
    Signed-off-by: ydsakshi <[email protected]>
    
    * generated files
    
    * Static checks failure - resolved
    
    ---------
    
    Signed-off-by: ydsakshi <[email protected]>
---
 .../api_fastapi/core_api/openapi/_private_ui.yaml  | 32 ++++++++++++++++
 .../api_fastapi/core_api/routes/ui/backfills.py    |  3 ++
 airflow-core/src/airflow/models/backfill.py        | 43 ++++++++++++++++++++--
 .../src/airflow/ui/openapi-gen/queries/common.ts   |  8 +++-
 .../ui/openapi-gen/queries/ensureQueryData.ts      | 12 +++++-
 .../src/airflow/ui/openapi-gen/queries/prefetch.ts | 12 +++++-
 .../src/airflow/ui/openapi-gen/queries/queries.ts  | 12 +++++-
 .../src/airflow/ui/openapi-gen/queries/suspense.ts | 12 +++++-
 .../ui/openapi-gen/requests/services.gen.ts        |  8 ++++
 .../airflow/ui/openapi-gen/requests/types.gen.ts   |  4 ++
 .../ui/src/pages/Dag/Backfills/Backfills.tsx       |  6 +++
 .../src/pages/Dag/Backfills/BackfillsFilters.tsx   |  2 +
 12 files changed, 141 insertions(+), 13 deletions(-)

diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml 
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
index de12f997600..f28adbd241c 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
+++ b/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
@@ -1634,6 +1634,38 @@ paths:
           - type: integer
           - type: 'null'
           title: Max Active Runs Lt
+      - name: duration_gte
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: number
+          - type: 'null'
+          title: Duration Gte
+      - name: duration_gt
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: number
+          - type: 'null'
+          title: Duration Gt
+      - name: duration_lte
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: number
+          - type: 'null'
+          title: Duration Lte
+      - name: duration_lt
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: number
+          - type: 'null'
+          title: Duration Lt
       - name: reprocess_behavior
         in: query
         required: false
diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/backfills.py 
b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/backfills.py
index ff8782e9316..eda81be7115 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/backfills.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/backfills.py
@@ -32,6 +32,7 @@ from airflow.api_fastapi.common.parameters import (
     SortParam,
     datetime_range_filter_factory,
     filter_param_factory,
+    float_range_filter_factory,
     int_range_filter_factory,
 )
 from airflow.api_fastapi.common.router import AirflowRouter
@@ -60,6 +61,7 @@ def list_backfills_ui(
     created_at: Annotated[RangeFilter, 
Depends(datetime_range_filter_factory("created_at", Backfill))],
     completed_at: Annotated[RangeFilter, 
Depends(datetime_range_filter_factory("completed_at", Backfill))],
     max_active_runs: Annotated[RangeFilter, 
Depends(int_range_filter_factory("max_active_runs", Backfill))],
+    duration_range: Annotated[RangeFilter, 
Depends(float_range_filter_factory("duration", Backfill))],
     reprocess_behavior: Annotated[
         FilterParam, Depends(filter_param_factory(Backfill.reprocess_behavior, 
ReprocessBehavior | None))
     ],
@@ -86,6 +88,7 @@ def list_backfills_ui(
             created_at,
             completed_at,
             max_active_runs,
+            duration_range,
             reprocess_behavior,
         ],
         order_by=order_by,
diff --git a/airflow-core/src/airflow/models/backfill.py 
b/airflow-core/src/airflow/models/backfill.py
index 5153c5c4c6c..8e74f3e7fab 100644
--- a/airflow-core/src/airflow/models/backfill.py
+++ b/airflow-core/src/airflow/models/backfill.py
@@ -26,7 +26,7 @@ from __future__ import annotations
 from collections.abc import Iterable
 from datetime import datetime
 from enum import Enum
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Any
 
 import sqlalchemy as sa
 import structlog
@@ -37,18 +37,26 @@ from sqlalchemy import (
     Integer,
     String,
     UniqueConstraint,
+    case,
     delete,
     func,
     select,
+    text,
 )
 from sqlalchemy.exc import IntegrityError, OperationalError
+from sqlalchemy.ext.hybrid import hybrid_property
 from sqlalchemy.orm import Mapped, mapped_column, relationship, validates
 
 from airflow._shared.timezones import timezone
 from airflow.exceptions import AirflowException, DagNotFound, 
DagRunTypeNotAllowed
 from airflow.models.base import Base, StringID
-from airflow.utils.session import create_session
-from airflow.utils.sqlalchemy import UtcDateTime, is_lock_not_available_error, 
with_row_locks
+from airflow.utils.db import get_dialect_name
+from airflow.utils.session import NEW_SESSION, create_session, provide_session
+from airflow.utils.sqlalchemy import (
+    UtcDateTime,
+    is_lock_not_available_error,
+    with_row_locks,
+)
 from airflow.utils.state import DagRunState
 from airflow.utils.types import DagRunTriggeredByType, DagRunType
 
@@ -203,6 +211,35 @@ class Backfill(Base):
     def __repr__(self):
         return f"Backfill({self.dag_id=}, {self.from_date=}, {self.to_date=})"
 
+    @hybrid_property
+    def duration(self) -> float | None:
+        if self.completed_at and self.created_at:
+            return (self.completed_at - self.created_at).total_seconds()
+        return None
+
+    @duration.expression  # type: ignore[no-redef]
+    def duration(cls) -> Any:
+        @provide_session
+        def _get_dialect(*, session: Session = NEW_SESSION) -> str:
+            return get_dialect_name(session=session)
+
+        dialect_name = _get_dialect()
+
+        duration_expr: Any
+        if dialect_name == "mysql":
+            duration_expr = func.timestampdiff(text("SECOND"), cls.created_at, 
cls.completed_at)
+        elif dialect_name == "sqlite":
+            duration_expr = (func.julianday(cls.completed_at) - 
func.julianday(cls.created_at)) * 86400
+        else:
+            duration_expr = func.extract("epoch", cls.completed_at - 
cls.created_at)  # type: ignore[operator, arg-type]
+
+        when_condition = (
+            cls.completed_at.isnot(None) & cls.created_at.isnot(None),  # 
type: ignore[union-attr, attr-defined]
+            duration_expr,
+        )
+
+        return case(when_condition, else_=None)
+
 
 class BackfillDagRunExceptionReason(str, Enum):
     """
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts 
b/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
index bbdde559034..4eb17d203b9 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
@@ -139,7 +139,7 @@ export const UseBackfillServiceListBackfillDagRunsKeyFn = 
({ backfillId, limit,
 export type BackfillServiceListBackfillsUiDefaultResponse = 
Awaited<ReturnType<typeof BackfillService.listBackfillsUi>>;
 export type BackfillServiceListBackfillsUiQueryResult<TData = 
BackfillServiceListBackfillsUiDefaultResponse, TError = unknown> = 
UseQueryResult<TData, TError>;
 export const useBackfillServiceListBackfillsUiKey = 
"BackfillServiceListBackfillsUi";
-export const UseBackfillServiceListBackfillsUiKeyFn = ({ active, 
completedAtGt, completedAtGte, completedAtLt, completedAtLte, createdAtGt, 
createdAtGte, createdAtLt, createdAtLte, dagId, fromDateGt, fromDateGte, 
fromDateLt, fromDateLte, limit, maxActiveRunsGt, maxActiveRunsGte, 
maxActiveRunsLt, maxActiveRunsLte, offset, orderBy, reprocessBehavior, 
toDateGt, toDateGte, toDateLt, toDateLte }: {
+export const UseBackfillServiceListBackfillsUiKeyFn = ({ active, 
completedAtGt, completedAtGte, completedAtLt, completedAtLte, createdAtGt, 
createdAtGte, createdAtLt, createdAtLte, dagId, durationGt, durationGte, 
durationLt, durationLte, fromDateGt, fromDateGte, fromDateLt, fromDateLte, 
limit, maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, maxActiveRunsLte, 
offset, orderBy, reprocessBehavior, toDateGt, toDateGte, toDateLt, toDateLte }: 
{
   active?: boolean;
   completedAtGt?: string;
   completedAtGte?: string;
@@ -150,6 +150,10 @@ export const UseBackfillServiceListBackfillsUiKeyFn = ({ 
active, completedAtGt,
   createdAtLt?: string;
   createdAtLte?: string;
   dagId?: string;
+  durationGt?: number;
+  durationGte?: number;
+  durationLt?: number;
+  durationLte?: number;
   fromDateGt?: string;
   fromDateGte?: string;
   fromDateLt?: string;
@@ -166,7 +170,7 @@ export const UseBackfillServiceListBackfillsUiKeyFn = ({ 
active, completedAtGt,
   toDateGte?: string;
   toDateLt?: string;
   toDateLte?: string;
-} = {}, queryKey?: Array<unknown>) => [useBackfillServiceListBackfillsUiKey, 
...(queryKey ?? [{ active, completedAtGt, completedAtGte, completedAtLt, 
completedAtLte, createdAtGt, createdAtGte, createdAtLt, createdAtLte, dagId, 
fromDateGt, fromDateGte, fromDateLt, fromDateLte, limit, maxActiveRunsGt, 
maxActiveRunsGte, maxActiveRunsLt, maxActiveRunsLte, offset, orderBy, 
reprocessBehavior, toDateGt, toDateGte, toDateLt, toDateLte }])];
+} = {}, queryKey?: Array<unknown>) => [useBackfillServiceListBackfillsUiKey, 
...(queryKey ?? [{ active, completedAtGt, completedAtGte, completedAtLt, 
completedAtLte, createdAtGt, createdAtGte, createdAtLt, createdAtLte, dagId, 
durationGt, durationGte, durationLt, durationLte, fromDateGt, fromDateGte, 
fromDateLt, fromDateLte, limit, maxActiveRunsGt, maxActiveRunsGte, 
maxActiveRunsLt, maxActiveRunsLte, offset, orderBy, reprocessBehavior, 
toDateGt, toDateGte, toDateLt, toDateLte }])];
 export type ConnectionServiceGetConnectionDefaultResponse = 
Awaited<ReturnType<typeof ConnectionService.getConnection>>;
 export type ConnectionServiceGetConnectionQueryResult<TData = 
ConnectionServiceGetConnectionDefaultResponse, TError = unknown> = 
UseQueryResult<TData, TError>;
 export const useConnectionServiceGetConnectionKey = 
"ConnectionServiceGetConnection";
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts 
b/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
index 35783c93ac1..508e8a98620 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
@@ -279,6 +279,10 @@ export const 
ensureUseBackfillServiceListBackfillDagRunsData = (queryClient: Que
 * @param data.maxActiveRunsGt
 * @param data.maxActiveRunsLte
 * @param data.maxActiveRunsLt
+* @param data.durationGte
+* @param data.durationGt
+* @param data.durationLte
+* @param data.durationLt
 * @param data.reprocessBehavior
 * @param data.orderBy Attributes to order by, multi criteria sort is 
supported. Prefix with `-` for descending order. Supported attributes: `id`
 * @param data.dagId
@@ -286,7 +290,7 @@ export const 
ensureUseBackfillServiceListBackfillDagRunsData = (queryClient: Que
 * @returns BackfillCollectionResponse Successful Response
 * @throws ApiError
 */
-export const ensureUseBackfillServiceListBackfillsUiData = (queryClient: 
QueryClient, { active, completedAtGt, completedAtGte, completedAtLt, 
completedAtLte, createdAtGt, createdAtGte, createdAtLt, createdAtLte, dagId, 
fromDateGt, fromDateGte, fromDateLt, fromDateLte, limit, maxActiveRunsGt, 
maxActiveRunsGte, maxActiveRunsLt, maxActiveRunsLte, offset, orderBy, 
reprocessBehavior, toDateGt, toDateGte, toDateLt, toDateLte }: {
+export const ensureUseBackfillServiceListBackfillsUiData = (queryClient: 
QueryClient, { active, completedAtGt, completedAtGte, completedAtLt, 
completedAtLte, createdAtGt, createdAtGte, createdAtLt, createdAtLte, dagId, 
durationGt, durationGte, durationLt, durationLte, fromDateGt, fromDateGte, 
fromDateLt, fromDateLte, limit, maxActiveRunsGt, maxActiveRunsGte, 
maxActiveRunsLt, maxActiveRunsLte, offset, orderBy, reprocessBehavior, 
toDateGt, toDateGte, toDateLt, toDateLte }: {
   active?: boolean;
   completedAtGt?: string;
   completedAtGte?: string;
@@ -297,6 +301,10 @@ export const ensureUseBackfillServiceListBackfillsUiData = 
(queryClient: QueryCl
   createdAtLt?: string;
   createdAtLte?: string;
   dagId?: string;
+  durationGt?: number;
+  durationGte?: number;
+  durationLt?: number;
+  durationLte?: number;
   fromDateGt?: string;
   fromDateGte?: string;
   fromDateLt?: string;
@@ -313,7 +321,7 @@ export const ensureUseBackfillServiceListBackfillsUiData = 
(queryClient: QueryCl
   toDateGte?: string;
   toDateLt?: string;
   toDateLte?: string;
-} = {}) => queryClient.ensureQueryData({ queryKey: 
Common.UseBackfillServiceListBackfillsUiKeyFn({ active, completedAtGt, 
completedAtGte, completedAtLt, completedAtLte, createdAtGt, createdAtGte, 
createdAtLt, createdAtLte, dagId, fromDateGt, fromDateGte, fromDateLt, 
fromDateLte, limit, maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, 
maxActiveRunsLte, offset, orderBy, reprocessBehavior, toDateGt, toDateGte, 
toDateLt, toDateLte }), queryFn: () => BackfillService.listBackfillsUi({ activ 
[...]
+} = {}) => queryClient.ensureQueryData({ queryKey: 
Common.UseBackfillServiceListBackfillsUiKeyFn({ active, completedAtGt, 
completedAtGte, completedAtLt, completedAtLte, createdAtGt, createdAtGte, 
createdAtLt, createdAtLte, dagId, durationGt, durationGte, durationLt, 
durationLte, fromDateGt, fromDateGte, fromDateLt, fromDateLte, limit, 
maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, maxActiveRunsLte, offset, 
orderBy, reprocessBehavior, toDateGt, toDateGte, toDateLt, toDateLte }), quer 
[...]
 /**
 * Get Connection
 * Get a connection entry.
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts 
b/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
index 451c62087c6..5c48648cda9 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
@@ -279,6 +279,10 @@ export const prefetchUseBackfillServiceListBackfillDagRuns 
= (queryClient: Query
 * @param data.maxActiveRunsGt
 * @param data.maxActiveRunsLte
 * @param data.maxActiveRunsLt
+* @param data.durationGte
+* @param data.durationGt
+* @param data.durationLte
+* @param data.durationLt
 * @param data.reprocessBehavior
 * @param data.orderBy Attributes to order by, multi criteria sort is 
supported. Prefix with `-` for descending order. Supported attributes: `id`
 * @param data.dagId
@@ -286,7 +290,7 @@ export const prefetchUseBackfillServiceListBackfillDagRuns 
= (queryClient: Query
 * @returns BackfillCollectionResponse Successful Response
 * @throws ApiError
 */
-export const prefetchUseBackfillServiceListBackfillsUi = (queryClient: 
QueryClient, { active, completedAtGt, completedAtGte, completedAtLt, 
completedAtLte, createdAtGt, createdAtGte, createdAtLt, createdAtLte, dagId, 
fromDateGt, fromDateGte, fromDateLt, fromDateLte, limit, maxActiveRunsGt, 
maxActiveRunsGte, maxActiveRunsLt, maxActiveRunsLte, offset, orderBy, 
reprocessBehavior, toDateGt, toDateGte, toDateLt, toDateLte }: {
+export const prefetchUseBackfillServiceListBackfillsUi = (queryClient: 
QueryClient, { active, completedAtGt, completedAtGte, completedAtLt, 
completedAtLte, createdAtGt, createdAtGte, createdAtLt, createdAtLte, dagId, 
durationGt, durationGte, durationLt, durationLte, fromDateGt, fromDateGte, 
fromDateLt, fromDateLte, limit, maxActiveRunsGt, maxActiveRunsGte, 
maxActiveRunsLt, maxActiveRunsLte, offset, orderBy, reprocessBehavior, 
toDateGt, toDateGte, toDateLt, toDateLte }: {
   active?: boolean;
   completedAtGt?: string;
   completedAtGte?: string;
@@ -297,6 +301,10 @@ export const prefetchUseBackfillServiceListBackfillsUi = 
(queryClient: QueryClie
   createdAtLt?: string;
   createdAtLte?: string;
   dagId?: string;
+  durationGt?: number;
+  durationGte?: number;
+  durationLt?: number;
+  durationLte?: number;
   fromDateGt?: string;
   fromDateGte?: string;
   fromDateLt?: string;
@@ -313,7 +321,7 @@ export const prefetchUseBackfillServiceListBackfillsUi = 
(queryClient: QueryClie
   toDateGte?: string;
   toDateLt?: string;
   toDateLte?: string;
-} = {}) => queryClient.prefetchQuery({ queryKey: 
Common.UseBackfillServiceListBackfillsUiKeyFn({ active, completedAtGt, 
completedAtGte, completedAtLt, completedAtLte, createdAtGt, createdAtGte, 
createdAtLt, createdAtLte, dagId, fromDateGt, fromDateGte, fromDateLt, 
fromDateLte, limit, maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, 
maxActiveRunsLte, offset, orderBy, reprocessBehavior, toDateGt, toDateGte, 
toDateLt, toDateLte }), queryFn: () => BackfillService.listBackfillsUi({ 
active, [...]
+} = {}) => queryClient.prefetchQuery({ queryKey: 
Common.UseBackfillServiceListBackfillsUiKeyFn({ active, completedAtGt, 
completedAtGte, completedAtLt, completedAtLte, createdAtGt, createdAtGte, 
createdAtLt, createdAtLte, dagId, durationGt, durationGte, durationLt, 
durationLte, fromDateGt, fromDateGte, fromDateLt, fromDateLte, limit, 
maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, maxActiveRunsLte, offset, 
orderBy, reprocessBehavior, toDateGt, toDateGte, toDateLt, toDateLte }), queryF 
[...]
 /**
 * Get Connection
 * Get a connection entry.
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts 
b/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
index 17e50def559..1dd1fb98a06 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
@@ -279,6 +279,10 @@ export const useBackfillServiceListBackfillDagRuns = 
<TData = Common.BackfillSer
 * @param data.maxActiveRunsGt
 * @param data.maxActiveRunsLte
 * @param data.maxActiveRunsLt
+* @param data.durationGte
+* @param data.durationGt
+* @param data.durationLte
+* @param data.durationLt
 * @param data.reprocessBehavior
 * @param data.orderBy Attributes to order by, multi criteria sort is 
supported. Prefix with `-` for descending order. Supported attributes: `id`
 * @param data.dagId
@@ -286,7 +290,7 @@ export const useBackfillServiceListBackfillDagRuns = <TData 
= Common.BackfillSer
 * @returns BackfillCollectionResponse Successful Response
 * @throws ApiError
 */
-export const useBackfillServiceListBackfillsUi = <TData = 
Common.BackfillServiceListBackfillsUiDefaultResponse, TError = unknown, 
TQueryKey extends Array<unknown> = unknown[]>({ active, completedAtGt, 
completedAtGte, completedAtLt, completedAtLte, createdAtGt, createdAtGte, 
createdAtLt, createdAtLte, dagId, fromDateGt, fromDateGte, fromDateLt, 
fromDateLte, limit, maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, 
maxActiveRunsLte, offset, orderBy, reprocessBehavior, toDateGt, toDateGte, [...]
+export const useBackfillServiceListBackfillsUi = <TData = 
Common.BackfillServiceListBackfillsUiDefaultResponse, TError = unknown, 
TQueryKey extends Array<unknown> = unknown[]>({ active, completedAtGt, 
completedAtGte, completedAtLt, completedAtLte, createdAtGt, createdAtGte, 
createdAtLt, createdAtLte, dagId, durationGt, durationGte, durationLt, 
durationLte, fromDateGt, fromDateGte, fromDateLt, fromDateLte, limit, 
maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, maxActiveRunsLte, offset 
[...]
   active?: boolean;
   completedAtGt?: string;
   completedAtGte?: string;
@@ -297,6 +301,10 @@ export const useBackfillServiceListBackfillsUi = <TData = 
Common.BackfillService
   createdAtLt?: string;
   createdAtLte?: string;
   dagId?: string;
+  durationGt?: number;
+  durationGte?: number;
+  durationLt?: number;
+  durationLte?: number;
   fromDateGt?: string;
   fromDateGte?: string;
   fromDateLt?: string;
@@ -313,7 +321,7 @@ export const useBackfillServiceListBackfillsUi = <TData = 
Common.BackfillService
   toDateGte?: string;
   toDateLt?: string;
   toDateLte?: string;
-} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey: 
Common.UseBackfillServiceListBackfillsUiKeyFn({ active, completedAtGt, 
completedAtGte, completedAtLt, completedAtLte, createdAtGt, createdAtGte, 
createdAtLt, createdAtLte, dagId, fromDateGt, fromDateGte, fromDateLt, 
fromDateLte, limit, maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, 
maxActiveRunsLte, offset, orderBy, reprocessBehavior, toDateGt, [...]
+} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey: 
Common.UseBackfillServiceListBackfillsUiKeyFn({ active, completedAtGt, 
completedAtGte, completedAtLt, completedAtLte, createdAtGt, createdAtGte, 
createdAtLt, createdAtLte, dagId, durationGt, durationGte, durationLt, 
durationLte, fromDateGt, fromDateGte, fromDateLt, fromDateLte, limit, 
maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, maxActiveRuns [...]
 /**
 * Get Connection
 * Get a connection entry.
diff --git a/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts 
b/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
index ffc31253bbd..9b762754d93 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
@@ -279,6 +279,10 @@ export const useBackfillServiceListBackfillDagRunsSuspense 
= <TData = Common.Bac
 * @param data.maxActiveRunsGt
 * @param data.maxActiveRunsLte
 * @param data.maxActiveRunsLt
+* @param data.durationGte
+* @param data.durationGt
+* @param data.durationLte
+* @param data.durationLt
 * @param data.reprocessBehavior
 * @param data.orderBy Attributes to order by, multi criteria sort is 
supported. Prefix with `-` for descending order. Supported attributes: `id`
 * @param data.dagId
@@ -286,7 +290,7 @@ export const useBackfillServiceListBackfillDagRunsSuspense 
= <TData = Common.Bac
 * @returns BackfillCollectionResponse Successful Response
 * @throws ApiError
 */
-export const useBackfillServiceListBackfillsUiSuspense = <TData = 
Common.BackfillServiceListBackfillsUiDefaultResponse, TError = unknown, 
TQueryKey extends Array<unknown> = unknown[]>({ active, completedAtGt, 
completedAtGte, completedAtLt, completedAtLte, createdAtGt, createdAtGte, 
createdAtLt, createdAtLte, dagId, fromDateGt, fromDateGte, fromDateLt, 
fromDateLte, limit, maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, 
maxActiveRunsLte, offset, orderBy, reprocessBehavior, toDateGt, to [...]
+export const useBackfillServiceListBackfillsUiSuspense = <TData = 
Common.BackfillServiceListBackfillsUiDefaultResponse, TError = unknown, 
TQueryKey extends Array<unknown> = unknown[]>({ active, completedAtGt, 
completedAtGte, completedAtLt, completedAtLte, createdAtGt, createdAtGte, 
createdAtLt, createdAtLte, dagId, durationGt, durationGte, durationLt, 
durationLte, fromDateGt, fromDateGte, fromDateLt, fromDateLte, limit, 
maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, maxActiveRunsLte [...]
   active?: boolean;
   completedAtGt?: string;
   completedAtGte?: string;
@@ -297,6 +301,10 @@ export const useBackfillServiceListBackfillsUiSuspense = 
<TData = Common.Backfil
   createdAtLt?: string;
   createdAtLte?: string;
   dagId?: string;
+  durationGt?: number;
+  durationGte?: number;
+  durationLt?: number;
+  durationLte?: number;
   fromDateGt?: string;
   fromDateGte?: string;
   fromDateLt?: string;
@@ -313,7 +321,7 @@ export const useBackfillServiceListBackfillsUiSuspense = 
<TData = Common.Backfil
   toDateGte?: string;
   toDateLt?: string;
   toDateLte?: string;
-} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey: 
Common.UseBackfillServiceListBackfillsUiKeyFn({ active, completedAtGt, 
completedAtGte, completedAtLt, completedAtLte, createdAtGt, createdAtGte, 
createdAtLt, createdAtLte, dagId, fromDateGt, fromDateGte, fromDateLt, 
fromDateLte, limit, maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, 
maxActiveRunsLte, offset, orderBy, reprocessBehavior, t [...]
+} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey: 
Common.UseBackfillServiceListBackfillsUiKeyFn({ active, completedAtGt, 
completedAtGte, completedAtLt, completedAtLte, createdAtGt, createdAtGte, 
createdAtLt, createdAtLte, dagId, durationGt, durationGte, durationLt, 
durationLte, fromDateGt, fromDateGte, fromDateLt, fromDateLte, limit, 
maxActiveRunsGt, maxActiveRunsGte, maxActiveRunsLt, maxAc [...]
 /**
 * Get Connection
 * Get a connection entry.
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts 
b/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
index 12161426709..eeb9bab1271 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/services.gen.ts
@@ -714,6 +714,10 @@ export class BackfillService {
      * @param data.maxActiveRunsGt
      * @param data.maxActiveRunsLte
      * @param data.maxActiveRunsLt
+     * @param data.durationGte
+     * @param data.durationGt
+     * @param data.durationLte
+     * @param data.durationLt
      * @param data.reprocessBehavior
      * @param data.orderBy Attributes to order by, multi criteria sort is 
supported. Prefix with `-` for descending order. Supported attributes: `id`
      * @param data.dagId
@@ -748,6 +752,10 @@ export class BackfillService {
                 max_active_runs_gt: data.maxActiveRunsGt,
                 max_active_runs_lte: data.maxActiveRunsLte,
                 max_active_runs_lt: data.maxActiveRunsLt,
+                duration_gte: data.durationGte,
+                duration_gt: data.durationGt,
+                duration_lte: data.durationLte,
+                duration_lt: data.durationLt,
                 reprocess_behavior: data.reprocessBehavior,
                 order_by: data.orderBy,
                 dag_id: data.dagId,
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts 
b/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
index ddadbd19f28..9b88dfd07c8 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/types.gen.ts
@@ -3515,6 +3515,10 @@ export type ListBackfillsUiData = {
     createdAtLt?: string | null;
     createdAtLte?: string | null;
     dagId?: string | null;
+    durationGt?: number | null;
+    durationGte?: number | null;
+    durationLt?: number | null;
+    durationLte?: number | null;
     fromDateGt?: string | null;
     fromDateGte?: string | null;
     fromDateLt?: string | null;
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 971373ba5ff..4bb14409c29 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
@@ -41,6 +41,8 @@ const {
   COMPLETED_AT_LTE: COMPLETED_AT_LTE_PARAM,
   CREATED_AT_GTE: CREATED_AT_GTE_PARAM,
   CREATED_AT_LTE: CREATED_AT_LTE_PARAM,
+  DURATION_GTE: DURATION_GTE_PARAM,
+  DURATION_LTE: DURATION_LTE_PARAM,
   FROM_DATE_GTE: FROM_DATE_GTE_PARAM,
   FROM_DATE_LTE: FROM_DATE_LTE_PARAM,
   MAX_ACTIVE_RUNS_GTE: MAX_ACTIVE_RUNS_GTE_PARAM,
@@ -173,6 +175,8 @@ export const Backfills = () => {
   const completedAtLte = searchParams.get(COMPLETED_AT_LTE_PARAM);
   const maxActiveRunsGte = searchParams.get(MAX_ACTIVE_RUNS_GTE_PARAM);
   const maxActiveRunsLte = searchParams.get(MAX_ACTIVE_RUNS_LTE_PARAM);
+  const durationGte = searchParams.get(DURATION_GTE_PARAM);
+  const durationLte = searchParams.get(DURATION_LTE_PARAM);
   const reprocessBehaviorParam = searchParams.get(REPROCESS_BEHAVIOR_PARAM);
   const reprocessBehavior = isReprocessBehavior(reprocessBehaviorParam) ? 
reprocessBehaviorParam : undefined;
 
@@ -182,6 +186,8 @@ export const Backfills = () => {
     createdAtGte: createdAtGte ?? undefined,
     createdAtLte: createdAtLte ?? undefined,
     dagId,
+    durationGte: durationGte !== null && durationGte !== "" ? 
Number(durationGte) : undefined,
+    durationLte: durationLte !== null && durationLte !== "" ? 
Number(durationLte) : undefined,
     fromDateGte: fromDateGte ?? undefined,
     fromDateLte: fromDateLte ?? undefined,
     limit: pagination.pageSize,
diff --git 
a/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillsFilters.tsx 
b/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillsFilters.tsx
index e69893ddadd..48b9694d6ec 100644
--- a/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillsFilters.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillsFilters.tsx
@@ -31,6 +31,8 @@ export const BackfillsFilters = () => {
     SearchParamsKeys.COMPLETED_AT_RANGE,
     SearchParamsKeys.MAX_ACTIVE_RUNS_GTE,
     SearchParamsKeys.MAX_ACTIVE_RUNS_LTE,
+    SearchParamsKeys.DURATION_GTE,
+    SearchParamsKeys.DURATION_LTE,
     SearchParamsKeys.REPROCESS_BEHAVIOR,
   ];
 

Reply via email to