Skip to content

fix(fields,plugin-grid): a grid date column reads in one absolute face - #26341

Merged
objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/issue-25884-grid-date-absolute
Oct 27, 2026
Merged

objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/issue-25884-grid-date-absolute

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #25884

Clause-②: no
Metadata-protocol: none

What changes

A list grid's date column used to mix three faces in one column, for example "Yesterday · 3 days ago · Sep 25 · Sep 20, 2025". The cause was DateCellRenderer, which defaulted an undeclared format to 'relative'. formatRelativeDate is relative only within ±7 days and absolute outside that window.

This PR follows the seat's route on the 2026-10-25 ruling: absolute in a sortable column, relative at most as a tooltip.

  • @object-ui/fields
    • CellRendererProps gains inGridColumn?: boolean.
    • When inGridColumn is set and the date field declares no format, DateCellRenderer paints formatDate(v, undefined, …). That is the locale's short absolute date, with the year shown only when it is not the current year. No new formatter or i18n key is added, and date-display.ts is untouched.
    • The relative phrase the cell no longer paints ("Yesterday", "In 2 days", "Overdue 3d" on a declared dueLike) becomes the cell's title. It replaces the raw ISO title, but only when the phrase differs from the face. Outside the ±7-day window the phrase is the absolute face, so the ISO title stays there.
    • The overdue red is unchanged (isOverdueInstant).
    • A declared format still wins, 'relative' included.
    • The DateTimeCellRenderer region is not touched.
  • @object-ui/plugin-grid
    • ObjectGrid passes inGridColumn on all seven column-cell call sites generateColumns builds (paths A to D, link cells included).
    • temporalGroupHeading restates the same selection (format || undefined), so a group heading still reads like the cell under it.
    • Its record panel (renderFieldValue) and the mobile card's percent slot draw their cells without the prop and keep the old default.

Why a prop, not a shared flip

DateCellRenderer is shared by the record detail body, the header highlights strip, kanban and gallery cards, the tree and RelatedList. Flipping its default would change every one of those surfaces. The seat asked that only grid columns change, and the prop is the seam for that. It follows the precedent of alwaysShowYear, a host-declared presentation input on the same props.

Tests

  • Red first, then green. ObjectGrid.dateColumnOneFace-25884.test.tsx (new) drives every column path of the real grid: A object columns, B string columns, C the inline-data projection, D the object-schema default columns. One column holds dates at −1, −3, −6, +2, −40 and −400 days.
    • Before the fix (4f461580, the test alone on e05e0de8), 4/4 failed with expected 'Yesterday' not to match …. The in-window rows painted relative phrases and the out-of-window rows painted absolute dates.
    • After the fix, 4/4 pass.
    • The test also pins the tooltip (Overdue 3d, In 2 days, Yesterday) and the red on a past dueLike row. Its control is a field declaring format: 'relative', which keeps "Yesterday" / "3 days ago".
  • Pins flipped. One file, ui/packages/plugin-grid/src/__tests__/ObjectGrid.deadlineSettled-11815.test.tsx (7 cases). It read "Overdue 5d" / "5 days ago" / "4 days ago" as the cell TEXT, which was the old default. It now reads them from the cell's title, asserts the cell text is the absolute date, and still asserts red on the open row and no red on the done row and on the undeclared control.
  • Held unchanged.
    • groupDateHeading-13234.test.tsx holds every heading equal to its cell for formats undefined, 'relative', 'short' and 'YYYY-MM-DD'. It stays green because both sides moved together.
    • The fields-level DateCellRenderer, dateCells.deadlineSettled-11815, dateCell.overdueZone-10183, dateCell.unparsableValue-8581 and date-locale-channel suites stay green unchanged, because a cell without inGridColumn keeps 'relative'.
    • The detail, kanban, tree and list deadlineSettled-11815 pins and HeaderHighlight.dateYear-13331 stay green unchanged.

Verification (after merging origin/main, under the shared verify lock)

The suites, type-checks and sdui record ran at b5bc0328. The head, aa24a3a2, differs from it only in the changeset's prose. The derived gates ran at aa24a3a2.

  • Suites. pnpm exec vitest run packages/fields packages/plugin-grid plus the eight cross-package date pins (plugin-list, plugin-detail, plugin-kanban, plugin-tree), run with --maxWorkers=2: Test Files 538 passed, 1 skipped (539); Tests 6566 passed, 7 skipped.
  • Type-checks. type-check passes in @object-ui/fields (exit 0) and in @object-ui/plugin-grid (exit 0).
  • sdui record. node scripts/gen-sdui-manifest-node.mjs re-recorded 2 of 27 package records, fields and plugin-grid, and left sdui.manifest.json unchanged. node scripts/check-sdui-manifest.mjs exits 0.
  • Derived gates (at aa24a3a2). dispatch-gates --commands derived 46 families; 45 ran with exit 0. pnpm check:type-check-debt exited 3 because the closure build it runs under the shared lock never got a turn, so it is NOT-MEASURED here; CI runs it in Lint & Repo Gates. --ran reconciles: 46 accounted, 0 UNRUN.

Acceptance notes

  • RelatedList keeps the old default. plugin-detail's RelatedList builds its own table cells, at RelatedList.tsx around line 1654, and does not pass inGridColumn. Its date columns therefore still mix faces. It is outside this claim's file surface and is left as is; RelatedList is not addressed here.
  • One mobile-card case changes. The grid's mobile card draws its title slot and its non-date slots through the column cell. A grid whose name or title column is a date field therefore reads absolute on mobile too. The card's other date slots already used the absolute 'short' face.

Generated by Claude Code

