From 2b16eb35ddd8a945d980440f5ac6534d1a321079 Mon Sep 17 00:00:00 2001 From: pierrejeambrun Date: Thu, 28 May 2026 12:20:24 +0200 Subject: [PATCH 1/2] Apply note in one shot when clearing a Dag Run / task instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both the single-run and bulk Clear dialogs used to issue two requests: first ``POST .../clear`` to clear the run / task instances, then a follow-up ``PATCH .../dagRuns/{run_id}`` or ``PATCH .../taskInstances/...`` to set the note typed in the dialog. That race-prone double-call goes away here. ``ClearTaskInstancesBody`` already carries a ``note`` field that the clear endpoint applies via ``_patch_task_instance_note`` in the same transaction. This commit ports the same convention to ``DAGRunClearBody`` — adding ``note: str | None`` and applying it to the cleared Dag Run in ``clear_dag_run`` after the clear succeeds. Semantics match the bulk-update / patch convention: ``note=None`` (the default) leaves the existing note untouched; any string value (including ``""``) replaces it. Dry-run never writes. UI changes: ``ClearRunDialog``, ``ClearTaskInstanceDialog`` and ``useBulkClearDagRuns`` now pass ``note`` directly in the clear body when it changed and drop their secondary ``patchDagRun`` / ``patchTaskInstance`` mutations. Bulk clear of task instances already followed this pattern and is unchanged. --- .../core_api/datamodels/dag_run.py | 7 ++++ .../openapi/v2-rest-api-generated.yaml | 9 +++++ .../core_api/routes/public/dag_run.py | 9 +++++ .../ui/openapi-gen/requests/schemas.gen.ts | 13 +++++++ .../ui/openapi-gen/requests/types.gen.ts | 4 +++ .../components/Clear/Run/ClearRunDialog.tsx | 17 ++-------- .../TaskInstance/ClearTaskInstanceDialog.tsx | 27 ++++----------- .../ui/src/queries/useBulkClearDagRuns.ts | 23 ++----------- .../core_api/routes/public/test_dag_run.py | 34 +++++++++++++++++++ .../airflowctl/api/datamodels/generated.py | 26 ++++++++++++-- 10 files changed, 112 insertions(+), 57 deletions(-) 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 97b37fdaae5ea..f2659414b1e8e 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 @@ -73,6 +73,13 @@ class DAGRunClearBody(StrictBaseModel): "then the ``[core] rerun_with_latest_version`` config option, " "and finally ``False`` (the historical default for clear/rerun).", ) + note: str | None = Field( + default=None, + max_length=1000, + description="Optional note to attach to the Dag Run as part of the clear. " + "``None`` (the default) leaves the existing note untouched; any string value " + '(including ``""``) replaces it.', + ) @model_validator(mode="before") @classmethod 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 618356a1ce793..57b505f3df0c2 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 @@ -13021,6 +13021,15 @@ components: after clearing the Dag Run. If not specified, falls back to the DAG-level ``rerun_with_latest_version`` parameter, then the ``[core] rerun_with_latest_version`` config option, and finally ``False`` (the historical default for clear/rerun). + note: + anyOf: + - type: string + maxLength: 1000 + - type: 'null' + title: Note + description: Optional note to attach to the Dag Run as part of the clear. + ``None`` (the default) leaves the existing note untouched; any string + value (including ``""``) replaces it. additionalProperties: false type: object title: DAGRunClearBody 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 a5c76550be559..e7907b522d6bd 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 @@ -319,6 +319,7 @@ def clear_dag_run( body: DAGRunClearBody, dag_bag: DagBagDep, session: SessionDep, + user: GetUserDep, ) -> ClearTaskInstanceCollectionResponse | DAGRunResponse: dag_run = session.scalar( select(DagRun).filter_by(dag_id=dag_id, run_id=dag_run_id).options(joinedload(DagRun.dag_model)) @@ -388,6 +389,14 @@ def clear_dag_run( dag_run_cleared = session.scalar(select(DagRun).where(DagRun.id == dag_run.id)) if not dag_run_cleared: raise HTTPException(status.HTTP_404_NOT_FOUND, "Dag run not found after clearing") + # ``note=None`` means "leave existing note untouched"; any string (including ``""``) + # replaces it. Mirrors the convention used by ``ClearTaskInstancesBody``. + if body.note is not None: + if dag_run_cleared.dag_run_note is None: + dag_run_cleared.note = (body.note, user.get_id()) + else: + dag_run_cleared.dag_run_note.content = body.note + dag_run_cleared.dag_run_note.user_id = user.get_id() return dag_run_cleared 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 4a4b95f183023..34c270b018ddc 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 @@ -2778,6 +2778,19 @@ export const $DAGRunClearBody = { ], title: 'Run On Latest Version', description: '(Experimental) Run on the latest bundle version of the Dag after clearing the Dag Run. If not specified, falls back to the DAG-level ``rerun_with_latest_version`` parameter, then the ``[core] rerun_with_latest_version`` config option, and finally ``False`` (the historical default for clear/rerun).' + }, + note: { + anyOf: [ + { + type: 'string', + maxLength: 1000 + }, + { + type: 'null' + } + ], + title: 'Note', + description: 'Optional note to attach to the Dag Run as part of the clear. ``None`` (the default) leaves the existing note untouched; any string value (including ``""``) replaces it.' } }, additionalProperties: false, 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 77380eec73833..880cbf626e10d 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 @@ -751,6 +751,10 @@ export type DAGRunClearBody = { * (Experimental) Run on the latest bundle version of the Dag after clearing the Dag Run. If not specified, falls back to the DAG-level ``rerun_with_latest_version`` parameter, then the ``[core] rerun_with_latest_version`` config option, and finally ``False`` (the historical default for clear/rerun). */ run_on_latest_version?: boolean | null; + /** + * Optional note to attach to the Dag Run as part of the clear. ``None`` (the default) leaves the existing note untouched; any string value (including ``""``) replaces it. + */ + note?: string | null; }; /** diff --git a/airflow-core/src/airflow/ui/src/components/Clear/Run/ClearRunDialog.tsx b/airflow-core/src/airflow/ui/src/components/Clear/Run/ClearRunDialog.tsx index 05f15856c6bfe..62710def9d4c0 100644 --- a/airflow-core/src/airflow/ui/src/components/Clear/Run/ClearRunDialog.tsx +++ b/airflow-core/src/airflow/ui/src/components/Clear/Run/ClearRunDialog.tsx @@ -29,7 +29,6 @@ import { Checkbox, Dialog } from "src/components/ui"; import SegmentedControl from "src/components/ui/SegmentedControl"; import { useClearDagRunDryRun } from "src/queries/useClearDagRunDryRun"; import { useClearDagRun } from "src/queries/useClearRun"; -import { usePatchDagRun } from "src/queries/usePatchDagRun"; import { isStatePending, useAutoRefresh } from "src/utils"; type Props = { @@ -80,12 +79,6 @@ const ClearRunDialog = ({ dagRun, onClose, open }: Props) => { onSuccessConfirm: onClose, }); - const { isPending: isPendingPatchDagRun, mutate: mutatePatchDagRun } = usePatchDagRun({ - dagId, - dagRunId, - onSuccess: onClose, - }); - // Check if DAG versions differ (works for both bundle-versioned and local bundles) const latestDagVersionNumber = dagDetails?.latest_dag_version?.version_number; const dagRunVersionNumber = dagRun.dag_versions.at(-1)?.version_number; @@ -148,25 +141,19 @@ const ClearRunDialog = ({ dagRun, onClose, open }: Props) => { ) : undefined} @@ -255,6 +245,8 @@ const ClearTaskInstanceDialog = (props: Props) => { }} onClose={onClose} onConfirm={() => { + const noteChanged = note !== (taskInstance?.note ?? null); + mutate({ dagId, requestBody: { @@ -264,21 +256,16 @@ const ClearTaskInstanceDialog = (props: Props) => { include_future: future, include_past: past, include_upstream: upstream, + // The clear endpoint applies the note in the same transaction + // when it is provided; leaving it off leaves any existing note + // on the cleared TIs untouched. + ...(noteChanged ? { note } : {}), only_failed: onlyFailed, run_on_latest_version: runOnLatestVersion, task_ids: allMapped ? [taskId] : [[taskId, mapIndex as number]], ...(preventRunningTask ? { prevent_running_task: true } : {}), }, }); - if (note !== (taskInstance?.note ?? null)) { - mutatePatchTaskInstance({ - dagId, - dagRunId, - ...(allMapped ? {} : { mapIndex }), - requestBody: { note }, - taskId, - }); - } onCloseDialog(); }} open={open} diff --git a/airflow-core/src/airflow/ui/src/queries/useBulkClearDagRuns.ts b/airflow-core/src/airflow/ui/src/queries/useBulkClearDagRuns.ts index 33288985fd9f1..f231baae4ae68 100644 --- a/airflow-core/src/airflow/ui/src/queries/useBulkClearDagRuns.ts +++ b/airflow-core/src/airflow/ui/src/queries/useBulkClearDagRuns.ts @@ -106,6 +106,9 @@ export const useBulkClearDagRuns = ({ deselectKeys, onSuccessConfirm }: Props) = dagRunId: dagRun.dag_run_id, requestBody: { dry_run: false, + // The clear endpoint applies the note in the same transaction when + // it is provided; ``null`` / unset leaves the existing note alone. + ...(options.note === null ? {} : { note: options.note }), only_failed: options.onlyFailed, only_new: options.onlyNew, }, @@ -130,26 +133,6 @@ export const useBulkClearDagRuns = ({ deselectKeys, onSuccessConfirm }: Props) = } }); - if (succeeded.length > 0 && options.note !== null) { - const noteSettled = await Promise.allSettled( - succeeded - .filter((dagRun) => dagRun.note !== options.note) - .map((dagRun) => - DagRunService.patchDagRun({ - dagId: dagRun.dag_id, - dagRunId: dagRun.dag_run_id, - requestBody: { note: options.note }, - }).then(() => dagRun), - ), - ); - - noteSettled.forEach((outcome) => { - if (outcome.status === "rejected") { - errors.push({ error: `note: ${formatError(outcome.reason)}` }); - } - }); - } - await invalidateQueries(dagRuns); if (succeeded.length > 0) { diff --git a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dag_run.py b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dag_run.py index bc59d204378fa..4ffcc12bc76af 100644 --- a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dag_run.py +++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dag_run.py @@ -1693,6 +1693,40 @@ def test_should_respond_403(self, unauthorized_test_client): ) assert response.status_code == 403 + @pytest.mark.parametrize( + ("body", "expected_note"), + [ + ({"dry_run": False, "note": "cleared by test"}, "cleared by test"), + ({"dry_run": False, "note": ""}, ""), + ({"dry_run": False, "note": None}, "test_note"), + ({"dry_run": False}, "test_note"), + ], + ids=["set-new-note", "set-empty-note", "explicit-null-leaves-existing", "omit-leaves-existing"], + ) + @pytest.mark.usefixtures("configure_git_connection_for_dag_bundle") + def test_clear_dag_run_applies_note(self, test_client, session, body, expected_note): + """``note`` in the clear body writes to the Dag Run; ``None`` / unset leaves it alone.""" + response = test_client.post(f"/dags/{DAG1_ID}/dagRuns/{DAG1_RUN1_ID}/clear", json=body) + assert response.status_code == 200 + assert response.json()["note"] == expected_note + dag_run = session.scalar( + select(DagRun).where(DagRun.dag_id == DAG1_ID, DagRun.run_id == DAG1_RUN1_ID) + ) + assert dag_run.note == expected_note + + @pytest.mark.usefixtures("configure_git_connection_for_dag_bundle") + def test_clear_dag_run_dry_run_does_not_apply_note(self, test_client, session): + """``note`` is ignored on dry-run (no side effects).""" + response = test_client.post( + f"/dags/{DAG1_ID}/dagRuns/{DAG1_RUN1_ID}/clear", + json={"dry_run": True, "note": "ignored"}, + ) + assert response.status_code == 200 + dag_run = session.scalar( + select(DagRun).where(DagRun.dag_id == DAG1_ID, DagRun.run_id == DAG1_RUN1_ID) + ) + assert dag_run.note == "test_note" + @pytest.mark.parametrize( ("body", "dag_run_id", "expected_state"), [ diff --git a/airflow-ctl/src/airflowctl/api/datamodels/generated.py b/airflow-ctl/src/airflowctl/api/datamodels/generated.py index f05fa65cf56f8..e312ace1bcb8a 100644 --- a/airflow-ctl/src/airflowctl/api/datamodels/generated.py +++ b/airflow-ctl/src/airflowctl/api/datamodels/generated.py @@ -345,6 +345,17 @@ class DAGPatchBody(BaseModel): is_paused: Annotated[bool, Field(title="Is Paused")] +class Note2(RootModel[str]): + root: Annotated[ + str, + Field( + description='Optional note to attach to the Dag Run as part of the clear. ``None`` (the default) leaves the existing note untouched; any string value (including ``""``) replaces it.', + max_length=1000, + title="Note", + ), + ] + + class DAGRunClearBody(BaseModel): """ Dag Run serializer for clear endpoint body. @@ -369,6 +380,17 @@ class DAGRunClearBody(BaseModel): title="Run On Latest Version", ), ] = None + note: Annotated[ + Note2 | None, + Field( + description='Optional note to attach to the Dag Run as part of the clear. ``None`` (the default) leaves the existing note untouched; any string value (including ``""``) replaces it.', + title="Note", + ), + ] = None + + +class Note3(RootModel[str]): + root: Annotated[str, Field(max_length=1000, title="Note")] class DAGSourceResponse(BaseModel): @@ -1613,7 +1635,7 @@ class DAGRunPatchBody(BaseModel): extra="forbid", ) state: DagRunMutableStates | None = None - note: Annotated[Note | None, Field(title="Note")] = None + note: Annotated[Note3 | None, Field(title="Note")] = None class DAGRunResponse(BaseModel): @@ -1782,7 +1804,7 @@ class PatchTaskInstanceBody(BaseModel): extra="forbid", ) new_state: TaskInstanceState | None = None - note: Annotated[Note | None, Field(title="Note")] = None + note: Annotated[Note3 | None, Field(title="Note")] = None include_upstream: Annotated[bool | None, Field(title="Include Upstream")] = False include_downstream: Annotated[bool | None, Field(title="Include Downstream")] = False include_future: Annotated[bool | None, Field(title="Include Future")] = False From 0247c6ec31f8ea5e68a21ab1c1e84c9bb50301c5 Mon Sep 17 00:00:00 2001 From: pierrejeambrun Date: Thu, 28 May 2026 14:24:46 +0200 Subject: [PATCH 2/2] Address review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UI: replace ``...(cond ? { note } : {})`` spreads with a direct ``note: ?? undefined`` / ternary in the request body — same serialized output (``undefined`` keys are dropped by JSON.stringify), one less object spread. - Backend: drop the verbose ``description=`` on ``DAGRunClearBody.note`` so its OpenAPI schema matches the existing patch-body ``note`` fields. ``datamodel-code-generator`` was emitting two extra ``Note2`` / ``Note3`` ``RootModel`` classes purely because the description made the Field signature distinct; with it gone, all the ``note`` fields collapse back onto the single ``Note`` model in ``airflow-ctl/src/airflowctl/api/datamodels/generated.py``. --- .../core_api/datamodels/dag_run.py | 3 --- .../openapi/v2-rest-api-generated.yaml | 3 --- .../core_api/routes/public/dag_run.py | 2 -- .../ui/openapi-gen/requests/schemas.gen.ts | 3 +-- .../ui/openapi-gen/requests/types.gen.ts | 3 --- .../TaskInstance/ClearTaskInstanceDialog.tsx | 5 +--- .../ui/src/queries/useBulkClearDagRuns.ts | 4 +-- .../airflowctl/api/datamodels/generated.py | 27 +++---------------- 8 files changed, 6 insertions(+), 44 deletions(-) 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 f2659414b1e8e..8373847328d34 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 @@ -76,9 +76,6 @@ class DAGRunClearBody(StrictBaseModel): note: str | None = Field( default=None, max_length=1000, - description="Optional note to attach to the Dag Run as part of the clear. " - "``None`` (the default) leaves the existing note untouched; any string value " - '(including ``""``) replaces it.', ) @model_validator(mode="before") 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 57b505f3df0c2..009e9c6f2f7e2 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 @@ -13027,9 +13027,6 @@ components: maxLength: 1000 - type: 'null' title: Note - description: Optional note to attach to the Dag Run as part of the clear. - ``None`` (the default) leaves the existing note untouched; any string - value (including ``""``) replaces it. additionalProperties: false type: object title: DAGRunClearBody 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 e7907b522d6bd..aa82b14fefd58 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 @@ -389,8 +389,6 @@ def clear_dag_run( dag_run_cleared = session.scalar(select(DagRun).where(DagRun.id == dag_run.id)) if not dag_run_cleared: raise HTTPException(status.HTTP_404_NOT_FOUND, "Dag run not found after clearing") - # ``note=None`` means "leave existing note untouched"; any string (including ``""``) - # replaces it. Mirrors the convention used by ``ClearTaskInstancesBody``. if body.note is not None: if dag_run_cleared.dag_run_note is None: dag_run_cleared.note = (body.note, user.get_id()) 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 34c270b018ddc..27ce470d7ced1 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 @@ -2789,8 +2789,7 @@ export const $DAGRunClearBody = { type: 'null' } ], - title: 'Note', - description: 'Optional note to attach to the Dag Run as part of the clear. ``None`` (the default) leaves the existing note untouched; any string value (including ``""``) replaces it.' + title: 'Note' } }, additionalProperties: false, 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 880cbf626e10d..3f5ea4f962369 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 @@ -751,9 +751,6 @@ export type DAGRunClearBody = { * (Experimental) Run on the latest bundle version of the Dag after clearing the Dag Run. If not specified, falls back to the DAG-level ``rerun_with_latest_version`` parameter, then the ``[core] rerun_with_latest_version`` config option, and finally ``False`` (the historical default for clear/rerun). */ run_on_latest_version?: boolean | null; - /** - * Optional note to attach to the Dag Run as part of the clear. ``None`` (the default) leaves the existing note untouched; any string value (including ``""``) replaces it. - */ note?: string | null; }; diff --git a/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx b/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx index d97f32ce15e2d..b152566eb7d05 100644 --- a/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx +++ b/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx @@ -256,10 +256,7 @@ const ClearTaskInstanceDialog = (props: Props) => { include_future: future, include_past: past, include_upstream: upstream, - // The clear endpoint applies the note in the same transaction - // when it is provided; leaving it off leaves any existing note - // on the cleared TIs untouched. - ...(noteChanged ? { note } : {}), + note: noteChanged ? note : undefined, only_failed: onlyFailed, run_on_latest_version: runOnLatestVersion, task_ids: allMapped ? [taskId] : [[taskId, mapIndex as number]], diff --git a/airflow-core/src/airflow/ui/src/queries/useBulkClearDagRuns.ts b/airflow-core/src/airflow/ui/src/queries/useBulkClearDagRuns.ts index f231baae4ae68..b3caa1a77ac90 100644 --- a/airflow-core/src/airflow/ui/src/queries/useBulkClearDagRuns.ts +++ b/airflow-core/src/airflow/ui/src/queries/useBulkClearDagRuns.ts @@ -106,9 +106,7 @@ export const useBulkClearDagRuns = ({ deselectKeys, onSuccessConfirm }: Props) = dagRunId: dagRun.dag_run_id, requestBody: { dry_run: false, - // The clear endpoint applies the note in the same transaction when - // it is provided; ``null`` / unset leaves the existing note alone. - ...(options.note === null ? {} : { note: options.note }), + note: options.note ?? undefined, only_failed: options.onlyFailed, only_new: options.onlyNew, }, diff --git a/airflow-ctl/src/airflowctl/api/datamodels/generated.py b/airflow-ctl/src/airflowctl/api/datamodels/generated.py index e312ace1bcb8a..666b2bb19c70f 100644 --- a/airflow-ctl/src/airflowctl/api/datamodels/generated.py +++ b/airflow-ctl/src/airflowctl/api/datamodels/generated.py @@ -345,17 +345,6 @@ class DAGPatchBody(BaseModel): is_paused: Annotated[bool, Field(title="Is Paused")] -class Note2(RootModel[str]): - root: Annotated[ - str, - Field( - description='Optional note to attach to the Dag Run as part of the clear. ``None`` (the default) leaves the existing note untouched; any string value (including ``""``) replaces it.', - max_length=1000, - title="Note", - ), - ] - - class DAGRunClearBody(BaseModel): """ Dag Run serializer for clear endpoint body. @@ -380,17 +369,7 @@ class DAGRunClearBody(BaseModel): title="Run On Latest Version", ), ] = None - note: Annotated[ - Note2 | None, - Field( - description='Optional note to attach to the Dag Run as part of the clear. ``None`` (the default) leaves the existing note untouched; any string value (including ``""``) replaces it.', - title="Note", - ), - ] = None - - -class Note3(RootModel[str]): - root: Annotated[str, Field(max_length=1000, title="Note")] + note: Annotated[Note | None, Field(title="Note")] = None class DAGSourceResponse(BaseModel): @@ -1635,7 +1614,7 @@ class DAGRunPatchBody(BaseModel): extra="forbid", ) state: DagRunMutableStates | None = None - note: Annotated[Note3 | None, Field(title="Note")] = None + note: Annotated[Note | None, Field(title="Note")] = None class DAGRunResponse(BaseModel): @@ -1804,7 +1783,7 @@ class PatchTaskInstanceBody(BaseModel): extra="forbid", ) new_state: TaskInstanceState | None = None - note: Annotated[Note3 | None, Field(title="Note")] = None + note: Annotated[Note | None, Field(title="Note")] = None include_upstream: Annotated[bool | None, Field(title="Include Upstream")] = False include_downstream: Annotated[bool | None, Field(title="Include Downstream")] = False include_future: Annotated[bool | None, Field(title="Include Future")] = False