Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .changeset/27524-record-page-activity-i18n.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
'@object-ui/i18n': patch
---

feat(i18n)!: 「动态」 (Activity) names the record page's stream in all ten packs; the timeline column's two keys leave

Clause-②: yes (narrowing)
Metadata-protocol: none

<!-- adr-0087: not-required (runtime-interface-only ui/packages/i18n/src/locales/en.ts#TranslationKeys) the key type of the console's own translation catalogue: no Zod schema, no spec declaration and no stored metadata reads it, so the compiler is the channel that reaches every caller -->

The record page's stream is called 「动态」 in zh and "Activity" in en, in the record page's panel, its tab and the right-column switch's labels (record page v4).

- `detail.timeline` changes value in all ten packs: 动态 · Activity · アクティビティ · 활동 · Aktivität · Activité · Actividad · Atividade · Активность · النشاط.
- `detail.relatedColumn` now names the right column (「右栏」, "Right column"), and `console.shortcuts.toggleRelated` shows or hides it.
- `detail.timelineComposer` (the 动态 panel's one-line composer, 「写一条备注… @ 提到同事」) arrives in all ten packs.

**BREAKING** (`@object-ui/i18n`, TypeScript only): the exported `TranslationKeys` (`typeof en`) loses `detail.timelineFolded` and `console.shortcuts.toggleTimeline`, which named the retired timeline column and its shortcut. Both leave every pack. A `t()` call naming one still compiles, since its key is a `string`, and reads the key back. Nothing replaces them: the column is gone.
40 changes: 40 additions & 0 deletions .changeset/27524-record-page-tiers-activity-panel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
'@object-ui/plugin-detail': patch
'@object-ui/components': patch
'@object-ui/app-shell': patch
---

feat(plugin-detail)!: one record page laid out by its own width — details beside a right column from 760 px, one column below; 动态 is the right column's first panel; ⊟ shows or hides the right column

Clause-②: yes (narrowing)
Metadata-protocol: none

<!-- adr-0087: not-required (runtime-export-retired @object-ui/plugin-detail#RECORD_PAGE_THREE_COLUMN_MIN_WIDTH, @object-ui/plugin-detail#recordPageArrangementFor, @object-ui/plugin-detail#recordPageColumnDefaults, @object-ui/plugin-detail#recordTimelineDefaultReason, @object-ui/plugin-detail#RecordPageColumnSwitches, @object-ui/plugin-detail#RecordPageArrangement, @object-ui/plugin-detail#RecordPageObjectLike, @object-ui/plugin-detail#RecordTimelineDefaultReason, @object-ui/plugin-detail#DefaultPageColumns.relatedCount, @object-ui/plugin-detail#UseRecordPageTierOptions.embedded, @object-ui/plugin-detail#RecordPageColumnsProps.switches) the retired operands are the synthesized record page's layout helpers, their option and prop members, and the types they took, in a published ui package's entry that only the console's own record view imported; no packages/spec schema, no registered node type, no ADR-0087 conversion surface and no stored shape names them, so there is nothing for `objectstack migrate meta` to rewrite -->

The synthesized record page (record page v4) is laid out by one rule, the width of the container it occupies. The page, the split pane, the overlay drawer and the maximized pane all follow it.

- **At 760 px and wider**, the details sit beside a right column 320 px wide. **At 1120 px and wider** the right column is 380 px, a details section takes up to three field columns (two otherwise), and the 动态 panel shows five entries (three otherwise).
- **Below 760 px** (the split pane at 720 px, a phone) the page is ONE column: the details, then the right column's panels in their order.
- The three-column tier, the tabbed tier and the 「相关 N」 rail are gone, and so are the resident timeline column, its ⊞ switch and the per-object default that decided it.
- **动态** (formerly the timeline) is the first panel of the right column. It has the same header as a related panel: 「动态」 and the stream's count, and the header row opens the 动态 tab. Its body is a one-line composer (pressed, it opens the full composer, focused), the newest entries one line each, and 「查看全部 N 条」 when the stream holds more. The 动态 tab (`?related=timeline`) is the full stream: the 全部 · 活动 · 讨论 · 变更 chips, threaded replies, and "Load more" for the next page.
- **⊟** (「右栏」, `⌘⇧,`) is one icon at the end of the record header's action row, drawn only where the tier has a right column. Off, the details take the row. It keeps the reader's earlier related-column choice: the stored preference `record.columns.related` is unchanged. The record header's `PanelToggles` (`@object-ui/components`) now draws icon-only toggles named by their label.
- The 动态 panel is on screen at open in every tier, so a synthesized page reads its feed and its audit history at open. An authored page with tabs still waits for the tab that holds them.
- **Tab labels** (`page:tabs`, `@object-ui/components`). A synthesized page that keeps its tab strip (one the layout cannot partition) labels its stream tab `Activity stream`, which the strip reads as 「动态」. An authored `Timeline` tab, such as the served approval page's history, is no longer read as the record stream: it keeps the pack's own word for a timeline (「时间线」, タイムライン, and so on).

**BREAKING** (`@object-ui/plugin-detail`, TypeScript only). The only importer is the console's own record view. `RecordPageTier` is now `'stack' | 'two-column' | 'wide'`: there is no tabbed tier, and the widest tier is called `wide`. `recordPageTierFor(width)` takes no second argument. `useRecordPageTier` answers `null` only while the page is not laid out (disabled, or not yet measured). `RecordPageColumnsProps.tier` takes every `RecordPageTier`. A caller still naming a retired symbol gets a compile error that names it.

What leaves, and what to write instead:

- FROM `RECORD_PAGE_THREE_COLUMN_MIN_WIDTH` TO `RECORD_PAGE_WIDE_MIN_WIDTH`, the same 1120 px floor under its new name.
- FROM `recordPageArrangementFor` TO `recordPageTierHasRightColumn(tier)` and the reader's ⊟: every laid-out page is the details and, where the tier has room, the right column.
- FROM `recordPageColumnDefaults` TO no call: every object's page opens with its right column, and ⊟ defaults to on.
- FROM `recordTimelineDefaultReason` TO no call, for the same reason: no object decides a timeline column any more.
- FROM `RecordPageColumnSwitches` TO a `boolean`, the right column's switch.
- FROM `RecordPageArrangement` TO the `RecordPageTier` itself, read through `recordPageTierHasRightColumn`.
- FROM `RecordPageObjectLike` TO no type: no helper takes an object definition any more.
- FROM `RecordTimelineDefaultReason` TO no type, with `recordTimelineDefaultReason`.
- FROM `DefaultPageColumns.relatedCount` TO the length of `columns.related`; the rail it labelled is gone.
- FROM `UseRecordPageTierOptions.embedded` TO no option: an embedded page follows the same width rule.
- FROM `RecordPageColumnsProps.switches` TO `RecordPageColumnsProps.rightColumn`, one `boolean`.

`RECORD_PAGE_WIDE_MIN_WIDTH`, `recordPageTierHasRightColumn` and `RECORD_PAGE_TIMELINE_PANEL` (the 动态 tab's `?related=` id) are new.
60 changes: 30 additions & 30 deletions content/docs/ui/pages.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -180,33 +180,33 @@ replacement.
### The synthesized default

A record page needs no authoring. With no page assigned, the Console synthesizes one from
the object: a header, the highlights strip and a tab strip of **Details**, **Timeline** and
**Related**, plus **Approvals** when the record has approval requests. A relationship whose
child field declares `relatedList: 'primary'` is part of the record's body: its list is a
full-width table inside **Details**, after the first field section, with no tab of its own.
The other related lists are cards in the shared **Related** tab, which an object with
`enable: { files: true }` closes with its attachments. **Timeline** is one stream: the
discussion composer on top, then the discussion, the activity and, with
`enable: { trackHistory: true }`, the record's field changes, filtered by All / Activity /
Discussion / Changes; there is no separate History tab. Moving a child table into the
record's body is therefore a one-word change on the relationship field, not a
page-authoring task, and `relatedList: false` leaves a child off the page.

The Console lays the page out by the width of the surface it occupies (the drawer, the
split pane or the full page), never by the viewport. From 1280 px the tabs become three
columns: details, the timeline stream and the
related lists as cards with Approvals, Attachments and the created/updated line. From
1024 px the related column folds into a rail behind a **Related (N)** toggle. Below that, and
always in a drawer or split pane, the tab strip is drawn. `?tab=` selects a tab in the strip.

In the column tiers the related column loads in steps, and the details column never waits for
it. The page asks every card's count in one request set, sent beside the record read, and the
cards show placeholders until those counts land. A card counted at 0 is its title row alone
and reads no rows. A card above 0 reads its first three rows once it scrolls into view, asking
only for the record's name field and one status or date field. When the timeline column is
switched off, its **Activity** card in the related column stays closed, and reads nothing, until
it is opened. In a drawer, the record that **↑** / **↓** would show next has its related counts
read ahead.
the object: a header, the highlights strip, the record's **details**, and a right column of
panels: **动态** (Activity) first, then the related lists, **Approvals** when the record has
approval requests, and the attachments of an object with `enable: { files: true }`. A
relationship whose child field declares `relatedList: 'primary'` is part of the record's body:
its list is a full-width table in the details, after the first field section, with no panel of
its own. **动态** is one stream: the discussion, the activity and, with
`enable: { trackHistory: true }`, the record's field changes; there is no separate History tab.
Its panel shows a one-line composer and the newest entries, and its header opens the whole
stream (`?related=timeline`), filtered by All / Activity / Discussion / Changes. A related
panel's header opens that list's whole table the same way (`?related=<object>.<field>`).
Moving a child table into the record's body is therefore a one-word change on the
relationship field, not a page-authoring task, and `relatedList: false` leaves a child off the
page.

The Console lays the page out by the width of the surface it occupies (the full page, the split
pane or the drawer), never by the viewport, and by one rule. From 760 px the details sit beside
the right column, 320 px wide; from 1120 px the right column is 380 px and a details section
takes up to three field columns. Below 760 px (the split pane, a phone) the page is one column:
the details, then the right column's panels in their order. The **⊟** switch at the end of the
record header's actions (`⌘⇧,`) hides the right column for the reader, per object.

The related panels load in steps, and the details never wait for them. The page asks every
panel's count in one request set, sent beside the record read, and the panels show
placeholders until those counts land. A panel counted at 0 reads no rows, and two or more of
them fold into one line. A panel above 0 reads its first three rows once it scrolls into view,
asking only for the record's name field and one status or date field. In a drawer, the record
that **↑** / **↓** would show next has its related counts read ahead.

### Slotted pages

Expand All @@ -219,12 +219,12 @@ synthesizer fills in the rest. A slotted page authors `slots`, not `regions`:
| `actions` | The action bar (`record:quick_actions`) |
| `alerts` | The alert banners above the body |
| `highlights` | The highlights strip |
| `details` | The body of the Details tab; the other tabs stay synthesized |
| `details` | The record's details; the rest of the page stays synthesized |
| `discussion` | The discussion panel |

Each slot takes one component or an array of them, and replaces its part whole: there is no
deep merge. There is no `tabs` slot: the tab strip is composed from the object's fields and
relationship flags. To change which related lists appear or their order, set `relatedList` /
deep merge. There is no `tabs` slot: the page's panels are composed from the object's fields
and relationship flags. To change which related lists appear or their order, set `relatedList` /
`relatedList: 'primary'` on the child's reference field; a page that needs its own strip is
`kind: 'full'`, drawn as authored. `slots.tabs`, `slots.related` and `slots.relatedLists` are
refused by name, and `os migrate meta --from 17` drops a stored `slots.tabs`.
Expand Down
Loading
Loading