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

RNHTTR 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 80db0f249fd Backfills UI filters (#71467)
80db0f249fd is described below

commit 80db0f249fddcbfac67e63ef387a4de1294ccbe7
Author: Phinhas Asmelash <[email protected]>
AuthorDate: Tue Sep 8 05:04:53 2026 -0700

    Backfills UI filters (#71467)
    
    * added filters to the backfills tab ui
    
    * Frontend unit tests for backfill filter component
    
    * Documentation for backfill tab view
    
    * Fix Backfills tab documentation for Dag UI
    
    * clean up unwanted comments
    
    * removed irrelevant backfill documenation
    
    * Add backfill filter translation keys
    
    * Refactor tests after new backfill functionality
    
    * added filters to the backfills tab ui
    
    * Documentation for backfill tab view
    
    * clean up unwanted comments
    
    * removed irrelevant backfill documenation
    
    * Refactor tests after new backfill functionality
    
    * Update airflow-core/docs/ui.rst
    
    Co-authored-by: Brent Bovenzi <[email protected]>
    
    * Update 
airflow-core/src/airflow/api_fastapi/core_api/routes/ui/backfills.py
    
    Co-authored-by: Brent Bovenzi <[email protected]>
    
    * Update 
airflow-core/src/airflow/api_fastapi/core_api/routes/ui/backfills.py
    
    Co-authored-by: Brent Bovenzi <[email protected]>
    
    * Rename date range values to be consistent with backfill values
    
    * Validate reprocess behavior as reprocess behavior type
    
    * Fix reprocess behavior type error and delete duplicate code
    
    * Fix reprocess behavior parameter names
    
    * Add translation keys to backfill reprocess behavior options
    
    * Move completed at backfill filter to common filters
    
    * Remove unused search param constants
    
    * Add back the needed search param constants
    
    * Added more relevant icon to backfill max_active_runs filter type
    
    * Fix reprocess behavior casting issue and change factory for 
max_active_runs
    
    * Apply suggestion from @bbovenzi
    
    * Static check fix for filterConfigMap
    
    * Fix from lint checks
    
    ---------
    
    Co-authored-by: Brent Bovenzi <[email protected]>
---
 .../src/airflow/api_fastapi/common/parameters.py   |  22 +++
 .../api_fastapi/core_api/openapi/_private_ui.yaml  | 184 +++++++++++++++++++++
 .../api_fastapi/core_api/routes/ui/backfills.py    |  25 ++-
 .../src/airflow/ui/openapi-gen/queries/common.ts   |  27 ++-
 .../ui/openapi-gen/queries/ensureQueryData.ts      |  48 +++++-
 .../src/airflow/ui/openapi-gen/queries/prefetch.ts |  48 +++++-
 .../src/airflow/ui/openapi-gen/queries/queries.ts  |  48 +++++-
 .../src/airflow/ui/openapi-gen/queries/suspense.ts |  48 +++++-
 .../ui/openapi-gen/requests/services.gen.ts        |  42 +++++
 .../airflow/ui/openapi-gen/requests/types.gen.ts   |  21 +++
 .../airflow/ui/public/i18n/locales/en/common.json  |   3 +
 .../src/airflow/ui/src/constants/filterConfigs.tsx |  46 +++++-
 .../ui/src/constants/reprocessBehaviourParams.ts   |   6 +-
 .../src/airflow/ui/src/constants/searchParams.ts   |  12 ++
 .../src/airflow/ui/src/mocks/handlers/backfills.ts |  86 ++++++++++
 .../src/airflow/ui/src/mocks/handlers/index.ts     |   2 +
 .../ui/src/pages/Dag/Backfills/Backfills.test.tsx  |  21 ++-
 .../ui/src/pages/Dag/Backfills/Backfills.tsx       |  59 ++++++-
 .../Dag/Backfills/BackfillsDateFilter.test.tsx     |  52 ++++++
 .../src/pages/Dag/Backfills/BackfillsFilters.tsx   |  48 ++++++
 .../src/airflow/ui/src/utils/useFiltersHandler.ts  |   6 +
 .../core_api/routes/ui/test_backfills.py           |  85 +++++++++-
 22 files changed, 910 insertions(+), 29 deletions(-)

diff --git a/airflow-core/src/airflow/api_fastapi/common/parameters.py 
b/airflow-core/src/airflow/api_fastapi/common/parameters.py
index dfc255f4683..a7a870df99b 100644
--- a/airflow-core/src/airflow/api_fastapi/common/parameters.py
+++ b/airflow-core/src/airflow/api_fastapi/common/parameters.py
@@ -1268,6 +1268,28 @@ def float_range_filter_factory(
     return depends_float
 
 
+def int_range_filter_factory(
+    filter_name: str, model: Base
+) -> Callable[[int | None, int | None, int | None, int | None], RangeFilter]:
+    def depends_int(
+        lower_bound_gte: int | None = Query(alias=f"{filter_name}_gte", 
default=None),
+        lower_bound_gt: int | None = Query(alias=f"{filter_name}_gt", 
default=None),
+        upper_bound_lte: int | None = Query(alias=f"{filter_name}_lte", 
default=None),
+        upper_bound_lt: int | None = Query(alias=f"{filter_name}_lt", 
default=None),
+    ) -> RangeFilter:
+        return RangeFilter(
+            Range(
+                lower_bound_gte=lower_bound_gte,
+                lower_bound_gt=lower_bound_gt,
+                upper_bound_lte=upper_bound_lte,
+                upper_bound_lt=upper_bound_lt,
+            ),
+            getattr(model, filter_name),
+        )
+
+    return depends_int
+
+
 # Common Safe DateTime
 DateTimeQuery = Annotated[str, AfterValidator(_safe_parse_datetime)]
 OptionalDateTimeQuery = Annotated[str | None, 
AfterValidator(_safe_parse_datetime_optional)]
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 f713c4137dc..a51f805f09d 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
@@ -1356,6 +1356,190 @@ paths:
           minimum: 0
           default: 0
           title: Offset
+      - name: from_date_gte
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: From Date Gte
+      - name: from_date_gt
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: From Date Gt
+      - name: from_date_lte
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: From Date Lte
+      - name: from_date_lt
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: From Date Lt
+      - name: to_date_gte
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: To Date Gte
+      - name: to_date_gt
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: To Date Gt
+      - name: to_date_lte
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: To Date Lte
+      - name: to_date_lt
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: To Date Lt
+      - name: created_at_gte
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: Created At Gte
+      - name: created_at_gt
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: Created At Gt
+      - name: created_at_lte
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: Created At Lte
+      - name: created_at_lt
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: Created At Lt
+      - name: completed_at_gte
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: Completed At Gte
+      - name: completed_at_gt
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: Completed At Gt
+      - name: completed_at_lte
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: Completed At Lte
+      - name: completed_at_lt
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+            format: date-time
+          - type: 'null'
+          title: Completed At Lt
+      - name: max_active_runs_gte
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: integer
+          - type: 'null'
+          title: Max Active Runs Gte
+      - name: max_active_runs_gt
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: integer
+          - type: 'null'
+          title: Max Active Runs Gt
+      - name: max_active_runs_lte
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: integer
+          - type: 'null'
+          title: Max Active Runs Lte
+      - name: max_active_runs_lt
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: integer
+          - type: 'null'
+          title: Max Active Runs Lt
+      - name: reprocess_behavior
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - $ref: '#/components/schemas/ReprocessBehavior'
+          - type: 'null'
+          title: Reprocess Behavior
       - name: order_by
         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 02583a8355b..ff8782e9316 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
@@ -28,8 +28,11 @@ from airflow.api_fastapi.common.parameters import (
     FilterParam,
     QueryLimit,
     QueryOffset,
+    RangeFilter,
     SortParam,
+    datetime_range_filter_factory,
     filter_param_factory,
+    int_range_filter_factory,
 )
 from airflow.api_fastapi.common.router import AirflowRouter
 from airflow.api_fastapi.core_api.datamodels.backfills import 
BackfillCollectionResponse, BackfillResponse
@@ -37,7 +40,7 @@ from airflow.api_fastapi.core_api.openapi.exceptions import (
     create_openapi_http_exception_doc,
 )
 from airflow.api_fastapi.core_api.security import ReadableBackfillsFilterDep, 
requires_access_backfill
-from airflow.models.backfill import Backfill
+from airflow.models.backfill import Backfill, ReprocessBehavior
 
 backfills_router = AirflowRouter(tags=["Backfill"], prefix="/backfills")
 
@@ -52,6 +55,14 @@ backfills_router = AirflowRouter(tags=["Backfill"], 
prefix="/backfills")
 def list_backfills_ui(
     limit: QueryLimit,
     offset: QueryOffset,
+    start_date_range: Annotated[RangeFilter, 
Depends(datetime_range_filter_factory("from_date", Backfill))],
+    end_date_range: Annotated[RangeFilter, 
Depends(datetime_range_filter_factory("to_date", Backfill))],
+    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))],
+    reprocess_behavior: Annotated[
+        FilterParam, Depends(filter_param_factory(Backfill.reprocess_behavior, 
ReprocessBehavior | None))
+    ],
     order_by: Annotated[
         SortParam,
         Depends(SortParam(["id"], Backfill).dynamic_depends()),
@@ -66,7 +77,17 @@ def list_backfills_ui(
 ) -> BackfillCollectionResponse:
     select_stmt, total_entries = paginated_select(
         statement=select(Backfill).options(joinedload(Backfill.dag_model)),
-        filters=[dag_id, active, readable_backfills_filter],
+        filters=[
+            dag_id,
+            active,
+            readable_backfills_filter,
+            start_date_range,
+            end_date_range,
+            created_at,
+            completed_at,
+            max_active_runs,
+            reprocess_behavior,
+        ],
         order_by=order_by,
         offset=offset,
         limit=limit,
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 206e6c29c87..0feff40cc43 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
@@ -2,7 +2,7 @@
 
 import { UseQueryResult } from "@tanstack/react-query";
 import { AssetService, AssetStateStoreService, AuthLinksService, 
BackfillService, CalendarService, ConfigService, ConnectionService, 
DagParsingService, DagRunService, DagService, DagSourceService, 
DagStatsService, DagVersionService, DagWarningService, DashboardService, 
DeadlinesService, DependenciesService, EventLogService, ExperimentalService, 
ExtraLinksService, GanttService, GridService, ImportErrorService, JobService, 
LoginService, MonitorService, PartitionedDagRunService, PluginServi [...]
-import { DagRunState, DagWarningType } from "../requests/types.gen";
+import { DagRunState, DagWarningType, ReprocessBehavior } from 
"../requests/types.gen";
 export type AssetServiceGetAssetsDefaultResponse = Awaited<ReturnType<typeof 
AssetService.getAssets>>;
 export type AssetServiceGetAssetsQueryResult<TData = 
AssetServiceGetAssetsDefaultResponse, TError = unknown> = UseQueryResult<TData, 
TError>;
 export const useAssetServiceGetAssetsKey = "AssetServiceGetAssets";
@@ -138,13 +138,34 @@ 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, dagId, limit, 
offset, orderBy }: {
+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 }: {
   active?: boolean;
+  completedAtGt?: string;
+  completedAtGte?: string;
+  completedAtLt?: string;
+  completedAtLte?: string;
+  createdAtGt?: string;
+  createdAtGte?: string;
+  createdAtLt?: string;
+  createdAtLte?: string;
   dagId?: string;
+  fromDateGt?: string;
+  fromDateGte?: string;
+  fromDateLt?: string;
+  fromDateLte?: string;
   limit?: number;
+  maxActiveRunsGt?: number;
+  maxActiveRunsGte?: number;
+  maxActiveRunsLt?: number;
+  maxActiveRunsLte?: number;
   offset?: number;
   orderBy?: string[];
-} = {}, queryKey?: Array<unknown>) => [useBackfillServiceListBackfillsUiKey, 
...(queryKey ?? [{ active, dagId, limit, offset, orderBy }])];
+  reprocessBehavior?: ReprocessBehavior;
+  toDateGt?: string;
+  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 }])];
 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 bd88502f1e1..a554befbafe 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
