UI: Fix Gantt tooltip showing wrong end date on queued/scheduled bars#68570
UI: Fix Gantt tooltip showing wrong end date on queued/scheduled bars#68570Aaryan123456679 wants to merge 1 commit into
Conversation
The tooltip on the queued and scheduled segments of a Gantt bar reported the end of that segment (e.g. the moment queueing ended) as the task's End Date, instead of the task's actual end. This was a regression from the start-date fix in apache#68176, which made the Start Date consistent across segments but left the End Date per-segment. Carry the task's effective end (end_date, or "now" while running) on every segment of a try as `end_when`, mirroring `start_when`, and use it for the tooltip's End Date so all segments of a try report the same start and end. closes: apache#68174
|
Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contributors' Guide
|
|
can you share before/after images? |
@eladkal Pls find attached the screenshots. |
|
Hi @eladkal , any update on this? |
pierrejeambrun
left a comment
There was a problem hiding this comment.
Thanks @Aaryan123456679 — fix mirrors the existing start_when plumbing cleanly and the screenshots make the win obvious. One small nit on the new running-task test below.
| for (const segment of result) { | ||
| expect(segment.end_when).toBe(firstEnd); | ||
| expect(segment.end_when).not.toBeUndefined(); | ||
| } |
There was a problem hiding this comment.
Could you tighten this to pin the actual value of end_when, not just that it's consistent across segments? With vi.useFakeTimers() + vi.setSystemTime(...) you can also assert end_when matches that fixed "now" — otherwise a regression returning a stale or zero timestamp would slip past.
| } | |
| it("uses the current time as end_when on every segment while the task is still running", () => { | |
| vi.useFakeTimers(); | |
| vi.setSystemTime(new Date("2024-03-14T10:02:00+00:00")); | |
| try { | |
| const result = transformGanttData({ | |
| allTries: [ | |
| { | |
| end_date: null, | |
| is_mapped: false, | |
| queued_dttm: "2024-03-14T09:59:00+00:00", | |
| scheduled_dttm: null, | |
| start_date: "2024-03-14T10:00:00+00:00", | |
| state: "running", | |
| task_display_name: "task_1", | |
| task_id: "task_1", | |
| try_number: 1, | |
| }, | |
| ], | |
| flatNodes: [{ depth: 0, id: "task_1", is_mapped: false, label: "task_1" }], | |
| gridSummaries: [], | |
| }); | |
| const expectedEnd = new Date("2024-03-14T10:02:00+00:00").toISOString(); | |
| for (const segment of result) { | |
| expect(segment.end_when).toBe(expectedEnd); | |
| } | |
| } finally { | |
| vi.useRealTimers(); | |
| } | |
| }); |
pierrejeambrun
left a comment
There was a problem hiding this comment.
One more thing on top of the test nit — the new end_when line is asymmetric with start_when in two ways that I think can be smoothed out together.
| ...(scheduledMs === undefined ? {} : { scheduled_when: scheduledDttm }), | ||
| ...(queuedMs === undefined ? {} : { queued_when: queuedDttm }), | ||
| ...(startDate === null ? {} : { start_when: startDate }), | ||
| ...(startDate === null && !hasTaskRunning ? {} : { end_when: dayjs(endMs).toISOString() }), |
There was a problem hiding this comment.
These two lines aren't symmetric with each other:
- Gate:
start_whenskips only whenstartDate === null;end_whenadds&& !hasTaskRunning. The extra branch only fires for queued/scheduled tasks (isStatePendingis true) with nostart_date, where the tooltip would then showStart Date= the bar's own start (segment fallback) +End Date=Date.now(). Two different scales in the same tooltip. - Value:
start_whenkeeps the raw API string ("2024-03-14T10:00:00+00:00");end_whenis re-serialized viadayjs(endMs).toISOString()to"...Z"with.000millis. The test even pins this skew. Renders fine because dayjs reparses, but it's needless and it's the reason thetryWhenForTooltipblock had to move belowendMs.
Suggest collapsing both into a single symmetric form — derive an effectiveEndDate and gate on it like start_when does on startDate:
| ...(startDate === null && !hasTaskRunning ? {} : { end_when: dayjs(endMs).toISOString() }), | |
| const effectiveEndDate = hasTaskRunning ? new Date().toISOString() : endDate; | |
| // Include scheduled/queued/start/end times in tooltip data whenever the timestamps exist. | |
| // start_when/end_when are carried on every segment of a try so the tooltip reports the | |
| // task's actual start and end on the scheduled and queued bars too, not just the | |
| // execution bar's own bounds. | |
| const tryWhenForTooltip = { | |
| ...(scheduledMs === undefined ? {} : { scheduled_when: scheduledDttm }), | |
| ...(queuedMs === undefined ? {} : { queued_when: queuedDttm }), | |
| ...(startDate === null ? {} : { start_when: startDate }), | |
| ...(effectiveEndDate === null ? {} : { end_when: effectiveEndDate }), | |
| }; |
Then the block doesn't need to live below endMs anymore (no ordering dependency) and finished tasks keep the API's raw end_date string. The test for the finished task can drop the new Date(...).toISOString() wrapping and assert against the raw "2024-03-14T10:05:00+00:00" like it does for start_when.


The Gantt tooltip showed the wrong End Date when hovering over the queued or scheduled segment of a task bar: it reported the end of that segment (e.g. the instant queueing ended) rather than the task's actual end.
This was a regression from #68176, which fixed the Start Date by carrying the task's real
start_dateon every segment of a try (start_when) but left the End Date derived from each segment's own bounds (max_end_date = segment.x[1]).This PR mirrors that approach for the end: each segment of a try now carries the task's effective end (
end_date, or "now" while the task is still running) asend_when, and the tooltip uses it for the End Date. As a result, the scheduled, queued, and execution bars of the same try all report a consistent Start Date, End Date, and duration.Tests added in
Gantt/utils.test.tsassert thatstart_when/end_whenare carried consistently across all segments of a finished task and of a running task.closes: #68174
Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Opus 4.8) following the guidelines