A date field with no declared format defaulted to the relative face, which is
absolute outside a 7-day window, so one grid column mixed three faces. The
date cell now takes inGridColumn; ObjectGrid passes it on every column cell,
and the group heading restates the same selection. The relative phrase moves
to the cell's tooltip; a declared format still wins.

Claude-Session: https://claude.ai/code/session_01SMps7wq7rBTk53e8KTSEup
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

ACCEPT · seat 2 · 2026-10-26T21:58Z · PR #26341 head aa24a3a2 (#25884)

check reading
scope 7 files, +294/−26: fields/src/index.tsx (CellRendererProps.inGridColumn, DateCellRenderer), plugin-grid/ObjectGrid.tsx (the flag on all 7 column-cell call sites; temporalGroupHeading restates format || undefined), one new pin, one flipped pin, sources/fields.json + plugin-grid.json, root .changeset/
behaviour in a grid column an undeclared date paints formatDate's absolute face (year only outside the current year); the relative phrase becomes the title when it differs; overdue red stays; a declared format (incl. 'relative') wins; detail body, highlights, kanban, gallery, tree and the record panel keep relative
pin flips ObjectGrid.deadlineSettled-11815 (7 cases) now reads the relative words from the title and the absolute date from the text, red kept on the open row; groupDateHeading-13234 unchanged (heading == cell, both moved)
red first new pin 4/4 red at base, green after
tests fields + plugin-grid full + 8 cross-package date pins: 538 files / 6566 tests green post-merge; both type-checks exit 0; check-sdui-manifest exit 0
gates 46 derived, 45 run exit 0; check:type-check-debt NOT MEASURED locally (lock)
governance NOT governed, 320 lines; git merge-tree against origin/main clean

Rulings on the open questions (seat 2):

  1. Metadata-protocol: none, patch: A. No authorable key, accepted value or spec default changed. The renderer's presentation default for one host moves, and the changeset says so.
  2. Tooltip: A. Replace the ISO title only when the relative phrase says something the face does not.
  3. RelatedList's date columns: A. Filed as record page: a related list's date column still mixes relative and absolute faces (RelatedList builds its cells without inGridColumn, which #25884 added for grids) #26344, blocked by this PR.

Not armed yet: on the plugin-grid / fields line, #26307 (p2, one argument) goes first. After it, seat 1's #25994 slice 1 (p2) goes ahead of this p3 if it is green. Otherwise this PR goes next, with a re-record if a record moved.

…id-date-absolute

Claude-Session: https://claude.ai/code/session_01SMps7wq7rBTk53e8KTSEup
Co-authored-by: Claude <noreply@anthropic.com>
…id-date-absolute

The per-package SDUI records under scripts/sdui-manifest.sources/ are
retired on main; this branch's fields and plugin-grid records are deleted
with them.

Claude-Session: https://claude.ai/code/session_01SMps7wq7rBTk53e8KTSEup
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读

改了什么:表格列里没有声明格式的日期,从相对说法(「3 天前」)改为绝对日期(今年内只显示月日,跨年带年份);相对说法移到鼠标悬停提示里,且只在与绝对日期说的不同时才出现;逾期标红照旧。分组标题的日期与单元格一致。
为什么改:同一列里一会儿「昨天」一会儿「2025-12-01」,读表和排序时无法比较(#25884)。
风险与回滚:只改表格列里的默认显示;字段声明了 format(包括 relative)仍以声明为准;详情页、高亮、看板、画廊、树和记录面板仍是相对说法。回滚 = revert 本 PR。
先看:ui/packages/fields/src/index.tsx(CellRendererProps.inGridColumn 与 DateCellRenderer)→ ui/packages/plugin-grid/src/ObjectGrid.tsx(7 处列单元格传 inGridColumn,temporalGroupHeading)→ 新钉子 ObjectGrid.dateColumnOneFace-25884。
两分钟验证:在 ui/ 下运行 pnpm exec vitest run packages/plugin-grid/src/__tests__/ObjectGrid.dateColumnOneFace-25884,预期全部通过。
需要你做的:无,席位落地。
席位意见:ACCEPT。行为与此前席位 ACCEPT 相同;此后两轮只合 main(含 #26367 删除按包记录)。PR 正文 What changes 里「sdui record … re-recorded fields and plugin-grid」一句已过时:本 PR 现不含任何记录文件。

席位核对

seat 2 · 2026-10-27T02:35Z · head 5dc16e94 (#25884)

item reading
form 5 files, +292/−24: fields/src/index.tsx (inGridColumn, DateCellRenderer), plugin-grid/ObjectGrid.tsx (7 call sites + temporalGroupHeading), new pin dateColumnOneFace-25884, flipped pin deadlineSettled-11815, root .changeset/; no sources/*.json (retired on main by #26367)
premise measured after ObjectGrid split slices 1–2 (#26323, #26354) all 7 inGridColumn sites and temporalGroupHeading still sit in ObjectGrid.tsx; no split module builds column cells
gates (check-runs on 5dc16e94) 53 runs: 45 success, 8 skipped, 0 failed. Local: fields + plugin-grid type-checks exit 0; 4 pin files / 47 tests; check-sdui-manifest exit 0; 36 of 36 derived gates exit 0. Full fields + plugin-grid suites last read at c17032e0 (531 files / 6551 tests); the merge since brought no change to either package
accepted deviations none new
out of scope RelatedList date columns → #26344 (unblocked when this merges)
landing NOT governed (check-governed-merges --pr 26341: 316 lines, no hit path); git merge-tree against origin/main clean

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 27, 2026 02:36
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 27, 2026 02:36
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit 9c3097e Oct 27, 2026
54 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-25884-grid-date-absolute branch October 27, 2026 03:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling

Projects

None yet

2 participants