@@ -2,7 +2,7 @@
 
 import { type QueryClient } from "@tanstack/react-query";
 import { AssetService, AssetStateStoreService, AuthLinksService, 
BackfillService, CalendarService, ConfigService, ConnectionService, 
DagRunService, DagService, DagSourceService, DagStatsService, 
DagVersionService, DagWarningService, DashboardService, DeadlinesService, 
DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, 
GanttService, GridService, ImportErrorService, JobService, LoginService, 
MonitorService, PartitionedDagRunService, PluginService, PoolService, Pr [...]
-import { DagRunState, DagWarningType } from "../requests/types.gen";
+import { DagRunState, DagWarningType, ReprocessBehavior } from 
"../requests/types.gen";
 import * as Common from "./common";
 /**
 * Get Assets
@@ -257,19 +257,61 @@ export const 
ensureUseBackfillServiceListBackfillDagRunsData = (queryClient: Que
 * @param data The data for the request.
 * @param data.limit
 * @param data.offset
+* @param data.fromDateGte
+* @param data.fromDateGt
+* @param data.fromDateLte
+* @param data.fromDateLt
+* @param data.toDateGte
+* @param data.toDateGt
+* @param data.toDateLte
+* @param data.toDateLt
+* @param data.createdAtGte
+* @param data.createdAtGt
+* @param data.createdAtLte
+* @param data.createdAtLt
+* @param data.completedAtGte
+* @param data.completedAtGt
+* @param data.completedAtLte
+* @param data.completedAtLt
+* @param data.maxActiveRunsGte
+* @param data.maxActiveRunsGt
+* @param data.maxActiveRunsLte
+* @param data.maxActiveRunsLt
+* @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
 * @param data.active
 * @returns BackfillCollectionResponse Successful Response
 * @throws ApiError
 */
-export const ensureUseBackfillServiceListBackfillsUiData = (queryClient: 
QueryClient, { active, dagId, limit, offset, orderBy }: {
+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 }: {
   active?: boolean;
+  completedAtGt?: string;
+  completedAtGte?: string;
+  completedAtLt?: string;
+  completedAtLte?: string;
+  createdAtGt?: string;
+  createdAtGte?: string;
+  createdAtLt?: string;
+  createdAtLte?: string;
   dagId?: string;
+  fromDateGt?: string;
+  fromDateGte?: string;
+  fromDateLt?: string;
+  fromDateLte?: string;
   limit?: number;
+  maxActiveRunsGt?: number;
+  maxActiveRunsGte?: number;
+  maxActiveRunsLt?: number;
+  maxActiveRunsLte?: number;
   offset?: number;
   orderBy?: string[];
-} = {}) => queryClient.ensureQueryData({ queryKey: 
Common.UseBackfillServiceListBackfillsUiKeyFn({ active, dagId, limit, offset, 
orderBy }), queryFn: () => BackfillService.listBackfillsUi({ active, dagId, 
limit, offset, orderBy }) });
+  reprocessBehavior?: ReprocessBehavior;
+  toDateGt?: string;
+  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 
[...]
 /**
 * 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 8d28a3aa001..e8e799e50c3 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
@@ -2,7 +2,7 @@
 
 import { type QueryClient } from "@tanstack/react-query";
 import { AssetService, AssetStateStoreService, AuthLinksService, 
BackfillService, CalendarService, ConfigService, ConnectionService, 
DagRunService, DagService, DagSourceService, DagStatsService, 
DagVersionService, DagWarningService, DashboardService, DeadlinesService, 
DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, 
GanttService, GridService, ImportErrorService, JobService, LoginService, 
MonitorService, PartitionedDagRunService, PluginService, PoolService, Pr [...]
-import { DagRunState, DagWarningType } from "../requests/types.gen";
+import { DagRunState, DagWarningType, ReprocessBehavior } from 
"../requests/types.gen";
 import * as Common from "./common";
 /**
 * Get Assets
@@ -257,19 +257,61 @@ export const 
prefetchUseBackfillServiceListBackfillDagRuns = (queryClient: Query
 * @param data The data for the request.
 * @param data.limit
 * @param data.offset
+* @param data.fromDateGte
+* @param data.fromDateGt
+* @param data.fromDateLte
+* @param data.fromDateLt
+* @param data.toDateGte
+* @param data.toDateGt
+* @param data.toDateLte
+* @param data.toDateLt
+* @param data.createdAtGte
+* @param data.createdAtGt
+* @param data.createdAtLte
+* @param data.createdAtLt
+* @param data.completedAtGte
+* @param data.completedAtGt
+* @param data.completedAtLte
+* @param data.completedAtLt
+* @param data.maxActiveRunsGte
+* @param data.maxActiveRunsGt
+* @param data.maxActiveRunsLte
+* @param data.maxActiveRunsLt
+* @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
 * @param data.active
 * @returns BackfillCollectionResponse Successful Response
 * @throws ApiError
 */
-export const prefetchUseBackfillServiceListBackfillsUi = (queryClient: 
QueryClient, { active, dagId, limit, offset, orderBy }: {
+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 }: {
   active?: boolean;
+  completedAtGt?: string;
+  completedAtGte?: string;
+  completedAtLt?: string;
+  completedAtLte?: string;
+  createdAtGt?: string;
+  createdAtGte?: string;
+  createdAtLt?: string;
+  createdAtLte?: string;
   dagId?: string;
+  fromDateGt?: string;
+  fromDateGte?: string;
+  fromDateLt?: string;
+  fromDateLte?: string;
   limit?: number;
+  maxActiveRunsGt?: number;
+  maxActiveRunsGte?: number;
+  maxActiveRunsLt?: number;
+  maxActiveRunsLte?: number;
   offset?: number;
   orderBy?: string[];
-} = {}) => queryClient.prefetchQuery({ queryKey: 
Common.UseBackfillServiceListBackfillsUiKeyFn({ active, dagId, limit, offset, 
orderBy }), queryFn: () => BackfillService.listBackfillsUi({ active, dagId, 
limit, offset, orderBy }) });
+  reprocessBehavior?: ReprocessBehavior;
+  toDateGt?: string;
+  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, [...]
 /**
 * 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 9c7971fb2d6..97d4a025a51 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
@@ -2,7 +2,7 @@
 
 import { UseMutationOptions, UseQueryOptions, useMutation, useQuery } from 
"@tanstack/react-query";
 import { AssetService, AssetStateStoreService, AuthLinksService, 
BackfillService, CalendarService, ConfigService, ConnectionService, 
DagParsingService, DagRunService, DagService, DagSourceService, 
DagStatsService, DagVersionService, DagWarningService, DashboardService, 
DeadlinesService, DependenciesService, EventLogService, ExperimentalService, 
ExtraLinksService, GanttService, GridService, ImportErrorService, JobService, 
LoginService, MonitorService, PartitionedDagRunService, PluginServi [...]
-import { AssetStateStoreBody, BackfillPostBody, BulkBody_BulkDAGRunBody_, 
BulkBody_BulkTaskInstanceBody_, BulkBody_ConnectionBody_, BulkBody_PoolBody_, 
BulkBody_VariableBody_, BulkDAGRunClearBody, ClearPartitionsBody, 
ClearTaskInstancesBody, ConnectionBody, ConnectionTestRequestBody, 
CreateAssetEventsBody, DAGPatchBody, DAGRunClearBody, DAGRunPatchBody, 
DAGRunsBatchBody, DagRunState, DagWarningType, GenerateTokenBody, 
MaterializeAssetBody, PatchTaskInstanceBody, PoolBody, PoolPatchBody,  [...]
+import { AssetStateStoreBody, BackfillPostBody, BulkBody_BulkDAGRunBody_, 
BulkBody_BulkTaskInstanceBody_, BulkBody_ConnectionBody_, BulkBody_PoolBody_, 
BulkBody_VariableBody_, BulkDAGRunClearBody, ClearPartitionsBody, 
ClearTaskInstancesBody, ConnectionBody, ConnectionTestRequestBody, 
CreateAssetEventsBody, DAGPatchBody, DAGRunClearBody, DAGRunPatchBody, 
DAGRunsBatchBody, DagRunState, DagWarningType, GenerateTokenBody, 
MaterializeAssetBody, PatchTaskInstanceBody, PoolBody, PoolPatchBody,  [...]
 import * as Common from "./common";
 /**
 * Get Assets
@@ -257,19 +257,61 @@ export const useBackfillServiceListBackfillDagRuns = 
<TData = Common.BackfillSer
 * @param data The data for the request.
 * @param data.limit
 * @param data.offset
+* @param data.fromDateGte
+* @param data.fromDateGt
+* @param data.fromDateLte
+* @param data.fromDateLt
+* @param data.toDateGte
+* @param data.toDateGt
+* @param data.toDateLte
+* @param data.toDateLt
+* @param data.createdAtGte
+* @param data.createdAtGt
+* @param data.createdAtLte
+* @param data.createdAtLt
+* @param data.completedAtGte
+* @param data.completedAtGt
+* @param data.completedAtLte
+* @param data.completedAtLt
+* @param data.maxActiveRunsGte
+* @param data.maxActiveRunsGt
+* @param data.maxActiveRunsLte
+* @param data.maxActiveRunsLt
+* @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
 * @param data.active
 * @returns BackfillCollectionResponse Successful Response
 * @throws ApiError
 */
-export const useBackfillServiceListBackfillsUi = <TData = 
Common.BackfillServiceListBackfillsUiDefaultResponse, TError = unknown, 
TQueryKey extends Array<unknown> = unknown[]>({ active, dagId, limit, offset, 
orderBy }: {
+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, [...]
   active?: boolean;
+  completedAtGt?: string;
+  completedAtGte?: string;
+  completedAtLt?: string;
+  completedAtLte?: string;
+  createdAtGt?: string;
+  createdAtGte?: string;
+  createdAtLt?: string;
+  createdAtLte?: string;
   dagId?: string;
+  fromDateGt?: string;
+  fromDateGte?: string;
+  fromDateLt?: string;
+  fromDateLte?: string;
   limit?: number;
+  maxActiveRunsGt?: number;
+  maxActiveRunsGte?: number;
+  maxActiveRunsLt?: number;
+  maxActiveRunsLte?: number;
   offset?: number;
   orderBy?: string[];
-} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey: 
Common.UseBackfillServiceListBackfillsUiKeyFn({ active, dagId, limit, offset, 
orderBy }, queryKey), queryFn: () => BackfillService.listBackfillsUi({ active, 
dagId, limit, offset, orderBy }) as TData, ...options });
+  reprocessBehavior?: ReprocessBehavior;
+  toDateGt?: string;
+  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, [...]
 /**
 * 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 6fd74cd8483..e983042bf0e 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
@@ -2,7 +2,7 @@
 
 import { UseQueryOptions, useSuspenseQuery } from "@tanstack/react-query";
 import { AssetService, AssetStateStoreService, AuthLinksService, 
BackfillService, CalendarService, ConfigService, ConnectionService, 
DagRunService, DagService, DagSourceService, DagStatsService, 
DagVersionService, DagWarningService, DashboardService, DeadlinesService, 
DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, 
GanttService, GridService, ImportErrorService, JobService, LoginService, 
MonitorService, PartitionedDagRunService, PluginService, PoolService, Pr [...]
-import { DagRunState, DagWarningType } from "../requests/types.gen";
+import { DagRunState, DagWarningType, ReprocessBehavior } from 
"../requests/types.gen";
 import * as Common from "./common";
 /**
 * Get Assets
@@ -257,19 +257,61 @@ export const 
useBackfillServiceListBackfillDagRunsSuspense = <TData = Common.Bac
 * @param data The data for the request.
 * @param data.limit
 * @param data.offset
+* @param data.fromDateGte
+* @param data.fromDateGt
+* @param data.fromDateLte
+* @param data.fromDateLt
+* @param data.toDateGte
+* @param data.toDateGt
+* @param data.toDateLte
+* @param data.toDateLt
+* @param data.createdAtGte
+* @param data.createdAtGt
+* @param data.createdAtLte
+* @param data.createdAtLt
+* @param data.completedAtGte
+* @param data.completedAtGt
+* @param data.completedAtLte
+* @param data.completedAtLt
+* @param data.maxActiveRunsGte
+* @param data.maxActiveRunsGt
+* @param data.maxActiveRunsLte
+* @param data.maxActiveRunsLt
+* @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
 * @param data.active
 * @returns BackfillCollectionResponse Successful Response
 * @throws ApiError
 */
