Skip to content

List filter panel: offer relative dates on date rows — 本周 and 今天 today store a fixed date, so a saved filter silently goes wrong #29115

Closed

Description

@objectstack-fleet

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. :1183 shows value: '{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

  1. On a date or datetime row of the list filter panel, between offers the spec's DATE_RANGE_PRESETS (all 13, in spec order) beside a custom option that keeps today's two date inputs.
  2. before and after offer today, yesterday and tomorrow beside a fixed date.
  3. 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 spec ViewFilterRule.
  4. 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.
  5. The value survives unchanged through uf__filter, the stored preference and 「保存为视图」.
  6. 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:

Acceptance

  • Choosing 本周 on a date between row sends ['{week_start}', '{week_end}'], and the rows match the same REST query. On a datetime column, the last day is covered to its end.
  • Choosing 今天 on before sends '{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 value is 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

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    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.

    • Read fresh. The fix lands in the list filter panel's date value editor in ui/packages/components/src/custom/filter-builder.tsx (reading the spec's DATE_RANGE_PRESETS, with at most a small reverse-lookup helper beside packages/spec/src/data/date-range-presets.ts), so domain:ui. It is p2 as a user-visible feature: the card adds no operator, metadata key or configuration, so the protocol-addition p1 rule does not apply. The maintainer ruled it as its own card to merge before the first execution card of [Decision] Named personal list views: can a reader save their own named list, and what is the end state? #28971, with named locations and acceptance, so pm:queue.

    Generated by Claude Code

  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    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 session session_01QsR2jV4dWohojjbTJTQq5m
    Account: zhuangjianguo
    Branch: claude/project-thread-bga9c5 (platform-assigned to the card thread; it can push only this branch)
    Worktree: objectstack-issue-29115
    Domain: domain:ui
    Seat: domain:ui#3
    File surface: ui/packages/components/src/custom/filter-builder.tsx and helpers beside it in ui/packages/components/src/custom/, the i18n packs ui/packages/i18n/src/locales/*.ts only for labels the dashboard keys don't cover, their tests, and a changeset (stop on breach; explain in the report). No packages/spec edit without a claim amendment first.
    Container & model: M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: 6572558418
    Premise: holds (at origin/main c44c8ac4: DATE_RANGE_PRESETS and DATE_RANGE_PRESET_MACRO_WINDOWS are exported from packages/spec/src/data/date-range-presets.ts via data/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.

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    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"
      ]
    }
  4. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m

    Landed: PR #29263 merged at 2026-11-02T12:05Z as 27715752. Fixes #29115 closed this card; pm:dispatched removed. Delivered: a date row in the shared filter builder offers the 13 range presets on between and 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchdomain:uienhancementNew feature or requestpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions