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

jscheffl 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 65aa40899ef Add run_id_pattern search for Dag Run API. (#52437)
65aa40899ef is described below

commit 65aa40899effa07f573d8ec7f8d13dc6834c2cb4
Author: NOEUN KIM <[email protected]>
AuthorDate: Wed Jul 9 05:25:22 2025 +0900

    Add run_id_pattern search for Dag Run API. (#52437)
    
    * Add run_id filter for dag runs
    
    * Update i18n support for run_id filter in Dag Runs page
    
    * Apply param dependency injection and update i18n key structure
    
    * Apply _SearchParam to support pattern search
    
    * Rename run_id to run_id_pattern and refactor DagRuns ui to use SearchBar
    
    * Resolve merge conflict
    
    * Improve test cases
    
    * Resolve test failure
    
    * Fix: resolve Advanced Search button visibility
    
    * Improve filter layout and variable consistency
---
 .../core_api/openapi/v2-rest-api-generated.yaml    | 12 ++++++
 .../api_fastapi/core_api/routes/public/dag_run.py  |  4 ++
 .../src/airflow/ui/openapi-gen/queries/common.ts   |  5 ++-
 .../ui/openapi-gen/queries/ensureQueryData.ts      |  6 ++-
 .../src/airflow/ui/openapi-gen/queries/prefetch.ts |  6 ++-
 .../src/airflow/ui/openapi-gen/queries/queries.ts  |  6 ++-
 .../src/airflow/ui/openapi-gen/queries/suspense.ts |  6 ++-
 .../ui/openapi-gen/requests/services.gen.ts        |  4 +-
 .../airflow/ui/openapi-gen/requests/types.gen.ts   |  4 ++
 .../airflow/ui/public/i18n/locales/en/dags.json    |  3 +-
 .../src/airflow/ui/src/constants/searchParams.ts   |  1 +
 airflow-core/src/airflow/ui/src/pages/DagRuns.tsx  | 45 ++++++++++++++++++----
 .../core_api/routes/public/test_dag_run.py         | 17 +++++++-
 13 files changed, 99 insertions(+), 20 deletions(-)

diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
 
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
index d00a383f5b8..c0b2e81c718 100644
--- 
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
+++ 
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
@@ -2041,6 +2041,18 @@ paths:
           type: string
           default: id
           title: Order By
+      - name: run_id_pattern
+        in: query
+        required: false
+        schema:
+          anyOf:
+          - type: string
+          - type: 'null'
+          description: "SQL LIKE expression \u2014 use `%` / `_` wildcards 
(e.g. `%customer_%`).\
+            \ Regular expressions are **not** supported."
+          title: Run Id Pattern
+        description: "SQL LIKE expression \u2014 use `%` / `_` wildcards (e.g. 
`%customer_%`).\
+          \ Regular expressions are **not** supported."
       responses:
         '200':
           description: Successful Response
diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dag_run.py 
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dag_run.py
index f50b92cb27b..63e27f60cda 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dag_run.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dag_run.py
@@ -46,7 +46,9 @@ from airflow.api_fastapi.common.parameters import (
     Range,
     RangeFilter,
     SortParam,
+    _SearchParam,
     datetime_range_filter_factory,
+    search_param_factory,
 )
 from airflow.api_fastapi.common.router import AirflowRouter
 from airflow.api_fastapi.core_api.datamodels.assets import 
AssetEventCollectionResponse
@@ -334,6 +336,7 @@ def get_dag_runs(
     readable_dag_runs_filter: ReadableDagRunsFilterDep,
     session: SessionDep,
     dag_bag: DagBagDep,
+    run_id_pattern: Annotated[_SearchParam, 
Depends(search_param_factory(DagRun.run_id, "run_id_pattern"))],
 ) -> DAGRunCollectionResponse:
     """
     Get all DAG Runs.
@@ -360,6 +363,7 @@ def get_dag_runs(
             state,
             run_type,
             readable_dag_runs_filter,
+            run_id_pattern,
         ],
         order_by=order_by,
         offset=offset,
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 cb1c91f37d5..4c76141a70d 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
@@ -140,7 +140,7 @@ export const UseDagRunServiceGetUpstreamAssetEventsKeyFn = 
({ dagId, dagRunId }:
 export type DagRunServiceGetDagRunsDefaultResponse = Awaited<ReturnType<typeof 
DagRunService.getDagRuns>>;
 export type DagRunServiceGetDagRunsQueryResult<TData = 
DagRunServiceGetDagRunsDefaultResponse, TError = unknown> = 
UseQueryResult<TData, TError>;
 export const useDagRunServiceGetDagRunsKey = "DagRunServiceGetDagRuns";
-export const UseDagRunServiceGetDagRunsKeyFn = ({ dagId, endDateGte, 
endDateLte, limit, logicalDateGte, logicalDateLte, offset, orderBy, 
runAfterGte, runAfterLte, runType, startDateGte, startDateLte, state, 
updatedAtGte, updatedAtLte }: {
+export const UseDagRunServiceGetDagRunsKeyFn = ({ dagId, endDateGte, 
endDateLte, limit, logicalDateGte, logicalDateLte, offset, orderBy, 
runAfterGte, runAfterLte, runIdPattern, runType, startDateGte, startDateLte, 
state, updatedAtGte, updatedAtLte }: {
   dagId: string;
   endDateGte?: string;
   endDateLte?: string;
@@ -151,13 +151,14 @@ export const UseDagRunServiceGetDagRunsKeyFn = ({ dagId, 
endDateGte, endDateLte,
   orderBy?: string;
   runAfterGte?: string;
   runAfterLte?: string;
+  runIdPattern?: string;
   runType?: string[];
   startDateGte?: string;
   startDateLte?: string;
   state?: string[];
   updatedAtGte?: string;
   updatedAtLte?: string;
-}, queryKey?: Array<unknown>) => [useDagRunServiceGetDagRunsKey, ...(queryKey 
?? [{ dagId, endDateGte, endDateLte, limit, logicalDateGte, logicalDateLte, 
offset, orderBy, runAfterGte, runAfterLte, runType, startDateGte, startDateLte, 
state, updatedAtGte, updatedAtLte }])];
+}, queryKey?: Array<unknown>) => [useDagRunServiceGetDagRunsKey, ...(queryKey 
?? [{ dagId, endDateGte, endDateLte, limit, logicalDateGte, logicalDateLte, 
offset, orderBy, runAfterGte, runAfterLte, runIdPattern, runType, startDateGte, 
startDateLte, state, updatedAtGte, updatedAtLte }])];
 export type DagSourceServiceGetDagSourceDefaultResponse = 
Awaited<ReturnType<typeof DagSourceService.getDagSource>>;
 export type DagSourceServiceGetDagSourceQueryResult<TData = 
DagSourceServiceGetDagSourceDefaultResponse, TError = unknown> = 
UseQueryResult<TData, TError>;
 export const useDagSourceServiceGetDagSourceKey = 
"DagSourceServiceGetDagSource";
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 e87e8bc4994..99e3a1f56aa 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
@@ -272,10 +272,11 @@ export const 
ensureUseDagRunServiceGetUpstreamAssetEventsData = (queryClient: Qu
 * @param data.runType
 * @param data.state
 * @param data.orderBy
+* @param data.runIdPattern SQL LIKE expression — use `%` / `_` wildcards (e.g. 
`%customer_%`). Regular expressions are **not** supported.
 * @returns DAGRunCollectionResponse Successful Response
 * @throws ApiError
 */
-export const ensureUseDagRunServiceGetDagRunsData = (queryClient: QueryClient, 
{ dagId, endDateGte, endDateLte, limit, logicalDateGte, logicalDateLte, offset, 
orderBy, runAfterGte, runAfterLte, runType, startDateGte, startDateLte, state, 
updatedAtGte, updatedAtLte }: {
+export const ensureUseDagRunServiceGetDagRunsData = (queryClient: QueryClient, 
{ dagId, endDateGte, endDateLte, limit, logicalDateGte, logicalDateLte, offset, 
orderBy, runAfterGte, runAfterLte, runIdPattern, runType, startDateGte, 
startDateLte, state, updatedAtGte, updatedAtLte }: {
   dagId: string;
   endDateGte?: string;
   endDateLte?: string;
@@ -286,13 +287,14 @@ export const ensureUseDagRunServiceGetDagRunsData = 
(queryClient: QueryClient, {
   orderBy?: string;
   runAfterGte?: string;
   runAfterLte?: string;
+  runIdPattern?: string;
   runType?: string[];
   startDateGte?: string;
   startDateLte?: string;
   state?: string[];
   updatedAtGte?: string;
   updatedAtLte?: string;
-}) => queryClient.ensureQueryData({ queryKey: 
Common.UseDagRunServiceGetDagRunsKeyFn({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runType, startDateGte, startDateLte, state, updatedAtGte, updatedAtLte }), 
queryFn: () => DagRunService.getDagRuns({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runType, startDateGte, startDateLte, state, updatedAtGte, upda [...]
+}) => queryClient.ensureQueryData({ queryKey: 
Common.UseDagRunServiceGetDagRunsKeyFn({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runIdPattern, runType, startDateGte, startDateLte, state, updatedAtGte, 
updatedAtLte }), queryFn: () => DagRunService.getDagRuns({ dagId, endDateGte, 
endDateLte, limit, logicalDateGte, logicalDateLte, offset, orderBy, 
runAfterGte, runAfterLte, runIdPattern, runType, startDateGte, startDateLt [...]
 /**
 * Get Dag Source
 * Get source code using file token.
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 0c1b6bbbc1a..aff2296830e 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
@@ -272,10 +272,11 @@ export const 
prefetchUseDagRunServiceGetUpstreamAssetEvents = (queryClient: Quer
 * @param data.runType
 * @param data.state
 * @param data.orderBy
+* @param data.runIdPattern SQL LIKE expression — use `%` / `_` wildcards (e.g. 
`%customer_%`). Regular expressions are **not** supported.
 * @returns DAGRunCollectionResponse Successful Response
 * @throws ApiError
 */
-export const prefetchUseDagRunServiceGetDagRuns = (queryClient: QueryClient, { 
dagId, endDateGte, endDateLte, limit, logicalDateGte, logicalDateLte, offset, 
orderBy, runAfterGte, runAfterLte, runType, startDateGte, startDateLte, state, 
updatedAtGte, updatedAtLte }: {
+export const prefetchUseDagRunServiceGetDagRuns = (queryClient: QueryClient, { 
dagId, endDateGte, endDateLte, limit, logicalDateGte, logicalDateLte, offset, 
orderBy, runAfterGte, runAfterLte, runIdPattern, runType, startDateGte, 
startDateLte, state, updatedAtGte, updatedAtLte }: {
   dagId: string;
   endDateGte?: string;
   endDateLte?: string;
@@ -286,13 +287,14 @@ export const prefetchUseDagRunServiceGetDagRuns = 
(queryClient: QueryClient, { d
   orderBy?: string;
   runAfterGte?: string;
   runAfterLte?: string;
+  runIdPattern?: string;
   runType?: string[];
   startDateGte?: string;
   startDateLte?: string;
   state?: string[];
   updatedAtGte?: string;
   updatedAtLte?: string;
-}) => queryClient.prefetchQuery({ queryKey: 
Common.UseDagRunServiceGetDagRunsKeyFn({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runType, startDateGte, startDateLte, state, updatedAtGte, updatedAtLte }), 
queryFn: () => DagRunService.getDagRuns({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runType, startDateGte, startDateLte, state, updatedAtGte, update [...]
+}) => queryClient.prefetchQuery({ queryKey: 
Common.UseDagRunServiceGetDagRunsKeyFn({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runIdPattern, runType, startDateGte, startDateLte, state, updatedAtGte, 
updatedAtLte }), queryFn: () => DagRunService.getDagRuns({ dagId, endDateGte, 
endDateLte, limit, logicalDateGte, logicalDateLte, offset, orderBy, 
runAfterGte, runAfterLte, runIdPattern, runType, startDateGte, startDateLte, 
[...]
 /**
 * Get Dag Source
 * Get source code using file token.
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 67540a96d3f..86294553c8d 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
@@ -272,10 +272,11 @@ export const useDagRunServiceGetUpstreamAssetEvents = 
<TData = Common.DagRunServ
 * @param data.runType
 * @param data.state
 * @param data.orderBy
+* @param data.runIdPattern SQL LIKE expression — use `%` / `_` wildcards (e.g. 
`%customer_%`). Regular expressions are **not** supported.
 * @returns DAGRunCollectionResponse Successful Response
 * @throws ApiError
 */
-export const useDagRunServiceGetDagRuns = <TData = 
Common.DagRunServiceGetDagRunsDefaultResponse, TError = unknown, TQueryKey 
extends Array<unknown> = unknown[]>({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runType, startDateGte, startDateLte, state, updatedAtGte, updatedAtLte }: {
+export const useDagRunServiceGetDagRuns = <TData = 
Common.DagRunServiceGetDagRunsDefaultResponse, TError = unknown, TQueryKey 
extends Array<unknown> = unknown[]>({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runIdPattern, runType, startDateGte, startDateLte, state, updatedAtGte, 
updatedAtLte }: {
   dagId: string;
   endDateGte?: string;
   endDateLte?: string;
@@ -286,13 +287,14 @@ export const useDagRunServiceGetDagRuns = <TData = 
Common.DagRunServiceGetDagRun
   orderBy?: string;
   runAfterGte?: string;
   runAfterLte?: string;
+  runIdPattern?: string;
   runType?: string[];
   startDateGte?: string;
   startDateLte?: string;
   state?: string[];
   updatedAtGte?: string;
   updatedAtLte?: string;
-}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey: 
Common.UseDagRunServiceGetDagRunsKeyFn({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runType, startDateGte, startDateLte, state, updatedAtGte, updatedAtLte }, 
queryKey), queryFn: () => DagRunService.getDagRuns({ dagId, endDateGte, 
endDateLte, limit, logicalDateGte, logicalDateLte, offse [...]
+}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey: 
Common.UseDagRunServiceGetDagRunsKeyFn({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runIdPattern, runType, startDateGte, startDateLte, state, updatedAtGte, 
updatedAtLte }, queryKey), queryFn: () => DagRunService.getDagRuns({ dagId, 
endDateGte, endDateLte, limit, logicalDateGte, logical [...]
 /**
 * Get Dag Source
 * Get source code using file token.
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 522cceedbdf..6ce89341810 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
@@ -272,10 +272,11 @@ export const 
useDagRunServiceGetUpstreamAssetEventsSuspense = <TData = Common.Da
 * @param data.runType
 * @param data.state
 * @param data.orderBy
+* @param data.runIdPattern SQL LIKE expression — use `%` / `_` wildcards (e.g. 
`%customer_%`). Regular expressions are **not** supported.
 * @returns DAGRunCollectionResponse Successful Response
 * @throws ApiError
 */
-export const useDagRunServiceGetDagRunsSuspense = <TData = 
Common.DagRunServiceGetDagRunsDefaultResponse, TError = unknown, TQueryKey 
extends Array<unknown> = unknown[]>({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runType, startDateGte, startDateLte, state, updatedAtGte, updatedAtLte }: {
+export const useDagRunServiceGetDagRunsSuspense = <TData = 
Common.DagRunServiceGetDagRunsDefaultResponse, TError = unknown, TQueryKey 
extends Array<unknown> = unknown[]>({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runIdPattern, runType, startDateGte, startDateLte, state, updatedAtGte, 
updatedAtLte }: {
   dagId: string;
   endDateGte?: string;
   endDateLte?: string;
@@ -286,13 +287,14 @@ export const useDagRunServiceGetDagRunsSuspense = <TData 
= Common.DagRunServiceG
   orderBy?: string;
   runAfterGte?: string;
   runAfterLte?: string;
+  runIdPattern?: string;
   runType?: string[];
   startDateGte?: string;
   startDateLte?: string;
   state?: string[];
   updatedAtGte?: string;
   updatedAtLte?: string;
-}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey: 
Common.UseDagRunServiceGetDagRunsKeyFn({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runType, startDateGte, startDateLte, state, updatedAtGte, updatedAtLte }, 
queryKey), queryFn: () => DagRunService.getDagRuns({ dagId, endDateGte, 
endDateLte, limit, logicalDateGte, logicalDateLt [...]
+}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>, 
"queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey: 
Common.UseDagRunServiceGetDagRunsKeyFn({ dagId, endDateGte, endDateLte, limit, 
logicalDateGte, logicalDateLte, offset, orderBy, runAfterGte, runAfterLte, 
runIdPattern, runType, startDateGte, startDateLte, state, updatedAtGte, 
updatedAtLte }, queryKey), queryFn: () => DagRunService.getDagRuns({ dagId, 
endDateGte, endDateLte, limit, logicalDateGte, [...]
 /**
 * Get Dag Source
 * Get source code using file token.
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 97e4245c2c2..d3dc37b8e66 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
@@ -983,6 +983,7 @@ export class DagRunService {
      * @param data.runType
      * @param data.state
      * @param data.orderBy
+     * @param data.runIdPattern SQL LIKE expression — use `%` / `_` wildcards 
(e.g. `%customer_%`). Regular expressions are **not** supported.
      * @returns DAGRunCollectionResponse Successful Response
      * @throws ApiError
      */
@@ -1008,7 +1009,8 @@ export class DagRunService {
                 updated_at_lte: data.updatedAtLte,
                 run_type: data.runType,
                 state: data.state,
-                order_by: data.orderBy
+                order_by: data.orderBy,
+                run_id_pattern: data.runIdPattern
             },
             errors: {
                 401: 'Unauthorized',
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 1fb875d7e4f..b1590d732fe 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
@@ -2195,6 +2195,10 @@ export type GetDagRunsData = {
     orderBy?: string;
     runAfterGte?: string | null;
     runAfterLte?: string | null;
+    /**
+     * SQL LIKE expression — use `%` / `_` wildcards (e.g. `%customer_%`). 
Regular expressions are **not** supported.
+     */
+    runIdPattern?: string | null;
     runType?: Array<(string)>;
     startDateGte?: string | null;
     startDateLte?: string | null;
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/en/dags.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/en/dags.json
index 8e88677bc6d..d1ee6a3d0ee 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/en/dags.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/en/dags.json
@@ -19,7 +19,8 @@
       "active": "Active",
       "all": "All",
       "paused": "Paused"
-    }
+    },
+    "runIdPatternFilter": "Search Dag Runs"
   },
   "ownerLink": "Owner link for {{owner}}",
   "runAndTaskActions": {
diff --git a/airflow-core/src/airflow/ui/src/constants/searchParams.ts 
b/airflow-core/src/airflow/ui/src/constants/searchParams.ts
index fdeef3c5bb4..b5dc9200e27 100644
--- a/airflow-core/src/airflow/ui/src/constants/searchParams.ts
+++ b/airflow-core/src/airflow/ui/src/constants/searchParams.ts
@@ -27,6 +27,7 @@ export enum SearchParamsKeys {
   OFFSET = "offset",
   PAUSED = "paused",
   POOL = "pool",
+  RUN_ID_PATTERN = "run_id_pattern",
   RUN_TYPE = "run_type",
   SORT = "sort",
   SOURCE = "log_source",
diff --git a/airflow-core/src/airflow/ui/src/pages/DagRuns.tsx 
b/airflow-core/src/airflow/ui/src/pages/DagRuns.tsx
index 5bb722ecbd1..3afeab6ded1 100644
--- a/airflow-core/src/airflow/ui/src/pages/DagRuns.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/DagRuns.tsx
@@ -18,7 +18,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { Flex, HStack, Link, type SelectValueChangeDetails, Text } from 
"@chakra-ui/react";
+import { Flex, HStack, Link, type SelectValueChangeDetails, Text, Box } from 
"@chakra-ui/react";
 import type { ColumnDef } from "@tanstack/react-table";
 import type { TFunction } from "i18next";
 import { useCallback } from "react";
@@ -36,6 +36,7 @@ import { LimitedItemsList } from 
"src/components/LimitedItemsList";
 import { MarkRunAsButton } from "src/components/MarkAs";
 import RenderedJsonField from "src/components/RenderedJsonField";
 import { RunTypeIcon } from "src/components/RunTypeIcon";
+import { SearchBar } from "src/components/SearchBar";
 import { StateBadge } from "src/components/StateBadge";
 import Time from "src/components/Time";
 import { Select } from "src/components/ui";
@@ -47,6 +48,7 @@ import { renderDuration, useAutoRefresh, isStatePending } 
from "src/utils";
 type DagRunRow = { row: { original: DAGRunResponse } };
 const {
   END_DATE: END_DATE_PARAM,
+  RUN_ID_PATTERN: RUN_ID_PATTERN_PARAM,
   RUN_TYPE: RUN_TYPE_PARAM,
   START_DATE: START_DATE_PARAM,
   STATE: STATE_PARAM,
@@ -156,8 +158,10 @@ export const DagRuns = () => {
   const [sort] = sorting;
   const orderBy = sort ? `${sort.desc ? "-" : ""}${sort.id}` : "-run_after";
 
+  const { pageIndex, pageSize } = pagination;
   const filteredState = searchParams.get(STATE_PARAM);
   const filteredType = searchParams.get(RUN_TYPE_PARAM);
+  const filteredRunIdPattern = searchParams.get(RUN_ID_PATTERN_PARAM);
   const startDate = searchParams.get(START_DATE_PARAM);
   const endDate = searchParams.get(END_DATE_PARAM);
 
@@ -167,16 +171,17 @@ export const DagRuns = () => {
     {
       dagId: dagId ?? "~",
       endDateLte: endDate ?? undefined,
-      limit: pagination.pageSize,
-      offset: pagination.pageIndex * pagination.pageSize,
+      limit: pageSize,
+      offset: pageIndex * pageSize,
       orderBy,
+      runIdPattern: filteredRunIdPattern ?? undefined,
       runType: filteredType === null ? undefined : [filteredType],
       startDateGte: startDate ?? undefined,
       state: filteredState === null ? undefined : [filteredState],
     },
     undefined,
     {
-      enabled: !isNaN(pagination.pageSize),
+      enabled: !isNaN(pageSize),
       refetchInterval: (query) =>
         query.state.data?.dag_runs.some((run) => isStatePending(run.state)) ? 
refetchInterval : false,
     },
@@ -218,9 +223,34 @@ export const DagRuns = () => {
     [pagination, searchParams, setSearchParams, setTableURLState, sorting],
   );
 
+  const handleRunIdPatternChange = useCallback(
+    (value: string) => {
+      if (value === "") {
+        searchParams.delete(RUN_ID_PATTERN_PARAM);
+      } else {
+        searchParams.set(RUN_ID_PATTERN_PARAM, value);
+      }
+      setTableURLState({
+        pagination: { ...pagination, pageIndex: 0 },
+        sorting,
+      });
+      setSearchParams(searchParams);
+    },
+    [pagination, searchParams, setSearchParams, setTableURLState, sorting],
+  );
+
   return (
     <>
-      <Flex gap={1}>
+      <HStack paddingY="4px">
+        <Box>
+          <SearchBar
+            defaultValue={filteredRunIdPattern ?? ""}
+            hideAdvanced
+            hotkeyDisabled={false}
+            onChange={handleRunIdPatternChange}
+            placeHolder={translate("dags:filters.runIdPatternFilter")}
+          />
+        </Box>
         <Select.Root
           collection={stateOptions}
           maxW="200px"
@@ -252,13 +282,14 @@ export const DagRuns = () => {
             ))}
           </Select.Content>
         </Select.Root>
+
         <Select.Root
           collection={dagRunTypeOptions}
           maxW="200px"
           onValueChange={handleTypeChange}
           value={[filteredType ?? "all"]}
         >
-          <Select.Trigger colorPalette="blue" 
isActive={Boolean(filteredState)} minW="max-content">
+          <Select.Trigger colorPalette="blue" isActive={Boolean(filteredType)} 
minW="max-content">
             <Select.ValueText width="auto">
               {() =>
                 filteredType === null ? (
@@ -287,7 +318,7 @@ export const DagRuns = () => {
             ))}
           </Select.Content>
         </Select.Root>
-      </Flex>
+      </HStack>
       <DataTable
         columns={runColumns(translate, dagId)}
         data={data?.dag_runs ?? []}
diff --git 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dag_run.py 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dag_run.py
index 1e91d51bc43..acb054cb3f9 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dag_run.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dag_run.py
@@ -464,6 +464,21 @@ class TestGetDagRuns:
                 },
                 [DAG1_RUN2_ID],
             ),
+            (DAG1_ID, {"run_id_pattern": DAG1_RUN1_ID}, [DAG1_RUN1_ID]),
+            (DAG2_ID, {"run_id_pattern": DAG2_RUN1_ID}, [DAG2_RUN1_ID]),
+            ("~", {"run_id_pattern": DAG1_RUN1_ID}, [DAG1_RUN1_ID]),
+            ("~", {"run_id_pattern": "non_existent_run_id"}, []),
+            (DAG1_ID, {"run_id_pattern": "run_1"}, [DAG1_RUN1_ID]),
+            (DAG1_ID, {"run_id_pattern": "dag_%_1"}, [DAG1_RUN1_ID]),
+            ("~", {"run_id_pattern": "dag_run_"}, [DAG1_RUN1_ID, DAG1_RUN2_ID, 
DAG2_RUN1_ID, DAG2_RUN2_ID]),
+            (
+                DAG1_ID,
+                {
+                    "run_id_pattern": DAG1_RUN1_ID,
+                    "state": DagRunState.SUCCESS.value,
+                },
+                [DAG1_RUN1_ID],
+            ),
         ],
     )
     @pytest.mark.usefixtures("configure_git_connection_for_dag_bundle")
@@ -1315,12 +1330,12 @@ class TestTriggerDagRun:
             "run_after": fixed_now.replace("+00:00", "Z"),
             "start_date": None,
             "duration": None,
+            "run_type": "manual",
             "state": "queued",
             "data_interval_end": expected_data_interval_end,
             "data_interval_start": expected_data_interval_start,
             "queued_at": fixed_now.replace("+00:00", "Z"),
             "last_scheduling_decision": None,
-            "run_type": "manual",
             "note": note,
             "triggered_by": "rest_api",
             "triggering_user_name": "test",

Reply via email to