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",