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",

Reply via email to