Skip to content

Commit 71de060

Browse files
fix(plugin-calendar): a calendar opens on the date its calendar.initialDate declares (#28334)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} --> _Requested by **Tesla** · [project thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoLJGCL3hNmpJbWmkBbjD1pU)_ Fixes #28102 Clause-②: yes Metadata-protocol: none `Clause-②: yes` because the diff touches `packages/spec`: the `[PLANNED — not yet rendered]` marker leaves `CalendarConfigSchema.initialDate`'s describe, which is split one sentence per form (carry-forward 6537924895). The accepted set is unchanged: same pattern, same refusal, no key added or removed. ## 维护者速读 - 改了什么:日历视图现在按 `calendar.initialDate` 打开——日期宏(如 `{next_month_start}`)直接跳到对应日期,`first_record` / `next_record` 先查一条记录再跳到它所在的月/周/日;没写或查不到时仍是今天。列表视图和 ObjectView 两个生成日历节点的地方也把这个键传下去了。 - 为什么改:规范半边已声明这个键,但控制台从不读它;续约日历这种记录都在几个月后的视图,打开永远是空的当月。 - 风险与回滚:仅在声明了该键的日历上多一次一行查询,初始日期只在挂载时设一次,之后用户翻页说了算;回滚即 revert 本 PR,未声明该键的日历行为不变(有对照测试)。 - 先看:`ui/packages/plugin-calendar/src/ObjectCalendar.tsx`(seed 与 anchor 查询的 effect)、`ui/packages/plugin-calendar/src/initialDate.ts`(查询形状与 `next_record` 的今天边界)、`ui/packages/plugin-list/src/ListView.tsx`(calendarBlock 里新增的一行转发)。 - 两分钟验证:`pnpm --dir ui exec vitest run packages/plugin-calendar/src/ObjectCalendar.initialDate-28102.test.tsx`,预期 14 个用例全部通过。 - 需要你做的:无,席位落地。 ## What changes - **`ObjectCalendar` seeds its date from `calendar.initialDate`, once, on mount** (`ui/packages/plugin-calendar/src/initialDate.ts` holds the pure half): - absent ⇒ today, as before; - a wrapped date-macro token ⇒ the date `resolveDateMacros()` (`@object-ui/core`, the resolver filter values use) gives it, read in the `useState` initializer, so the first visible range the calendar reports to a windowing host is already the seeded one; - `first_record` / `next_record` ⇒ one one-row read from the same source the record fetch reads (the `object` provider's data source, or a `ValueDataSource` over inline rows), behind the same object-schema gate: the view's resolved `filter` AND a present start date (`first_record`) or a start date on or after the start of today (`next_record`), `$orderby` start field ascending, `$top: 1`. The `next_record` bound is spelled by the start field's declared type through the file's existing `toStoredDateValue`: a `date` field as the local calendar day, anything else as the instant of local midnight; - no qualifying record, no source to read, or a failed read (one `console.warn`) ⇒ today. The calendar shows the month, week or day of its active mode that holds the date. A navigation flag makes a late anchor answer a no-op once the user has navigated, and the seed flag is set when the answer lands, not when the read starts, so a re-run that discards an in-flight read asks again. - **Both producers forward the key.** `ListView`'s calendar branch (the `calendarBlock` literal) and `ObjectView`'s `generateViewSchema` calendar branch forward the block's keys by name, so `initialDate` died there and a stored list view never reached the renderer with it. Each now forwards it inside the node's `calendar` block (seat-approved surface extension). - **Spec:** the `[PLANNED — not yet rendered]` marker leaves `CalendarConfigSchema.initialDate`; the describe now reads an intro plus one sentence per form, and the TSDoc names the reader instead of promising one. `content/docs/references/ui/{component,view}.mdx` regenerated (`gen:docs`). - **Liveness:** `packages/spec/liveness/view.json`'s `calendar` row note now states `initialDate` as plain live, citing the renderer read and both producer forwards. - **ui-owned key copies kept in step:** the `object-calendar` / `calendar` registry `calendar` input description (it also lacked `allDayField`), the `list-view` registry `calendar` input description, and the hand-typed `calendar` options in `ui/packages/types/src/designer.ts`. `sdui.manifest.json`, its record and `content/docs/ui/components/plugins.mdx` regenerated. - **Changeset:** `.changeset/28102-calendar-opens-on-initial-date.md`, patch on the five packages moved. ## Tests - `ui/packages/plugin-calendar/src/ObjectCalendar.initialDate-28102.test.tsx` (14 rows): CONTROL — no key opens on today and issues no anchor read; `{next_month_start}` (and the first reported range already holds it); `{3_months_from_now}`; `first_record` opens on the read's date; the read's exact shape (`$top: 1`, `$orderby { due: 'asc' }`, `['and', VIEW_FILTER, ['due', 'is_not_null']]`); no record ⇒ today; failed read ⇒ today; inline `staticData` earliest dated row with an undated row skipped; `next_record` bound as a calendar day on a `date` field and as the local-midnight instant on a `datetime` field; inline past rows skipped; no record ahead ⇒ today; a navigation after the seed survives a re-render (one anchor read); an anchor answer landing after the user navigated is discarded. - `ui/packages/plugin-list/src/__tests__/ListView.calendarInitialDate-28102.test.tsx` and `ui/packages/plugin-view/src/__tests__/ObjectView.calendarInitialDate-28102.test.tsx` (4 rows each): each form reaches the node inside `calendar`, never flat; CONTROL — a block without the key carries none. ## Acceptance notes - **The anchor reads the view's authored `filter`, not toolbar filters or search.** That is the spec's wording ("the records the view's filter selects"); a user filter applied later does not re-seed, by the seed-once rule. - **A host that hands `data` down with no data source** (an embedded renderer) has nothing to read an anchor from, so it opens on today. Both console producers hand a data source down. - **`ListView`'s first window still assumes today** (`initialCalendarWindow` in `plugin-list/src/calendarWindow.ts`, and its comment says the hosted calendar opens on today). With a seeded date the calendar's first report differs from that window, so the list fetches once more for the seeded window: correct rows, one extra request. Left alone because it is outside this card's approved `ListView` lines; it is a cost note, not a defect. - **`next_record` with an undeclared field type** (an adapter with no `getObjectSchema`) bounds at the local-midnight instant; a date-only value compared against it as a string is still right east of UTC and drops today's records west of UTC. Declared `date` fields are bounded as days. - **Token resolution is the client resolver's.** A token the spec accepts that `resolveDateMacros` leaves unresolved opens on today rather than throwing; no such token was found. - Dedupe words: calendar initialDate renderer, ObjectCalendar currentDate seed, calendar first_record next_record. ## Verification Head `471be6e7` (includes a merge of `origin/main`); every reading below is on that tree unless it says pre-merge. <details><summary>Derived gates — 115 derived, 113 run green, 2 NOT MEASURED</summary> `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, every line run with stdin closed, exit codes recorded before any pipe; reconciled with `--ran`: `✓ dispatch-gates --ran: 115 derived famil(ies) accounted for — 113 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3).` - NOT MEASURED, prerequisite: `pnpm --filter @objectstack/spec run check:skill-examples` (needs `packages/client-react/dist`), `pnpm check:dual-build-cjs-loads` (needs a full `pnpm build`). Neither reads a file this diff touches; CI runs both. - `node scripts/check-plugin-teardown-shape.mjs --self-test` first refused (exit 3, shallow clone could not read its pinned fixture commit); after fetching that one commit it ran green (exit 0, 48 cases). - Post-merge re-runs on the merged tree: `check-sdui-manifest`, `check:sdui-reference`, `check:liveness`, `check:issue-citations`, `check:doc-authoring` all exit 0. </details> <details><summary>Tests and type-check</summary> - `pnpm --dir ui exec vitest run packages/plugin-calendar/ packages/plugin-list/src/__tests__/ListView.calendar packages/plugin-view/src/__tests__/ObjectView.calendar` on the merged tree: `Test Files 74 passed (74)`, `Tests 530 passed | 95 skipped (625)` (the skips are pre-existing in plugin-calendar). - Pre-merge: `pnpm --dir ui exec vitest run packages/plugin-list/src/__tests__/ListView.calendar packages/plugin-view/src/__tests__/ObjectView.calendar packages/types/` → `392 passed`; spec `src/ui/calendar-config-initial-date.test.ts src/ui/view.test.ts` → `537 passed`. - `pnpm --filter @object-ui/plugin-calendar --filter @object-ui/plugin-list --filter @object-ui/plugin-view --filter @object-ui/types run type-check` → all four `Done`, VERDICT command-exit 0. - `pnpm --filter @objectstack/spec build && check:generated` on the merged tree → `✓ All 14 generated artifacts are up to date`. - `node scripts/gen-sdui-manifest-node.mjs` + `node scripts/gen-sdui-reference.mjs` re-run on the merged tree. </details> <details><summary>Reverse verification — five ablations, direction predicted before running</summary> Each through `node scripts/ablation-replace.mjs` (anchor must hit; restore proven by blob == HEAD and an empty `git diff HEAD`). The tests import the source directly, so no build sits between the mutation and the run. - A — delete the `ListView` forward: 3 forward rows red, CONTROL green. - B — delete the `ObjectView` forward: 3 forward rows red, CONTROL green. - C — seed `useState` with `new Date()` only: the two macro rows red, 12 green. - D — drop `setCurrentDate(anchorDate)`: 5 anchor rows red (incl. the navigation-survives row, which waits for the seed), the shape / no-record / failure rows green. - E — drop the user-navigated guard: only the late-answer row red. </details> ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` passes. (Repo-wide lint is CI's run.) - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. - [x] 6. `packages/spec` touched: its generated artifacts are regenerated and committed. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English. - [x] The *Before Submitting* list in CONTRIBUTING.md is done. --- _Generated by [Claude Code](https://claude.ai/code/session_01L9qibxTJuzeiDxzGXxzFbe)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent d35db2c commit 71de060

18 files changed

Lines changed: 652 additions & 21 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
'@object-ui/plugin-calendar': patch
3+
'@object-ui/plugin-list': patch
4+
'@object-ui/plugin-view': patch
5+
'@object-ui/types': patch
6+
'@objectstack/spec': patch
7+
---
8+
9+
fix(plugin-calendar): a calendar opens on the date its `calendar.initialDate` declares
10+
11+
Clause-②: yes
12+
Metadata-protocol: none
13+
14+
`calendar.initialDate` is now read where `ObjectCalendar` seeds the date it opens on. Before, every calendar opened on today whatever the key said, so a renewals calendar whose records fall months ahead opened on an empty month.
15+
16+
- **Absent:** today, as before.
17+
- **A wrapped date-macro token** (`{today}`, `{next_month_start}`, `{3_months_from_now}`, …): the date the token resolves to when the calendar opens, through the same `resolveDateMacros` resolver filter values use.
18+
- **`first_record` / `next_record`:** one extra one-row read — the view's filter, plus a present start date (`first_record`) or a start date on or after the start of today (`next_record`), sorted by the start field ascending, one row — and the calendar opens on that record's start date. A `date` start field is bounded as a calendar day, any other as the instant of local midnight. No qualifying record, or a failed read, opens on today.
19+
20+
The calendar shows the month, week or day of its active mode that holds the date. The seed happens once, on mount: after it, the user's navigation owns the date, and an anchor answer that arrives after the user has navigated is discarded.
21+
22+
Both producers of the `object-calendar` node — a list view's calendar branch (`ListView`) and `ObjectView`'s generated calendar view — now forward `initialDate` inside the node's `calendar` block; before, they forwarded the block's five field bindings by name and dropped it. The `[PLANNED — not yet rendered]` marker is gone from `CalendarConfigSchema.initialDate`'s description, which now reads one sentence per form, and the `calendar` registry input descriptions of `object-calendar` and `list-view`, plus the designer's `calendar` options type, list the key.

‎content/docs/references/ui/component.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ const result = ActionButtonPropsSchema.parse(data);
503503
| **titleField** | `string` | optional | Field displayed as the event title. Omit to fall back to the record display name (ADR-0079 resolver chain) |
504504
| **colorField** | `string` | optional | Field to derive each event color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else the calendar theme-aware palette color hashed from the value |
505505
| **allDayField** | `string` | optional | Field carrying the all-day flag for each event (names a boolean field, not a value): a record whose flag is true is drawn as an all-day band rather than at a clock time, and one whose flag is absent or false is not all-day. Omit to leave the renderer inference in place — an event with no end date draws as all-day |
506-
| **initialDate** | `string` | optional | [PLANNED — not yet rendered] Where the calendar opens. No console reads it yet: until the calendar renderer reads it, a calendar that declares it still opens on today. Two forms. A record anchor: `first_record` opens on the period containing the earliest start date (the startDateField value) among the records the view's filter selects (its whole filter scope, not only the visible window), `next_record` on the period containing the earliest start date on or after today among those records; when no record qualifies, the calendar opens on today. "Today" is the viewer's local calendar day, and a `date` start field compares as a calendar day. Or a wrapped date-macro token, resolved each time the calendar opens: `{today}`, `{next_month_start}`, `{current_quarter_start}`, `{3_months_from_now}` (the full vocabulary is `DATE_MACRO_TOKENS` and the parameterised `DATE_MACRO_PARAM_RE` grammar in `@objectstack/spec/data`). Omit the key to open on today. The period is the month, week or day the active view mode shows. A fixed calendar date is not accepted: it goes stale as time passes, while a macro does not |
506+
| **initialDate** | `string` | optional | Where the calendar opens: the month, week or day the active view mode shows that holds this date; omit it to open on today. A record anchor: `first_record` opens on the earliest start date (the startDateField value) among the records the view's filter selects, `next_record` on the earliest on or after the viewer's today (a `date` start field compares as a calendar day), and either opens on today when no record qualifies. Or a wrapped date-macro token, resolved each time the calendar opens: `{today}`, `{next_month_start}`, `{current_quarter_start}`, `{3_months_from_now}` (the full vocabulary is `DATE_MACRO_TOKENS` and the parameterised `DATE_MACRO_PARAM_RE` grammar in `@objectstack/spec/data`); a fixed calendar date is not accepted, because it goes stale as time passes. |
507507

508508
### Nested Shape: `ObjectCalendarProps.filter[number]`
509509

‎content/docs/references/ui/view.mdx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ Appearance and visualization configuration
109109
| **titleField** | `string` | optional | Field displayed as the event title. Omit to fall back to the record display name (ADR-0079 resolver chain) |
110110
| **colorField** | `string` | optional | Field to derive each event color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else the calendar theme-aware palette color hashed from the value |
111111
| **allDayField** | `string` | optional | Field carrying the all-day flag for each event (names a boolean field, not a value): a record whose flag is true is drawn as an all-day band rather than at a clock time, and one whose flag is absent or false is not all-day. Omit to leave the renderer inference in place — an event with no end date draws as all-day |
112-
| **initialDate** | `string` | optional | [PLANNED — not yet rendered] Where the calendar opens. No console reads it yet: until the calendar renderer reads it, a calendar that declares it still opens on today. Two forms. A record anchor: `first_record` opens on the period containing the earliest start date (the startDateField value) among the records the view's filter selects (its whole filter scope, not only the visible window), `next_record` on the period containing the earliest start date on or after today among those records; when no record qualifies, the calendar opens on today. "Today" is the viewer's local calendar day, and a `date` start field compares as a calendar day. Or a wrapped date-macro token, resolved each time the calendar opens: `{today}`, `{next_month_start}`, `{current_quarter_start}`, `{3_months_from_now}` (the full vocabulary is `DATE_MACRO_TOKENS` and the parameterised `DATE_MACRO_PARAM_RE` grammar in `@objectstack/spec/data`). Omit the key to open on today. The period is the month, week or day the active view mode shows. A fixed calendar date is not accepted: it goes stale as time passes, while a macro does not |
112+
| **initialDate** | `string` | optional | Where the calendar opens: the month, week or day the active view mode shows that holds this date; omit it to open on today. A record anchor: `first_record` opens on the earliest start date (the startDateField value) among the records the view's filter selects, `next_record` on the earliest on or after the viewer's today (a `date` start field compares as a calendar day), and either opens on today when no record qualifies. Or a wrapped date-macro token, resolved each time the calendar opens: `{today}`, `{next_month_start}`, `{current_quarter_start}`, `{3_months_from_now}` (the full vocabulary is `DATE_MACRO_TOKENS` and the parameterised `DATE_MACRO_PARAM_RE` grammar in `@objectstack/spec/data`); a fixed calendar date is not accepted, because it goes stale as time passes. |
113113

114114

115115
---
@@ -918,7 +918,7 @@ View filter rule
918918
| **titleField** | `string` | optional | Field displayed as the event title. Omit to fall back to the record display name (ADR-0079 resolver chain) |
919919
| **colorField** | `string` | optional | Field to derive each event color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else the calendar theme-aware palette color hashed from the value |
920920
| **allDayField** | `string` | optional | Field carrying the all-day flag for each event (names a boolean field, not a value): a record whose flag is true is drawn as an all-day band rather than at a clock time, and one whose flag is absent or false is not all-day. Omit to leave the renderer inference in place — an event with no end date draws as all-day |
921-
| **initialDate** | `string` | optional | [PLANNED — not yet rendered] Where the calendar opens. No console reads it yet: until the calendar renderer reads it, a calendar that declares it still opens on today. Two forms. A record anchor: `first_record` opens on the period containing the earliest start date (the startDateField value) among the records the view's filter selects (its whole filter scope, not only the visible window), `next_record` on the period containing the earliest start date on or after today among those records; when no record qualifies, the calendar opens on today. "Today" is the viewer's local calendar day, and a `date` start field compares as a calendar day. Or a wrapped date-macro token, resolved each time the calendar opens: `{today}`, `{next_month_start}`, `{current_quarter_start}`, `{3_months_from_now}` (the full vocabulary is `DATE_MACRO_TOKENS` and the parameterised `DATE_MACRO_PARAM_RE` grammar in `@objectstack/spec/data`). Omit the key to open on today. The period is the month, week or day the active view mode shows. A fixed calendar date is not accepted: it goes stale as time passes, while a macro does not |
921+
| **initialDate** | `string` | optional | Where the calendar opens: the month, week or day the active view mode shows that holds this date; omit it to open on today. A record anchor: `first_record` opens on the earliest start date (the startDateField value) among the records the view's filter selects, `next_record` on the earliest on or after the viewer's today (a `date` start field compares as a calendar day), and either opens on today when no record qualifies. Or a wrapped date-macro token, resolved each time the calendar opens: `{today}`, `{next_month_start}`, `{current_quarter_start}`, `{3_months_from_now}` (the full vocabulary is `DATE_MACRO_TOKENS` and the parameterised `DATE_MACRO_PARAM_RE` grammar in `@objectstack/spec/data`); a fixed calendar date is not accepted, because it goes stale as time passes. |
922922

923923
### Nested Shape: `ListView.gantt`
924924

@@ -1289,7 +1289,7 @@ View filter rule
12891289
| **titleField** | `string` | optional | Field displayed as the event title. Omit to fall back to the record display name (ADR-0079 resolver chain) |
12901290
| **colorField** | `string` | optional | Field to derive each event color from (it names a field, not a color): the option color declared on that field for the record value, else the value itself when it already is a color literal (hex, rgb() or hsl()), else the calendar theme-aware palette color hashed from the value |
12911291
| **allDayField** | `string` | optional | Field carrying the all-day flag for each event (names a boolean field, not a value): a record whose flag is true is drawn as an all-day band rather than at a clock time, and one whose flag is absent or false is not all-day. Omit to leave the renderer inference in place — an event with no end date draws as all-day |
1292-
| **initialDate** | `string` | optional | [PLANNED — not yet rendered] Where the calendar opens. No console reads it yet: until the calendar renderer reads it, a calendar that declares it still opens on today. Two forms. A record anchor: `first_record` opens on the period containing the earliest start date (the startDateField value) among the records the view's filter selects (its whole filter scope, not only the visible window), `next_record` on the period containing the earliest start date on or after today among those records; when no record qualifies, the calendar opens on today. "Today" is the viewer's local calendar day, and a `date` start field compares as a calendar day. Or a wrapped date-macro token, resolved each time the calendar opens: `{today}`, `{next_month_start}`, `{current_quarter_start}`, `{3_months_from_now}` (the full vocabulary is `DATE_MACRO_TOKENS` and the parameterised `DATE_MACRO_PARAM_RE` grammar in `@objectstack/spec/data`). Omit the key to open on today. The period is the month, week or day the active view mode shows. A fixed calendar date is not accepted: it goes stale as time passes, while a macro does not |
1292+
| **initialDate** | `string` | optional | Where the calendar opens: the month, week or day the active view mode shows that holds this date; omit it to open on today. A record anchor: `first_record` opens on the earliest start date (the startDateField value) among the records the view's filter selects, `next_record` on the earliest on or after the viewer's today (a `date` start field compares as a calendar day), and either opens on today when no record qualifies. Or a wrapped date-macro token, resolved each time the calendar opens: `{today}`, `{next_month_start}`, `{current_quarter_start}`, `{3_months_from_now}` (the full vocabulary is `DATE_MACRO_TOKENS` and the parameterised `DATE_MACRO_PARAM_RE` grammar in `@objectstack/spec/data`); a fixed calendar date is not accepted, because it goes stale as time passes. |
12931293

12941294
### Nested Shape: `ObjectListView.gantt`
12951295

‎content/docs/ui/components/plugins.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Namespace `plugin-calendar`.
2121
| Input | Type | Required | Description |
2222
| :--- | :--- | :--- | :--- |
2323
| `objectName` | `string` | | ObjectQL object name. The record source is one of `data`, `staticData` and `objectName`; the `object-calendar` schema refuses a block that declares none of them, unless the node's `dataSource.object` names the object, which then lands on this key. |
24-
| `calendar` | `object` | | startDateField, endDateField, titleField, colorField |
24+
| `calendar` | `object` | | startDateField, endDateField, titleField, colorField, allDayField, initialDate (where the calendar opens: `first_record`, `next_record` or a date-macro token such as `{next_month_start}`; omitted, today) |
2525
| `filter` | `array` | | Base query filter — the `ViewFilterRule` array `[{ field, operator, value }, ...]`, narrowing the records the calendar fetches. Lowered to `$filter` on the query. |
2626
| `sort` | `array` | | Sort order in `[{ field, order }]` form, ordering the records the calendar fetches. Lowered to `$orderby` on the query. |
2727
| `defaultView` | `enum`: `month`, `week`, `day` | | The grid the calendar opens on. A narrow viewport downgrades `day` to `month`; the author’s choice is otherwise honoured on first render. |
@@ -312,7 +312,7 @@ Namespace `plugin-list`.
312312
| `bulkActions` | `array` of `string` | | Names of the actions offered once rows are selected. Needs a multi-row `selection`. |
313313
| `bulkActionDefs` | `array` of `object` | | Full bulk-action definitions, the spec's `BulkActionDef`: a mass update (`operation: "update"` with a `patch`) or delete, or a named action run once for the whole selection. |
314314
| `kanban` | `object` | | The board, the spec's kanban block: `{ groupByField, columns, titleField, summarizeField }`. `groupByField` is the lane field and `columns` the fields on each card. |
315-
| `calendar` | `object` | | The calendar, `{ startDateField, endDateField, titleField, colorField, allDayField }`. |
315+
| `calendar` | `object` | | The calendar, `{ startDateField, endDateField, titleField, colorField, allDayField, initialDate }`; `initialDate` is where it opens: `first_record`, `next_record` or a date-macro token such as `{next_month_start}`, today when omitted. |
316316
| `gantt` | `object` | | The gantt chart, `{ startDateField, endDateField, titleField, progressField, dependenciesField }`. Both date fields are needed to draw it. |
317317
| `gallery` | `object` | | The gallery, `{ coverField, titleField, visibleFields, cardSize, … }`. |
318318
| `timeline` | `object` | | The timeline, `{ startDateField, endDateField, titleField, groupByField, colorField, scale }`. |

‎packages/spec/liveness/view.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
},
106106
"calendar": {
107107
"status": "live",
108-
"note": "objectui: calendar-view-renderer.tsx:147 (audit L16). One key rides this blanket verdict at PLANNED strength, as `viewMode` does on the gantt row: `initialDate` (the date the calendar opens on: a record anchor first_record / next_record, or a wrapped date-macro token such as {today} or {next_month_start} resolved when the calendar opens; absent meaning today) is declared ahead of its reader — at this repo's `ui/` tree on 549203d040, ui/packages/plugin-calendar/src/ObjectCalendar.tsx#ObjectCalendar still seeds `currentDate` with `useState(new Date())` and reads no anchor. Amend this note to plain live, citing that read, when the console half lands. Read points of the `calendar` view-binding row in packages/spec/src/kernel/functional-completeness.ts (moved out of spec source, #23434), re-read at objectui @b9814b334 (2026-10-14): objectui @b9814b334 packages/plugin-list/src/ListView.tsx#ListView (its `case 'calendar'` arm restates only the bindings the view declared; the `startDateField || 'start_date'` / `endDateField || 'end_date'` floors were deleted by objectui#7029); objectui @b9814b334 packages/plugin-calendar/src/ObjectCalendar.tsx#getCalendarConfig returns `null` with neither a `calendar` block nor a flat `startDateField`, and the `if (!calendarConfig)` arm in objectui @b9814b334 packages/plugin-calendar/src/ObjectCalendar.tsx#ObjectCalendar renders the localised `calendar.configRequired` refusal naming `startDateField` (objectui#10101; `titleField` is not required, objectui#8170)."
108+
"note": "objectui: calendar-view-renderer.tsx:147 (audit L16). `initialDate` (the date the calendar opens on: a record anchor first_record / next_record, or a wrapped date-macro token such as {today} or {next_month_start}; absent meaning today) is live: ui/packages/plugin-calendar/src/ObjectCalendar.tsx#ObjectCalendar seeds `currentDate` from it once on mount, a token through `resolveDateMacros` and a record anchor through its own one-row read (ui/packages/plugin-calendar/src/initialDate.ts#recordAnchorQuery), and both producers of the `object-calendar` node (ui/packages/plugin-list/src/ListView.tsx#ListView, ui/packages/plugin-view/src/ObjectView.tsx#generateViewSchema) forward it inside the `calendar` block. Read points of the `calendar` view-binding row in packages/spec/src/kernel/functional-completeness.ts (moved out of spec source, #23434), re-read at objectui @b9814b334 (2026-10-14): objectui @b9814b334 packages/plugin-list/src/ListView.tsx#ListView (its `case 'calendar'` arm restates only the bindings the view declared; the `startDateField || 'start_date'` / `endDateField || 'end_date'` floors were deleted by objectui#7029); objectui @b9814b334 packages/plugin-calendar/src/ObjectCalendar.tsx#getCalendarConfig returns `null` with neither a `calendar` block nor a flat `startDateField`, and the `if (!calendarConfig)` arm in objectui @b9814b334 packages/plugin-calendar/src/ObjectCalendar.tsx#ObjectCalendar renders the localised `calendar.configRequired` refusal naming `startDateField` (objectui#10101; `titleField` is not required, objectui#8170)."
109109
},
110110
"gantt": {
111111
"status": "live",

0 commit comments

Comments
 (0)