-export const useBackfillServiceListBackfillsUiSuspense = <TData = 
Common.BackfillServiceListBackfillsUiDefaultResponse, TError = unknown, 
TQueryKey extends Array<unknown> = unknown[]>({ active, dagId, limit, offset, 
orderBy }: {
+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 [...]
   active?: boolean;
+  completedAtGt?: string;
+  completedAtGte?: string;
+  completedAtLt?: string;
+  completedAtLte?: string;
+  createdAtGt?: string;
+  createdAtGte?: string;
+  createdAtLt?: string;
+  createdAtLte?: string;
   dagId?: string;
+  fromDateGt?: string;
+  fromDateGte?: string;
+  fromDateLt?: string;
+  fromDateLte?: string;
   limit?: number;
+  maxActiveRunsGt?: number;
+  maxActiveRunsGte?: number;
+  maxActiveRunsLt?: number;
+  maxActiveRunsLte?: number;
   offset?: number;
   orderBy?: string[];
-} = {}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey: 
Common.UseBackfillServiceListBackfillsUiKeyFn({ active, dagId, limit, offset, 
orderBy }, queryKey), queryFn: () => BackfillService.listBackfillsUi({ active, 
dagId, limit, offset, orderBy }) as TData, ...options });
+  reprocessBehavior?: ReprocessBehavior;
+  toDateGt?: string;
+  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 [...]
 /**
 * 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 0564552f6eb..7a35da59e9b 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
@@ -691,6 +691,27 @@ export class BackfillService {
      * @param data The data for the request.
      * @param data.limit
      * @param data.offset
+     * @param data.fromDateGte
+     * @param data.fromDateGt
+     * @param data.fromDateLte
+     * @param data.fromDateLt
+     * @param data.toDateGte
+     * @param data.toDateGt
+     * @param data.toDateLte
+     * @param data.toDateLt
+     * @param data.createdAtGte
+     * @param data.createdAtGt
+     * @param data.createdAtLte
+     * @param data.createdAtLt
+     * @param data.completedAtGte
+     * @param data.completedAtGt
+     * @param data.completedAtLte
+     * @param data.completedAtLt
+     * @param data.maxActiveRunsGte
+     * @param data.maxActiveRunsGt
+     * @param data.maxActiveRunsLte
+     * @param data.maxActiveRunsLt
+     * @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
      * @param data.active
@@ -704,6 +725,27 @@ export class BackfillService {
             query: {
                 limit: data.limit,
                 offset: data.offset,
+                from_date_gte: data.fromDateGte,
+                from_date_gt: data.fromDateGt,
+                from_date_lte: data.fromDateLte,
+                from_date_lt: data.fromDateLt,
+                to_date_gte: data.toDateGte,
+                to_date_gt: data.toDateGt,
+                to_date_lte: data.toDateLte,
+                to_date_lt: data.toDateLt,
+                created_at_gte: data.createdAtGte,
+                created_at_gt: data.createdAtGt,
+                created_at_lte: data.createdAtLte,
+                created_at_lt: data.createdAtLt,
+                completed_at_gte: data.completedAtGte,
+                completed_at_gt: data.completedAtGt,
+                completed_at_lte: data.completedAtLte,
+                completed_at_lt: data.completedAtLt,
+                max_active_runs_gte: data.maxActiveRunsGte,
+                max_active_runs_gt: data.maxActiveRunsGt,
+                max_active_runs_lte: data.maxActiveRunsLte,
+                max_active_runs_lt: data.maxActiveRunsLt,
+                reprocess_behavior: data.reprocessBehavior,
                 order_by: data.orderBy,
                 dag_id: data.dagId,
                 active: data.active
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 da6f155d7c5..a4c17a6723d 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
@@ -3176,13 +3176,34 @@ export type CreateBackfillDryRunResponse = 
DryRunBackfillCollectionResponse;
 
 export type ListBackfillsUiData = {
     active?: boolean | null;
+    completedAtGt?: string | null;
+    completedAtGte?: string | null;
+    completedAtLt?: string | null;
+    completedAtLte?: string | null;
+    createdAtGt?: string | null;
+    createdAtGte?: string | null;
+    createdAtLt?: string | null;
+    createdAtLte?: string | null;
     dagId?: string | null;
+    fromDateGt?: string | null;
+    fromDateGte?: string | null;
+    fromDateLt?: string | null;
+    fromDateLte?: string | null;
     limit?: number;
+    maxActiveRunsGt?: number | null;
+    maxActiveRunsGte?: number | null;
+    maxActiveRunsLt?: number | null;
+    maxActiveRunsLte?: number | null;
     offset?: number;
     /**
      * Attributes to order by, multi criteria sort is supported. Prefix with 
`-` for descending order. Supported attributes: `id`
      */
     orderBy?: Array<(string)>;
+    reprocessBehavior?: ReprocessBehavior | null;
+    toDateGt?: string | null;
+    toDateGte?: string | null;
+    toDateLt?: string | null;
+    toDateLte?: string | null;
 };
 
 export type ListBackfillsUiResponse = BackfillCollectionResponse;
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/en/common.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/en/common.json
index 2bed02c1a22..43025657615 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/en/common.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/en/common.json
@@ -140,12 +140,15 @@
   "filter": "Filter",
   "filters": {
     "addFilter": "Add Filter",
+    "completedAt": "Completed At",
     "date": "Date",
     "durationFrom": "Duration From",
     "durationTo": "Duration To",
     "endTime": "End Time",
     "logicalDateFrom": "Logical Date From",
     "logicalDateTo": "Logical Date To",
+    "maxActiveRunsFrom": "Max Active Runs From",
+    "maxActiveRunsTo": "Max Active Runs To",
     "removeFilter": "Remove Filter",
     "runAfterFrom": "Run After From",
     "runAfterTo": "Run After To",
diff --git a/airflow-core/src/airflow/ui/src/constants/filterConfigs.tsx 
b/airflow-core/src/airflow/ui/src/constants/filterConfigs.tsx
index bfc4fedfb74..1faabf884ab 100644
--- a/airflow-core/src/airflow/ui/src/constants/filterConfigs.tsx
+++ b/airflow-core/src/airflow/ui/src/constants/filterConfigs.tsx
@@ -16,10 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+/* eslint-disable max-lines */
 import { Box } from "@chakra-ui/react";
 import { useTranslation } from "react-i18next";
 import { BiTargetLock } from "react-icons/bi";
-import { FiBarChart, FiDatabase, FiTag, FiUser, FiUsers } from 
"react-icons/fi";
+import { FiActivity, FiBarChart, FiDatabase, FiTag, FiUser, FiUsers } from 
"react-icons/fi";
 import { LuBrackets } from "react-icons/lu";
 import {
   MdBuild,
@@ -49,6 +50,7 @@ import { StateBadge } from "src/components/StateBadge";
 
 import { DagIcon } from "src/assets/DagIcon";
 import { TaskIcon } from "src/assets/TaskIcon";
+import { reprocessBehaviors } from "src/constants/reprocessBehaviourParams";
 import {
   dagRunStateOptions,
   dagRunTypeOptions,
@@ -118,6 +120,13 @@ export const useFilterConfigs = () => {
       label: translate("components:versionDetails.bundleVersion"),
       type: FilterTypes.TEXT,
     },
+    [SearchParamsKeys.COMPLETED_AT_RANGE]: {
+      endKey: SearchParamsKeys.COMPLETED_AT_LTE,
+      icon: <MdDateRange />,
+      label: translate("common:filters.completedAt"),
+      startKey: SearchParamsKeys.COMPLETED_AT_GTE,
+      type: FilterTypes.DATERANGE,
+    },
     [SearchParamsKeys.CONF_CONTAINS]: {
       hotkeyDisabled: true,
       icon: <MdCode />,
@@ -227,6 +236,13 @@ export const useFilterConfigs = () => {
       placeholder: translate("dags:filters.favoriteStatePlaceholder"),
       type: FilterTypes.SELECT,
     },
+    [SearchParamsKeys.FROM_RANGE]: {
+      endKey: SearchParamsKeys.FROM_DATE_LTE,
+      icon: <MdDateRange />,
+      label: translate("common:table.from"),
+      startKey: SearchParamsKeys.FROM_DATE_GTE,
+      type: FilterTypes.DATERANGE,
+    },
     [SearchParamsKeys.GROUP_PATTERN]: {
       hotkeyDisabled: true,
       icon: <FiDatabase />,
@@ -292,6 +308,18 @@ export const useFilterConfigs = () => {
       min: -1,
       type: FilterTypes.NUMBER,
     },
+    [SearchParamsKeys.MAX_ACTIVE_RUNS_GTE]: {
+      icon: <FiActivity />,
+      label: translate("common:filters.maxActiveRunsFrom"),
+      min: 1,
+      type: FilterTypes.NUMBER,
+    },
+    [SearchParamsKeys.MAX_ACTIVE_RUNS_LTE]: {
+      icon: <FiActivity />,
+      label: translate("common:filters.maxActiveRunsTo"),
+      min: 1,
+      type: FilterTypes.NUMBER,
+    },
     [SearchParamsKeys.MISSED]: {
       icon: <MdCheckCircle />,
       label: translate("browse:deadlines.filters.status"),
@@ -366,6 +394,15 @@ export const useFilterConfigs = () => {
       supportsAdvancedSearch: true,
       type: FilterTypes.TEXT,
     },
+    [SearchParamsKeys.REPROCESS_BEHAVIOR]: {
+      icon: <MdPlayArrow />,
+      label: translate("components:backfill.reprocessBehavior"),
+      options: reprocessBehaviors.map((option) => ({
+        label: translate(option.label),
+        value: option.value,
+      })),
+      type: FilterTypes.SELECT,
+    },
     [SearchParamsKeys.RESPONDED_BY_USER_NAME]: {
       hotkeyDisabled: true,
       icon: <FiUser />,
@@ -483,6 +520,13 @@ export const useFilterConfigs = () => {
       label: translate("dags:filters.timetableType"),
       type: FilterTypes.MULTISELECT,
     },
+    [SearchParamsKeys.TO_RANGE]: {
+      endKey: SearchParamsKeys.TO_DATE_LTE,
+      icon: <MdDateRange />,
+      label: translate("common:table.from"),
+      startKey: SearchParamsKeys.TO_DATE_GTE,
+      type: FilterTypes.DATERANGE,
+    },
     [SearchParamsKeys.TRIGGERING_USER_NAME_PATTERN]: {
       hotkeyDisabled: true,
       icon: <FiUser />,
diff --git 
a/airflow-core/src/airflow/ui/src/constants/reprocessBehaviourParams.ts 
b/airflow-core/src/airflow/ui/src/constants/reprocessBehaviourParams.ts
index d19f435fdeb..957f22050d8 100644
--- a/airflow-core/src/airflow/ui/src/constants/reprocessBehaviourParams.ts
+++ b/airflow-core/src/airflow/ui/src/constants/reprocessBehaviourParams.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 export const reprocessBehaviors = [
-  { label: "backfill.missingRuns", value: "none" },
-  { label: "backfill.missingAndErroredRuns", value: "failed" },
-  { label: "backfill.allRuns", value: "completed" },
+  { label: "components:backfill.missingRuns", value: "none" },
+  { label: "components:backfill.missingAndErroredRuns", value: "failed" },
+  { label: "components:backfill.allRuns", value: "completed" },
 ];
diff --git a/airflow-core/src/airflow/ui/src/constants/searchParams.ts 
b/airflow-core/src/airflow/ui/src/constants/searchParams.ts
index b2ac5532911..5a08c1c8c11 100644
--- a/airflow-core/src/airflow/ui/src/constants/searchParams.ts
+++ b/airflow-core/src/airflow/ui/src/constants/searchParams.ts
@@ -22,6 +22,9 @@ export enum SearchParamsKeys {
   BEFORE = "before",
   BODY_SEARCH = "body_search",
   BUNDLE_VERSION = "bundle_version",
+  COMPLETED_AT_GTE = "completed_at_gte",
+  COMPLETED_AT_LTE = "completed_at_lte",
+  COMPLETED_AT_RANGE = "completed_at_range",
   CONF_CONTAINS = "conf_contains",
   CONSUMING_ASSET_PATTERN = "consuming_asset_pattern",
   CREATED_AT_GTE = "created_at_gte",
@@ -48,6 +51,9 @@ export enum SearchParamsKeys {
   EXCLUDED_EVENTS = "excluded_events",
   EXECUTOR_CLASS = "executor_class",
   FAVORITE = "favorite",
+  FROM_DATE_GTE = "from_date_gte",
+  FROM_DATE_LTE = "from_date_lte",
+  FROM_RANGE = "from_range",
   GANTT = "gantt",
   GRAPH_DURATION_GTE = "graph-duration_gte",
   GRAPH_MAP_INDEX = "graph-map_index",
@@ -71,6 +77,8 @@ export enum SearchParamsKeys {
   LOGICAL_DATE_RANGE = "logical_date_range",
   MAP_INDEX = "map_index",
   MAPPED = "mapped",
+  MAX_ACTIVE_RUNS_GTE = "max_active_runs_gte",
+  MAX_ACTIVE_RUNS_LTE = "max_active_runs_lte",
   MISSED = "missed",
   NAME_PATTERN = "name_pattern",
   NEEDS_REVIEW = "needs_review",
@@ -84,6 +92,7 @@ export enum SearchParamsKeys {
   POOL_NAME_PATTERN = "pool_name_pattern",
   QUEUE_NAME_PATTERN = "queue_name_pattern",
   RENDERED_MAP_INDEX = "rendered_map_index",
+  REPROCESS_BEHAVIOR = "reprocess_behavior",
   RESPONDED_BY_USER_NAME = "responded_by_user_name",
   RESPONSE_RECEIVED = "response_received",
   RETRIES = "retries",
@@ -109,6 +118,9 @@ export enum SearchParamsKeys {
   TASK_STATE = "task_state",
   TEAMS = "teams",
   TIMETABLE_TYPE = "timetable_type",
+  TO_DATE_GTE = "to_date_gte",
+  TO_DATE_LTE = "to_date_lte",
+  TO_RANGE = "to_range",
   TRIGGER_RULE = "trigger_rule",
   TRIGGERING_USER = "triggering_user",
   TRIGGERING_USER_NAME_PATTERN = "triggering_user_name_pattern",
diff --git a/airflow-core/src/airflow/ui/src/mocks/handlers/backfills.ts 
b/airflow-core/src/airflow/ui/src/mocks/handlers/backfills.ts
new file mode 100644
index 00000000000..ee895e16987
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/mocks/handlers/backfills.ts
@@ -0,0 +1,86 @@
+/*!
+ * 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 { http, HttpResponse, type HttpHandler } from "msw";
+
+const backfillBeforeFilter = {
+  completed_at: "2024-12-31T01:00:00Z",
+  created_at: "2024-12-31T00:00:00Z",
+  dag_display_name: "tutorial_taskflow_api",
+  dag_id: "tutorial_taskflow_api",
+  dag_run_conf: {},
+  from_date: "2024-12-01T00:00:00Z",
+  id: 1,
+  is_paused: false,
+  max_active_runs: 10,
+  reprocess_behavior: "none",
+  to_date: "2024-12-31T00:00:00Z",
+  updated_at: "2024-12-31T01:00:00Z",
+};
+
+const backfillInRange = {
+  completed_at: "2025-01-16T01:00:00Z",
+  created_at: "2025-01-16T00:00:00Z",
+  dag_display_name: "tutorial_taskflow_api",
+  dag_id: "tutorial_taskflow_api",
+  dag_run_conf: {},
+  from_date: "2025-01-01T00:00:00Z",
+  id: 2,
+  is_paused: false,
+  max_active_runs: 10,
+  reprocess_behavior: "none",
+  to_date: "2025-01-15T00:00:00Z",
+  updated_at: "2025-01-16T01:00:00Z",
+};
+
+export const handlers: Array<HttpHandler> = [
+  http.get("/ui/backfills", ({ request }) => {
+    const url = new URL(request.url);
+    const fromDateGte = url.searchParams.get("from_date_gte");
+    const fromDateLte = url.searchParams.get("from_date_lte");
+    const toDateGte = url.searchParams.get("to_date_gte");
+    const toDateLte = url.searchParams.get("to_date_lte");
+
+    const allBackfills = [backfillBeforeFilter, backfillInRange];
+
+    const filtered = allBackfills.filter((backfill) => {
+      const fromDate = new Date(backfill.from_date);
+      const toDate = new Date(backfill.to_date);
+
+      if (fromDateGte !== null && fromDate < new Date(fromDateGte)) {
+        return false;
+      }
+      if (fromDateLte !== null && fromDate > new Date(fromDateLte)) {
+        return false;
+      }
+      if (toDateGte !== null && toDate < new Date(toDateGte)) {
+        return false;
+      }
+      if (toDateLte !== null && toDate > new Date(toDateLte)) {
+        return false;
+      }
+
+      return true;
+    });
+
+    return HttpResponse.json({
+      backfills: filtered,
+      total_entries: filtered.length,
+    });
+  }),
+];
diff --git a/airflow-core/src/airflow/ui/src/mocks/handlers/index.ts 
b/airflow-core/src/airflow/ui/src/mocks/handlers/index.ts
index 3d9e36b8602..57f95730c1b 100644
--- a/airflow-core/src/airflow/ui/src/mocks/handlers/index.ts
+++ b/airflow-core/src/airflow/ui/src/mocks/handlers/index.ts
@@ -17,6 +17,7 @@
  * under the License.
  */
 import { handlers as assetsHandlers } from "./assets";
+import { handlers as backfillsHandlers } from "./backfills";
 import { handlers as configHandlers } from "./config";
 import { handlers as dagHandlers } from "./dag";
 import { handlers as dagRunsHandlers } from "./dag_runs";
@@ -24,6 +25,7 @@ import { handlers as dagsHandlers } from "./dags";
 import { handlers as logHandlers } from "./log";
 
 export const handlers = [
+  ...backfillsHandlers,
   ...assetsHandlers,
   ...configHandlers,
   ...dagHandlers,
diff --git 
a/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/Backfills.test.tsx 
b/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/Backfills.test.tsx
index 698f38f2699..4ffffdf8c93 100644
--- a/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/Backfills.test.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/Backfills.test.tsx
@@ -30,6 +30,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
 
 import type { BackfillDagRunResponse, BackfillResponse } from 
"openapi/requests/types.gen";
 
+import { TimezoneProvider } from "src/context/timezone";
 import type * as Utils from "src/utils";
 import { BaseWrapper } from "src/utils/Wrapper";
 
@@ -39,12 +40,14 @@ const mocks = vi.hoisted(() => ({
   getBackfill: vi.fn(),
   listBackfillDagRuns: vi.fn(),
   listBackfills: vi.fn(),
+  listTeams: vi.fn(),
 }));
 
 vi.mock("openapi/queries", () => ({
   useBackfillServiceGetBackfill: mocks.getBackfill,
   useBackfillServiceListBackfillDagRuns: mocks.listBackfillDagRuns,
   useBackfillServiceListBackfillsUi: mocks.listBackfills,
+  useTeamsServiceListTeams: mocks.listTeams,
 }));
 
 vi.mock("react-i18next", () => ({
@@ -128,10 +131,12 @@ const renderBackfills = (initialEntry = 
"/dags/example_dag/backfills") =>
   render(
     <BaseWrapper>
       <MemoryRouter initialEntries={[initialEntry]}>
-        <Routes>
-          <Route element={<Backfills />} path="/dags/:dagId/backfills" />
-          <Route element={<Backfills />} 
path="/dags/:dagId/backfills/:backfillId" />
-        </Routes>
+        <TimezoneProvider>
+          <Routes>
+            <Route element={<Backfills />} path="/dags/:dagId/backfills" />
+            <Route element={<Backfills />} 
path="/dags/:dagId/backfills/:backfillId" />
+          </Routes>
+        </TimezoneProvider>
       </MemoryRouter>
     </BaseWrapper>,
   );
@@ -174,11 +179,17 @@ const expectDagRunsQuery = (backfillId: number) => {
   return options.refetchInterval;
 };
 
-describe("Backfills", () => {
+describe("Backfills filters", () => {
   beforeEach(() => {
     mocks.getBackfill.mockReset();
     mocks.listBackfillDagRuns.mockReset();
     mocks.listBackfills.mockReset();
+    mocks.listTeams.mockReset();
+    mocks.listTeams.mockReturnValue({
+      data: { teams: [], total_entries: 0 },
+      error: undefined,
+      isLoading: false,
+    });
   });
 
   it("opens a backfill's associated slots in a dialog", async () => {
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 27425422018..66964abd02e 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
@@ -20,19 +20,44 @@ import { Button, Text } from "@chakra-ui/react";
 import type { ColumnDef } from "@tanstack/react-table";
 import type { TFunction } from "i18next";
 import { useTranslation } from "react-i18next";
-import { useLocation, useNavigate, useParams } from "react-router-dom";
+import { useLocation, useNavigate, useParams, useSearchParams } from 
"react-router-dom";
 
 import { useBackfillServiceListBackfillsUi } from "openapi/queries";
-import type { BackfillResponse } from "openapi/requests/types.gen";
+import type { BackfillResponse, ReprocessBehavior } from 
"openapi/requests/types.gen";
 
 import { DataTable } from "src/components/DataTable";
 import { useTableURLState } from "src/components/DataTable/useTableUrlState";
 import { ErrorAlert } from "src/components/ErrorAlert";
 import Time from "src/components/Time";
 
+import { SearchParamsKeys, type SearchParamsKeysType } from 
"src/constants/searchParams";
 import { getDuration } from "src/utils";
 
 import { BackfillDagRunsModal } from "./BackfillDagRunsModal";
+import { BackfillsFilters } from "./BackfillsFilters";
+
+const {
+  COMPLETED_AT_GTE: COMPLETED_AT_GTE_PARAM,
+  COMPLETED_AT_LTE: COMPLETED_AT_LTE_PARAM,
+  CREATED_AT_GTE: CREATED_AT_GTE_PARAM,
+  CREATED_AT_LTE: CREATED_AT_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,
+  MAX_ACTIVE_RUNS_LTE: MAX_ACTIVE_RUNS_LTE_PARAM,
+  REPROCESS_BEHAVIOR: REPROCESS_BEHAVIOR_PARAM,
+  TO_DATE_GTE: TO_DATE_GTE_PARAM,
+  TO_DATE_LTE: TO_DATE_LTE_PARAM,
+}: SearchParamsKeysType = SearchParamsKeys;
+
+const REPROCESS_BEHAVIOR_VALUES = [
+  "failed",
+  "completed",
+  "none",
+] as const satisfies ReadonlyArray<ReprocessBehavior>;
+
+const isReprocessBehavior = (value: string | null): value is ReprocessBehavior 
=>
+  (REPROCESS_BEHAVIOR_VALUES as ReadonlyArray<string | null>).includes(value);
 
 const getColumns = (
   onSelectBackfill: (backfillId: number) => void,
@@ -128,10 +153,39 @@ export const Backfills = () => {
   const { backfillId, dagId = "" } = useParams();
   const selectedBackfillId = Number(backfillId);
   const hasSelectedBackfill = Number.isInteger(selectedBackfillId) && 
selectedBackfillId > 0;
+
+  const [searchParams] = useSearchParams();
+
+  const fromDateGte = searchParams.get(FROM_DATE_GTE_PARAM);
+  const fromDateLte = searchParams.get(FROM_DATE_LTE_PARAM);
+  const toDateGte = searchParams.get(TO_DATE_GTE_PARAM);
+  const toDateLte = searchParams.get(TO_DATE_LTE_PARAM);
+  const createdAtGte = searchParams.get(CREATED_AT_GTE_PARAM);
+  const createdAtLte = searchParams.get(CREATED_AT_LTE_PARAM);
+  const completedAtGte = searchParams.get(COMPLETED_AT_GTE_PARAM);
+  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 reprocessBehaviorParam = searchParams.get(REPROCESS_BEHAVIOR_PARAM);
+  const reprocessBehavior = isReprocessBehavior(reprocessBehaviorParam) ? 
reprocessBehaviorParam : undefined;
+
   const { data, error, isFetching, isLoading } = 
useBackfillServiceListBackfillsUi({
+    completedAtGte: completedAtGte ?? undefined,
+    completedAtLte: completedAtLte ?? undefined,
+    createdAtGte: createdAtGte ?? undefined,
+    createdAtLte: createdAtLte ?? undefined,
     dagId,
+    fromDateGte: fromDateGte ?? undefined,
+    fromDateLte: fromDateLte ?? undefined,
     limit: pagination.pageSize,
+    maxActiveRunsGte:
+      maxActiveRunsGte !== null && maxActiveRunsGte !== "" ? 
Number(maxActiveRunsGte) : undefined,
+    maxActiveRunsLte:
+      maxActiveRunsLte !== null && maxActiveRunsLte !== "" ? 
Number(maxActiveRunsLte) : undefined,
     offset: pagination.pageIndex * pagination.pageSize,
+    reprocessBehavior,
+    toDateGte: toDateGte ?? undefined,
+    toDateLte: toDateLte ?? undefined,
   });
 
   const onSelectBackfill = (id: number) => {
@@ -157,6 +211,7 @@ export const Backfills = () => {
 
   return (
     <>
+      <BackfillsFilters />
       <ErrorAlert error={error} />
       <DataTable
         columns={columns}
diff --git 
a/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillsDateFilter.test.tsx
 
b/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillsDateFilter.test.tsx
new file mode 100644
index 00000000000..e66fa301d2a
--- /dev/null
+++ 
b/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillsDateFilter.test.tsx
@@ -0,0 +1,52 @@
+/*!
+ * 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 "@testing-library/jest-dom";
+import { render, screen, waitFor } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+
+import { AppWrapper } from "src/utils/AppWrapper";
+
+// The backfills mock handler (see src/mocks/handlers/backfills.ts) returns:
+//   - id 1 (start_date: 2024-12-01, end_date: 2024-12-31) — excluded when 
filtering Jan 2025
+//   - id 2 (start_date: 2025-01-01, end_date: 2025-01-15) — included when 
filtering Jan 2025
+
+const getFromDateCells = () =>
+  screen.getAllByTestId("time-display").map((element) => 
element.getAttribute("datetime"));
+
+describe("Backfills start/end date filter", () => {
+  it("shows all backfills when no date filter is applied", async () => {
+    render(<AppWrapper 
initialEntries={["/dags/tutorial_taskflow_api/backfills"]} />);
+
+    await waitFor(() => 
expect(getFromDateCells()).toContain("2025-01-01T00:00:00Z"));
+    expect(getFromDateCells()).toContain("2024-12-01T00:00:00Z");
+  });
+
+  it("filters backfills by from_date_gte and to_date_lte URL params", async () 
=> {
+    render(
+      <AppWrapper
+        initialEntries={[
+          
"/dags/tutorial_taskflow_api/backfills?from_date_gte=2025-01-01T00%3A00%3A00Z&to_date_lte=2025-01-31T23%3A59%3A59Z",
+        ]}
+      />,
+    );
+
+    await waitFor(() => 
expect(getFromDateCells()).toContain("2025-01-01T00:00:00Z"));
+    expect(getFromDateCells()).not.toContain("2024-12-01T00:00:00Z");
+  });
+});
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
new file mode 100644
index 00000000000..e69893ddadd
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/pages/Dag/Backfills/BackfillsFilters.tsx
@@ -0,0 +1,48 @@
+/*!
+ * 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 { VStack } from "@chakra-ui/react";
+
+import { FilterBar } from "src/components/FilterBar";
+
+import { SearchParamsKeys } from "src/constants/searchParams";
+import { useFiltersHandler, type FilterableSearchParamsKeys } from "src/utils";
+
+export const BackfillsFilters = () => {
+  const searchParamKeys: Array<FilterableSearchParamsKeys> = [
+    SearchParamsKeys.FROM_RANGE,
+    SearchParamsKeys.TO_RANGE,
+    SearchParamsKeys.CREATED_AT_RANGE,
+    SearchParamsKeys.COMPLETED_AT_RANGE,
+    SearchParamsKeys.MAX_ACTIVE_RUNS_GTE,
+    SearchParamsKeys.MAX_ACTIVE_RUNS_LTE,
+    SearchParamsKeys.REPROCESS_BEHAVIOR,
+  ];
+
+  const { filterConfigs, handleFiltersChange, initialValues } = 
useFiltersHandler(searchParamKeys);
+
+  return (
+    <VStack align="start" gap={4} paddingY="4px">
+      <FilterBar
+        configs={filterConfigs}
+        initialValues={initialValues}
+        onFiltersChange={handleFiltersChange}
+      />
+    </VStack>
+  );
+};
diff --git a/airflow-core/src/airflow/ui/src/utils/useFiltersHandler.ts 
b/airflow-core/src/airflow/ui/src/utils/useFiltersHandler.ts
index dfd17785c48..d28b674353a 100644
--- a/airflow-core/src/airflow/ui/src/utils/useFiltersHandler.ts
+++ b/airflow-core/src/airflow/ui/src/utils/useFiltersHandler.ts
@@ -60,6 +60,7 @@ export type FilterableSearchParamsKeys =
   | SearchParamsKeys.ASSET_EVENT_DATE_RANGE
   | SearchParamsKeys.BODY_SEARCH
   | SearchParamsKeys.BUNDLE_VERSION
+  | SearchParamsKeys.COMPLETED_AT_RANGE
   | SearchParamsKeys.CONF_CONTAINS
   | SearchParamsKeys.CONSUMING_ASSET_PATTERN
   | SearchParamsKeys.CREATED_AT_RANGE
@@ -76,6 +77,7 @@ export type FilterableSearchParamsKeys =
   | SearchParamsKeys.EVENT_TYPE
   | SearchParamsKeys.EXECUTOR_CLASS
   | SearchParamsKeys.FAVORITE
+  | SearchParamsKeys.FROM_RANGE
   | SearchParamsKeys.GROUP_PATTERN
   | SearchParamsKeys.HOSTNAME
   | SearchParamsKeys.JOB_STATE
@@ -85,6 +87,8 @@ export type FilterableSearchParamsKeys =
   | SearchParamsKeys.LAST_DAG_RUN_STATE
   | SearchParamsKeys.LOGICAL_DATE_RANGE
   | SearchParamsKeys.MAP_INDEX
+  | SearchParamsKeys.MAX_ACTIVE_RUNS_GTE
+  | SearchParamsKeys.MAX_ACTIVE_RUNS_LTE
   | SearchParamsKeys.MISSED
   | SearchParamsKeys.NAME_PATTERN
   | SearchParamsKeys.NEEDS_REVIEW
@@ -95,6 +99,7 @@ export type FilterableSearchParamsKeys =
   | SearchParamsKeys.POOL_NAME_PATTERN
   | SearchParamsKeys.QUEUE_NAME_PATTERN
   | SearchParamsKeys.RENDERED_MAP_INDEX
+  | SearchParamsKeys.REPROCESS_BEHAVIOR
   | SearchParamsKeys.RESPONDED_BY_USER_NAME
   | SearchParamsKeys.RESPONSE_RECEIVED
   | SearchParamsKeys.RUN_AFTER_RANGE
@@ -110,6 +115,7 @@ export type FilterableSearchParamsKeys =
   | SearchParamsKeys.TASK_STATE
   | SearchParamsKeys.TEAMS
   | SearchParamsKeys.TIMETABLE_TYPE
+  | SearchParamsKeys.TO_RANGE
   | SearchParamsKeys.TRIGGERING_USER_NAME_PATTERN
   | SearchParamsKeys.TRY_NUMBER
   | SearchParamsKeys.USER;
diff --git 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_backfills.py 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_backfills.py
index ebb23efff7d..36e2d94a757 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_backfills.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_backfills.py
@@ -16,13 +16,14 @@
 # under the License.
 from __future__ import annotations
 
+from datetime import timedelta
 from unittest import mock
 
 import pytest
 
 from airflow._shared.timezones import timezone
 from airflow.models import DagModel
-from airflow.models.backfill import Backfill
+from airflow.models.backfill import Backfill, ReprocessBehavior
 from airflow.utils.session import provide_session
 
 from tests_common.test_utils.asserts import assert_queries_count
@@ -160,6 +161,88 @@ class TestListBackfills(TestBackfillEndpoint):
             "total_entries": total_entries,
         }
 
+    def test_list_backfill_by_start_end_date(self, test_client, session, 
testing_dag_bundle):
+        (dag,) = self._create_dag_models(count=1)
+        from_date = timezone.utcnow()
+        b1 = Backfill(dag_id=dag.dag_id, from_date=from_date, 
to_date=from_date)
+        other_date = from_date + timedelta(days=1)
+        b2 = Backfill(dag_id=dag.dag_id, from_date=other_date, 
to_date=other_date)
+        session.add_all([b1, b2])
+        session.commit()
+
+        response = test_client.get(
+            "/backfills",
+            params={
+                "from_date_gte": from_datetime_to_zulu(other_date),
+                "to_date_lte": from_datetime_to_zulu(other_date),
+            },
+        )
+        assert response.status_code == 200
+        assert [each["id"] for each in response.json()["backfills"]] == [b2.id]
+
+    def test_list_backfill_by_completed_at(self, test_client, session, 
testing_dag_bundle):
+        (dag,) = self._create_dag_models(count=1)
+        from_date = timezone.utcnow()
+        b1 = Backfill(dag_id=dag.dag_id, from_date=from_date, 
to_date=from_date)
+        other_completed_at = timezone.utcnow() + timedelta(days=1)
+        b2 = Backfill(
+            dag_id=dag.dag_id, from_date=from_date, to_date=from_date, 
completed_at=other_completed_at
+        )
+        session.add_all([b1, b2])
+        session.commit()
+
+        # b1's completed_at is NULL, so it never matches a bound
+        response = test_client.get(
+            "/backfills", params={"completed_at_gte": 
from_datetime_to_zulu(other_completed_at)}
+        )
+        assert response.status_code == 200
+        assert [each["id"] for each in response.json()["backfills"]] == [b2.id]
+
+    def test_list_backfill_by_created_at(self, test_client, session, 
testing_dag_bundle):
+        (dag,) = self._create_dag_models(count=1)
+        from_date = timezone.utcnow()
+        b1 = Backfill(dag_id=dag.dag_id, from_date=from_date, 
to_date=from_date)
+        other_created_at = timezone.utcnow() - timedelta(days=1)
+        b2 = Backfill(dag_id=dag.dag_id, from_date=from_date, 
to_date=from_date, created_at=other_created_at)
+        session.add_all([b1, b2])
+        session.commit()
+
+        # b1's created_at defaults to ~now, b2's is 1 day in the past
+        response = test_client.get(
+            "/backfills", params={"created_at_lte": 
from_datetime_to_zulu(other_created_at)}
+        )
+        assert response.status_code == 200
+        assert [each["id"] for each in response.json()["backfills"]] == [b2.id]
+
+    def test_list_backfill_by_reprocess_behavior(self, test_client, session, 
testing_dag_bundle):
+        (dag,) = self._create_dag_models(count=1)
+        from_date = timezone.utcnow()
+        b1 = Backfill(dag_id=dag.dag_id, from_date=from_date, 
to_date=from_date)
+        b2 = Backfill(
+            dag_id=dag.dag_id,
+            from_date=from_date,
+            to_date=from_date,
+            reprocess_behavior=ReprocessBehavior.COMPLETED,
+        )
+        session.add_all([b1, b2])
+        session.commit()
+
+        response = test_client.get("/backfills", params={"reprocess_behavior": 
"completed"})
+        assert response.status_code == 200
+        assert [each["id"] for each in response.json()["backfills"]] == [b2.id]
+
+    def test_list_backfill_by_max_active_runs(self, test_client, session, 
testing_dag_bundle):
+        (dag,) = self._create_dag_models(count=1)
+        from_date = timezone.utcnow()
+        b1 = Backfill(dag_id=dag.dag_id, from_date=from_date, 
to_date=from_date)  # default max_active_runs=10
+        b2 = Backfill(dag_id=dag.dag_id, from_date=from_date, 
to_date=from_date, max_active_runs=3)
+        session.add_all([b1, b2])
+        session.commit()
+
+        response = test_client.get("/backfills", 
params={"max_active_runs_lte": 5})
+        assert response.status_code == 200
+        assert [each["id"] for each in response.json()["backfills"]] == [b2.id]
+
     def test_should_response_401(self, unauthenticated_test_client):
         response = unauthenticated_test_client.get("/backfills", params={})
         assert response.status_code == 401

Reply via email to