Repository navigation
fix(plugin-timeline,i18n): a past date on a timeline is "Earlier", not "Overdue" (objectui#11676) - #11700
Conversation
…t "Overdue" Without a groupByField, ObjectTimeline buckets entries by date, and every day before today went under timeline.bucket.overdue whatever the bucketed field meant: the showcase's created_at timeline drew all ten tasks under "Overdue", Done records included. "Overdue" needs two facts (the date is a due date, the record is open) and nothing the timeline reads declares either: TimelineConfigSchema has no due-date role and no closed-state marker. A past day now buckets as the neutral timeline.bucket.earlier, translated in all ten packs; no field name or status value is guessed. The overdue key stays, with no call site, pending the card's open question on the due-date half. Part of objectui#11676. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FngvPpdrnhHMdHHq6vwwju
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract reviewServed-tier: Inputs read: card #11676 (body and all three comments: the claim, the ① Derived judgmentsAccept-set: nothing moves. No schema, validator, prop type or registry input is touched; Public surface, Public surface,
Tests: the three expectation edits are exactly the pins the arm change implies ( Docs: ② Semver levelChangeset
③ Boundary flagsDev deviations (4), each answered:
Check-runs on the head at the writing of this record: 31 success, 3 skipped ( Implemented-by: VERDICT: PASS Generated by Claude Code |
Part of #11676. This lands the neutral-bucket half and its pins. The due-date half (the card's second pin: a due-date timeline marks an open past-due record "Overdue" but not a closed one) stays open: nothing the timeline reads declares a due date or a closed record, so it needs a decision, and that question is on the card with options. The card stays open when this merges.
Clause-②: yes
What changed
Without a
groupByField,ObjectTimelinegroups entries into date buckets, anddateBucketreturnedtimeline.bucket.overduefor any day before today, whatever the bucketed field meant. The showcase's Activity Timeline (startDateField: 'created_at') drew all its tasks under "Overdue", the Done ones included.packages/plugin-timeline/src/ObjectTimeline.tsx: indateBucket, a day before today now returnst('timeline.bucket.earlier'). Today, Tomorrow, This week, Next week, Later and No date are unchanged. A comment abovedateBucketrecords why: "Overdue" needs two facts that nothing the timeline reads declares, and neither a field name nor a status value is read as one.packages/plugin-timeline/src/useTimelineTranslation.ts: new default row'timeline.bucket.earlier': 'Earlier'. Theoverduerow stays, with a note that it has no call site until the card's open question is decided.packages/i18n/src/locales/*.ts(all ten packs): new keytimeline.bucket.earlier, placed afteroverdue. Values: en Earlier, zh 更早, ja 以前, ko 이전, de Früher, fr Plus tôt, es Antes, pt Antes, ru Ранее, ar سابقاً.__tests__/ObjectTimeline.pastBucket-11676.test.tsx. Two existing pins now expect the new label:objectTimelineInputs-11168.test.tsx(date buckets withoutgroupByField) and the two west-of-UTC cases inObjectTimeline.dateOnlyZone-10866.test.tsx..changeset/11676-timeline-past-bucket.md:minorfor@object-ui/plugin-timelineand@object-ui/i18n.Premises checked on
main(57d82cb)dateBucketreturnedtimeline.bucket.overduefor everytsbeforetoday, and the grouping fed itm.startDateonly. Confirmed.TimelineConfigSchema(strict,@objectstack/spec17.6.0 as installed) hasstartDateField,endDateField,titleField,groupByField,colorFieldandscale.ListViewTimelineConfigadds only the legacydateField. None of them is a due-date role or a closed-state marker. The spec'sSelectOptionSchema(label, value, description, color, default, visibleWhen) has no closed or terminal flag. The onlyterminalin the spec is onrecord:pathstages, a page component the timeline never reads.dueLikekey, declared in@object-ui/typesand read by@object-ui/fields'resolveDueLike. The spec'sFieldSchemadoes not declare it, so an object served by the platform cannot carry it. Its reader also falls back to a field-name regex, and the card rules out guessing from field names. The timeline's built-instatus/prioritychips are chosen by field name, and nothing declares which status values are closed.created_attimeline and its copy in objectstack's lint fixtures. No due-date timeline exists in either repo's examples.Built declarations (Clause-② reading)
Both packages were built at the base and again at the head, and every
dist/**/*.d.tswas compared byte for byte:@object-ui/i18n:locales/en.d.tsgains one member,readonly earlier: "Earlier", undertimeline.bucket.TranslationKeys = typeof entherefore gainstimeline.bucket.earlier. The other nine pack declarations each gain their ownearlier, andlocales/index.d.tsgains the same member in each pack type. Nothing else changed: every diff line is an addition.@object-ui/plugin-timeline: all five emitted declarations (index,ObjectTimeline,renderer,renderHandoff,useTimelineTranslation) are byte-identical, base to head.TIMELINE_DEFAULT_TRANSLATIONSis typedRecordof string to string, so a new row does not change its type. Only the bundle changed:dist/index.jscontainstimeline.bucket.earlier2 times, against 0 at the base.Verification (head
047cf47)pnpm exec vitest run packages/plugin-timeline/: 44 files passed, 552 tests passed, 34 skipped.pnpm exec vitest run packages/i18n/: 79 files passed, 1290 tests passed, 13 skipped.pnpm exec vitest run scripts/__tests__/date-only-zone-pins-10183.test.ts scripts/__tests__/defaults-population-parity-7904.test.ts packages/app-shell/src/__tests__/defaults-maps-mirror-en-pack.test.tsx: 3 files, 46 tests passed. The first one drives the forked west and east zone cases ofObjectTimeline.dateOnlyZone-10866.test.tsx, which the plain run skips.pnpm --filter @object-ui/plugin-timeline type-checkandpnpm --filter @object-ui/i18n type-check: exit 0.tsc -p tsconfig.test.json --listFileslists all 44 timeline test files, the new one included.pnpm --filter @object-ui/plugin-timeline lintandpnpm --filter @object-ui/i18n lint: exit 0. Read as JSON: 50 and 110 files, 0 errors. The new test file has 0 warnings.check:i18n-keys,check:i18n-drift,check:i18n-dead-keys(report-only),check:new-line-citations(0 new),check:control-bytes,check:changeset-claims,check:pending-changeset-literals,check:test-path-roots,check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shape,check:unreferenced-sources,node scripts/check-changeset-no-major.mjs,node scripts/check-changeset-presence.mjs.check:eager-locale-catalogues. It answered PREREQUISITE NOT MET because it needs a full console build. That gate checks which catalogues are loaded eagerly, and this diff does not change that. CI runs it.Ablation (one run, committed tree, restored).
scripts/ablation-replace.mjs(objectstack) replacedt('timeline.bucket.earlier')witht('timeline.bucket.overdue')indateBucket. The anchor was found once and the blob changed. Then the new pin file andobjectTimelineInputs-11168.test.tsxwere run. Predicted: red in 5 cases (the 4 new ones and the 11168 date-bucket row). Observed: 5 failed and 65 passed, exactly those 5. After the restore the blob equals HEAD andgit diff HEADis empty. The tests import../ObjectTimelinefrom source, so no build was involved.Acceptance notes
timeline.bucket.overduehas no call site after this change. It stays in the defaults row and all ten packs because the decision either reuses it or retires it.check:i18n-dead-keyslists it as needs-review, a report-only reading.created_at, everything before today now shares one "Earlier" header. Finer past buckets such as Yesterday or Last week would be a separate capability, so this change does not add them.content/docs/plugins/plugin-timeline.mdx) and the published config description inplugin-timeline/src/index.tsxsay only that entries "group into date buckets" and name no bucket, so neither went stale. This change does not edit them.Generated by Claude Code