This is an automated email from the ASF dual-hosted git repository.
bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new f822744a0a1 Fix None child state rendering in UI (#67552)
f822744a0a1 is described below
commit f822744a0a1030d23f8889044b1a3e2ed5f54e88
Author: Aditya Patel <[email protected]>
AuthorDate: Thu Jun 4 14:03:22 2026 -0400
Fix None child state rendering in UI (#67552)
* Fix None child state rendering in UI
* Apply UI lint formatting
* Normalize None child states in grid API
* Remove uv lockfile changes
* Remove uv lockfile changes
---
.../api_fastapi/core_api/datamodels/ui/grid.py | 3 ++-
.../api_fastapi/core_api/services/ui/grid.py | 6 +++++-
.../ui/src/components/TaskInstanceTooltip.test.tsx | 22 ++++++++++++++++++++++
airflow-core/src/airflow/ui/src/theme.ts | 1 +
.../api_fastapi/core_api/routes/ui/test_grid.py | 12 ++++++------
5 files changed, 36 insertions(+), 8 deletions(-)
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/grid.py
b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/grid.py
index 70b0c590c3f..19278430d3f 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/grid.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/grid.py
@@ -18,6 +18,7 @@
from __future__ import annotations
from datetime import datetime
+from typing import Literal
from airflow.api_fastapi.core_api.base import BaseModel
from airflow.utils.state import TaskInstanceState
@@ -29,7 +30,7 @@ class LightGridTaskInstanceSummary(BaseModel):
task_id: str
task_display_name: str
state: TaskInstanceState | None
- child_states: dict[TaskInstanceState | None, int] | None
+ child_states: dict[TaskInstanceState | Literal["none"], int] | None
min_start_date: datetime | None
max_end_date: datetime | None
dag_version_number: int | None = None
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 3ea7c5b21a4..bff2fd66296 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
@@ -122,12 +122,16 @@ def agg_state(states):
return None
+def _serialize_child_states(child_states: Counter[Any]) -> dict[str, int]:
+ return {state if state is not None else "none": count for state, count in
child_states.items()}
+
+
def _get_aggs_for_node(summary: GridNodeAgg) -> dict[str, Any]:
return {
"state": agg_state(summary.child_states),
"min_start_date": summary.min_start_date,
"max_end_date": summary.max_end_date,
- "child_states": dict(summary.child_states),
+ "child_states": _serialize_child_states(summary.child_states),
"dag_version_number": summary.dag_version_number,
}
diff --git
a/airflow-core/src/airflow/ui/src/components/TaskInstanceTooltip.test.tsx
b/airflow-core/src/airflow/ui/src/components/TaskInstanceTooltip.test.tsx
index e131a129edb..34b75620d4f 100644
--- a/airflow-core/src/airflow/ui/src/components/TaskInstanceTooltip.test.tsx
+++ b/airflow-core/src/airflow/ui/src/components/TaskInstanceTooltip.test.tsx
@@ -195,6 +195,28 @@ describe("TaskInstanceTooltip", () => {
expect(screen.getByText(/startDate/iu)).toBeInTheDocument();
});
+ it("renders API-normalized none child state in the breakdown", () => {
+ const taskInstance: LightGridTaskInstanceSummary = {
+ child_states: { none: 2, success: 1 },
+ max_end_date: null,
+ min_start_date: null,
+ state: null,
+ task_display_name: "Mapped Task",
+ task_id: "mapped_task",
+ };
+
+ render(
+ <TaskInstanceTooltip open taskInstance={taskInstance}>
+ <span>trigger</span>
+ </TaskInstanceTooltip>,
+ { wrapper: Wrapper },
+ );
+
+ expect(screen.getByText(/2\s+common:states\.none/iu)).toBeInTheDocument();
+ expect(screen.queryByText(/^common:states\.None$/iu)).toBeNull();
+
expect(screen.getByText(/1\s+common:states\.success/iu)).toBeInTheDocument();
+ });
+
it("shows run ID when provided explicitly for grid summaries", () => {
const taskInstance: LightGridTaskInstanceSummary = {
child_states: null,
diff --git a/airflow-core/src/airflow/ui/src/theme.ts
b/airflow-core/src/airflow/ui/src/theme.ts
index 232aa622e10..5dea56794a7 100644
--- a/airflow-core/src/airflow/ui/src/theme.ts
+++ b/airflow-core/src/airflow/ui/src/theme.ts
@@ -413,6 +413,7 @@ const defaultAirflowTheme: ThemingConfig = {
deferred: generateSemanticTokens("purple"),
scheduled: generateSemanticTokens("zinc"),
none: generateSemanticTokens("gray"),
+ no_status: generateSemanticTokens("gray"),
removed: generateSemanticTokens("slate"),
// TAILWIND 4.0 COLORS
red: generateSemanticTokens("red"),
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 0c8f4c17449..8700e7ce96d 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
@@ -837,7 +837,7 @@ class TestGetGridDataEndpoint:
expected = [
{
- "child_states": {"None": 1},
+ "child_states": {"none": 1},
"dag_version_number": 1,
"task_id": "mapped_task_2",
"task_display_name": "mapped_task_2",
@@ -846,7 +846,7 @@ class TestGetGridDataEndpoint:
"state": None,
},
{
- "child_states": {"success": 1, "running": 1, "None": 1},
+ "child_states": {"success": 1, "running": 1, "none": 1},
"dag_version_number": 1,
"max_end_date": "2024-12-30T01:02:03Z",
"min_start_date": "2024-12-30T01:00:00Z",
@@ -873,7 +873,7 @@ class TestGetGridDataEndpoint:
"min_start_date": None,
},
{
- "child_states": {"None": 6},
+ "child_states": {"none": 6},
"dag_version_number": 1,
"task_id": "task_group",
"task_display_name": "task_group",
@@ -882,7 +882,7 @@ class TestGetGridDataEndpoint:
"state": None,
},
{
- "child_states": {"None": 2},
+ "child_states": {"none": 2},
"dag_version_number": 1,
"task_id": "task_group.inner_task_group",
"task_display_name": "task_group.inner_task_group",
@@ -891,7 +891,7 @@ class TestGetGridDataEndpoint:
"state": None,
},
{
- "child_states": {"None": 2},
+ "child_states": {"none": 2},
"dag_version_number": 1,
"task_id":
"task_group.inner_task_group.inner_task_group_sub_task",
"task_display_name": "Inner Task Group Sub Task Label",
@@ -900,7 +900,7 @@ class TestGetGridDataEndpoint:
"state": None,
},
{
- "child_states": {"None": 4},
+ "child_states": {"none": 4},
"dag_version_number": 1,
"task_id": "task_group.mapped_task",
"task_display_name": "task_group.mapped_task",