This is an automated email from the ASF dual-hosted git repository.
bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new c6854682bc5 UI: Add team column and filter to the XComs list (#72158)
c6854682bc5 is described below
commit c6854682bc579dc2db693d9e8cb5d68327e45bdb
Author: Vincent <[email protected]>
AuthorDate: Mon Aug 31 16:24:19 2026 -0400
UI: Add team column and filter to the XComs list (#72158)
When multi-team mode is enabled, operators inspecting cross-task
communication
across teams need to see which team owns each XCom entry and to scope the
list
to a single team while investigating that team's Dags.
The column and the filter render only when the `multi_team` configuration is
enabled, and no team data is loaded when it is off, so single-team
deployments
are unaffected.
---
.../api_fastapi/core_api/datamodels/xcom.py | 1 +
.../core_api/openapi/v2-rest-api-generated.yaml | 23 +++++
.../api_fastapi/core_api/routes/public/xcom.py | 29 +++++-
.../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 +-
.../airflow/ui/openapi-gen/requests/schemas.gen.ts | 33 +++++++
.../ui/openapi-gen/requests/services.gen.ts | 2 +
.../airflow/ui/openapi-gen/requests/types.gen.ts | 4 +
.../src/airflow/ui/src/pages/XCom/XCom.tsx | 21 +++++
.../src/airflow/ui/src/pages/XCom/XComFilters.tsx | 6 ++
.../core_api/routes/public/test_xcom.py | 104 ++++++++++++++++++++-
.../src/airflowctl/api/datamodels/generated.py | 3 +
15 files changed, 240 insertions(+), 15 deletions(-)
diff --git a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/xcom.py
b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/xcom.py
index e6987502ad3..b5416489510 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/xcom.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/xcom.py
@@ -39,6 +39,7 @@ class XComResponse(BaseModel):
dag_display_name: str = Field(validation_alias=AliasPath("dag_run",
"dag_model", "dag_display_name"))
task_display_name: str = Field(validation_alias=AliasPath("task",
"task_display_name"))
run_after: datetime = Field(validation_alias=AliasPath("dag_run",
"run_after"))
+ team_name: str | None = Field(validation_alias=AliasPath("dag_run",
"team_name"), default=None)
def _stringify_if_needed(value):
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 099e1b9cb5e..c383236f795 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
@@ -6945,6 +6945,14 @@ paths:
format: date-time
- type: 'null'
title: Run After Lt
+ - name: teams
+ in: query
+ required: false
+ schema:
+ type: array
+ items:
+ type: string
+ title: Teams
- name: order_by
in: query
required: false
@@ -16936,6 +16944,11 @@ components:
type: string
format: date-time
title: Run After
+ team_name:
+ anyOf:
+ - type: string
+ - type: 'null'
+ title: Team Name
type: object
required:
- key
@@ -16987,6 +17000,11 @@ components:
type: string
format: date-time
title: Run After
+ team_name:
+ anyOf:
+ - type: string
+ - type: 'null'
+ title: Team Name
value:
title: Value
type: object
@@ -17041,6 +17059,11 @@ components:
type: string
format: date-time
title: Run After
+ team_name:
+ anyOf:
+ - type: string
+ - type: 'null'
+ title: Team Name
value:
anyOf:
- type: string
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/xcom.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/xcom.py
index 40bb97cfc9f..852051608fb 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/xcom.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/xcom.py
@@ -26,6 +26,7 @@ from sqlalchemy.orm import joinedload
from airflow.api_fastapi.auth.managers.models.resource_details import
DagAccessEntity
from airflow.api_fastapi.common.dagbag import DagBagDep,
get_dag_for_run_or_latest_version
from airflow.api_fastapi.common.db.common import SessionDep, paginated_select
+from airflow.api_fastapi.common.db.dags import eager_load_teams
from airflow.api_fastapi.common.parameters import (
FilterParam,
QueryLimit,
@@ -40,8 +41,10 @@ from airflow.api_fastapi.common.parameters import (
QueryXComTaskIdPrefixPatternSearch,
RangeFilter,
SortParam,
+ _DagIdTeamsFilter,
datetime_range_filter_factory,
filter_param_factory,
+ teams_filter_factory,
)
from airflow.api_fastapi.common.router import AirflowRouter
from airflow.api_fastapi.core_api.datamodels.xcom import (
@@ -92,7 +95,11 @@ def get_xcom_entry(
dag_ids=dag_id,
map_indexes=map_index,
limit=1,
- ).options(joinedload(XComModel.task),
joinedload(XComModel.dag_run).joinedload(DR.dag_model))
+ ).options(
+ joinedload(XComModel.task),
+ joinedload(XComModel.dag_run).joinedload(DR.dag_model),
+ *eager_load_teams(XComModel.dag_run, DR.dag_model),
+ )
# We use `BaseXCom.get_many` to fetch XComs directly from the database,
bypassing the XCom Backend.
# This avoids deserialization via the backend (e.g., from a remote storage
like S3) and instead
@@ -170,6 +177,7 @@ def get_xcom_entries(
],
logical_date_range: Annotated[RangeFilter,
Depends(datetime_range_filter_factory("logical_date", DR))],
run_after_range: Annotated[RangeFilter,
Depends(datetime_range_filter_factory("run_after", DR))],
+ teams: Annotated[_DagIdTeamsFilter,
Depends(teams_filter_factory(XComModel.dag_id))],
order_by: Annotated[
SortParam,
Depends(
@@ -194,7 +202,11 @@ def get_xcom_entries(
query = (
query.join(DR, and_(XComModel.dag_id == DR.dag_id, XComModel.run_id ==
DR.run_id))
.join(DagModel, DR.dag_id == DagModel.dag_id)
- .options(joinedload(XComModel.task),
joinedload(XComModel.dag_run).joinedload(DR.dag_model))
+ .options(
+ joinedload(XComModel.task),
+ joinedload(XComModel.dag_run).joinedload(DR.dag_model),
+ *eager_load_teams(XComModel.dag_run, DR.dag_model),
+ )
)
if task_id != "~":
@@ -221,6 +233,7 @@ def get_xcom_entries(
map_index_filter,
logical_date_range,
run_after_range,
+ teams,
],
order_by=order_by,
offset=offset,
@@ -315,7 +328,11 @@ def create_xcom_entry(
XComModel.map_index == request_body.map_index,
)
.limit(1)
- .options(joinedload(XComModel.task),
joinedload(XComModel.dag_run).joinedload(DR.dag_model))
+ .options(
+ joinedload(XComModel.task),
+ joinedload(XComModel.dag_run).joinedload(DR.dag_model),
+ *eager_load_teams(XComModel.dag_run, DR.dag_model),
+ )
)
return XComResponseNative.model_validate(xcom)
@@ -356,7 +373,11 @@ def update_xcom_entry(
XComModel.map_index == patch_body.map_index,
)
.limit(1)
- .options(joinedload(XComModel.task),
joinedload(XComModel.dag_run).joinedload(DR.dag_model))
+ .options(
+ joinedload(XComModel.task),
+ joinedload(XComModel.dag_run).joinedload(DR.dag_model),
+ *eager_load_teams(XComModel.dag_run, DR.dag_model),
+ )
)
xcom_entry = session.scalar(xcom_query)
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 5daf6e1d6d9..e5c078e4a11 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts
@@ -846,7 +846,7 @@ export const UseXcomServiceGetXcomEntryKeyFn = ({ dagId,
dagRunId, deserialize,
export type XcomServiceGetXcomEntriesDefaultResponse =
Awaited<ReturnType<typeof XcomService.getXcomEntries>>;
export type XcomServiceGetXcomEntriesQueryResult<TData =
XcomServiceGetXcomEntriesDefaultResponse, TError = unknown> =
UseQueryResult<TData, TError>;
export const useXcomServiceGetXcomEntriesKey = "XcomServiceGetXcomEntries";
-export const UseXcomServiceGetXcomEntriesKeyFn = ({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
xcomKey, xcomKeyPattern, xcomKeyPrefixPattern }: {
+export const UseXcomServiceGetXcomEntriesKeyFn = ({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
teams, xcomKey, xcomKeyPattern, xcomKeyPrefixPattern }: {
dagDisplayNamePattern?: string;
dagDisplayNamePrefixPattern?: string;
dagId: string;
@@ -869,10 +869,11 @@ export const UseXcomServiceGetXcomEntriesKeyFn = ({
dagDisplayNamePattern, dagDi
taskId: string;
taskIdPattern?: string;
taskIdPrefixPattern?: string;
+ teams?: string[];
xcomKey?: string;
xcomKeyPattern?: string;
xcomKeyPrefixPattern?: string;
-}, queryKey?: Array<unknown>) => [useXcomServiceGetXcomEntriesKey,
...(queryKey ?? [{ dagDisplayNamePattern, dagDisplayNamePrefixPattern, dagId,
dagRunId, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte,
mapIndex, mapIndexFilter, offset, orderBy, runAfterGt, runAfterGte, runAfterLt,
runAfterLte, runIdPattern, runIdPrefixPattern, taskId, taskIdPattern,
taskIdPrefixPattern, xcomKey, xcomKeyPattern, xcomKeyPrefixPattern }])];
+}, queryKey?: Array<unknown>) => [useXcomServiceGetXcomEntriesKey,
...(queryKey ?? [{ dagDisplayNamePattern, dagDisplayNamePrefixPattern, dagId,
dagRunId, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte,
mapIndex, mapIndexFilter, offset, orderBy, runAfterGt, runAfterGte, runAfterLt,
runAfterLte, runIdPattern, runIdPrefixPattern, taskId, taskIdPattern,
taskIdPrefixPattern, teams, xcomKey, xcomKeyPattern, xcomKeyPrefixPattern }])];
export type TaskServiceGetTasksDefaultResponse = Awaited<ReturnType<typeof
TaskService.getTasks>>;
export type TaskServiceGetTasksQueryResult<TData =
TaskServiceGetTasksDefaultResponse, TError = unknown> = UseQueryResult<TData,
TError>;
export const useTaskServiceGetTasksKey = "TaskServiceGetTasks";
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 2695e959e00..2da84b8596d 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts
@@ -1657,11 +1657,12 @@ export const ensureUseXcomServiceGetXcomEntryData =
(queryClient: QueryClient, {
* @param data.runAfterGt
* @param data.runAfterLte
* @param data.runAfterLt
+* @param data.teams
* @param data.orderBy Attributes to order by, multi criteria sort is
supported. Prefix with `-` for descending order. Supported attributes: `key,
dag_id, run_id, task_id, map_index, timestamp, run_after`
* @returns XComCollectionResponse Successful Response
* @throws ApiError
*/
-export const ensureUseXcomServiceGetXcomEntriesData = (queryClient:
QueryClient, { dagDisplayNamePattern, dagDisplayNamePrefixPattern, dagId,
dagRunId, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte,
mapIndex, mapIndexFilter, offset, orderBy, runAfterGt, runAfterGte, runAfterLt,
runAfterLte, runIdPattern, runIdPrefixPattern, taskId, taskIdPattern,
taskIdPrefixPattern, xcomKey, xcomKeyPattern, xcomKeyPrefixPattern }: {
+export const ensureUseXcomServiceGetXcomEntriesData = (queryClient:
QueryClient, { dagDisplayNamePattern, dagDisplayNamePrefixPattern, dagId,
dagRunId, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte,
mapIndex, mapIndexFilter, offset, orderBy, runAfterGt, runAfterGte, runAfterLt,
runAfterLte, runIdPattern, runIdPrefixPattern, taskId, taskIdPattern,
taskIdPrefixPattern, teams, xcomKey, xcomKeyPattern, xcomKeyPrefixPattern }: {
dagDisplayNamePattern?: string;
dagDisplayNamePrefixPattern?: string;
dagId: string;
@@ -1684,10 +1685,11 @@ export const ensureUseXcomServiceGetXcomEntriesData =
(queryClient: QueryClient,
taskId: string;
taskIdPattern?: string;
taskIdPrefixPattern?: string;
+ teams?: string[];
xcomKey?: string;
xcomKeyPattern?: string;
xcomKeyPrefixPattern?: string;
-}) => queryClient.ensureQueryData({ queryKey:
Common.UseXcomServiceGetXcomEntriesKeyFn({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
xcomKey, xcomKeyPattern, xcomKeyPrefixPattern }), queryFn: () =>
XcomService.getXcomEntries({ [...]
+}) => queryClient.ensureQueryData({ queryKey:
Common.UseXcomServiceGetXcomEntriesKeyFn({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
teams, xcomKey, xcomKeyPattern, xcomKeyPrefixPattern }), queryFn: () =>
XcomService.getXcomEnt [...]
/**
* Get Tasks
* Get tasks for Dag.
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 5e0cffc8e6d..917cc830f04 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts
@@ -1657,11 +1657,12 @@ export const prefetchUseXcomServiceGetXcomEntry =
(queryClient: QueryClient, { d
* @param data.runAfterGt
* @param data.runAfterLte
* @param data.runAfterLt
+* @param data.teams
* @param data.orderBy Attributes to order by, multi criteria sort is
supported. Prefix with `-` for descending order. Supported attributes: `key,
dag_id, run_id, task_id, map_index, timestamp, run_after`
* @returns XComCollectionResponse Successful Response
* @throws ApiError
*/
-export const prefetchUseXcomServiceGetXcomEntries = (queryClient: QueryClient,
{ dagDisplayNamePattern, dagDisplayNamePrefixPattern, dagId, dagRunId, limit,
logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte, mapIndex,
mapIndexFilter, offset, orderBy, runAfterGt, runAfterGte, runAfterLt,
runAfterLte, runIdPattern, runIdPrefixPattern, taskId, taskIdPattern,
taskIdPrefixPattern, xcomKey, xcomKeyPattern, xcomKeyPrefixPattern }: {
+export const prefetchUseXcomServiceGetXcomEntries = (queryClient: QueryClient,
{ dagDisplayNamePattern, dagDisplayNamePrefixPattern, dagId, dagRunId, limit,
logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte, mapIndex,
mapIndexFilter, offset, orderBy, runAfterGt, runAfterGte, runAfterLt,
runAfterLte, runIdPattern, runIdPrefixPattern, taskId, taskIdPattern,
taskIdPrefixPattern, teams, xcomKey, xcomKeyPattern, xcomKeyPrefixPattern }: {
dagDisplayNamePattern?: string;
dagDisplayNamePrefixPattern?: string;
dagId: string;
@@ -1684,10 +1685,11 @@ export const prefetchUseXcomServiceGetXcomEntries =
(queryClient: QueryClient, {
taskId: string;
taskIdPattern?: string;
taskIdPrefixPattern?: string;
+ teams?: string[];
xcomKey?: string;
xcomKeyPattern?: string;
xcomKeyPrefixPattern?: string;
-}) => queryClient.prefetchQuery({ queryKey:
Common.UseXcomServiceGetXcomEntriesKeyFn({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
xcomKey, xcomKeyPattern, xcomKeyPrefixPattern }), queryFn: () =>
XcomService.getXcomEntries({ da [...]
+}) => queryClient.prefetchQuery({ queryKey:
Common.UseXcomServiceGetXcomEntriesKeyFn({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
teams, xcomKey, xcomKeyPattern, xcomKeyPrefixPattern }), queryFn: () =>
XcomService.getXcomEntri [...]
/**
* Get Tasks
* Get tasks for Dag.
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 494f13de344..3ea1aede3b3 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts
@@ -1657,11 +1657,12 @@ export const useXcomServiceGetXcomEntry = <TData =
Common.XcomServiceGetXcomEntr
* @param data.runAfterGt
* @param data.runAfterLte
* @param data.runAfterLt
+* @param data.teams
* @param data.orderBy Attributes to order by, multi criteria sort is
supported. Prefix with `-` for descending order. Supported attributes: `key,
dag_id, run_id, task_id, map_index, timestamp, run_after`
* @returns XComCollectionResponse Successful Response
* @throws ApiError
*/
-export const useXcomServiceGetXcomEntries = <TData =
Common.XcomServiceGetXcomEntriesDefaultResponse, TError = unknown, TQueryKey
extends Array<unknown> = unknown[]>({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
xcomKey, xcomKe [...]
+export const useXcomServiceGetXcomEntries = <TData =
Common.XcomServiceGetXcomEntriesDefaultResponse, TError = unknown, TQueryKey
extends Array<unknown> = unknown[]>({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
teams, xcomKey, [...]
dagDisplayNamePattern?: string;
dagDisplayNamePrefixPattern?: string;
dagId: string;
@@ -1684,10 +1685,11 @@ export const useXcomServiceGetXcomEntries = <TData =
Common.XcomServiceGetXcomEn
taskId: string;
taskIdPattern?: string;
taskIdPrefixPattern?: string;
+ teams?: string[];
xcomKey?: string;
xcomKeyPattern?: string;
xcomKeyPrefixPattern?: string;
-}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>,
"queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey:
Common.UseXcomServiceGetXcomEntriesKeyFn({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
xcom [...]
+}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>,
"queryKey" | "queryFn">) => useQuery<TData, TError>({ queryKey:
Common.UseXcomServiceGetXcomEntriesKeyFn({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
team [...]
/**
* Get Tasks
* Get tasks for Dag.
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 af032fad3f3..d9aa328bcde 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts
@@ -1657,11 +1657,12 @@ export const useXcomServiceGetXcomEntrySuspense =
<TData = Common.XcomServiceGet
* @param data.runAfterGt
* @param data.runAfterLte
* @param data.runAfterLt
+* @param data.teams
* @param data.orderBy Attributes to order by, multi criteria sort is
supported. Prefix with `-` for descending order. Supported attributes: `key,
dag_id, run_id, task_id, map_index, timestamp, run_after`
* @returns XComCollectionResponse Successful Response
* @throws ApiError
*/
-export const useXcomServiceGetXcomEntriesSuspense = <TData =
Common.XcomServiceGetXcomEntriesDefaultResponse, TError = unknown, TQueryKey
extends Array<unknown> = unknown[]>({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
xcomKey [...]
+export const useXcomServiceGetXcomEntriesSuspense = <TData =
Common.XcomServiceGetXcomEntriesDefaultResponse, TError = unknown, TQueryKey
extends Array<unknown> = unknown[]>({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPattern,
teams, [...]
dagDisplayNamePattern?: string;
dagDisplayNamePrefixPattern?: string;
dagId: string;
@@ -1684,10 +1685,11 @@ export const useXcomServiceGetXcomEntriesSuspense =
<TData = Common.XcomServiceG
taskId: string;
taskIdPattern?: string;
taskIdPrefixPattern?: string;
+ teams?: string[];
xcomKey?: string;
xcomKeyPattern?: string;
xcomKeyPrefixPattern?: string;
-}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>,
"queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey:
Common.UseXcomServiceGetXcomEntriesKeyFn({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPatte [...]
+}, queryKey?: TQueryKey, options?: Omit<UseQueryOptions<TData, TError>,
"queryKey" | "queryFn">) => useSuspenseQuery<TData, TError>({ queryKey:
Common.UseXcomServiceGetXcomEntriesKeyFn({ dagDisplayNamePattern,
dagDisplayNamePrefixPattern, dagId, dagRunId, limit, logicalDateGt,
logicalDateGte, logicalDateLt, logicalDateLte, mapIndex, mapIndexFilter,
offset, orderBy, runAfterGt, runAfterGte, runAfterLt, runAfterLte,
runIdPattern, runIdPrefixPattern, taskId, taskIdPattern, taskIdPrefixPatte [...]
/**
* Get Tasks
* Get tasks for Dag.
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
b/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
index 888427fae8e..09e4248333c 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
@@ -8933,6 +8933,17 @@ export const $XComResponse = {
type: 'string',
format: 'date-time',
title: 'Run After'
+ },
+ team_name: {
+ anyOf: [
+ {
+ type: 'string'
+ },
+ {
+ type: 'null'
+ }
+ ],
+ title: 'Team Name'
}
},
type: 'object',
@@ -8993,6 +9004,17 @@ export const $XComResponseNative = {
format: 'date-time',
title: 'Run After'
},
+ team_name: {
+ anyOf: [
+ {
+ type: 'string'
+ },
+ {
+ type: 'null'
+ }
+ ],
+ title: 'Team Name'
+ },
value: {
title: 'Value'
}
@@ -9055,6 +9077,17 @@ export const $XComResponseString = {
format: 'date-time',
title: 'Run After'
},
+ team_name: {
+ anyOf: [
+ {
+ type: 'string'
+ },
+ {
+ type: 'null'
+ }
+ ],
+ title: 'Team Name'
+ },
value: {
anyOf: [
{
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 806b388fb1f..e90b107ca6f 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
@@ -4229,6 +4229,7 @@ export class XcomService {
* @param data.runAfterGt
* @param data.runAfterLte
* @param data.runAfterLt
+ * @param data.teams
* @param data.orderBy Attributes to order by, multi criteria sort is
supported. Prefix with `-` for descending order. Supported attributes: `key,
dag_id, run_id, task_id, map_index, timestamp, run_after`
* @returns XComCollectionResponse Successful Response
* @throws ApiError
@@ -4264,6 +4265,7 @@ export class XcomService {
run_after_gt: data.runAfterGt,
run_after_lte: data.runAfterLte,
run_after_lt: data.runAfterLt,
+ teams: data.teams,
order_by: data.orderBy
},
errors: {
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 be90b462bdb..16810c2219d 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
@@ -2197,6 +2197,7 @@ export type XComResponse = {
dag_display_name: string;
task_display_name: string;
run_after: string;
+ team_name?: string | null;
};
/**
@@ -2213,6 +2214,7 @@ export type XComResponseNative = {
dag_display_name: string;
task_display_name: string;
run_after: string;
+ team_name?: string | null;
value: unknown;
};
@@ -2230,6 +2232,7 @@ export type XComResponseString = {
dag_display_name: string;
task_display_name: string;
run_after: string;
+ team_name?: string | null;
value: string | null;
};
@@ -4549,6 +4552,7 @@ export type GetXcomEntriesData = {
* Case-sensitive, index-friendly prefix match. See "Filtering with
pattern parameters".
*/
taskIdPrefixPattern?: string | null;
+ teams?: Array<(string)>;
xcomKey?: string | null;
/**
* Case-insensitive substring match (SQL `ILIKE`). Slower than
`xcom_key_prefix_pattern` on large tables — see "Filtering with pattern
parameters".
diff --git a/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
b/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
index 24ee69494f0..d1a8812c784 100644
--- a/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
@@ -27,11 +27,13 @@ import { DataTable } from "src/components/DataTable";
import { useTableURLState } from "src/components/DataTable/useTableUrlState";
import { ErrorAlert } from "src/components/ErrorAlert";
import { ExpandCollapseButtons } from "src/components/ExpandCollapseButtons";
+import { TeamName } from "src/components/TeamName";
import Time from "src/components/Time";
import { TruncatedText } from "src/components/TruncatedText";
import { RouterLink } from "src/components/ui";
import { SearchParamsKeys, type SearchParamsKeysType } from
"src/constants/searchParams";
import { useAdvancedSearchArg } from "src/hooks/useAdvancedSearch";
+import { useConfig } from "src/queries/useConfig";
import { useDocumentTitle } from "src/utils";
import { getTaskInstanceLink } from "src/utils/links";
@@ -47,16 +49,19 @@ const {
MAP_INDEX: MAP_INDEX_PARAM,
RUN_ID_PATTERN: RUN_ID_PATTERN_PARAM,
TASK_ID_PATTERN: TASK_ID_PATTERN_PARAM,
+ TEAMS: TEAMS_PARAM,
}: SearchParamsKeysType = SearchParamsKeys;
type ColumnsProps = {
readonly isTaskInstancePage: boolean;
+ readonly multiTeam: boolean;
readonly open: boolean;
readonly translate: (key: string) => string;
};
const getColumns = ({
isTaskInstancePage,
+ multiTeam,
open,
translate,
}: ColumnsProps): Array<ColumnDef<XComResponse>> => [
@@ -76,6 +81,18 @@ const getColumns = ({
),
header: translate("xcom.columns.dag"),
},
+ ...(multiTeam
+ ? [
+ {
+ accessorKey: "team_name",
+ cell: ({ row: { original } }: { row: { original: XComResponse
} }) => (
+ <TeamName teamName={original.team_name} />
+ ),
+ enableSorting: false,
+ header: translate("common:dagDetails.team"),
+ },
+ ]
+ : []),
{
accessorKey: "run_id",
cell: ({ row: { original } }: { row: { original: XComResponse } })
=> (
@@ -151,6 +168,7 @@ const getColumns = ({
export const XCom = () => {
const { dagId = "~", mapIndex = "-1", runId = "~", taskId = "~" } =
useParams();
const { t: translate } = useTranslation(["browse", "common"]);
+ const multiTeamEnabled = Boolean(useConfig("multi_team"));
// Only the standalone list page owns the tab title; the task-instance tab
inherits that page's title.
useDocumentTitle(dagId === "~" ? translate("common:browse.xcoms") :
undefined);
@@ -168,6 +186,7 @@ export const XCom = () => {
const filteredMapIndex = searchParams.get(MAP_INDEX_PARAM);
const filteredRunId = searchParams.get(RUN_ID_PATTERN_PARAM);
const filteredTaskId = searchParams.get(TASK_ID_PATTERN_PARAM);
+ const teams = searchParams.getAll(TEAMS_PARAM);
const { LOGICAL_DATE_GTE, LOGICAL_DATE_LTE, RUN_AFTER_GTE, RUN_AFTER_LTE } =
SearchParamsKeys;
const logicalDateGte = searchParams.get(LOGICAL_DATE_GTE);
@@ -220,6 +239,7 @@ export const XCom = () => {
...runIdArg,
taskId,
...taskIdArg,
+ teams: teams.length > 0 ? teams : undefined,
...xcomKeyArg,
};
@@ -230,6 +250,7 @@ export const XCom = () => {
const columns = getColumns({
isTaskInstancePage,
+ multiTeam: multiTeamEnabled,
open,
translate,
});
diff --git a/airflow-core/src/airflow/ui/src/pages/XCom/XComFilters.tsx
b/airflow-core/src/airflow/ui/src/pages/XCom/XComFilters.tsx
index e666a6930f9..40cc8b1713b 100644
--- a/airflow-core/src/airflow/ui/src/pages/XCom/XComFilters.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/XCom/XComFilters.tsx
@@ -20,10 +20,12 @@ import { useParams } from "react-router-dom";
import { FilterBar } from "src/components/FilterBar";
import { SearchParamsKeys } from "src/constants/searchParams";
+import { useConfig } from "src/queries/useConfig";
import { useFiltersHandler, type FilterableSearchParamsKeys } from "src/utils";
export const XComFilters = () => {
const { dagId = "~", mapIndex = "-1", runId = "~", taskId = "~" } =
useParams();
+ const multiTeamEnabled = Boolean(useConfig("multi_team"));
const searchParamKeys: Array<FilterableSearchParamsKeys> = [
SearchParamsKeys.KEY_PATTERN,
@@ -33,6 +35,10 @@ export const XComFilters = () => {
if (dagId === "~") {
searchParamKeys.push(SearchParamsKeys.DAG_DISPLAY_NAME_PATTERN);
+
+ if (multiTeamEnabled) {
+ searchParamKeys.push(SearchParamsKeys.TEAMS);
+ }
}
if (runId === "~") {
diff --git
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_xcom.py
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_xcom.py
index 64ce784775c..296c7c31104 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_xcom.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_xcom.py
@@ -21,13 +21,16 @@ from typing import TYPE_CHECKING
from unittest import mock
import pytest
+from sqlalchemy import update
from sqlalchemy.orm import Session
from airflow._shared.timezones import timezone
from airflow.api_fastapi.core_api.datamodels.xcom import XComCreateBody
+from airflow.models.dag import DagModel
from airflow.models.dag_version import DagVersion
from airflow.models.dagbundle import DagBundleModel
from airflow.models.dagrun import DagRun
+from airflow.models.team import Team
from airflow.models.xcom import XComModel
from airflow.providers.standard.operators.empty import EmptyOperator
from airflow.sdk import DAG, AssetAlias
@@ -39,7 +42,13 @@ from airflow.utils.types import DagRunType
from tests_common.test_utils.asserts import assert_queries_count
from tests_common.test_utils.config import conf_vars
from tests_common.test_utils.dag import sync_dag_to_db
-from tests_common.test_utils.db import clear_db_dag_bundles, clear_db_dags,
clear_db_runs, clear_db_xcom
+from tests_common.test_utils.db import (
+ clear_db_dag_bundles,
+ clear_db_dags,
+ clear_db_runs,
+ clear_db_teams,
+ clear_db_xcom,
+)
from tests_common.test_utils.logs import check_last_log
from tests_common.test_utils.mock_operators import MockOperator
from tests_common.test_utils.taskinstance import create_task_instance
@@ -101,6 +110,17 @@ def _create_dag_run(dag_maker, *, session: Session =
NEW_SESSION):
session.commit()
+@provide_session
+def _attach_dag_to_team(dag_id: str, team_name: str, *, session: Session =
NEW_SESSION) -> None:
+ """Move a Dag into a team-scoped bundle, which is how a Dag gains a
team."""
+ bundle = DagBundleModel(name=f"team-bundle-{team_name}")
+ bundle.teams.append(Team(name=team_name))
+ session.add(bundle)
+ session.flush()
+ session.execute(update(DagModel).where(DagModel.dag_id ==
dag_id).values(bundle_name=bundle.name))
+ session.commit()
+
+
class CustomXCom(BaseXCom):
@classmethod
def deserialize_value(cls, xcom):
@@ -113,6 +133,7 @@ class TestXComEndpoint:
clear_db_dags()
clear_db_runs()
clear_db_dag_bundles()
+ clear_db_teams()
clear_db_xcom()
@pytest.fixture(autouse=True)
@@ -145,11 +166,23 @@ class TestGetXComEntry(TestXComEndpoint):
"key": TEST_XCOM_KEY,
"task_id": TEST_TASK_ID,
"task_display_name": TEST_TASK_DISPLAY_NAME,
+ "team_name": None,
"map_index": -1,
"timestamp": current_data["timestamp"],
"value": json.dumps(TEST_XCOM_VALUE),
}
+ @conf_vars({("core", "multi_team"): "True"})
+ def test_should_respond_200_with_team_name(self, test_client):
+ self._create_xcom(TEST_XCOM_KEY, TEST_XCOM_VALUE)
+ _attach_dag_to_team(TEST_DAG_ID, "team-xcom-entry")
+
+ response = test_client.get(
+
f"/dags/{TEST_DAG_ID}/dagRuns/{run_id}/taskInstances/{TEST_TASK_ID}/xcomEntries/{TEST_XCOM_KEY}"
+ )
+ assert response.status_code == 200
+ assert response.json()["team_name"] == "team-xcom-entry"
+
def test_should_respond_401(self, unauthenticated_test_client):
response = unauthenticated_test_client.get(
f"/dags/{TEST_DAG_ID}/dagRuns/{run_id}/taskInstances/{TEST_TASK_ID}/xcomEntries/{TEST_XCOM_KEY}"
@@ -259,6 +292,7 @@ class TestGetXComEntries(TestXComEndpoint):
"key": f"{TEST_XCOM_KEY}-0",
"task_id": TEST_TASK_ID,
"task_display_name": TEST_TASK_DISPLAY_NAME,
+ "team_name": None,
"timestamp": "TIMESTAMP",
"map_index": -1,
},
@@ -271,6 +305,7 @@ class TestGetXComEntries(TestXComEndpoint):
"key": f"{TEST_XCOM_KEY}-1",
"task_id": TEST_TASK_ID,
"task_display_name": TEST_TASK_DISPLAY_NAME,
+ "team_name": None,
"timestamp": "TIMESTAMP",
"map_index": -1,
},
@@ -301,6 +336,7 @@ class TestGetXComEntries(TestXComEndpoint):
"key": f"{TEST_XCOM_KEY}-0",
"task_id": TEST_TASK_ID,
"task_display_name": TEST_TASK_DISPLAY_NAME,
+ "team_name": None,
"timestamp": "TIMESTAMP",
"map_index": -1,
},
@@ -313,6 +349,7 @@ class TestGetXComEntries(TestXComEndpoint):
"key": f"{TEST_XCOM_KEY}-1",
"task_id": TEST_TASK_ID,
"task_display_name": TEST_TASK_DISPLAY_NAME,
+ "team_name": None,
"timestamp": "TIMESTAMP",
"map_index": -1,
},
@@ -325,6 +362,7 @@ class TestGetXComEntries(TestXComEndpoint):
"key": f"{TEST_XCOM_KEY}-0",
"task_id": TEST_TASK_ID_2,
"task_display_name": TEST_TASK_DISPLAY_NAME_2,
+ "team_name": None,
"timestamp": "TIMESTAMP",
"map_index": -1,
},
@@ -337,6 +375,7 @@ class TestGetXComEntries(TestXComEndpoint):
"key": f"{TEST_XCOM_KEY}-1",
"task_id": TEST_TASK_ID_2,
"task_display_name": TEST_TASK_DISPLAY_NAME_2,
+ "team_name": None,
"timestamp": "TIMESTAMP",
"map_index": -1,
},
@@ -368,6 +407,7 @@ class TestGetXComEntries(TestXComEndpoint):
"key": TEST_XCOM_KEY,
"task_id": TEST_TASK_ID,
"task_display_name": TEST_TASK_DISPLAY_NAME,
+ "team_name": None,
"timestamp": "TIMESTAMP",
"map_index": idx,
}
@@ -384,6 +424,7 @@ class TestGetXComEntries(TestXComEndpoint):
"key": TEST_XCOM_KEY,
"task_id": TEST_TASK_ID,
"task_display_name": TEST_TASK_DISPLAY_NAME,
+ "team_name": None,
"timestamp": "TIMESTAMP",
"map_index": map_index,
}
@@ -410,6 +451,7 @@ class TestGetXComEntries(TestXComEndpoint):
"key": TEST_XCOM_KEY,
"task_id": TEST_TASK_ID,
"task_display_name": TEST_TASK_DISPLAY_NAME,
+ "team_name": None,
"timestamp": "TIMESTAMP",
"map_index": 0,
},
@@ -422,6 +464,7 @@ class TestGetXComEntries(TestXComEndpoint):
"key": TEST_XCOM_KEY,
"task_id": TEST_TASK_ID,
"task_display_name": TEST_TASK_DISPLAY_NAME,
+ "team_name": None,
"timestamp": "TIMESTAMP",
"map_index": 1,
},
@@ -447,6 +490,40 @@ class TestGetXComEntries(TestXComEndpoint):
"total_entries": len(expected_entries),
}
+ @conf_vars({("core", "multi_team"): "True"})
+ def test_should_respond_200_with_team_name(self, test_client):
+ self._create_xcom_entries(TEST_DAG_ID, run_id, logical_date_parsed,
TEST_TASK_ID)
+ self._create_xcom_entries(TEST_DAG_ID_2, run_id, logical_date_parsed,
TEST_TASK_ID_2)
+ _attach_dag_to_team(TEST_DAG_ID, "team-xcom")
+
+ response =
test_client.get("/dags/~/dagRuns/~/taskInstances/~/xcomEntries")
+
+ assert response.status_code == 200
+ assert {(entry["dag_id"], entry["team_name"]) for entry in
response.json()["xcom_entries"]} == {
+ (TEST_DAG_ID, "team-xcom"),
+ (TEST_DAG_ID_2, None),
+ }
+
+ @conf_vars({("core", "multi_team"): "True"})
+ def test_should_respond_200_filtered_by_team(self, test_client):
+ self._create_xcom_entries(TEST_DAG_ID, run_id, logical_date_parsed,
TEST_TASK_ID)
+ self._create_xcom_entries(TEST_DAG_ID_2, run_id, logical_date_parsed,
TEST_TASK_ID_2)
+ _attach_dag_to_team(TEST_DAG_ID, "team-xcom")
+
+ response = test_client.get(
+ "/dags/~/dagRuns/~/taskInstances/~/xcomEntries", params={"teams":
["team-xcom"]}
+ )
+ assert response.status_code == 200
+ response_data = response.json()
+ assert response_data["total_entries"] == 2
+ assert {entry["dag_id"] for entry in response_data["xcom_entries"]} ==
{TEST_DAG_ID}
+
+ response = test_client.get(
+ "/dags/~/dagRuns/~/taskInstances/~/xcomEntries", params={"teams":
["team-without-dags"]}
+ )
+ assert response.status_code == 200
+ assert response.json()["total_entries"] == 0
+
@provide_session
def _create_xcom_entries(
self, dag_id, run_id, logical_date, task_id, mapped_ti=False, *,
session: Session = NEW_SESSION
@@ -696,6 +773,18 @@ class TestCreateXComEntry(TestXComEndpoint):
assert current_data["map_index"] == request_body.map_index
check_last_log(session, dag_id=TEST_DAG_ID, event="create_xcom_entry",
logical_date=None)
+ @conf_vars({("core", "multi_team"): "True"})
+ def test_create_xcom_entry_with_team_name(self, test_client):
+ _attach_dag_to_team(TEST_DAG_ID, "team-xcom-create")
+
+ response = test_client.post(
+
f"/dags/{TEST_DAG_ID}/dagRuns/{run_id}/taskInstances/{TEST_TASK_ID}/xcomEntries",
+ json=XComCreateBody(key=TEST_XCOM_KEY,
value=TEST_XCOM_VALUE).dict(),
+ )
+
+ assert response.status_code == 201
+ assert response.json()["team_name"] == "team-xcom-create"
+
def test_should_respond_401(self, unauthenticated_test_client):
response = unauthenticated_test_client.post(
"/dags/dag_id/dagRuns/dag_run_id/taskInstances/task_id/xcomEntries",
@@ -893,6 +982,19 @@ class TestPatchXComEntry(TestXComEndpoint):
assert response.json()["detail"] == expected_detail
check_last_log(session, dag_id=TEST_DAG_ID, event="update_xcom_entry",
logical_date=None)
+ @conf_vars({("core", "multi_team"): "True"})
+ def test_patch_xcom_entry_with_team_name(self, test_client):
+ self._create_xcom(TEST_XCOM_KEY, TEST_XCOM_VALUE)
+ _attach_dag_to_team(TEST_DAG_ID, "team-xcom-patch")
+
+ response = test_client.patch(
+
f"/dags/{TEST_DAG_ID}/dagRuns/{run_id}/taskInstances/{TEST_TASK_ID}/xcomEntries/{TEST_XCOM_KEY}",
+ json={"value": "new_value"},
+ )
+
+ assert response.status_code == 200
+ assert response.json()["team_name"] == "team-xcom-patch"
+
def test_should_respond_401(self, unauthenticated_test_client):
response = unauthenticated_test_client.patch(
f"/dags/{TEST_DAG_ID}/dagRuns/run_id/taskInstances/TEST_TASK_ID/xcomEntries/key",
diff --git a/airflow-ctl/src/airflowctl/api/datamodels/generated.py
b/airflow-ctl/src/airflowctl/api/datamodels/generated.py
index f2e0546f264..31e8b386eea 100644
--- a/airflow-ctl/src/airflowctl/api/datamodels/generated.py
+++ b/airflow-ctl/src/airflowctl/api/datamodels/generated.py
@@ -1284,6 +1284,7 @@ class XComResponse(BaseModel):
dag_display_name: Annotated[str, Field(title="Dag Display Name")]
task_display_name: Annotated[str, Field(title="Task Display Name")]
run_after: Annotated[datetime, Field(title="Run After")]
+ team_name: Annotated[str | None, Field(title="Team Name")] = None
class XComResponseNative(BaseModel):
@@ -1301,6 +1302,7 @@ class XComResponseNative(BaseModel):
dag_display_name: Annotated[str, Field(title="Dag Display Name")]
task_display_name: Annotated[str, Field(title="Task Display Name")]
run_after: Annotated[datetime, Field(title="Run After")]
+ team_name: Annotated[str | None, Field(title="Team Name")] = None
value: Annotated[Any, Field(title="Value")]
@@ -1319,6 +1321,7 @@ class XComResponseString(BaseModel):
dag_display_name: Annotated[str, Field(title="Dag Display Name")]
task_display_name: Annotated[str, Field(title="Task Display Name")]
run_after: Annotated[datetime, Field(title="Run After")]
+ team_name: Annotated[str | None, Field(title="Team Name")] = None
value: Annotated[str | None, Field(title="Value")]