This is an automated email from the ASF dual-hosted git repository.
uranusjr pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 50e27b3d463 Expose timetable_partitioned in UI API (#62777)
50e27b3d463 is described below
commit 50e27b3d46336bd6ea5f69cb55324730864dd5d2
Author: Tzu-ping Chung <[email protected]>
AuthorDate: Wed Mar 4 08:36:12 2026 +0800
Expose timetable_partitioned in UI API (#62777)
---
.../api_fastapi/core_api/datamodels/dags.py | 1 +
.../api_fastapi/core_api/openapi/_private_ui.yaml | 4 ++
.../core_api/openapi/v2-rest-api-generated.yaml | 8 +++
.../src/airflow/cli/commands/dag_command.py | 1 +
.../airflow/ui/openapi-gen/requests/schemas.gen.ts | 18 +++++-
.../airflow/ui/openapi-gen/requests/types.gen.ts | 3 +
.../airflow/ui/src/pages/DagsList/DagCard.test.tsx | 1 +
.../core_api/routes/public/test_dags.py | 67 +++++++++++-----------
.../src/airflowctl/api/datamodels/generated.py | 2 +
.../tests/airflow_ctl/api/test_operations.py | 2 +
.../airflow_ctl/ctl/commands/test_dag_command.py | 2 +
11 files changed, 74 insertions(+), 35 deletions(-)
diff --git a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dags.py
b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dags.py
index 3bf599d6a95..6c07f1ed8a8 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dags.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dags.py
@@ -74,6 +74,7 @@ class DAGResponse(BaseModel):
description: str | None
timetable_summary: str | None
timetable_description: str | None
+ timetable_partitioned: bool
tags: list[DagTagResponse]
max_active_tasks: int
max_active_runs: int | None
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
index a0339372b8d..f60a7781130 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
+++ b/airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
@@ -1847,6 +1847,9 @@ components:
- type: string
- type: 'null'
title: Timetable Description
+ timetable_partitioned:
+ type: boolean
+ title: Timetable Partitioned
tags:
items:
$ref: '#/components/schemas/DagTagResponse'
@@ -1945,6 +1948,7 @@ components:
- description
- timetable_summary
- timetable_description
+ - timetable_partitioned
- tags
- max_active_tasks
- max_active_runs
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 f50499bdb85..92ca0df16b3 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
@@ -10206,6 +10206,9 @@ components:
- type: string
- type: 'null'
title: Timetable Description
+ timetable_partitioned:
+ type: boolean
+ title: Timetable Partitioned
tags:
items:
$ref: '#/components/schemas/DagTagResponse'
@@ -10385,6 +10388,7 @@ components:
- description
- timetable_summary
- timetable_description
+ - timetable_partitioned
- tags
- max_active_tasks
- max_active_runs
@@ -10490,6 +10494,9 @@ components:
- type: string
- type: 'null'
title: Timetable Description
+ timetable_partitioned:
+ type: boolean
+ title: Timetable Partitioned
tags:
items:
$ref: '#/components/schemas/DagTagResponse'
@@ -10569,6 +10576,7 @@ components:
- description
- timetable_summary
- timetable_description
+ - timetable_partitioned
- tags
- max_active_tasks
- max_active_runs
diff --git a/airflow-core/src/airflow/cli/commands/dag_command.py
b/airflow-core/src/airflow/cli/commands/dag_command.py
index d054f364c16..6572f467ff3 100644
--- a/airflow-core/src/airflow/cli/commands/dag_command.py
+++ b/airflow-core/src/airflow/cli/commands/dag_command.py
@@ -261,6 +261,7 @@ def _get_dagbag_dag_details(dag: DAG) -> dict:
"description": dag.description,
"timetable_summary": core_timetable.summary,
"timetable_description": core_timetable.description,
+ "timetable_partitioned": core_timetable.partitioned,
"tags": dag.tags,
"max_active_tasks": dag.max_active_tasks,
"max_active_runs": dag.max_active_runs,
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 a82a6598449..0b41a478c25 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
@@ -1881,6 +1881,10 @@ export const $DAGDetailsResponse = {
],
title: 'Timetable Description'
},
+ timetable_partitioned: {
+ type: 'boolean',
+ title: 'Timetable Partitioned'
+ },
tags: {
items: {
'$ref': '#/components/schemas/DagTagResponse'
@@ -2176,7 +2180,7 @@ Deprecated: Use max_active_tasks instead.`,
}
},
type: 'object',
- required: ['dag_id', 'dag_display_name', 'is_paused', 'is_stale',
'last_parsed_time', 'last_parse_duration', 'last_expired', 'bundle_name',
'bundle_version', 'relative_fileloc', 'fileloc', 'description',
'timetable_summary', 'timetable_description', 'tags', 'max_active_tasks',
'max_active_runs', 'max_consecutive_failed_dag_runs',
'has_task_concurrency_limits', 'has_import_errors', 'next_dagrun_logical_date',
'next_dagrun_data_interval_start', 'next_dagrun_data_interval_end', 'next_da
[...]
+ required: ['dag_id', 'dag_display_name', 'is_paused', 'is_stale',
'last_parsed_time', 'last_parse_duration', 'last_expired', 'bundle_name',
'bundle_version', 'relative_fileloc', 'fileloc', 'description',
'timetable_summary', 'timetable_description', 'timetable_partitioned', 'tags',
'max_active_tasks', 'max_active_runs', 'max_consecutive_failed_dag_runs',
'has_task_concurrency_limits', 'has_import_errors', 'next_dagrun_logical_date',
'next_dagrun_data_interval_start', 'next_dagrun_dat [...]
title: 'DAGDetailsResponse',
description: 'Specific serializer for DAG Details responses.'
} as const;
@@ -2318,6 +2322,10 @@ export const $DAGResponse = {
],
title: 'Timetable Description'
},
+ timetable_partitioned: {
+ type: 'boolean',
+ title: 'Timetable Partitioned'
+ },
tags: {
items: {
'$ref': '#/components/schemas/DagTagResponse'
@@ -2429,7 +2437,7 @@ export const $DAGResponse = {
}
},
type: 'object',
- required: ['dag_id', 'dag_display_name', 'is_paused', 'is_stale',
'last_parsed_time', 'last_parse_duration', 'last_expired', 'bundle_name',
'bundle_version', 'relative_fileloc', 'fileloc', 'description',
'timetable_summary', 'timetable_description', 'tags', 'max_active_tasks',
'max_active_runs', 'max_consecutive_failed_dag_runs',
'has_task_concurrency_limits', 'has_import_errors', 'next_dagrun_logical_date',
'next_dagrun_data_interval_start', 'next_dagrun_data_interval_end', 'next_da
[...]
+ required: ['dag_id', 'dag_display_name', 'is_paused', 'is_stale',
'last_parsed_time', 'last_parse_duration', 'last_expired', 'bundle_name',
'bundle_version', 'relative_fileloc', 'fileloc', 'description',
'timetable_summary', 'timetable_description', 'timetable_partitioned', 'tags',
'max_active_tasks', 'max_active_runs', 'max_consecutive_failed_dag_runs',
'has_task_concurrency_limits', 'has_import_errors', 'next_dagrun_logical_date',
'next_dagrun_data_interval_start', 'next_dagrun_dat [...]
title: 'DAGResponse',
description: 'DAG serializer for responses.'
} as const;
@@ -7679,6 +7687,10 @@ export const $DAGWithLatestDagRunsResponse = {
],
title: 'Timetable Description'
},
+ timetable_partitioned: {
+ type: 'boolean',
+ title: 'Timetable Partitioned'
+ },
tags: {
items: {
'$ref': '#/components/schemas/DagTagResponse'
@@ -7820,7 +7832,7 @@ export const $DAGWithLatestDagRunsResponse = {
}
},
type: 'object',
- required: ['dag_id', 'dag_display_name', 'is_paused', 'is_stale',
'last_parsed_time', 'last_parse_duration', 'last_expired', 'bundle_name',
'bundle_version', 'relative_fileloc', 'fileloc', 'description',
'timetable_summary', 'timetable_description', 'tags', 'max_active_tasks',
'max_active_runs', 'max_consecutive_failed_dag_runs',
'has_task_concurrency_limits', 'has_import_errors', 'next_dagrun_logical_date',
'next_dagrun_data_interval_start', 'next_dagrun_data_interval_end', 'next_da
[...]
+ required: ['dag_id', 'dag_display_name', 'is_paused', 'is_stale',
'last_parsed_time', 'last_parse_duration', 'last_expired', 'bundle_name',
'bundle_version', 'relative_fileloc', 'fileloc', 'description',
'timetable_summary', 'timetable_description', 'timetable_partitioned', 'tags',
'max_active_tasks', 'max_active_runs', 'max_consecutive_failed_dag_runs',
'has_task_concurrency_limits', 'has_import_errors', 'next_dagrun_logical_date',
'next_dagrun_data_interval_start', 'next_dagrun_dat [...]
title: 'DAGWithLatestDagRunsResponse',
description: 'DAG with latest dag runs response serializer.'
} as const;
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 53c9e259d64..fe7062b70df 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
@@ -540,6 +540,7 @@ export type DAGDetailsResponse = {
description: string | null;
timetable_summary: string | null;
timetable_description: string | null;
+ timetable_partitioned: boolean;
tags: Array<DagTagResponse>;
max_active_tasks: number;
max_active_runs: number | null;
@@ -618,6 +619,7 @@ export type DAGResponse = {
description: string | null;
timetable_summary: string | null;
timetable_description: string | null;
+ timetable_partitioned: boolean;
tags: Array<DagTagResponse>;
max_active_tasks: number;
max_active_runs: number | null;
@@ -1893,6 +1895,7 @@ export type DAGWithLatestDagRunsResponse = {
description: string | null;
timetable_summary: string | null;
timetable_description: string | null;
+ timetable_partitioned: boolean;
tags: Array<DagTagResponse>;
max_active_tasks: number;
max_active_runs: number | null;
diff --git a/airflow-core/src/airflow/ui/src/pages/DagsList/DagCard.test.tsx
b/airflow-core/src/airflow/ui/src/pages/DagsList/DagCard.test.tsx
index e520dce9d81..ad0e34b6607 100644
--- a/airflow-core/src/airflow/ui/src/pages/DagsList/DagCard.test.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/DagsList/DagCard.test.tsx
@@ -109,6 +109,7 @@ const mockDag = {
relative_fileloc: "nested_task_groups.py",
tags: [],
timetable_description: "Every minute",
+ timetable_partitioned: false,
timetable_summary: "* * * * *",
} satisfies DAGWithLatestDagRunsResponse;
diff --git
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dags.py
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dags.py
index 41d11545689..55515b76931 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dags.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_dags.py
@@ -934,20 +934,21 @@ class TestDagDetails(TestDagEndpoint):
last_parsed_time = res_json["last_parsed_time"]
file_token = res_json["file_token"]
expected = {
+ "active_runs_count": 0,
+ "allowed_run_types": None,
+ "asset_expression": None,
"bundle_name": "dag_maker",
"bundle_version": None,
- "asset_expression": None,
"catchup": False,
"concurrency": 16,
- "dag_id": dag_id,
"dag_display_name": dag_display_name,
+ "dag_id": dag_id,
"dag_run_timeout": None,
"default_args": {
"depends_on_past": False,
"retries": 1,
"retry_delay": "PT5M",
},
- "allowed_run_types": None,
"description": None,
"doc_md": "details",
"end_date": None,
@@ -955,9 +956,10 @@ class TestDagDetails(TestDagEndpoint):
"file_token": file_token,
"has_import_errors": False,
"has_task_concurrency_limits": True,
- "is_stale": False,
+ "is_favorite": False,
"is_paused": False,
"is_paused_upon_creation": None,
+ "is_stale": False,
"latest_dag_version": {
"bundle_name": "dag_maker",
"bundle_url": "http://test_host.github.com/tree/None/dags",
@@ -983,22 +985,21 @@ class TestDagDetails(TestDagEndpoint):
"owner_links": {},
"params": {
"foo": {
- "value": 1,
- "schema": {},
"description": None,
+ "schema": {},
"source": None,
+ "value": 1,
}
},
"relative_fileloc": "test_dags.py",
"render_template_as_native_obj": False,
- "timetable_summary": None,
"start_date": start_date,
"tags": [],
"template_search_path": None,
"timetable_description": "Never, external triggers only",
+ "timetable_partitioned": False,
+ "timetable_summary": None,
"timezone": UTC_JSON_REPR,
- "is_favorite": False,
- "active_runs_count": 0,
}
assert res_json == expected
@@ -1032,20 +1033,21 @@ class TestDagDetails(TestDagEndpoint):
last_parse_duration = res_json["last_parse_duration"]
file_token = res_json["file_token"]
expected = {
+ "active_runs_count": 0,
+ "allowed_run_types": None,
+ "asset_expression": None,
"bundle_name": "dag_maker",
"bundle_version": None,
- "asset_expression": None,
"catchup": False,
"concurrency": 16,
- "dag_id": dag_id,
"dag_display_name": dag_display_name,
+ "dag_id": dag_id,
"dag_run_timeout": None,
"default_args": {
"depends_on_past": False,
"retries": 1,
"retry_delay": "PT5M",
},
- "allowed_run_types": None,
"description": None,
"doc_md": "details",
"end_date": None,
@@ -1053,6 +1055,7 @@ class TestDagDetails(TestDagEndpoint):
"file_token": file_token,
"has_import_errors": False,
"has_task_concurrency_limits": True,
+ "is_favorite": False,
"is_stale": False,
"is_paused": False,
"is_paused_upon_creation": None,
@@ -1062,9 +1065,9 @@ class TestDagDetails(TestDagEndpoint):
"bundle_version": None,
"created_at": mock.ANY,
"dag_id": "test_dag2",
+ "dag_display_name": dag_display_name,
"id": mock.ANY,
"version_number": 1,
- "dag_display_name": dag_display_name,
},
"last_expired": None,
"last_parsed": last_parsed,
@@ -1081,22 +1084,21 @@ class TestDagDetails(TestDagEndpoint):
"owner_links": {},
"params": {
"foo": {
- "value": 1,
- "schema": {},
"description": None,
+ "schema": {},
"source": None,
+ "value": 1,
}
},
"relative_fileloc": "test_dags.py",
"render_template_as_native_obj": False,
- "timetable_summary": None,
"start_date": start_date,
"tags": [],
"template_search_path": None,
+ "timetable_summary": None,
"timetable_description": "Never, external triggers only",
+ "timetable_partitioned": False,
"timezone": UTC_JSON_REPR,
- "is_favorite": False,
- "active_runs_count": 0,
}
assert res_json == expected
@@ -1226,30 +1228,31 @@ class TestGetDag(TestDagEndpoint):
"dag_id": dag_id,
"dag_display_name": dag_display_name,
"allowed_run_types": None,
+ "bundle_name": "dag_maker",
+ "bundle_version": None,
"description": None,
"fileloc": __file__,
"file_token": file_token,
+ "has_import_errors": False,
+ "has_task_concurrency_limits": True,
"is_paused": False,
"is_stale": False,
- "owners": ["airflow"],
- "timetable_summary": None,
- "tags": tags,
- "has_task_concurrency_limits": True,
+ "last_expired": None,
+ "last_parse_duration": last_parse_duration,
+ "last_parsed_time": last_parsed_time,
+ "max_active_runs": 16,
+ "max_active_tasks": 16,
+ "max_consecutive_failed_dag_runs": 0,
"next_dagrun_data_interval_start": None,
"next_dagrun_data_interval_end": None,
"next_dagrun_logical_date": None,
"next_dagrun_run_after": None,
- "max_active_runs": 16,
- "max_consecutive_failed_dag_runs": 0,
- "last_expired": None,
- "max_active_tasks": 16,
- "last_parsed_time": last_parsed_time,
- "last_parse_duration": last_parse_duration,
- "timetable_description": "Never, external triggers only",
- "has_import_errors": False,
- "bundle_name": "dag_maker",
- "bundle_version": None,
+ "owners": ["airflow"],
"relative_fileloc": "test_dags.py",
+ "tags": tags,
+ "timetable_description": "Never, external triggers only",
+ "timetable_partitioned": False,
+ "timetable_summary": None,
}
assert res_json == expected
diff --git a/airflow-ctl/src/airflowctl/api/datamodels/generated.py
b/airflow-ctl/src/airflowctl/api/datamodels/generated.py
index 0ca5629b532..fde516ef5c7 100644
--- a/airflow-ctl/src/airflowctl/api/datamodels/generated.py
+++ b/airflow-ctl/src/airflowctl/api/datamodels/generated.py
@@ -1357,6 +1357,7 @@ class DAGDetailsResponse(BaseModel):
description: Annotated[str | None, Field(title="Description")] = None
timetable_summary: Annotated[str | None, Field(title="Timetable Summary")]
= None
timetable_description: Annotated[str | None, Field(title="Timetable
Description")] = None
+ timetable_partitioned: Annotated[bool, Field(title="Timetable
Partitioned")]
tags: Annotated[list[DagTagResponse], Field(title="Tags")]
max_active_tasks: Annotated[int, Field(title="Max Active Tasks")]
max_active_runs: Annotated[int | None, Field(title="Max Active Runs")] =
None
@@ -1421,6 +1422,7 @@ class DAGResponse(BaseModel):
description: Annotated[str | None, Field(title="Description")] = None
timetable_summary: Annotated[str | None, Field(title="Timetable Summary")]
= None
timetable_description: Annotated[str | None, Field(title="Timetable
Description")] = None
+ timetable_partitioned: Annotated[bool, Field(title="Timetable
Partitioned")]
tags: Annotated[list[DagTagResponse], Field(title="Tags")]
max_active_tasks: Annotated[int, Field(title="Max Active Tasks")]
max_active_runs: Annotated[int | None, Field(title="Max Active Runs")] =
None
diff --git a/airflow-ctl/tests/airflow_ctl/api/test_operations.py
b/airflow-ctl/tests/airflow_ctl/api/test_operations.py
index 701440eeb5a..65f058d6656 100644
--- a/airflow-ctl/tests/airflow_ctl/api/test_operations.py
+++ b/airflow-ctl/tests/airflow_ctl/api/test_operations.py
@@ -684,6 +684,7 @@ class TestDagOperations:
description="description",
timetable_summary="timetable_summary",
timetable_description="timetable_description",
+ timetable_partitioned=False,
tags=[],
max_active_tasks=1,
max_active_runs=1,
@@ -711,6 +712,7 @@ class TestDagOperations:
description="description",
timetable_summary="timetable_summary",
timetable_description="timetable_description",
+ timetable_partitioned=False,
tags=[],
max_active_tasks=1,
max_active_runs=1,
diff --git a/airflow-ctl/tests/airflow_ctl/ctl/commands/test_dag_command.py
b/airflow-ctl/tests/airflow_ctl/ctl/commands/test_dag_command.py
index fbc6ee1240b..600a553109b 100644
--- a/airflow-ctl/tests/airflow_ctl/ctl/commands/test_dag_command.py
+++ b/airflow-ctl/tests/airflow_ctl/ctl/commands/test_dag_command.py
@@ -41,6 +41,7 @@ class TestDagCommands:
description="description",
timetable_summary="timetable_summary",
timetable_description="timetable_description",
+ timetable_partitioned=False,
tags=[],
max_active_tasks=1,
max_active_runs=1,
@@ -68,6 +69,7 @@ class TestDagCommands:
description="description",
timetable_summary="timetable_summary",
timetable_description="timetable_description",
+ timetable_partitioned=False,
tags=[],
max_active_tasks=1,
max_active_runs=1,