You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Filed unassigned, found while implementing #6759 (the unusable-date-range diagnostic). Not covered by that card, and deliberately left out of it — see "Why #6759 does not cover this" below.
Measured on a64e96ca8 — the #6759 branch head, i.e. with that card's guards already in the tree — with a throwaway probe, since no pin covers this input.
The defect
new Date(null).getTime() is 0, not NaN. That is the Unix epoch, not an invalid date, so a null gantt date passes every parse check there is and flows straight into the arithmetic as 1970-01-01.
Three things go wrong at once, and none of them says so:
The axis spans fifty-four years — 649 month columns for a task that lasts two months.
The bar gets width: -100%, a negative width, because endDate (epoch) is before startDate (2024).
left: 100% puts it off the right-hand edge of a chart it is not on anyway.
No error, no diagnostic, no console warning. This is the same disease as #6759's case 2 — a gantt drawing a confidently wrong picture — reached through a different door.
Why it is plausible input, not a curiosity
null is what a record mapping produces for an empty date field. Any generator that builds gantt rows from records — a project plan whose tasks do not all have an end date yet, a query that left-joins — emits endDate: null rather than omitting the key. An omittedendDate is already refused by #6759 (new Date(undefined) is NaN); writing the same absence as null instead silently draws the chart above.
#6759 refuses a date that does not parse. null parses — to the epoch — so it never reaches that guard, and the guard was written not to reach for it:
⚠️null is deliberately NOT a fault here. new Date(null).getTime() is 0, not NaN — the epoch, not an invalid date — so a null date has always drawn a bar anchored at 1970 rather than crashing. Refusing it would be a behaviour change on an input class this card did not measure or adjudicate; it is filed separately instead.
Verified as unchanged by that card: with #6759's guards in the tree the probe above still renders the 1970 axis and the negative-width bar (alert: null — no diagnostic fires).
Why this is a policy question and not a mechanical fix
new Date(null) === epoch is correct JavaScript, and there is a real choice about what a null date should MEAN on a gantt, with at least three defensible answers:
Treat it as open-ended — a task with no end date runs to the end of the axis. Plausible for real plans, but it is a new rendering behaviour, not a guard.
Which one is right is a product decision about what an author is told versus what they are shown, so it wants the same adjudication #6759's wording got rather than a fixer picking one.
Where it lives
packages/plugin-timeline/src/renderer.tsx — findUnusableGanttDate (the parse check null passes) and calculateDateRange / calculateBarDimensions (which then treat the epoch as a real bound). Line numbers deliberately omitted: re-derive them on your base.
Filed unassigned, found while implementing #6759 (the unusable-date-range diagnostic). Not covered by that card, and deliberately left out of it — see "Why #6759 does not cover this" below.
Measured on
a64e96ca8— the #6759 branch head, i.e. with that card's guards already in the tree — with a throwaway probe, since no pin covers this input.The defect
new Date(null).getTime()is0, notNaN. That is the Unix epoch, not an invalid date, so anullgantt date passes every parse check there is and flows straight into the arithmetic as1970-01-01.Input:
variant: 'gantt', one row,items: [{ title: 'T', startDate: '2024-01-01', endDate: null }].Three things go wrong at once, and none of them says so:
width: -100%, a negative width, becauseendDate(epoch) is beforestartDate(2024).left: 100%puts it off the right-hand edge of a chart it is not on anyway.No error, no diagnostic, no console warning. This is the same disease as #6759's case 2 — a gantt drawing a confidently wrong picture — reached through a different door.
Why it is plausible input, not a curiosity
nullis what a record mapping produces for an empty date field. Any generator that builds gantt rows from records — a project plan whose tasks do not all have an end date yet, a query that left-joins — emitsendDate: nullrather than omitting the key. An omittedendDateis already refused by #6759 (new Date(undefined)isNaN); writing the same absence asnullinstead silently draws the chart above.Why #6759 does not cover this
#6759 refuses a date that does not parse.
nullparses — to the epoch — so it never reaches that guard, and the guard was written not to reach for it:Verified as unchanged by that card: with #6759's guards in the tree the probe above still renders the 1970 axis and the negative-width bar (
alert: null— no diagnostic fires).Why this is a policy question and not a mechanical fix
new Date(null) === epochis correct JavaScript, and there is a real choice about what anulldate should MEAN on a gantt, with at least three defensible answers:variant: "gantt"throws —calculateDateRangereads a row shapeObjectTimelinenever composes #6655 next door.startDate, drawing a zero-width (degenerate) bar, which finding(plugin-timeline): a gantt timeline with an EMPTY literalitemsarray throws —calculateDateRangereduces an empty list #6750'stotalDuration === 0guard already renders as a full-width bar on a degenerate axis.Which one is right is a product decision about what an author is told versus what they are shown, so it wants the same adjudication #6759's wording got rather than a fixer picking one.
Where it lives
packages/plugin-timeline/src/renderer.tsx—findUnusableGanttDate(the parse checknullpasses) andcalculateDateRange/calculateBarDimensions(which then treat the epoch as a real bound). Line numbers deliberately omitted: re-derive them on your base.