From 9dfb1bbab5ee6a050b6dbea6edcd988adaf0319c Mon Sep 17 00:00:00 2001 From: pierrejeambrun Date: Mon, 18 May 2026 11:08:54 +0200 Subject: [PATCH 1/8] Add bulk delete endpoint for Dag Runs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restores feature parity with Airflow 2.x where DagRunModelView exposed collective Delete on the Dag Runs list view. Adds: - PATCH /dags/{dag_id}/dagRuns — bulk endpoint structured like the existing bulk task-instances endpoint. Only ``delete`` is supported in this PR; ``create`` and ``update`` are wired to return 405 in the BulkResponse so future PRs can fill them in without changing the route surface. - BulkDagRunService with deletable-state enforcement (matches the single-run delete: only QUEUED / SUCCESS / FAILED can be deleted), per-Dag authorization caching for the wildcard path /dags/~/dagRuns, and ``action_on_non_existence: fail | skip`` semantics. - Row selection + a Delete bulk action on the runs list page, mirroring how Task Instances does it. Bulk Mark-as and Bulk Clear are intentionally out of scope and will follow in separate PRs. The grid view stays single-select; multi-select on the grid was not available in 2.x either, and the runs list page is the natural target for bulk operations on a filtered set (e.g. state=failed). closes: #52439 --- .../core_api/datamodels/dag_run.py | 7 + .../openapi/v2-rest-api-generated.yaml | 310 +++++++++++++----- .../core_api/routes/public/dag_run.py | 22 +- .../core_api/services/public/dag_run.py | 165 +++++++++- .../airflow/ui/openapi-gen/queries/common.ts | 17 +- .../ui/openapi-gen/queries/ensureQueryData.ts | 26 +- .../ui/openapi-gen/queries/prefetch.ts | 26 +- .../airflow/ui/openapi-gen/queries/queries.ts | 78 +++-- .../ui/openapi-gen/queries/suspense.ts | 26 +- .../ui/openapi-gen/requests/schemas.gen.ts | 154 +++++++++ .../ui/openapi-gen/requests/services.gen.ts | 98 ++++-- .../ui/openapi-gen/requests/types.gen.ts | 142 ++++++-- .../ui/src/pages/BulkDeleteDagRunsButton.tsx | 151 +++++++++ .../src/airflow/ui/src/pages/DagRuns.tsx | 74 ++++- .../ui/src/pages/bulkDagRunsColumns.tsx | 48 +++ .../airflow/ui/src/queries/useBulkDagRuns.ts | 97 ++++++ .../core_api/routes/public/test_dag_run.py | 192 +++++++++++ .../airflowctl/api/datamodels/generated.py | 71 ++++ 18 files changed, 1476 insertions(+), 228 deletions(-) create mode 100644 airflow-core/src/airflow/ui/src/pages/BulkDeleteDagRunsButton.tsx create mode 100644 airflow-core/src/airflow/ui/src/pages/bulkDagRunsColumns.tsx create mode 100644 airflow-core/src/airflow/ui/src/queries/useBulkDagRuns.ts diff --git a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dag_run.py b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dag_run.py index b1e2500203ecb..40c2a2fc0cafc 100644 --- a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dag_run.py +++ b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dag_run.py @@ -50,6 +50,13 @@ class DAGRunPatchBody(StrictBaseModel): note: str | None = Field(None, max_length=1000) +class BulkDAGRunBody(StrictBaseModel): + """Request body for bulk delete operations on Dag Runs.""" + + dag_run_id: str + dag_id: str | None = None + + class DAGRunClearBody(StrictBaseModel): """Dag Run serializer for clear endpoint body.""" 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 00a9c60d85838..5e70a0f2f20f6 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 @@ -2052,67 +2052,13 @@ paths: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' - /api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/upstreamAssetEvents: - get: - tags: - - DagRun - summary: Get Upstream Asset Events - description: If dag run is asset-triggered, return the asset events that triggered - it. - operationId: get_upstream_asset_events - security: - - OAuth2PasswordBearer: [] - - HTTPBearer: [] - parameters: - - name: dag_id - in: path - required: true - schema: - type: string - title: Dag Id - - name: dag_run_id - in: path - required: true - schema: - type: string - title: Dag Run Id - responses: - '200': - description: Successful Response - content: - application/json: - schema: - $ref: '#/components/schemas/AssetEventCollectionResponse' - '401': - content: - application/json: - schema: - $ref: '#/components/schemas/HTTPExceptionResponse' - description: Unauthorized - '403': - content: - application/json: - schema: - $ref: '#/components/schemas/HTTPExceptionResponse' - description: Forbidden - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/HTTPExceptionResponse' - description: Not Found - '422': - description: Validation Error - content: - application/json: - schema: - $ref: '#/components/schemas/HTTPValidationError' - /api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/clear: - post: + /api/v2/dags/{dag_id}/dagRuns: + patch: tags: - DagRun - summary: Clear Dag Run - operationId: clear_dag_run + summary: Bulk Dag Runs + description: Bulk delete Dag Runs. + operationId: bulk_dag_runs security: - OAuth2PasswordBearer: [] - HTTPBearer: [] @@ -2123,28 +2069,19 @@ paths: schema: type: string title: Dag Id - - name: dag_run_id - in: path - required: true - schema: - type: string - title: Dag Run Id requestBody: required: true content: application/json: schema: - $ref: '#/components/schemas/DAGRunClearBody' + $ref: '#/components/schemas/BulkBody_BulkDAGRunBody_' responses: '200': description: Successful Response content: application/json: schema: - anyOf: - - $ref: '#/components/schemas/ClearTaskInstanceCollectionResponse' - - $ref: '#/components/schemas/DAGRunResponse' - title: Response Clear Dag Run + $ref: '#/components/schemas/BulkResponse' '401': content: application/json: @@ -2157,19 +2094,12 @@ paths: schema: $ref: '#/components/schemas/HTTPExceptionResponse' description: Forbidden - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/HTTPExceptionResponse' - description: Not Found '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' - /api/v2/dags/{dag_id}/dagRuns: get: tags: - DagRun @@ -2792,6 +2722,123 @@ paths: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' + /api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/upstreamAssetEvents: + get: + tags: + - DagRun + summary: Get Upstream Asset Events + description: If dag run is asset-triggered, return the asset events that triggered + it. + operationId: get_upstream_asset_events + security: + - OAuth2PasswordBearer: [] + - HTTPBearer: [] + parameters: + - name: dag_id + in: path + required: true + schema: + type: string + title: Dag Id + - name: dag_run_id + in: path + required: true + schema: + type: string + title: Dag Run Id + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/AssetEventCollectionResponse' + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPExceptionResponse' + description: Unauthorized + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPExceptionResponse' + description: Forbidden + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPExceptionResponse' + description: Not Found + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/clear: + post: + tags: + - DagRun + summary: Clear Dag Run + operationId: clear_dag_run + security: + - OAuth2PasswordBearer: [] + - HTTPBearer: [] + parameters: + - name: dag_id + in: path + required: true + schema: + type: string + title: Dag Id + - name: dag_run_id + in: path + required: true + schema: + type: string + title: Dag Run Id + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/DAGRunClearBody' + responses: + '200': + description: Successful Response + content: + application/json: + schema: + anyOf: + - $ref: '#/components/schemas/ClearTaskInstanceCollectionResponse' + - $ref: '#/components/schemas/DAGRunResponse' + title: Response Clear Dag Run + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPExceptionResponse' + description: Unauthorized + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPExceptionResponse' + description: Forbidden + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPExceptionResponse' + description: Not Found + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' /api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/wait: get: tags: @@ -11560,6 +11607,21 @@ components: This structure helps users understand which key actions succeeded and which failed.' + BulkBody_BulkDAGRunBody_: + properties: + actions: + items: + oneOf: + - $ref: '#/components/schemas/BulkCreateAction_BulkDAGRunBody_' + - $ref: '#/components/schemas/BulkUpdateAction_BulkDAGRunBody_' + - $ref: '#/components/schemas/BulkDeleteAction_BulkDAGRunBody_' + type: array + title: Actions + additionalProperties: false + type: object + required: + - actions + title: BulkBody[BulkDAGRunBody] BulkBody_BulkTaskInstanceBody_: properties: actions: @@ -11620,6 +11682,28 @@ components: required: - actions title: BulkBody[VariableBody] + BulkCreateAction_BulkDAGRunBody_: + properties: + action: + type: string + const: create + title: Action + description: The action to be performed on the entities. + entities: + items: + $ref: '#/components/schemas/BulkDAGRunBody' + type: array + title: Entities + description: A list of entities to be created. + action_on_existence: + $ref: '#/components/schemas/BulkActionOnExistence' + default: fail + additionalProperties: false + type: object + required: + - action + - entities + title: BulkCreateAction[BulkDAGRunBody] BulkCreateAction_BulkTaskInstanceBody_: properties: action: @@ -11708,6 +11792,46 @@ components: - action - entities title: BulkCreateAction[VariableBody] + BulkDAGRunBody: + properties: + dag_run_id: + type: string + title: Dag Run Id + dag_id: + anyOf: + - type: string + - type: 'null' + title: Dag Id + additionalProperties: false + type: object + required: + - dag_run_id + title: BulkDAGRunBody + description: Request body for bulk delete operations on Dag Runs. + BulkDeleteAction_BulkDAGRunBody_: + properties: + action: + type: string + const: delete + title: Action + description: The action to be performed on the entities. + entities: + items: + anyOf: + - type: string + - $ref: '#/components/schemas/BulkDAGRunBody' + type: array + title: Entities + description: A list of entity id/key or entity objects to be deleted. + action_on_non_existence: + $ref: '#/components/schemas/BulkActionNotOnExistence' + default: fail + additionalProperties: false + type: object + required: + - action + - entities + title: BulkDeleteAction[BulkDAGRunBody] BulkDeleteAction_BulkTaskInstanceBody_: properties: action: @@ -11889,6 +12013,38 @@ components: - task_id title: BulkTaskInstanceBody description: Request body for bulk update, and delete task instances. + BulkUpdateAction_BulkDAGRunBody_: + properties: + action: + type: string + const: update + title: Action + description: The action to be performed on the entities. + entities: + items: + $ref: '#/components/schemas/BulkDAGRunBody' + type: array + title: Entities + description: A list of entities to be updated. + update_mask: + anyOf: + - items: + type: string + type: array + - type: 'null' + title: Update Mask + description: A list of field names to update for each entity.Only these + fields will be applied from the request body to the database model.Any + extra fields provided will be ignored. + action_on_non_existence: + $ref: '#/components/schemas/BulkActionNotOnExistence' + default: fail + additionalProperties: false + type: object + required: + - action + - entities + title: BulkUpdateAction[BulkDAGRunBody] BulkUpdateAction_BulkTaskInstanceBody_: properties: action: 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 4577a5160892d..c34679654305f 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 @@ -76,7 +76,9 @@ from airflow.api_fastapi.common.types import Mimetype from airflow.api_fastapi.core_api.base import OrmClause from airflow.api_fastapi.core_api.datamodels.assets import AssetEventCollectionResponse +from airflow.api_fastapi.core_api.datamodels.common import BulkBody, BulkResponse from airflow.api_fastapi.core_api.datamodels.dag_run import ( + BulkDAGRunBody, DAGRunClearBody, DAGRunCollectionResponse, DAGRunPatchBody, @@ -97,8 +99,7 @@ requires_access_asset, requires_access_dag, ) -from airflow.api_fastapi.core_api.services.public.common import resolve_run_on_latest_version -from airflow.api_fastapi.core_api.services.public.dag_run import DagRunWaiter +from airflow.api_fastapi.core_api.services.public.dag_run import BulkDagRunService, DagRunWaiter from airflow.api_fastapi.logging.decorators import action_logging from airflow.exceptions import ParamValidationError from airflow.listeners.listener import get_listener_manager @@ -253,6 +254,23 @@ def patch_dag_run( return final_dag_run +@dag_run_router.patch( + "", + dependencies=[ + Depends(requires_access_dag(method="DELETE", access_entity=DagAccessEntity.RUN)), + Depends(action_logging()), + ], +) +def bulk_dag_runs( + request: BulkBody[BulkDAGRunBody], + session: SessionDep, + dag_id: str, + user: GetUserDep, +) -> BulkResponse: + """Bulk delete Dag Runs.""" + return BulkDagRunService(session=session, request=request, dag_id=dag_id, user=user).handle_request() + + @dag_run_router.get( "/{dag_run_id}/upstreamAssetEvents", responses=create_openapi_http_exception_doc( diff --git a/airflow-core/src/airflow/api_fastapi/core_api/services/public/dag_run.py b/airflow-core/src/airflow/api_fastapi/core_api/services/public/dag_run.py index e7d7cb98c939f..04b6f7839d432 100644 --- a/airflow-core/src/airflow/api_fastapi/core_api/services/public/dag_run.py +++ b/airflow-core/src/airflow/api_fastapi/core_api/services/public/dag_run.py @@ -21,11 +21,28 @@ import itertools import json import operator -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Literal import attrs +import structlog +from fastapi import status from sqlalchemy import select +from sqlalchemy.orm import Session +from airflow.api_fastapi.app import get_auth_manager +from airflow.api_fastapi.auth.managers.models.resource_details import DagAccessEntity, DagDetails +from airflow.api_fastapi.core_api.datamodels.common import ( + BulkActionNotOnExistence, + BulkActionResponse, + BulkBody, + BulkCreateAction, + BulkDeleteAction, + BulkUpdateAction, +) +from airflow.api_fastapi.core_api.datamodels.dag_run import BulkDAGRunBody, DAGRunPatchStates +from airflow.api_fastapi.core_api.security import GetUserDep +from airflow.api_fastapi.core_api.services.public.common import BulkService +from airflow.models.dag import DagModel from airflow.models.dagrun import DagRun from airflow.models.xcom import XCOM_RETURN_KEY, XComModel from airflow.utils.session import create_session_async @@ -34,6 +51,8 @@ if TYPE_CHECKING: from collections.abc import AsyncGenerator, Iterator +log = structlog.get_logger(__name__) + @attrs.define class DagRunWaiter: @@ -86,3 +105,147 @@ async def wait(self) -> AsyncGenerator[str, None]: await asyncio.sleep(self.interval) yield await self._serialize_response(dag_run := await self._get_dag_run()) yield "\n" + + +class BulkDagRunService(BulkService[BulkDAGRunBody]): + """Service for handling bulk operations on Dag Runs.""" + + def __init__( + self, + session: Session, + request: BulkBody[BulkDAGRunBody], + dag_id: str, + user: GetUserDep, + ): + super().__init__(session, request) + self.dag_id = dag_id + self.user = user + + def _resolve_dag_id(self, entity: str | BulkDAGRunBody) -> tuple[str, str]: + """Resolve the (dag_id, dag_run_id) pair for an entity, falling back to the path ``dag_id``.""" + if isinstance(entity, str): + return self.dag_id, entity + return entity.dag_id or self.dag_id, entity.dag_run_id + + def _check_dag_authorization( + self, + dag_id: str, + method: Literal["GET", "POST", "PUT", "DELETE"], + action_name: str, + cache: dict[str, bool], + results: BulkActionResponse, + ) -> bool: + """Cache and enforce per-Dag authorization for a bulk action.""" + if dag_id not in cache: + team_name = DagModel.get_team_name(dag_id, session=self.session) + cache[dag_id] = get_auth_manager().is_authorized_dag( + method=method, + access_entity=DagAccessEntity.RUN, + details=DagDetails(id=dag_id, team_name=team_name), + user=self.user, + ) + if not cache[dag_id]: + results.errors.append( + { + "error": f"User is not authorized to {action_name} Dag Runs for DAG '{dag_id}'", + "status_code": status.HTTP_403_FORBIDDEN, + } + ) + return False + return True + + @staticmethod + def _result_key(dag_id: str, dag_run_id: str) -> str: + return f"{dag_id}.{dag_run_id}" + + def _fetch_dag_runs( + self, + keys: set[tuple[str, str]], + ) -> tuple[dict[tuple[str, str], DagRun], set[tuple[str, str]]]: + if not keys: + return {}, set() + dag_ids = {dag_id for dag_id, _ in keys} + run_ids = {run_id for _, run_id in keys} + dag_runs = self.session.scalars( + select(DagRun).where(DagRun.dag_id.in_(dag_ids), DagRun.run_id.in_(run_ids)) + ).all() + dag_run_map = {(dr.dag_id, dr.run_id): dr for dr in dag_runs if (dr.dag_id, dr.run_id) in keys} + not_found = keys - dag_run_map.keys() + return dag_run_map, not_found + + def handle_bulk_create( + self, action: BulkCreateAction[BulkDAGRunBody], results: BulkActionResponse + ) -> None: + results.errors.append( + { + "error": "Dag Runs bulk create is not supported. Use the trigger Dag Run endpoint instead.", + "status_code": status.HTTP_405_METHOD_NOT_ALLOWED, + } + ) + + def handle_bulk_update( + self, action: BulkUpdateAction[BulkDAGRunBody], results: BulkActionResponse + ) -> None: + results.errors.append( + { + "error": "Dag Runs bulk update is not supported yet. Use the patch Dag Run endpoint per run instead.", + "status_code": status.HTTP_405_METHOD_NOT_ALLOWED, + } + ) + + def handle_bulk_delete( + self, action: BulkDeleteAction[BulkDAGRunBody], results: BulkActionResponse + ) -> None: + """Bulk delete Dag Runs.""" + authorization_cache: dict[str, bool] = {} + keys: set[tuple[str, str]] = set() + + for entity in action.entities: + dag_id, dag_run_id = self._resolve_dag_id(entity) + if dag_id == "~": + results.errors.append( + { + "error": ( + "When using wildcard in path, dag_id must be specified " + f"in the request body for dag_run_id: {dag_run_id}" + ), + "status_code": status.HTTP_400_BAD_REQUEST, + } + ) + continue + if not self._check_dag_authorization( + dag_id, method="DELETE", action_name="delete", cache=authorization_cache, results=results + ): + continue + keys.add((dag_id, dag_run_id)) + + if not keys: + return + + dag_run_map, not_found = self._fetch_dag_runs(keys) + + if not_found and action.action_on_non_existence == BulkActionNotOnExistence.FAIL: + not_found_ids = [{"dag_id": dag_id, "dag_run_id": run_id} for dag_id, run_id in sorted(not_found)] + results.errors.append( + { + "error": f"The Dag Runs with these identifiers: {not_found_ids} were not found", + "status_code": status.HTTP_404_NOT_FOUND, + } + ) + return + + deletable_states = {s.value for s in DAGRunPatchStates} + for key, dag_run in dag_run_map.items(): + if dag_run.state not in deletable_states: + results.errors.append( + { + "error": ( + f"The DagRun with dag_id: `{key[0]}` and run_id: `{key[1]}` " + f"cannot be deleted in {dag_run.state} state" + ), + "status_code": status.HTTP_409_CONFLICT, + } + ) + continue + self.session.delete(dag_run) + results.success.append(self._result_key(key[0], key[1])) 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 812a41d9d082f..f8e3dbe9af638 100644 --- a/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts +++ b/airflow-core/src/airflow/ui/openapi-gen/queries/common.ts @@ -138,13 +138,6 @@ export const UseDagRunServiceGetDagRunKeyFn = ({ dagId, dagRunId }: { dagId: string; dagRunId: string; }, queryKey?: Array) => [useDagRunServiceGetDagRunKey, ...(queryKey ?? [{ dagId, dagRunId }])]; -export type DagRunServiceGetUpstreamAssetEventsDefaultResponse = Awaited>; -export type DagRunServiceGetUpstreamAssetEventsQueryResult = UseQueryResult; -export const useDagRunServiceGetUpstreamAssetEventsKey = "DagRunServiceGetUpstreamAssetEvents"; -export const UseDagRunServiceGetUpstreamAssetEventsKeyFn = ({ dagId, dagRunId }: { - dagId: string; - dagRunId: string; -}, queryKey?: Array) => [useDagRunServiceGetUpstreamAssetEventsKey, ...(queryKey ?? [{ dagId, dagRunId }])]; export type DagRunServiceGetDagRunsDefaultResponse = Awaited>; export type DagRunServiceGetDagRunsQueryResult = UseQueryResult; export const useDagRunServiceGetDagRunsKey = "DagRunServiceGetDagRuns"; @@ -193,6 +186,13 @@ export const UseDagRunServiceGetDagRunsKeyFn = ({ bundleVersion, confContains, c updatedAtLt?: string; updatedAtLte?: string; }, queryKey?: Array) => [useDagRunServiceGetDagRunsKey, ...(queryKey ?? [{ bundleVersion, confContains, consumingAssetPattern, cursor, dagId, dagIdPattern, dagIdPrefixPattern, dagVersion, durationGt, durationGte, durationLt, durationLte, endDateGt, endDateGte, endDateLt, endDateLte, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte, offset, orderBy, partitionKeyPattern, partitionKeyPrefixPattern, runAfterGt, runAfterGte, runAfterLt, runAfterLte, runIdPattern, runIdPrefixPattern, runType, startDateGt, startDateGte, startDateLt, startDateLte, state, triggeringUserNamePattern, triggeringUserNamePrefixPattern, updatedAtGt, updatedAtGte, updatedAtLt, updatedAtLte }])]; +export type DagRunServiceGetUpstreamAssetEventsDefaultResponse = Awaited>; +export type DagRunServiceGetUpstreamAssetEventsQueryResult = UseQueryResult; +export const useDagRunServiceGetUpstreamAssetEventsKey = "DagRunServiceGetUpstreamAssetEvents"; +export const UseDagRunServiceGetUpstreamAssetEventsKeyFn = ({ dagId, dagRunId }: { + dagId: string; + dagRunId: string; +}, queryKey?: Array) => [useDagRunServiceGetUpstreamAssetEventsKey, ...(queryKey ?? [{ dagId, dagRunId }])]; export type DagRunServiceWaitDagRunUntilFinishedDefaultResponse = Awaited>; export type DagRunServiceWaitDagRunUntilFinishedQueryResult = UseQueryResult; export const useDagRunServiceWaitDagRunUntilFinishedKey = "DagRunServiceWaitDagRunUntilFinished"; @@ -1034,8 +1034,8 @@ export type BackfillServiceCreateBackfillDryRunMutationResult = Awaited>; export type ConnectionServiceTestConnectionMutationResult = Awaited>; export type ConnectionServiceCreateDefaultConnectionsMutationResult = Awaited>; -export type DagRunServiceClearDagRunMutationResult = Awaited>; export type DagRunServiceTriggerDagRunMutationResult = Awaited>; +export type DagRunServiceClearDagRunMutationResult = Awaited>; export type DagRunServiceGetListDagRunsBatchMutationResult = Awaited>; export type DagServiceFavoriteDagMutationResult = Awaited>; export type DagServiceUnfavoriteDagMutationResult = Awaited>; @@ -1054,6 +1054,7 @@ export type DagParsingServiceReparseDagFileMutationResult = Awaited>; export type ConnectionServiceBulkConnectionsMutationResult = Awaited>; export type DagRunServicePatchDagRunMutationResult = Awaited>; +export type DagRunServiceBulkDagRunsMutationResult = Awaited>; export type DagServicePatchDagsMutationResult = Awaited>; export type DagServicePatchDagMutationResult = Awaited>; export type TaskInstanceServicePatchTaskInstanceMutationResult = Awaited>; 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 32d74fed6e957..f124d321a1f88 100644 --- a/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts +++ b/airflow-core/src/airflow/ui/openapi-gen/queries/ensureQueryData.ts @@ -264,19 +264,6 @@ export const ensureUseDagRunServiceGetDagRunData = (queryClient: QueryClient, { dagRunId: string; }) => queryClient.ensureQueryData({ queryKey: Common.UseDagRunServiceGetDagRunKeyFn({ dagId, dagRunId }), queryFn: () => DagRunService.getDagRun({ dagId, dagRunId }) }); /** -* Get Upstream Asset Events -* If dag run is asset-triggered, return the asset events that triggered it. -* @param data The data for the request. -* @param data.dagId -* @param data.dagRunId -* @returns AssetEventCollectionResponse Successful Response -* @throws ApiError -*/ -export const ensureUseDagRunServiceGetUpstreamAssetEventsData = (queryClient: QueryClient, { dagId, dagRunId }: { - dagId: string; - dagRunId: string; -}) => queryClient.ensureQueryData({ queryKey: Common.UseDagRunServiceGetUpstreamAssetEventsKeyFn({ dagId, dagRunId }), queryFn: () => DagRunService.getUpstreamAssetEvents({ dagId, dagRunId }) }); -/** * Get Dag Runs * Get all Dag Runs. * @@ -391,6 +378,19 @@ export const ensureUseDagRunServiceGetDagRunsData = (queryClient: QueryClient, { updatedAtLte?: string; }) => queryClient.ensureQueryData({ queryKey: Common.UseDagRunServiceGetDagRunsKeyFn({ bundleVersion, confContains, consumingAssetPattern, cursor, dagId, dagIdPattern, dagIdPrefixPattern, dagVersion, durationGt, durationGte, durationLt, durationLte, endDateGt, endDateGte, endDateLt, endDateLte, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte, offset, orderBy, partitionKeyPattern, partitionKeyPrefixPattern, runAfterGt, runAfterGte, runAfterLt, runAfterLte, runIdPattern, runIdPrefixPattern, runType, startDateGt, startDateGte, startDateLt, startDateLte, state, triggeringUserNamePattern, triggeringUserNamePrefixPattern, updatedAtGt, updatedAtGte, updatedAtLt, updatedAtLte }), queryFn: () => DagRunService.getDagRuns({ bundleVersion, confContains, consumingAssetPattern, cursor, dagId, dagIdPattern, dagIdPrefixPattern, dagVersion, durationGt, durationGte, durationLt, durationLte, endDateGt, endDateGte, endDateLt, endDateLte, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte, offset, orderBy, partitionKeyPattern, partitionKeyPrefixPattern, runAfterGt, runAfterGte, runAfterLt, runAfterLte, runIdPattern, runIdPrefixPattern, runType, startDateGt, startDateGte, startDateLt, startDateLte, state, triggeringUserNamePattern, triggeringUserNamePrefixPattern, updatedAtGt, updatedAtGte, updatedAtLt, updatedAtLte }) }); /** +* Get Upstream Asset Events +* If dag run is asset-triggered, return the asset events that triggered it. +* @param data The data for the request. +* @param data.dagId +* @param data.dagRunId +* @returns AssetEventCollectionResponse Successful Response +* @throws ApiError +*/ +export const ensureUseDagRunServiceGetUpstreamAssetEventsData = (queryClient: QueryClient, { dagId, dagRunId }: { + dagId: string; + dagRunId: string; +}) => queryClient.ensureQueryData({ queryKey: Common.UseDagRunServiceGetUpstreamAssetEventsKeyFn({ dagId, dagRunId }), queryFn: () => DagRunService.getUpstreamAssetEvents({ dagId, dagRunId }) }); +/** * Experimental: Wait for a dag run to complete, and return task results if requested. * 🚧 This is an experimental endpoint and may change or be removed without notice.Successful response are streamed as newline-delimited JSON (NDJSON). Each line is a JSON object representing the Dag run state. * @param data The data for the request. 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 ae01253916044..5bdcfe667b228 100644 --- a/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts +++ b/airflow-core/src/airflow/ui/openapi-gen/queries/prefetch.ts @@ -264,19 +264,6 @@ export const prefetchUseDagRunServiceGetDagRun = (queryClient: QueryClient, { da dagRunId: string; }) => queryClient.prefetchQuery({ queryKey: Common.UseDagRunServiceGetDagRunKeyFn({ dagId, dagRunId }), queryFn: () => DagRunService.getDagRun({ dagId, dagRunId }) }); /** -* Get Upstream Asset Events -* If dag run is asset-triggered, return the asset events that triggered it. -* @param data The data for the request. -* @param data.dagId -* @param data.dagRunId -* @returns AssetEventCollectionResponse Successful Response -* @throws ApiError -*/ -export const prefetchUseDagRunServiceGetUpstreamAssetEvents = (queryClient: QueryClient, { dagId, dagRunId }: { - dagId: string; - dagRunId: string; -}) => queryClient.prefetchQuery({ queryKey: Common.UseDagRunServiceGetUpstreamAssetEventsKeyFn({ dagId, dagRunId }), queryFn: () => DagRunService.getUpstreamAssetEvents({ dagId, dagRunId }) }); -/** * Get Dag Runs * Get all Dag Runs. * @@ -391,6 +378,19 @@ export const prefetchUseDagRunServiceGetDagRuns = (queryClient: QueryClient, { b updatedAtLte?: string; }) => queryClient.prefetchQuery({ queryKey: Common.UseDagRunServiceGetDagRunsKeyFn({ bundleVersion, confContains, consumingAssetPattern, cursor, dagId, dagIdPattern, dagIdPrefixPattern, dagVersion, durationGt, durationGte, durationLt, durationLte, endDateGt, endDateGte, endDateLt, endDateLte, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte, offset, orderBy, partitionKeyPattern, partitionKeyPrefixPattern, runAfterGt, runAfterGte, runAfterLt, runAfterLte, runIdPattern, runIdPrefixPattern, runType, startDateGt, startDateGte, startDateLt, startDateLte, state, triggeringUserNamePattern, triggeringUserNamePrefixPattern, updatedAtGt, updatedAtGte, updatedAtLt, updatedAtLte }), queryFn: () => DagRunService.getDagRuns({ bundleVersion, confContains, consumingAssetPattern, cursor, dagId, dagIdPattern, dagIdPrefixPattern, dagVersion, durationGt, durationGte, durationLt, durationLte, endDateGt, endDateGte, endDateLt, endDateLte, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte, offset, orderBy, partitionKeyPattern, partitionKeyPrefixPattern, runAfterGt, runAfterGte, runAfterLt, runAfterLte, runIdPattern, runIdPrefixPattern, runType, startDateGt, startDateGte, startDateLt, startDateLte, state, triggeringUserNamePattern, triggeringUserNamePrefixPattern, updatedAtGt, updatedAtGte, updatedAtLt, updatedAtLte }) }); /** +* Get Upstream Asset Events +* If dag run is asset-triggered, return the asset events that triggered it. +* @param data The data for the request. +* @param data.dagId +* @param data.dagRunId +* @returns AssetEventCollectionResponse Successful Response +* @throws ApiError +*/ +export const prefetchUseDagRunServiceGetUpstreamAssetEvents = (queryClient: QueryClient, { dagId, dagRunId }: { + dagId: string; + dagRunId: string; +}) => queryClient.prefetchQuery({ queryKey: Common.UseDagRunServiceGetUpstreamAssetEventsKeyFn({ dagId, dagRunId }), queryFn: () => DagRunService.getUpstreamAssetEvents({ dagId, dagRunId }) }); +/** * Experimental: Wait for a dag run to complete, and return task results if requested. * 🚧 This is an experimental endpoint and may change or be removed without notice.Successful response are streamed as newline-delimited JSON (NDJSON). Each line is a JSON object representing the Dag run state. * @param data The data for the request. 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 17ee1009ae01f..3cc173fea0b3b 100644 --- a/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts +++ b/airflow-core/src/airflow/ui/openapi-gen/queries/queries.ts @@ -1,8 +1,8 @@ // generated with @7nohe/openapi-react-query-codegen@1.6.2 import { UseMutationOptions, UseQueryOptions, useMutation, useQuery } from "@tanstack/react-query"; -import { AssetService, AssetStateService, AuthLinksService, BackfillService, CalendarService, ConfigService, ConnectionService, DagParsingService, DagRunService, DagService, DagSourceService, DagStatsService, DagVersionService, DagWarningService, DashboardService, DeadlinesService, DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, GanttService, GridService, ImportErrorService, JobService, LoginService, MonitorService, PartitionedDagRunService, PluginService, PoolService, ProviderService, StructureService, TaskInstanceService, TaskService, TaskStateService, TeamsService, VariableService, VersionService, XcomService } from "../requests/services.gen"; -import { AssetStateBody, BackfillPostBody, BulkBody_BulkTaskInstanceBody_, BulkBody_ConnectionBody_, BulkBody_PoolBody_, BulkBody_VariableBody_, ClearTaskInstancesBody, ConnectionBody, CreateAssetEventsBody, DAGPatchBody, DAGRunClearBody, DAGRunPatchBody, DAGRunsBatchBody, DagRunState, DagWarningType, GenerateTokenBody, MaterializeAssetBody, PatchTaskInstanceBody, PoolBody, PoolPatchBody, TaskInstancesBatchBody, TaskStateBody, TriggerDAGRunPostBody, UpdateHITLDetailPayload, VariableBody, XComCreateBody, XComUpdateBody } from "../requests/types.gen"; +import { AssetService, AuthLinksService, BackfillService, CalendarService, ConfigService, ConnectionService, DagParsingService, DagRunService, DagService, DagSourceService, DagStatsService, DagVersionService, DagWarningService, DashboardService, DeadlinesService, DependenciesService, EventLogService, ExperimentalService, ExtraLinksService, GanttService, GridService, ImportErrorService, JobService, LoginService, MonitorService, PartitionedDagRunService, PluginService, PoolService, ProviderService, StructureService, TaskInstanceService, TaskService, TeamsService, VariableService, VersionService, XcomService } from "../requests/services.gen"; +import { BackfillPostBody, BulkBody_BulkDAGRunBody_, BulkBody_BulkTaskInstanceBody_, BulkBody_ConnectionBody_, BulkBody_PoolBody_, BulkBody_VariableBody_, ClearTaskInstancesBody, ConnectionBody, CreateAssetEventsBody, DAGPatchBody, DAGRunClearBody, DAGRunPatchBody, DAGRunsBatchBody, DagRunState, DagWarningType, GenerateTokenBody, MaterializeAssetBody, PatchTaskInstanceBody, PoolBody, PoolPatchBody, TaskInstancesBatchBody, TriggerDAGRunPostBody, UpdateHITLDetailPayload, VariableBody, XComCreateBody, XComUpdateBody } from "../requests/types.gen"; import * as Common from "./common"; /** * Get Assets @@ -264,19 +264,6 @@ export const useDagRunServiceGetDagRun = , "queryKey" | "queryFn">) => useQuery({ queryKey: Common.UseDagRunServiceGetDagRunKeyFn({ dagId, dagRunId }, queryKey), queryFn: () => DagRunService.getDagRun({ dagId, dagRunId }) as TData, ...options }); /** -* Get Upstream Asset Events -* If dag run is asset-triggered, return the asset events that triggered it. -* @param data The data for the request. -* @param data.dagId -* @param data.dagRunId -* @returns AssetEventCollectionResponse Successful Response -* @throws ApiError -*/ -export const useDagRunServiceGetUpstreamAssetEvents = = unknown[]>({ dagId, dagRunId }: { - dagId: string; - dagRunId: string; -}, queryKey?: TQueryKey, options?: Omit, "queryKey" | "queryFn">) => useQuery({ queryKey: Common.UseDagRunServiceGetUpstreamAssetEventsKeyFn({ dagId, dagRunId }, queryKey), queryFn: () => DagRunService.getUpstreamAssetEvents({ dagId, dagRunId }) as TData, ...options }); -/** * Get Dag Runs * Get all Dag Runs. * @@ -391,6 +378,19 @@ export const useDagRunServiceGetDagRuns = , "queryKey" | "queryFn">) => useQuery({ queryKey: Common.UseDagRunServiceGetDagRunsKeyFn({ bundleVersion, confContains, consumingAssetPattern, cursor, dagId, dagIdPattern, dagIdPrefixPattern, dagVersion, durationGt, durationGte, durationLt, durationLte, endDateGt, endDateGte, endDateLt, endDateLte, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte, offset, orderBy, partitionKeyPattern, partitionKeyPrefixPattern, runAfterGt, runAfterGte, runAfterLt, runAfterLte, runIdPattern, runIdPrefixPattern, runType, startDateGt, startDateGte, startDateLt, startDateLte, state, triggeringUserNamePattern, triggeringUserNamePrefixPattern, updatedAtGt, updatedAtGte, updatedAtLt, updatedAtLte }, queryKey), queryFn: () => DagRunService.getDagRuns({ bundleVersion, confContains, consumingAssetPattern, cursor, dagId, dagIdPattern, dagIdPrefixPattern, dagVersion, durationGt, durationGte, durationLt, durationLte, endDateGt, endDateGte, endDateLt, endDateLte, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte, offset, orderBy, partitionKeyPattern, partitionKeyPrefixPattern, runAfterGt, runAfterGte, runAfterLt, runAfterLte, runIdPattern, runIdPrefixPattern, runType, startDateGt, startDateGte, startDateLt, startDateLte, state, triggeringUserNamePattern, triggeringUserNamePrefixPattern, updatedAtGt, updatedAtGte, updatedAtLt, updatedAtLte }) as TData, ...options }); /** +* Get Upstream Asset Events +* If dag run is asset-triggered, return the asset events that triggered it. +* @param data The data for the request. +* @param data.dagId +* @param data.dagRunId +* @returns AssetEventCollectionResponse Successful Response +* @throws ApiError +*/ +export const useDagRunServiceGetUpstreamAssetEvents = = unknown[]>({ dagId, dagRunId }: { + dagId: string; + dagRunId: string; +}, queryKey?: TQueryKey, options?: Omit, "queryKey" | "queryFn">) => useQuery({ queryKey: Common.UseDagRunServiceGetUpstreamAssetEventsKeyFn({ dagId, dagRunId }, queryKey), queryFn: () => DagRunService.getUpstreamAssetEvents({ dagId, dagRunId }) as TData, ...options }); +/** * Experimental: Wait for a dag run to complete, and return task results if requested. * 🚧 This is an experimental endpoint and may change or be removed without notice.Successful response are streamed as newline-delimited JSON (NDJSON). Each line is a JSON object representing the Dag run state. * @param data The data for the request. @@ -2160,6 +2160,22 @@ export const useConnectionServiceTestConnection = (options?: Omit, "mutationFn">) => useMutation({ mutationFn: () => ConnectionService.createDefaultConnections() as unknown as Promise, ...options }); /** +* Trigger Dag Run +* Trigger a Dag. +* @param data The data for the request. +* @param data.dagId +* @param data.requestBody +* @returns DAGRunResponse Successful Response +* @throws ApiError +*/ +export const useDagRunServiceTriggerDagRun = (options?: Omit, "mutationFn">) => useMutation({ mutationFn: ({ dagId, requestBody }) => DagRunService.triggerDagRun({ dagId, requestBody }) as unknown as Promise, ...options }); +/** * Clear Dag Run * @param data The data for the request. * @param data.dagId @@ -2178,22 +2194,6 @@ export const useDagRunServiceClearDagRun = ({ mutationFn: ({ dagId, dagRunId, requestBody }) => DagRunService.clearDagRun({ dagId, dagRunId, requestBody }) as unknown as Promise, ...options }); /** -* Trigger Dag Run -* Trigger a Dag. -* @param data The data for the request. -* @param data.dagId -* @param data.requestBody -* @returns DAGRunResponse Successful Response -* @throws ApiError -*/ -export const useDagRunServiceTriggerDagRun = (options?: Omit, "mutationFn">) => useMutation({ mutationFn: ({ dagId, requestBody }) => DagRunService.triggerDagRun({ dagId, requestBody }) as unknown as Promise, ...options }); -/** * Get List Dag Runs Batch * Get a list of Dag Runs. * @param data The data for the request. @@ -2482,6 +2482,22 @@ export const useDagRunServicePatchDagRun = ({ mutationFn: ({ dagId, dagRunId, requestBody, updateMask }) => DagRunService.patchDagRun({ dagId, dagRunId, requestBody, updateMask }) as unknown as Promise, ...options }); /** +* Bulk Dag Runs +* Bulk delete Dag Runs. +* @param data The data for the request. +* @param data.dagId +* @param data.requestBody +* @returns BulkResponse Successful Response +* @throws ApiError +*/ +export const useDagRunServiceBulkDagRuns = (options?: Omit, "mutationFn">) => useMutation({ mutationFn: ({ dagId, requestBody }) => DagRunService.bulkDagRuns({ dagId, requestBody }) as unknown as Promise, ...options }); +/** * Patch Dags * Patch multiple Dags. * 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 8cdfee041b63a..e11772395f0f6 100644 --- a/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts +++ b/airflow-core/src/airflow/ui/openapi-gen/queries/suspense.ts @@ -264,19 +264,6 @@ export const useDagRunServiceGetDagRunSuspense = , "queryKey" | "queryFn">) => useSuspenseQuery({ queryKey: Common.UseDagRunServiceGetDagRunKeyFn({ dagId, dagRunId }, queryKey), queryFn: () => DagRunService.getDagRun({ dagId, dagRunId }) as TData, ...options }); /** -* Get Upstream Asset Events -* If dag run is asset-triggered, return the asset events that triggered it. -* @param data The data for the request. -* @param data.dagId -* @param data.dagRunId -* @returns AssetEventCollectionResponse Successful Response -* @throws ApiError -*/ -export const useDagRunServiceGetUpstreamAssetEventsSuspense = = unknown[]>({ dagId, dagRunId }: { - dagId: string; - dagRunId: string; -}, queryKey?: TQueryKey, options?: Omit, "queryKey" | "queryFn">) => useSuspenseQuery({ queryKey: Common.UseDagRunServiceGetUpstreamAssetEventsKeyFn({ dagId, dagRunId }, queryKey), queryFn: () => DagRunService.getUpstreamAssetEvents({ dagId, dagRunId }) as TData, ...options }); -/** * Get Dag Runs * Get all Dag Runs. * @@ -391,6 +378,19 @@ export const useDagRunServiceGetDagRunsSuspense = , "queryKey" | "queryFn">) => useSuspenseQuery({ queryKey: Common.UseDagRunServiceGetDagRunsKeyFn({ bundleVersion, confContains, consumingAssetPattern, cursor, dagId, dagIdPattern, dagIdPrefixPattern, dagVersion, durationGt, durationGte, durationLt, durationLte, endDateGt, endDateGte, endDateLt, endDateLte, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte, offset, orderBy, partitionKeyPattern, partitionKeyPrefixPattern, runAfterGt, runAfterGte, runAfterLt, runAfterLte, runIdPattern, runIdPrefixPattern, runType, startDateGt, startDateGte, startDateLt, startDateLte, state, triggeringUserNamePattern, triggeringUserNamePrefixPattern, updatedAtGt, updatedAtGte, updatedAtLt, updatedAtLte }, queryKey), queryFn: () => DagRunService.getDagRuns({ bundleVersion, confContains, consumingAssetPattern, cursor, dagId, dagIdPattern, dagIdPrefixPattern, dagVersion, durationGt, durationGte, durationLt, durationLte, endDateGt, endDateGte, endDateLt, endDateLte, limit, logicalDateGt, logicalDateGte, logicalDateLt, logicalDateLte, offset, orderBy, partitionKeyPattern, partitionKeyPrefixPattern, runAfterGt, runAfterGte, runAfterLt, runAfterLte, runIdPattern, runIdPrefixPattern, runType, startDateGt, startDateGte, startDateLt, startDateLte, state, triggeringUserNamePattern, triggeringUserNamePrefixPattern, updatedAtGt, updatedAtGte, updatedAtLt, updatedAtLte }) as TData, ...options }); /** +* Get Upstream Asset Events +* If dag run is asset-triggered, return the asset events that triggered it. +* @param data The data for the request. +* @param data.dagId +* @param data.dagRunId +* @returns AssetEventCollectionResponse Successful Response +* @throws ApiError +*/ +export const useDagRunServiceGetUpstreamAssetEventsSuspense = = unknown[]>({ dagId, dagRunId }: { + dagId: string; + dagRunId: string; +}, queryKey?: TQueryKey, options?: Omit, "queryKey" | "queryFn">) => useSuspenseQuery({ queryKey: Common.UseDagRunServiceGetUpstreamAssetEventsKeyFn({ dagId, dagRunId }, queryKey), queryFn: () => DagRunService.getUpstreamAssetEvents({ dagId, dagRunId }) as TData, ...options }); +/** * Experimental: Wait for a dag run to complete, and return task results if requested. * 🚧 This is an experimental endpoint and may change or be removed without notice.Successful response are streamed as newline-delimited JSON (NDJSON). Each line is a JSON object representing the Dag run state. * @param data The data for the request. 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 108480b3dd175..cb92ec5750c71 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 @@ -684,6 +684,32 @@ The response includes a list of successful keys and any errors encountered durin This structure helps users understand which key actions succeeded and which failed.` } as const; +export const $BulkBody_BulkDAGRunBody_ = { + properties: { + actions: { + items: { + oneOf: [ + { + '$ref': '#/components/schemas/BulkCreateAction_BulkDAGRunBody_' + }, + { + '$ref': '#/components/schemas/BulkUpdateAction_BulkDAGRunBody_' + }, + { + '$ref': '#/components/schemas/BulkDeleteAction_BulkDAGRunBody_' + } + ] + }, + type: 'array', + title: 'Actions' + } + }, + additionalProperties: false, + type: 'object', + required: ['actions'], + title: 'BulkBody[BulkDAGRunBody]' +} as const; + export const $BulkBody_BulkTaskInstanceBody_ = { properties: { actions: { @@ -788,6 +814,33 @@ export const $BulkBody_VariableBody_ = { title: 'BulkBody[VariableBody]' } as const; +export const $BulkCreateAction_BulkDAGRunBody_ = { + properties: { + action: { + type: 'string', + const: 'create', + title: 'Action', + description: 'The action to be performed on the entities.' + }, + entities: { + items: { + '$ref': '#/components/schemas/BulkDAGRunBody' + }, + type: 'array', + title: 'Entities', + description: 'A list of entities to be created.' + }, + action_on_existence: { + '$ref': '#/components/schemas/BulkActionOnExistence', + default: 'fail' + } + }, + additionalProperties: false, + type: 'object', + required: ['action', 'entities'], + title: 'BulkCreateAction[BulkDAGRunBody]' +} as const; + export const $BulkCreateAction_BulkTaskInstanceBody_ = { properties: { action: { @@ -896,6 +949,65 @@ export const $BulkCreateAction_VariableBody_ = { title: 'BulkCreateAction[VariableBody]' } as const; +export const $BulkDAGRunBody = { + properties: { + dag_run_id: { + type: 'string', + title: 'Dag Run Id' + }, + dag_id: { + anyOf: [ + { + type: 'string' + }, + { + type: 'null' + } + ], + title: 'Dag Id' + } + }, + additionalProperties: false, + type: 'object', + required: ['dag_run_id'], + title: 'BulkDAGRunBody', + description: 'Request body for bulk delete operations on Dag Runs.' +} as const; + +export const $BulkDeleteAction_BulkDAGRunBody_ = { + properties: { + action: { + type: 'string', + const: 'delete', + title: 'Action', + description: 'The action to be performed on the entities.' + }, + entities: { + items: { + anyOf: [ + { + type: 'string' + }, + { + '$ref': '#/components/schemas/BulkDAGRunBody' + } + ] + }, + type: 'array', + title: 'Entities', + description: 'A list of entity id/key or entity objects to be deleted.' + }, + action_on_non_existence: { + '$ref': '#/components/schemas/BulkActionNotOnExistence', + default: 'fail' + } + }, + additionalProperties: false, + type: 'object', + required: ['action', 'entities'], + title: 'BulkDeleteAction[BulkDAGRunBody]' +} as const; + export const $BulkDeleteAction_BulkTaskInstanceBody_ = { properties: { action: { @@ -1166,6 +1278,48 @@ export const $BulkTaskInstanceBody = { description: 'Request body for bulk update, and delete task instances.' } as const; +export const $BulkUpdateAction_BulkDAGRunBody_ = { + properties: { + action: { + type: 'string', + const: 'update', + title: 'Action', + description: 'The action to be performed on the entities.' + }, + entities: { + items: { + '$ref': '#/components/schemas/BulkDAGRunBody' + }, + type: 'array', + title: 'Entities', + description: 'A list of entities to be updated.' + }, + update_mask: { + anyOf: [ + { + items: { + type: 'string' + }, + type: 'array' + }, + { + type: 'null' + } + ], + title: 'Update Mask', + description: 'A list of field names to update for each entity.Only these fields will be applied from the request body to the database model.Any extra fields provided will be ignored.' + }, + action_on_non_existence: { + '$ref': '#/components/schemas/BulkActionNotOnExistence', + default: 'fail' + } + }, + additionalProperties: false, + type: 'object', + required: ['action', 'entities'], + title: 'BulkUpdateAction[BulkDAGRunBody]' +} as const; + export const $BulkUpdateAction_BulkTaskInstanceBody_ = { properties: { action: { 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 bc1f44714703c..c5278876f8ea4 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 @@ -3,7 +3,7 @@ import type { CancelablePromise } from './core/CancelablePromise'; import { OpenAPI } from './core/OpenAPI'; import { request as __request } from './core/request'; -import type { GetAssetsData, GetAssetsResponse, GetAssetAliasesData, GetAssetAliasesResponse, GetAssetAliasData, GetAssetAliasResponse, GetAssetEventsData, GetAssetEventsResponse, CreateAssetEventData, CreateAssetEventResponse, MaterializeAssetData, MaterializeAssetResponse, GetAssetQueuedEventsData, GetAssetQueuedEventsResponse, DeleteAssetQueuedEventsData, DeleteAssetQueuedEventsResponse, GetAssetData, GetAssetResponse, GetDagAssetQueuedEventsData, GetDagAssetQueuedEventsResponse, DeleteDagAssetQueuedEventsData, DeleteDagAssetQueuedEventsResponse, GetDagAssetQueuedEventData, GetDagAssetQueuedEventResponse, DeleteDagAssetQueuedEventData, DeleteDagAssetQueuedEventResponse, NextRunAssetsData, NextRunAssetsResponse, ListBackfillsData, ListBackfillsResponse, CreateBackfillData, CreateBackfillResponse, GetBackfillData, GetBackfillResponse, PauseBackfillData, PauseBackfillResponse, UnpauseBackfillData, UnpauseBackfillResponse, CancelBackfillData, CancelBackfillResponse, CreateBackfillDryRunData, CreateBackfillDryRunResponse, ListBackfillsUiData, ListBackfillsUiResponse, DeleteConnectionData, DeleteConnectionResponse, GetConnectionData, GetConnectionResponse, PatchConnectionData, PatchConnectionResponse, GetConnectionsData, GetConnectionsResponse, PostConnectionData, PostConnectionResponse, BulkConnectionsData, BulkConnectionsResponse, TestConnectionData, TestConnectionResponse, CreateDefaultConnectionsResponse, HookMetaDataResponse, GetDagRunData, GetDagRunResponse, DeleteDagRunData, DeleteDagRunResponse, PatchDagRunData, PatchDagRunResponse, GetUpstreamAssetEventsData, GetUpstreamAssetEventsResponse, ClearDagRunData, ClearDagRunResponse, GetDagRunsData, GetDagRunsResponse, TriggerDagRunData, TriggerDagRunResponse, WaitDagRunUntilFinishedData, WaitDagRunUntilFinishedResponse, GetListDagRunsBatchData, GetListDagRunsBatchResponse, GetDagRunStatsData, GetDagRunStatsResponse, GetDagSourceData, GetDagSourceResponse, GetDagStatsData, GetDagStatsResponse, GetConfigData, GetConfigResponse, GetConfigValueData, GetConfigValueResponse, GetConfigsResponse, ListDagWarningsData, ListDagWarningsResponse, GetDagsData, GetDagsResponse, PatchDagsData, PatchDagsResponse, GetDagData, GetDagResponse, PatchDagData, PatchDagResponse, DeleteDagData, DeleteDagResponse, GetDagDetailsData, GetDagDetailsResponse, FavoriteDagData, FavoriteDagResponse, UnfavoriteDagData, UnfavoriteDagResponse, GetDagTagsData, GetDagTagsResponse, GetDagsUiData, GetDagsUiResponse, GetLatestRunInfoData, GetLatestRunInfoResponse, GetEventLogData, GetEventLogResponse, GetEventLogsData, GetEventLogsResponse, GetExtraLinksData, GetExtraLinksResponse, GetTaskInstanceData, GetTaskInstanceResponse, PatchTaskInstanceData, PatchTaskInstanceResponse, DeleteTaskInstanceData, DeleteTaskInstanceResponse, GetMappedTaskInstancesData, GetMappedTaskInstancesResponse, GetTaskInstanceDependenciesByMapIndexData, GetTaskInstanceDependenciesByMapIndexResponse, GetTaskInstanceDependenciesData, GetTaskInstanceDependenciesResponse, GetTaskInstanceTriesData, GetTaskInstanceTriesResponse, GetMappedTaskInstanceTriesData, GetMappedTaskInstanceTriesResponse, GetMappedTaskInstanceData, GetMappedTaskInstanceResponse, PatchTaskInstanceByMapIndexData, PatchTaskInstanceByMapIndexResponse, GetTaskInstancesData, GetTaskInstancesResponse, BulkTaskInstancesData, BulkTaskInstancesResponse, GetTaskInstancesBatchData, GetTaskInstancesBatchResponse, GetTaskInstanceTryDetailsData, GetTaskInstanceTryDetailsResponse, GetMappedTaskInstanceTryDetailsData, GetMappedTaskInstanceTryDetailsResponse, PostClearTaskInstancesData, PostClearTaskInstancesResponse, PatchTaskGroupInstancesData, PatchTaskGroupInstancesResponse, PatchTaskGroupInstancesDryRunData, PatchTaskGroupInstancesDryRunResponse, PatchTaskInstanceDryRunByMapIndexData, PatchTaskInstanceDryRunByMapIndexResponse, PatchTaskInstanceDryRunData, PatchTaskInstanceDryRunResponse, GetLogData, GetLogResponse, GetExternalLogUrlData, GetExternalLogUrlResponse, UpdateHitlDetailData, UpdateHitlDetailResponse, GetHitlDetailData, GetHitlDetailResponse, GetHitlDetailTryDetailData, GetHitlDetailTryDetailResponse, GetHitlDetailsData, GetHitlDetailsResponse, GetImportErrorData, GetImportErrorResponse, GetImportErrorsData, GetImportErrorsResponse, GetJobsData, GetJobsResponse, GetPluginsData, GetPluginsResponse, ImportErrorsResponse, DeletePoolData, DeletePoolResponse, GetPoolData, GetPoolResponse, PatchPoolData, PatchPoolResponse, GetPoolsData, GetPoolsResponse, PostPoolData, PostPoolResponse, BulkPoolsData, BulkPoolsResponse, GetProvidersData, GetProvidersResponse, ListAssetStatesData, ListAssetStatesResponse, ClearAssetStateData, ClearAssetStateResponse, GetAssetStateData, GetAssetStateResponse, SetAssetStateData, SetAssetStateResponse, DeleteAssetStateData, DeleteAssetStateResponse, ListTaskStatesData, ListTaskStatesResponse, ClearTaskStateData, ClearTaskStateResponse, GetTaskStateData, GetTaskStateResponse, SetTaskStateData, SetTaskStateResponse, DeleteTaskStateData, DeleteTaskStateResponse, GetXcomEntryData, GetXcomEntryResponse, UpdateXcomEntryData, UpdateXcomEntryResponse, DeleteXcomEntryData, DeleteXcomEntryResponse, GetXcomEntriesData, GetXcomEntriesResponse, CreateXcomEntryData, CreateXcomEntryResponse, GetTasksData, GetTasksResponse, GetTaskData, GetTaskResponse, DeleteVariableData, DeleteVariableResponse, GetVariableData, GetVariableResponse, PatchVariableData, PatchVariableResponse, GetVariablesData, GetVariablesResponse, PostVariableData, PostVariableResponse, BulkVariablesData, BulkVariablesResponse, ReparseDagFileData, ReparseDagFileResponse, GetDagVersionData, GetDagVersionResponse, GetDagVersionsData, GetDagVersionsResponse, GetHealthResponse, GetVersionResponse, LoginData, LoginResponse, LogoutResponse, GetAuthMenusResponse, GetCurrentUserInfoResponse, GenerateTokenData, GenerateTokenResponse2, GetPartitionedDagRunsData, GetPartitionedDagRunsResponse, GetPendingPartitionedDagRunData, GetPendingPartitionedDagRunResponse, GetDependenciesData, GetDependenciesResponse, HistoricalMetricsData, HistoricalMetricsResponse, DagStatsResponse2, GetDeadlinesData, GetDeadlinesResponse, GetDagDeadlineAlertsData, GetDagDeadlineAlertsResponse, StructureDataData, StructureDataResponse2, GetDagStructureData, GetDagStructureResponse, GetGridRunsData, GetGridRunsResponse, GetGridTiSummariesStreamData, GetGridTiSummariesStreamResponse, GetGanttDataData, GetGanttDataResponse, GetCalendarData, GetCalendarResponse, ListTeamsData, ListTeamsResponse } from './types.gen'; +import type { GetAssetsData, GetAssetsResponse, GetAssetAliasesData, GetAssetAliasesResponse, GetAssetAliasData, GetAssetAliasResponse, GetAssetEventsData, GetAssetEventsResponse, CreateAssetEventData, CreateAssetEventResponse, MaterializeAssetData, MaterializeAssetResponse, GetAssetQueuedEventsData, GetAssetQueuedEventsResponse, DeleteAssetQueuedEventsData, DeleteAssetQueuedEventsResponse, GetAssetData, GetAssetResponse, GetDagAssetQueuedEventsData, GetDagAssetQueuedEventsResponse, DeleteDagAssetQueuedEventsData, DeleteDagAssetQueuedEventsResponse, GetDagAssetQueuedEventData, GetDagAssetQueuedEventResponse, DeleteDagAssetQueuedEventData, DeleteDagAssetQueuedEventResponse, NextRunAssetsData, NextRunAssetsResponse, ListBackfillsData, ListBackfillsResponse, CreateBackfillData, CreateBackfillResponse, GetBackfillData, GetBackfillResponse, PauseBackfillData, PauseBackfillResponse, UnpauseBackfillData, UnpauseBackfillResponse, CancelBackfillData, CancelBackfillResponse, CreateBackfillDryRunData, CreateBackfillDryRunResponse, ListBackfillsUiData, ListBackfillsUiResponse, DeleteConnectionData, DeleteConnectionResponse, GetConnectionData, GetConnectionResponse, PatchConnectionData, PatchConnectionResponse, GetConnectionsData, GetConnectionsResponse, PostConnectionData, PostConnectionResponse, BulkConnectionsData, BulkConnectionsResponse, TestConnectionData, TestConnectionResponse, CreateDefaultConnectionsResponse, HookMetaDataResponse, GetDagRunData, GetDagRunResponse, DeleteDagRunData, DeleteDagRunResponse, PatchDagRunData, PatchDagRunResponse, BulkDagRunsData, BulkDagRunsResponse, GetDagRunsData, GetDagRunsResponse, TriggerDagRunData, TriggerDagRunResponse, GetUpstreamAssetEventsData, GetUpstreamAssetEventsResponse, ClearDagRunData, ClearDagRunResponse, WaitDagRunUntilFinishedData, WaitDagRunUntilFinishedResponse, GetListDagRunsBatchData, GetListDagRunsBatchResponse, GetDagRunStatsData, GetDagRunStatsResponse, GetDagSourceData, GetDagSourceResponse, GetDagStatsData, GetDagStatsResponse, GetConfigData, GetConfigResponse, GetConfigValueData, GetConfigValueResponse, GetConfigsResponse, ListDagWarningsData, ListDagWarningsResponse, GetDagsData, GetDagsResponse, PatchDagsData, PatchDagsResponse, GetDagData, GetDagResponse, PatchDagData, PatchDagResponse, DeleteDagData, DeleteDagResponse, GetDagDetailsData, GetDagDetailsResponse, FavoriteDagData, FavoriteDagResponse, UnfavoriteDagData, UnfavoriteDagResponse, GetDagTagsData, GetDagTagsResponse, GetDagsUiData, GetDagsUiResponse, GetLatestRunInfoData, GetLatestRunInfoResponse, GetEventLogData, GetEventLogResponse, GetEventLogsData, GetEventLogsResponse, GetExtraLinksData, GetExtraLinksResponse, GetTaskInstanceData, GetTaskInstanceResponse, PatchTaskInstanceData, PatchTaskInstanceResponse, DeleteTaskInstanceData, DeleteTaskInstanceResponse, GetMappedTaskInstancesData, GetMappedTaskInstancesResponse, GetTaskInstanceDependenciesByMapIndexData, GetTaskInstanceDependenciesByMapIndexResponse, GetTaskInstanceDependenciesData, GetTaskInstanceDependenciesResponse, GetTaskInstanceTriesData, GetTaskInstanceTriesResponse, GetMappedTaskInstanceTriesData, GetMappedTaskInstanceTriesResponse, GetMappedTaskInstanceData, GetMappedTaskInstanceResponse, PatchTaskInstanceByMapIndexData, PatchTaskInstanceByMapIndexResponse, GetTaskInstancesData, GetTaskInstancesResponse, BulkTaskInstancesData, BulkTaskInstancesResponse, GetTaskInstancesBatchData, GetTaskInstancesBatchResponse, GetTaskInstanceTryDetailsData, GetTaskInstanceTryDetailsResponse, GetMappedTaskInstanceTryDetailsData, GetMappedTaskInstanceTryDetailsResponse, PostClearTaskInstancesData, PostClearTaskInstancesResponse, PatchTaskGroupInstancesData, PatchTaskGroupInstancesResponse, PatchTaskGroupInstancesDryRunData, PatchTaskGroupInstancesDryRunResponse, PatchTaskInstanceDryRunByMapIndexData, PatchTaskInstanceDryRunByMapIndexResponse, PatchTaskInstanceDryRunData, PatchTaskInstanceDryRunResponse, GetLogData, GetLogResponse, GetExternalLogUrlData, GetExternalLogUrlResponse, UpdateHitlDetailData, UpdateHitlDetailResponse, GetHitlDetailData, GetHitlDetailResponse, GetHitlDetailTryDetailData, GetHitlDetailTryDetailResponse, GetHitlDetailsData, GetHitlDetailsResponse, GetImportErrorData, GetImportErrorResponse, GetImportErrorsData, GetImportErrorsResponse, GetJobsData, GetJobsResponse, GetPluginsData, GetPluginsResponse, ImportErrorsResponse, DeletePoolData, DeletePoolResponse, GetPoolData, GetPoolResponse, PatchPoolData, PatchPoolResponse, GetPoolsData, GetPoolsResponse, PostPoolData, PostPoolResponse, BulkPoolsData, BulkPoolsResponse, GetProvidersData, GetProvidersResponse, GetXcomEntryData, GetXcomEntryResponse, UpdateXcomEntryData, UpdateXcomEntryResponse, DeleteXcomEntryData, DeleteXcomEntryResponse, GetXcomEntriesData, GetXcomEntriesResponse, CreateXcomEntryData, CreateXcomEntryResponse, GetTasksData, GetTasksResponse, GetTaskData, GetTaskResponse, DeleteVariableData, DeleteVariableResponse, GetVariableData, GetVariableResponse, PatchVariableData, PatchVariableResponse, GetVariablesData, GetVariablesResponse, PostVariableData, PostVariableResponse, BulkVariablesData, BulkVariablesResponse, ReparseDagFileData, ReparseDagFileResponse, GetDagVersionData, GetDagVersionResponse, GetDagVersionsData, GetDagVersionsResponse, GetHealthResponse, GetVersionResponse, LoginData, LoginResponse, LogoutResponse, GetAuthMenusResponse, GetCurrentUserInfoResponse, GenerateTokenData, GenerateTokenResponse2, GetPartitionedDagRunsData, GetPartitionedDagRunsResponse, GetPendingPartitionedDagRunData, GetPendingPartitionedDagRunResponse, GetDependenciesData, GetDependenciesResponse, HistoricalMetricsData, HistoricalMetricsResponse, DagStatsResponse2, GetDeadlinesData, GetDeadlinesResponse, GetDagDeadlineAlertsData, GetDagDeadlineAlertsResponse, StructureDataData, StructureDataResponse2, GetDagStructureData, GetDagStructureResponse, GetGridRunsData, GetGridRunsResponse, GetGridTiSummariesStreamData, GetGridTiSummariesStreamResponse, GetGanttDataData, GetGanttDataResponse, GetCalendarData, GetCalendarResponse, ListTeamsData, ListTeamsResponse } from './types.gen'; export class AssetService { /** @@ -937,54 +937,26 @@ export class DagRunService { } /** - * Get Upstream Asset Events - * If dag run is asset-triggered, return the asset events that triggered it. + * Bulk Dag Runs + * Bulk delete Dag Runs. * @param data The data for the request. * @param data.dagId - * @param data.dagRunId - * @returns AssetEventCollectionResponse Successful Response - * @throws ApiError - */ - public static getUpstreamAssetEvents(data: GetUpstreamAssetEventsData): CancelablePromise { - return __request(OpenAPI, { - method: 'GET', - url: '/api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/upstreamAssetEvents', - path: { - dag_id: data.dagId, - dag_run_id: data.dagRunId - }, - errors: { - 401: 'Unauthorized', - 403: 'Forbidden', - 404: 'Not Found', - 422: 'Validation Error' - } - }); - } - - /** - * Clear Dag Run - * @param data The data for the request. - * @param data.dagId - * @param data.dagRunId * @param data.requestBody - * @returns unknown Successful Response + * @returns BulkResponse Successful Response * @throws ApiError */ - public static clearDagRun(data: ClearDagRunData): CancelablePromise { + public static bulkDagRuns(data: BulkDagRunsData): CancelablePromise { return __request(OpenAPI, { - method: 'POST', - url: '/api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/clear', + method: 'PATCH', + url: '/api/v2/dags/{dag_id}/dagRuns', path: { - dag_id: data.dagId, - dag_run_id: data.dagRunId + dag_id: data.dagId }, body: data.requestBody, mediaType: 'application/json', errors: { 401: 'Unauthorized', 403: 'Forbidden', - 404: 'Not Found', 422: 'Validation Error' } }); @@ -1148,6 +1120,60 @@ export class DagRunService { }); } + /** + * Get Upstream Asset Events + * If dag run is asset-triggered, return the asset events that triggered it. + * @param data The data for the request. + * @param data.dagId + * @param data.dagRunId + * @returns AssetEventCollectionResponse Successful Response + * @throws ApiError + */ + public static getUpstreamAssetEvents(data: GetUpstreamAssetEventsData): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/upstreamAssetEvents', + path: { + dag_id: data.dagId, + dag_run_id: data.dagRunId + }, + errors: { + 401: 'Unauthorized', + 403: 'Forbidden', + 404: 'Not Found', + 422: 'Validation Error' + } + }); + } + + /** + * Clear Dag Run + * @param data The data for the request. + * @param data.dagId + * @param data.dagRunId + * @param data.requestBody + * @returns unknown Successful Response + * @throws ApiError + */ + public static clearDagRun(data: ClearDagRunData): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/clear', + path: { + dag_id: data.dagId, + dag_run_id: data.dagRunId + }, + body: data.requestBody, + mediaType: 'application/json', + errors: { + 401: 'Unauthorized', + 403: 'Forbidden', + 404: 'Not Found', + 422: 'Validation Error' + } + }); + } + /** * Experimental: Wait for a dag run to complete, and return task results if requested. * 🚧 This is an experimental endpoint and may change or be removed without notice.Successful response are streamed as newline-delimited JSON (NDJSON). Each line is a JSON object representing the Dag run state. 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 1ea5961b91921..6ec1a8b4b6eb6 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 @@ -213,6 +213,10 @@ export type BulkActionResponse = { }>; }; +export type BulkBody_BulkDAGRunBody_ = { + actions: Array<(BulkCreateAction_BulkDAGRunBody_ | BulkUpdateAction_BulkDAGRunBody_ | BulkDeleteAction_BulkDAGRunBody_)>; +}; + export type BulkBody_BulkTaskInstanceBody_ = { actions: Array<(BulkCreateAction_BulkTaskInstanceBody_ | BulkUpdateAction_BulkTaskInstanceBody_ | BulkDeleteAction_BulkTaskInstanceBody_)>; }; @@ -229,6 +233,18 @@ export type BulkBody_VariableBody_ = { actions: Array<(BulkCreateAction_VariableBody_ | BulkUpdateAction_VariableBody_ | BulkDeleteAction_VariableBody_)>; }; +export type BulkCreateAction_BulkDAGRunBody_ = { + /** + * The action to be performed on the entities. + */ + action: "create"; + /** + * A list of entities to be created. + */ + entities: Array; + action_on_existence?: BulkActionOnExistence; +}; + export type BulkCreateAction_BulkTaskInstanceBody_ = { /** * The action to be performed on the entities. @@ -277,6 +293,26 @@ export type BulkCreateAction_VariableBody_ = { action_on_existence?: BulkActionOnExistence; }; +/** + * Request body for bulk delete operations on Dag Runs. + */ +export type BulkDAGRunBody = { + dag_run_id: string; + dag_id?: string | null; +}; + +export type BulkDeleteAction_BulkDAGRunBody_ = { + /** + * The action to be performed on the entities. + */ + action: "delete"; + /** + * A list of entity id/key or entity objects to be deleted. + */ + entities: Array<(string | BulkDAGRunBody)>; + action_on_non_existence?: BulkActionNotOnExistence; +}; + export type BulkDeleteAction_BulkTaskInstanceBody_ = { /** * The action to be performed on the entities. @@ -363,6 +399,22 @@ export type BulkTaskInstanceBody = { dag_run_id?: string | null; }; +export type BulkUpdateAction_BulkDAGRunBody_ = { + /** + * The action to be performed on the entities. + */ + action: "update"; + /** + * A list of entities to be updated. + */ + entities: Array; + /** + * A list of field names to update for each entity.Only these fields will be applied from the request body to the database model.Any extra fields provided will be ignored. + */ + update_mask?: Array<(string)> | null; + action_on_non_existence?: BulkActionNotOnExistence; +}; + export type BulkUpdateAction_BulkTaskInstanceBody_ = { /** * The action to be performed on the entities. @@ -2746,20 +2798,12 @@ export type PatchDagRunData = { export type PatchDagRunResponse = DAGRunResponse; -export type GetUpstreamAssetEventsData = { - dagId: string; - dagRunId: string; -}; - -export type GetUpstreamAssetEventsResponse = AssetEventCollectionResponse; - -export type ClearDagRunData = { +export type BulkDagRunsData = { dagId: string; - dagRunId: string; - requestBody: DAGRunClearBody; + requestBody: BulkBody_BulkDAGRunBody_; }; -export type ClearDagRunResponse = ClearTaskInstanceCollectionResponse | DAGRunResponse; +export type BulkDagRunsResponse = BulkResponse; export type GetDagRunsData = { bundleVersion?: string | null; @@ -2857,6 +2901,21 @@ export type TriggerDagRunData = { export type TriggerDagRunResponse = DAGRunResponse; +export type GetUpstreamAssetEventsData = { + dagId: string; + dagRunId: string; +}; + +export type GetUpstreamAssetEventsResponse = AssetEventCollectionResponse; + +export type ClearDagRunData = { + dagId: string; + dagRunId: string; + requestBody: DAGRunClearBody; +}; + +export type ClearDagRunResponse = ClearTaskInstanceCollectionResponse | DAGRunResponse; + export type WaitDagRunUntilFinishedData = { dagId: string; dagRunId: string; @@ -5201,14 +5260,35 @@ export type $OpenApiTs = { }; }; }; - '/api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/upstreamAssetEvents': { + '/api/v2/dags/{dag_id}/dagRuns': { + patch: { + req: BulkDagRunsData; + res: { + /** + * Successful Response + */ + 200: BulkResponse; + /** + * Unauthorized + */ + 401: HTTPExceptionResponse; + /** + * Forbidden + */ + 403: HTTPExceptionResponse; + /** + * Validation Error + */ + 422: HTTPValidationError; + }; + }; get: { - req: GetUpstreamAssetEventsData; + req: GetDagRunsData; res: { /** * Successful Response */ - 200: AssetEventCollectionResponse; + 200: DAGRunCollectionResponse; /** * Unauthorized */ @@ -5227,15 +5307,17 @@ export type $OpenApiTs = { 422: HTTPValidationError; }; }; - }; - '/api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/clear': { post: { - req: ClearDagRunData; + req: TriggerDagRunData; res: { /** * Successful Response */ - 200: ClearTaskInstanceCollectionResponse | DAGRunResponse; + 200: DAGRunResponse; + /** + * Bad Request + */ + 400: HTTPExceptionResponse; /** * Unauthorized */ @@ -5248,6 +5330,10 @@ export type $OpenApiTs = { * Not Found */ 404: HTTPExceptionResponse; + /** + * Conflict + */ + 409: HTTPExceptionResponse; /** * Validation Error */ @@ -5255,14 +5341,14 @@ export type $OpenApiTs = { }; }; }; - '/api/v2/dags/{dag_id}/dagRuns': { + '/api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/upstreamAssetEvents': { get: { - req: GetDagRunsData; + req: GetUpstreamAssetEventsData; res: { /** * Successful Response */ - 200: DAGRunCollectionResponse; + 200: AssetEventCollectionResponse; /** * Unauthorized */ @@ -5281,17 +5367,15 @@ export type $OpenApiTs = { 422: HTTPValidationError; }; }; + }; + '/api/v2/dags/{dag_id}/dagRuns/{dag_run_id}/clear': { post: { - req: TriggerDagRunData; + req: ClearDagRunData; res: { /** * Successful Response */ - 200: DAGRunResponse; - /** - * Bad Request - */ - 400: HTTPExceptionResponse; + 200: ClearTaskInstanceCollectionResponse | DAGRunResponse; /** * Unauthorized */ @@ -5304,10 +5388,6 @@ export type $OpenApiTs = { * Not Found */ 404: HTTPExceptionResponse; - /** - * Conflict - */ - 409: HTTPExceptionResponse; /** * Validation Error */ diff --git a/airflow-core/src/airflow/ui/src/pages/BulkDeleteDagRunsButton.tsx b/airflow-core/src/airflow/ui/src/pages/BulkDeleteDagRunsButton.tsx new file mode 100644 index 0000000000000..5553f394f5345 --- /dev/null +++ b/airflow-core/src/airflow/ui/src/pages/BulkDeleteDagRunsButton.tsx @@ -0,0 +1,151 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { Box, Button, Flex, Heading, Text, useDisclosure, VStack } from "@chakra-ui/react"; +import { useTranslation } from "react-i18next"; +import { FiTrash2 } from "react-icons/fi"; + +import type { DAGRunResponse } from "openapi/requests/types.gen"; +import { DataTable } from "src/components/DataTable"; +import { ErrorAlert } from "src/components/ErrorAlert"; +import { Accordion, Dialog } from "src/components/ui"; +import { useBulkDagRuns } from "src/queries/useBulkDagRuns"; + +import { getBulkDagRunsColumns } from "./bulkDagRunsColumns"; + +type Props = { + readonly clearSelections: VoidFunction; + readonly selectedDagRuns: Array; +}; + +const BulkDeleteDagRunsButton = ({ clearSelections, selectedDagRuns }: Props) => { + const { t: translate } = useTranslation(["common", "dags"]); + const { onClose, onOpen, open } = useDisclosure(); + const { bulkAction, error, isPending } = useBulkDagRuns({ + clearSelections, + onSuccessConfirm: onClose, + }); + + const columns = getBulkDagRunsColumns(translate); + + const byDagId = new Map>(); + + for (const dagRun of selectedDagRuns) { + const group = byDagId.get(dagRun.dag_id) ?? []; + + group.push(dagRun); + byDagId.set(dagRun.dag_id, group); + } + + const isGrouped = byDagId.size > 1; + + return ( + <> + + + + + + + + {translate("dags:runAndTaskActions.delete.dialog.title", { + type: translate("dagRun_other"), + })} + + + + + + + + {translate("dags:runAndTaskActions.delete.dialog.warning", { + type: translate("dagRun_other"), + })} + + + + {isGrouped ? ( + + {[...byDagId.entries()].map(([dagId, dagRuns]) => ( + + + + {translate("dagId")}: {dagId}{" "} + + ({dagRuns.length}) + + + + + + + + ))} + + ) : ( + + )} + + + + + + + + + + + ); +}; + +export default BulkDeleteDagRunsButton; diff --git a/airflow-core/src/airflow/ui/src/pages/DagRuns.tsx b/airflow-core/src/airflow/ui/src/pages/DagRuns.tsx index bc1aa2f3d14b9..11a489dd6007a 100644 --- a/airflow-core/src/airflow/ui/src/pages/DagRuns.tsx +++ b/airflow-core/src/airflow/ui/src/pages/DagRuns.tsx @@ -27,6 +27,7 @@ import type { DAGRunResponse } from "openapi/requests/types.gen"; import { ClearRunButton } from "src/components/Clear"; import { DagVersion } from "src/components/DagVersion"; import { DataTable } from "src/components/DataTable"; +import { useRowSelection, type GetColumnsParams } from "src/components/DataTable/useRowSelection"; import { useTableURLState } from "src/components/DataTable/useTableUrlState"; import { ErrorAlert } from "src/components/ErrorAlert"; import { LimitedItemsList } from "src/components/LimitedItemsList"; @@ -37,12 +38,17 @@ import { StateBadge } from "src/components/StateBadge"; import Time from "src/components/Time"; import { TruncatedText } from "src/components/TruncatedText"; import { RouterLink } from "src/components/ui"; +import { ActionBar } from "src/components/ui/ActionBar"; +import { Checkbox } from "src/components/ui/Checkbox"; import { SearchParamsKeys, type SearchParamsKeysType } from "src/constants/searchParams"; import { useAdvancedSearchArg } from "src/hooks/useAdvancedSearch"; +import BulkDeleteDagRunsButton from "src/pages/BulkDeleteDagRunsButton"; import { DagRunsFilters } from "src/pages/DagRunsFilters"; import DeleteRunButton from "src/pages/DeleteRunButton"; import { renderDuration, useAutoRefresh, isStatePending } from "src/utils"; +const getRowKey = (dagRun: DAGRunResponse) => `${dagRun.dag_id}:${dagRun.dag_run_id}`; + type DagRunRow = { row: { original: DAGRunResponse } }; const { BUNDLE_VERSION: BUNDLE_VERSION_PARAM, @@ -67,7 +73,43 @@ const { TRIGGERING_USER_NAME_PATTERN: TRIGGERING_USER_NAME_PATTERN_PARAM, }: SearchParamsKeysType = SearchParamsKeys; -const runColumns = (translate: TFunction, dagId?: string): Array> => [ +type ColumnProps = { + readonly dagId?: string; + readonly translate: TFunction; +} & GetColumnsParams; + +const runColumns = ({ + allRowsSelected, + dagId, + onRowSelect, + onSelectAll, + selectedRows, + translate, +}: ColumnProps): Array> => [ + { + accessorKey: "select", + cell: ({ row }) => ( + onRowSelect(getRowKey(row.original), Boolean(event.checked))} + /> + ), + enableHiding: false, + enableSorting: false, + header: () => ( + onSelectAll(Boolean(event.checked))} + /> + ), + meta: { + skeletonWidth: 10, + }, + }, ...(Boolean(dagId) ? [] : [ @@ -287,11 +329,27 @@ export const DagRuns = () => { }, ); - const columns = runColumns(translate, dagId); - const nextCursor = data?.next_cursor ?? undefined; const previousCursor = data?.previous_cursor ?? undefined; + const { allRowsSelected, clearSelections, handleRowSelect, handleSelectAll, selectedRows } = + useRowSelection({ + data: data?.dag_runs, + getKey: getRowKey, + }); + + const selectedDagRuns = (data?.dag_runs ?? []).filter((dagRun) => selectedRows.has(getRowKey(dagRun))); + + const columns = runColumns({ + allRowsSelected, + dagId, + multiTeam: false, + onRowSelect: handleRowSelect, + onSelectAll: handleSelectAll, + selectedRows, + translate, + }); + return ( <> @@ -306,6 +364,16 @@ export const DagRuns = () => { onStateChange={setTableURLState} previousCursor={previousCursor} /> + + + + {selectedRows.size} {translate("selected")} + + + + + + ); }; diff --git a/airflow-core/src/airflow/ui/src/pages/bulkDagRunsColumns.tsx b/airflow-core/src/airflow/ui/src/pages/bulkDagRunsColumns.tsx new file mode 100644 index 0000000000000..0937e2a81178b --- /dev/null +++ b/airflow-core/src/airflow/ui/src/pages/bulkDagRunsColumns.tsx @@ -0,0 +1,48 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { Text } from "@chakra-ui/react"; +import type { ColumnDef } from "@tanstack/react-table"; +import type { TFunction } from "i18next"; + +import type { DAGRunResponse } from "openapi/requests/types.gen"; +import { StateBadge } from "src/components/StateBadge"; +import Time from "src/components/Time"; + +export const getBulkDagRunsColumns = (translate: TFunction): Array> => [ + { + accessorKey: "dag_run_id", + cell: ({ row: { original } }) => {original.dag_run_id}, + enableSorting: false, + header: translate("dagRunId"), + }, + { + accessorKey: "state", + cell: ({ row: { original } }) => ( + {translate(`common:states.${original.state}`)} + ), + enableSorting: false, + header: translate("state"), + }, + { + accessorKey: "run_after", + cell: ({ row: { original } }) =>