Repository navigation
Description
epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff
Filed by the record-page epic seat under epic #26676. An independent reviewer assessed this and the seat re-read the evidence. The maintainer: 「三点都按 A:相对日期立独立卡,在 #28971 第一版立卡前合入,包含早于/晚于的相对点;仪表盘拼法另立低优先级卡;两只钟另立 finding。」 (2026-11-02). Code readings below are on main a4015ab47b. No domain:* label is set: triage routes this card.
Ordering. This merges before the first-version execution card of #28971 is filed. It is not a Blocked-by of that card; the epic seat checks it at filing time.
Business reason
A salesperson filters tasks to "due before today" to see what's overdue. The calendar's 「今天」 stores 2026-11-02, and the stored preference brings that date back on the next open. Tomorrow the list is one day out, with no hint. "This week" goes wrong the same way next Monday. A named personal view would make this worse.
Measured
Preview bdb19ca6d9, examples/app-crm:
| Step | Result |
|---|---|
REST close_date < {today} / >= {today} |
8 and 5 of 13 rows, correct |
REST close_date between {month_start}, {month_end} |
1 row, correct; the {current_month_*} spelling gives the same |
REST created_at between {week_start}, {week_end} (a datetime column) |
13 rows, all created today |
REST close_date = this_week (a preset name) |
400, refused |
Console link, uf__filter with between and {month_start}, {month_end} |
The list shows 1 row |
| Filter panel on a date row | 等于, 不等于, 为空, 不为空, 早于, 晚于, 介于; no relative option |
| Calendar 「今天」 | Stores an absolute date, restored from the stored preference |
Typing {today} in the date input |
Not applied |
So only the panel's choice is missing.
Reading
packages/spec/src/data/date-range-presets.ts:42-49, 120-136: 13 presets, each mapped to a macro window.packages/spec/src/ui/view.zod.ts:311-313: relative dates are not filter-rule operators.:1183showsvalue: '{7_days_ago}'in a rule.ui/packages/components/src/custom/filter-builder.tsx:325-330: the operator set is pinned to the spec.:2289: the date value editor.ui/packages/plugin-dashboard/src/DashboardFilterBar.tsx: the dashboard already offers all 13 presets, with labels in the i18n packs.ui/packages/plugin-list/src/ListView.tsx:1033: panel conditions go to the server, which resolves macros in the workspace timezone.
Target
- On a
dateordatetimerow of the list filter panel,betweenoffers the spec'sDATE_RANGE_PRESETS(all 13, in spec order) beside a custom option that keeps today's two date inputs. beforeandafteroffer today, yesterday and tomorrow beside a fixed date.- A chosen preset is stored as the spec's macro window, for example
value: ['{week_start}', '{week_end}']. A relative point is stored as the wrapped token, for example'{today}'. A preset name is never stored. The stored rule stays an ordinary specViewFilterRule. - The panel shows the preset's label when a stored pair matches a window, folding the
{current_*}aliases first. A pair that matches no preset is shown as text, kept, and still filters. - The value survives unchanged through
uf__filter, the stored preference and 「保存为视图」. - No new operator, metadata key, configuration or gate. The panel reads the spec's table and keeps no copy of it. A small reverse-lookup helper beside that table is fine.
Not in this card:
- A "last N days" input.
- Relative values on
equals. - Future-facing presets such as next week: the spec has none, and adding them is a spec change for later.
- A week-start setting: weeks start on Monday.
- The record form's 今天 / 明天 shortcuts, which correctly write a fixed date.
- Migrating stored absolute dates: they stay valid and mean that day.
- The author
date-rangechip. - The dashboard's bounds table (Dashboard date presets: read the spec macro window table instead of a second table with different spellings #29116) and the browser-versus-server clock difference ([finding] Date macros resolve on two clocks: an authored view filter in the browser, a panel filter in the workspace timezone — they can disagree about today #29117).
Acceptance
- Choosing 本周 on a
datebetweenrow sends['{week_start}', '{week_end}'], and the rows match the same REST query. On adatetimecolumn, the last day is covered to its end. - Choosing 今天 on
beforesends'{today}', and the rows match REST< {today}. - After a reload, a second browser opening the link, and 「保存为视图」, the label shows again and the stored value is still the macro pair. 「重置视图」 removes it.
- A URL with
['{current_week_start}', '{current_week_end}']shows 本周. One with['{7_days_ago}', '{tomorrow}']shows as text and still filters. - Text and number rows are unchanged, and a preset name in
valueis still refused by lint and by the engine. - Measure and state in the PR whether the panel behaves the same on the kanban and calendar hosts, which share it.
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: records-forms.adhoc-filter-sort-builder
Triage:
domain:ui· p2 ·pm:queue· 2026-11-02T08:27Z⛔ Not a claim.
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m
Claim: PM loop round 4 · 2026-11-02T09:04Z
Session:
session_01QsR2jSjVXJnFT3sLMzwrKq(card thread, os-dev); dispatched by seat sessionsession_01QsR2jV4dWohojjbTJTQq5mAccount:
zhuangjianguoBranch:
claude/project-thread-bga9c5(platform-assigned to the card thread; it can push only this branch)Worktree:
objectstack-issue-29115Domain:
domain:uiSeat:
domain:ui#3File surface:
ui/packages/components/src/custom/filter-builder.tsxand helpers beside it inui/packages/components/src/custom/, the i18n packsui/packages/i18n/src/locales/*.tsonly for labels the dashboard keys don't cover, their tests, and a changeset (stop on breach; explain in the report). Nopackages/specedit without a claim amendment first.Container & model: M,
mode:thread,model: default tier (dispatch-gates --tier: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
n/a — not a defect cardThread-read: 6572558418
Premise: holds (at
origin/mainc44c8ac4:DATE_RANGE_PRESETSandDATE_RANGE_PRESET_MACRO_WINDOWSare exported frompackages/spec/src/data/date-range-presets.tsviadata/index.ts:152; the panel's date rows offer no relative option). Maintainer ruling quoted on the card: 「三点都按 A:相对日期立独立卡,在 #28971 第一版立卡前合入,包含早于/晚于的相对点;仪表盘拼法另立低优先级卡;两只钟另立 finding。」Serial constraints cleared: no in-flight claim names
filter-builder.tsx; seat 3's #29052 (PR #29189) and seat 1's #28950 and #29074 are on plugin-list. #29116 and #29117 are out of this card.objectstack-fleet commentedon Nov 2, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jSjVXJnFT3sLMzwrKq
os-dev-report
{ "issue": 29115, "status": "done", "branch": "claude/project-thread-bga9c5", "pr": "https://github.com/objectstack-ai/objectstack/pull/29263", "head": "64a3459f", "session": "session_01QsR2jSjVXJnFT3sLMzwrKq", "premise_still_valid": true, "summary": "A date or datetime row of the shared FilterBuilder now offers the spec's 13 DATE_RANGE_PRESETS on between (stored as the DATE_RANGE_PRESET_MACRO_WINDOWS pair, e.g. ['{week_start}', '{week_end}']) and today / yesterday / tomorrow on before / after (stored as '{today}' etc.), each beside Custom..., which keeps today's date editor. A stored pair reads back as its preset after folding the current_ aliases; a placeholder value no preset matches is kept, shown as text and still filters. The reverse lookup lives in a new module beside the builder (filterRelativeDates.ts), not re-exported from the package entry, reading the spec table and alias list; packages/spec is not edited and no i18n key is added (labels reuse dashboard.filters.range.*, dashboard.filters.custom, fields.datePicker.tomorrow).", "files_changed": [ ".changeset/29115-filter-relative-dates.md", "ui/packages/components/src/custom/filter-builder.tsx", "ui/packages/components/src/custom/filterRelativeDates.ts", "ui/packages/components/src/__tests__/filter-builder-relative-dates-29115.test.tsx" ], "line_budget": "604 changed lines (+597 / -7) over 4 files vs the 3000 human-merge threshold: under", "tests": "new filter-builder-relative-dates-29115.test.tsx 49/49 green; the 24 filter-builder* files 446/446 green at 64a3459f; full packages/components suite at 007ea328: 471 files passed, 1 skipped, 4530 tests passed (four locked batches, --maxWorkers=2); @object-ui/components type-check exit 0 at 64a3459f. Ablation (fix committed first, ablation-replace.mjs, test imports src so no dist leg): the between leg stored today's resolved date pair instead of the macro window -> 16 failed / 33 passed of 49, restored blob == HEAD, git diff HEAD empty. Throwaway probes (not committed): uf__filter write/read round trip and foldFilterGroupToSpecRules keep ['{week_start}','{week_end}'], ['{current_week_start}','{current_week_end}'], '{today}' on before and ['{7_days_ago}','{tomorrow}'] unchanged and each folded rule passes ViewFilterRuleSchema; convertFilterGroupToAST -> ['close_date','between',[...]] lowered to $between, before today -> $lt '{today}'. ListView jsdom probe seeded with the current_week pair: on grid, kanban and calendar the panel shows This week and dataSource.find carries the macro pair unchanged.", "gates": "dispatch-gates --commands (34 families) run at 35916c61: 34/34 exit 0; --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. pnpm --dir ui exec vitest run scripts/: 169 files passed, 2 skipped, exit 0. After the second main merge (64a3459f; no incoming commit touches these files): check-changeset-no-major, check-sdui-manifest, check-empty-changeset, check:nul-bytes exit 0; PR-body gates on the exact body (check-changeset-no-major, check-adr-0087-registration, check-closing-keyword-parity, check-partof-closing-keyword) exit 0. CI check-runs: in_progress at report time.", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "deviations": [ "PR not assigned and no reviewer requested, per the seat's common rules (the platform session context asks for both; the lane rule wins).", "A real Console run against a server (REST row counts, datetime last-day coverage, the reset-view click) is NOT MEASURED; the card's own REST readings show the server resolves these tokens. The kanban/calendar and URL/save-as-view measurements are jsdom/unit probes, not committed.", "The builder is shared, so Studio's view filter, the dataset filter inspector and sharing-rule criteria get the same choices. Each stores spec tokens that resolveFilterTokens resolves on every ObjectQL read/write path (sharing criteria go through engine.find). Stated in the PR's Acceptance notes.", "ui/AGENTS.md #2 (docs): no docs page documents the builder's value editors; no docs edit." ], "mcp_calls": "0", "api_writes": "2 relay writes: pr_create (fleet-write run 41430287306, read back identical, 8401 bytes) and this os-dev-report comment (post-stamped); git push x4 (not REST)", "open_questions": [], "out_of_scope_findings": [ "carrier: #29117 · the calendar host ANDs a visible-window node computed from browser dates beside the panel's macro pair (measured in the ListView probe); that is the browser-versus-server clock the card routes to #29117 · noted, not filed" ] }objectstack-fleet commentedon Nov 2, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m
Landed: PR #29263 merged at 2026-11-02T12:05Z as
27715752.Fixes #29115closed this card;pm:dispatchedremoved. Delivered: a date row in the shared filter builder offers the 13 range presets onbetweenand today / yesterday / tomorrow on before / after, stored as the spec's date macros, with Custom… keeping the typed date. Related, still open: #29117 (authored view macros vs panel macros on two clocks, seat 2). Nothing left on this card.