This is an automated email from the ASF dual-hosted git repository.
pierrejeambrun pushed a commit to branch v3-2-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-2-test by this push:
new b768c891dbe [v3-2-test] Fix None child state rendering in UI (#67552)
(#68030)
b768c891dbe is described below
commit b768c891dbe2e259e8bcbf8ce796006e9b44798a
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Mon Jun 8 15:14:50 2026 +0200
[v3-2-test] Fix None child state rendering in UI (#67552) (#68030)
* 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
(cherry picked from commit f822744a0a1030d23f8889044b1a3e2ed5f54e88)
Co-authored-by: Aditya Patel
<[email protected]>
---
.../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 3f3d17a95de..c27e1953aeb 100644
--- a/airflow-core/src/airflow/ui/src/components/TaskInstanceTooltip.test.tsx
+++ b/airflow-core/src/airflow/ui/src/components/TaskInstanceTooltip.test.tsx
@@ -197,6 +197,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 71ed31dedd7..a1b113f9202 100644
--- a/airflow-core/src/airflow/ui/src/theme.ts
+++ b/airflow-core/src/airflow/ui/src/theme.ts
@@ -375,6 +375,7 @@ const defaultAirflowTheme = {
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 b0dab9012a5..e5c73f6533a 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
@@ -836,7 +836,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",
@@ -845,7 +845,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",
@@ -872,7 +872,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",
@@ -881,7 +881,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",
@@ -890,7 +890,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",
@@ -899,7 +899,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",