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
finding(plugin-timeline): two more unusable gantt date ranges — a malformed date still throws, and an inverted author-pinned range silently draws a negative-width bar on no axis #6759
Filed unassigned, found while implementing #6750 (the empty items guard, PR #6758). Neither case is fixed by that card, and both were deliberately left out of it — see "Why #6750 does not cover this" below.
Measured on a04c3cac2 (the #6750 branch head, i.e. with that card's guards already in the tree), with a throwaway probe since no pin covers either case.
Case 1 — a malformed date still throws
calculateDateRange guards the EMPTY list, but not a list whose dates do not parse. new Date('not-a-date').getTime() is NaN, Math.min(NaN) is NaN, and new Date(NaN).toISOString() throws the same RangeError#6750 was about:
CASE-1 malformed date -> RangeError: Invalid time value
Input: variant: 'gantt' with one row, items: [{ title: 'T', startDate: 'not-a-date', endDate: 'also-bad' }]. Hard render crash, same signature and same crash site as #6750, different input class.
Case 2 — an inverted author-pinned range renders silent nonsense
An author who pins minDate later than maxDate gets no error and no diagnostic. generateTimeScaleHeaders refuses an inverted range by returning no headers, so the axis has zero columns — but the row loop below it still runs, and calculateBarDimensions happily divides by a negativetotalDuration:
Input: variant: 'gantt', one legitimate row spanning 2024-01-01 to 2024-03-01, with minDate: '2030-01-01' and maxDate: '2026-03-15'. A bar positioned off-canvas at 158% with a negative width, hanging under a header row that has no cells. Nothing anywhere says the range was rejected.
#6750's triage split the card deliberately and scoped it to the empty list — the ordinary empty state of a valid schema. Both cases here are a different input class: a date the author got wrong, not a collection that is legitimately empty. Extending #6750's sentinel to swallow them would have been consumer-side tolerance that hides an author error behind a plausible-looking render, which is a policy decision rather than a mechanical fix, so it was filed rather than taken.
The two cases belong together because a fixer decides one policy for both — the same "decide it once for the whole branch" reasoning #6750's triage applied to the empty case. They fail in opposite directions today, which is itself the argument that no policy exists yet: case 1 crashes loudly, case 2 renders confidently wrong.
Validate at the authoring boundary so the renderer never sees an unusable range, if the date keys can be constrained where they are declared rather than where they are read.
Both touch what an author should be told, which is why this is filed rather than fixed.
Where it lives
packages/plugin-timeline/src/renderer.tsx — calculateDateRange for case 1; for case 2, the interaction between the gantt branch's schema.minDate || dateRange.minDate resolution, generateTimeScaleHeaders's inverted-range refusal, and calculateBarDimensions. Line numbers deliberately omitted: re-derive them on your base, since #6758 moves this file.
Filed unassigned, found while implementing #6750 (the empty
itemsguard, PR #6758). Neither case is fixed by that card, and both were deliberately left out of it — see "Why #6750 does not cover this" below.Measured on
a04c3cac2(the #6750 branch head, i.e. with that card's guards already in the tree), with a throwaway probe since no pin covers either case.Case 1 — a malformed date still throws
calculateDateRangeguards the EMPTY list, but not a list whose dates do not parse.new Date('not-a-date').getTime()isNaN,Math.min(NaN)isNaN, andnew Date(NaN).toISOString()throws the sameRangeError#6750 was about:Input:
variant: 'gantt'with one row,items: [{ title: 'T', startDate: 'not-a-date', endDate: 'also-bad' }]. Hard render crash, same signature and same crash site as #6750, different input class.Case 2 — an inverted author-pinned range renders silent nonsense
An author who pins
minDatelater thanmaxDategets no error and no diagnostic.generateTimeScaleHeadersrefuses an inverted range by returning no headers, so the axis has zero columns — but the row loop below it still runs, andcalculateBarDimensionshappily divides by a negativetotalDuration:Input:
variant: 'gantt', one legitimate row spanning 2024-01-01 to 2024-03-01, withminDate: '2030-01-01'andmaxDate: '2026-03-15'. A bar positioned off-canvas at 158% with a negative width, hanging under a header row that has no cells. Nothing anywhere says the range was rejected.Why #6750 does not cover this
#6750's triage split the card deliberately and scoped it to the empty list — the ordinary empty state of a valid schema. Both cases here are a different input class: a date the author got wrong, not a collection that is legitimately empty. Extending #6750's sentinel to swallow them would have been consumer-side tolerance that hides an author error behind a plausible-looking render, which is a policy decision rather than a mechanical fix, so it was filed rather than taken.
The two cases belong together because a fixer decides one policy for both — the same "decide it once for the whole branch" reasoning #6750's triage applied to the empty case. They fail in opposite directions today, which is itself the argument that no policy exists yet: case 1 crashes loudly, case 2 renders confidently wrong.
Directions, not a recommendation
variant: "gantt"throws —calculateDateRangereads a row shapeObjectTimelinenever composes #6655 refuses the object-bound gantt: an unusable range renders a diagnostic naming the offending value. Consistent with the neighbouring ruling, and it keeps a wrong date from ever looking like a right one.Both touch what an author should be told, which is why this is filed rather than fixed.
Where it lives
packages/plugin-timeline/src/renderer.tsx—calculateDateRangefor case 1; for case 2, the interaction between the gantt branch'sschema.minDate || dateRange.minDateresolution,generateTimeScaleHeaders's inverted-range refusal, andcalculateBarDimensions. Line numbers deliberately omitted: re-derive them on your base, since #6758 moves this file.