diff --git a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/common.py b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/common.py index 0f315326194e5..4fedad08e1c27 100644 --- a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/common.py +++ b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/common.py @@ -23,6 +23,7 @@ from pydantic import computed_field from airflow.api_fastapi.core_api.base import BaseModel +from airflow.utils import timezone from airflow.utils.state import TaskInstanceState from airflow.utils.types import DagRunType @@ -81,9 +82,10 @@ class GridRunsResponse(BaseModel): @computed_field def duration(self) -> int | None: - if self.start_date and self.end_date: - return (self.end_date - self.start_date).seconds - return None + if self.start_date: + end_date = self.end_date or timezone.utcnow() + return (end_date - self.start_date).seconds + return 0 class BaseGraphResponse(BaseModel, Generic[E, N]): diff --git a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/grid.py b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/grid.py index ce1a582a511f7..6af0f4e85c65d 100644 --- a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/grid.py +++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/grid.py @@ -480,7 +480,6 @@ def get_grid_runs( ) ), ], - response_model_exclude_none=True, ) def get_grid_ti_summaries( dag_id: str, diff --git a/airflow-core/src/airflow/api_fastapi/core_api/services/ui/grid.py b/airflow-core/src/airflow/api_fastapi/core_api/services/ui/grid.py index 04b031455a63f..73f70ea3f7e0e 100644 --- a/airflow-core/src/airflow/api_fastapi/core_api/services/ui/grid.py +++ b/airflow-core/src/airflow/api_fastapi/core_api/services/ui/grid.py @@ -323,7 +323,7 @@ def agg_state(states): for state in state_priority: if state in states: return state - return "no_status" + return None def _find_aggregates( diff --git a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_grid.py b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_grid.py index 908ebb24bebf4..9196fb74b10c2 100644 --- a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_grid.py +++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_grid.py @@ -1251,13 +1251,13 @@ def sort_dict(in_dict): expected = [ {"task_id": "mapped_task_group", "state": "running"}, - {"task_id": "task_group.inner_task_group"}, - {"task_id": "task_group"}, - {"task_id": "mapped_task_2"}, + {"task_id": "task_group.inner_task_group", "state": None}, + {"task_id": "task_group", "state": None}, + {"task_id": "mapped_task_2", "state": None}, {"task_id": "mapped_task_group.subtask", "state": "running"}, {"task_id": "task", "state": "success"}, - {"task_id": "task_group.inner_task_group.inner_task_group_sub_task"}, - {"task_id": "task_group.mapped_task"}, + {"task_id": "task_group.inner_task_group.inner_task_group_sub_task", "state": None}, + {"task_id": "task_group.mapped_task", "state": None}, ] expected = sort_dict(expected) actual = sort_dict(actual)