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 e4352cd20b8 Mark task-group aggregate bars on Gantt with a diagonal 
stripe (#72894)
e4352cd20b8 is described below

commit e4352cd20b8f2d0d6b2f52d48c1d47e35cabd15b
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Tue Sep 15 15:27:56 2026 +0200

    Mark task-group aggregate bars on Gantt with a diagonal stripe (#72894)
    
    A collapsed TaskGroup renders on the Gantt as a single bar spanning the
    envelope of its children's runtime. That bar looked identical to a real task
    and read as one very long-running task at a glance, exactly the confusion 
the
    linked issue describes.
    
    Overlay a diagonal stripe on group aggregate bars so they are visually
    distinct from real task bars while keeping their duration and position (so
    groups still line up with the sidebar for organisation). Composes on top of
    the badge's solid state colour so state is still legible.
    
    closes: #72434
---
 .../layouts/Details/Gantt/GanttTimeline.test.tsx   | 46 ++++++++++++++++++++++
 .../ui/src/layouts/Details/Gantt/GanttTimeline.tsx | 12 ++++++
 2 files changed, 58 insertions(+)

diff --git 
a/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/GanttTimeline.test.tsx 
b/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/GanttTimeline.test.tsx
index f7554c685bf..5448f3b5c68 100644
--- 
a/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/GanttTimeline.test.tsx
+++ 
b/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/GanttTimeline.test.tsx
@@ -329,4 +329,50 @@ describe("GanttTimeline segment bars", () => {
     // Only the execution bar should be rendered; scheduled and queued are too 
narrow.
     expect(screen.getAllByRole("link")).toHaveLength(1);
   });
+
+  it("hatches a task-group aggregate bar so it does not read as a single long 
task", () => {
+    const groupNode: GridTask = {
+      depth: 0,
+      id: "group_1",
+      is_mapped: false,
+      isGroup: true,
+      label: "group_1",
+    };
+    const groupSegment: GanttDataItem = {
+      queued_when: null,
+      scheduled_when: null,
+      state: "success",
+      taskId: "group_1",
+      tryNumber: undefined,
+      x: [new Date("2024-03-14T10:00:00Z").getTime(), new 
Date("2024-03-14T10:05:00Z").getTime()],
+      y: "group_1",
+    };
+    const leafSegment: GanttDataItem = {
+      queued_when: null,
+      scheduled_when: null,
+      state: "success",
+      taskId: "task_1",
+      tryNumber: 1,
+      x: [new Date("2024-03-14T10:00:00Z").getTime(), new 
Date("2024-03-14T10:05:00Z").getTime()],
+      y: "task_1",
+    };
+
+    render(
+      <GanttTimeline
+        {...defaultProps}
+        flatNodes={[groupNode, BASE_NODE]}
+        ganttDataItems={[groupSegment, leafSegment]}
+        rowSegments={[[groupSegment], [leafSegment]]}
+        scrollContainerRef={makeScrollRef()}
+      />,
+      { wrapper: TestWrapper },
+    );
+
+    const bars = screen.getAllByRole("link");
+
+    // Group aggregate bar carries the diagonal-stripe overlay.
+    
expect(bars[0]?.querySelector('[style*="repeating-linear-gradient"]')).not.toBeNull();
+    // Regular task bar does not.
+    
expect(bars[1]?.querySelector('[style*="repeating-linear-gradient"]')).toBeNull();
+  });
 });
diff --git 
a/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/GanttTimeline.tsx 
b/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/GanttTimeline.tsx
index 977322eeb38..06e5924a740 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/GanttTimeline.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/GanttTimeline.tsx
@@ -385,6 +385,18 @@ export const GanttTimeline = ({
                               justifyContent="center"
                               minH={0}
                               p={0}
+                              // Aggregate task-group bars are the envelope of 
their children's
+                              // runtime, not a real running task. Overlay a 
diagonal stripe so
+                              // they read as an aggregate at a glance and 
don't get mistaken for
+                              // a single long-running task.
+                              style={
+                                node.isGroup === true
+                                  ? {
+                                      backgroundImage:
+                                        "repeating-linear-gradient(45deg, 
rgba(255,255,255,0.4) 0px, rgba(255,255,255,0.4) 3px, transparent 3px, 
transparent 6px)",
+                                    }
+                                  : undefined
+                              }
                               variant="solid"
                               w="100%"
                             >

Reply via email to