@object-ui/plugin-detail 5.0.2 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/CHANGELOG.md +299 -0
  2. package/README.md +74 -0
  3. package/dist/index.js +1639 -1131
  4. package/dist/index.umd.cjs +3 -3
  5. package/dist/packages/plugin-detail/src/ActivityTimeline.d.ts.map +1 -1
  6. package/dist/packages/plugin-detail/src/ConcurrentUpdateDialog.d.ts +43 -0
  7. package/dist/packages/plugin-detail/src/ConcurrentUpdateDialog.d.ts.map +1 -0
  8. package/dist/packages/plugin-detail/src/DetailSection.d.ts.map +1 -1
  9. package/dist/packages/plugin-detail/src/DetailTabs.d.ts.map +1 -1
  10. package/dist/packages/plugin-detail/src/DetailView.d.ts.map +1 -1
  11. package/dist/packages/plugin-detail/src/HeaderHighlight.d.ts.map +1 -1
  12. package/dist/packages/plugin-detail/src/RecordActivityTimeline.d.ts +11 -1
  13. package/dist/packages/plugin-detail/src/RecordActivityTimeline.d.ts.map +1 -1
  14. package/dist/packages/plugin-detail/src/RecordChatterPanel.d.ts +17 -0
  15. package/dist/packages/plugin-detail/src/RecordChatterPanel.d.ts.map +1 -1
  16. package/dist/packages/plugin-detail/src/RichTextCommentInput.d.ts +7 -0
  17. package/dist/packages/plugin-detail/src/RichTextCommentInput.d.ts.map +1 -1
  18. package/dist/packages/plugin-detail/src/extractMentions.d.ts +27 -0
  19. package/dist/packages/plugin-detail/src/extractMentions.d.ts.map +1 -0
  20. package/dist/packages/plugin-detail/src/index.d.ts +6 -1
  21. package/dist/packages/plugin-detail/src/index.d.ts.map +1 -1
  22. package/dist/packages/plugin-detail/src/renderers/record-chatter.d.ts.map +1 -1
  23. package/dist/packages/plugin-detail/src/renderers/record-details.d.ts.map +1 -1
  24. package/dist/packages/plugin-detail/src/renderers/record-path.d.ts.map +1 -1
  25. package/dist/packages/plugin-detail/src/renderers/record-reference-rail.d.ts +33 -0
  26. package/dist/packages/plugin-detail/src/renderers/record-reference-rail.d.ts.map +1 -0
  27. package/dist/packages/plugin-detail/src/synth/buildDefaultPageSchema.d.ts +23 -1
  28. package/dist/packages/plugin-detail/src/synth/buildDefaultPageSchema.d.ts.map +1 -1
  29. package/dist/packages/plugin-detail/src/useDetailTranslation.d.ts.map +1 -1
  30. package/package.json +12 -12
package/CHANGELOG.md CHANGED
@@ -1,5 +1,304 @@
1
1
  # @object-ui/plugin-detail
2
2
 
3
+ ## 5.2.1
4
+
5
+ ## 5.2.0
6
+
7
+ ### Minor Changes
8
+
9
+ - 7c441f5: End-to-end @-mention notifications.
10
+
11
+ `@object-ui/plugin-detail` now exports `extractMentions(text, suggestions)`
12
+ — a small utility that resolves `@<label>` tokens in a comment body to
13
+ user ids, using the same suggestion list that drives the in-editor
14
+ dropdown. Handles labels with spaces ("@QA Test"), CJK ("@王小明"),
15
+ longest-match disambiguation ("Anna Lee" wins over "Anna"), and ignores
16
+ unknown @-tokens. 9 unit tests.
17
+
18
+ `@object-ui/app-shell` `RecordDetailView` now:
19
+ 1. Serializes the resolved mention ids into `sys_comment.mentions`
20
+ (previously hard-coded `'[]'`, so servers had no idea who was being
21
+ pinged).
22
+ 2. Fan-outs a `sys_notification` row per mentioned recipient
23
+ (self-mentions are filtered as noise) with the canonical bell-inbox
24
+ shape: `type: 'mention'`, `recipient_id`, `actor_name`, `title`,
25
+ `body` preview (≤140 chars), `source_object`/`source_id`/
26
+ `source_comment_id`, `is_read: false`, `created_at`.
27
+
28
+ The notification write tolerates 404 silently, so deployments without
29
+ a notification collection degrade to the previous behavior (mention
30
+ text + highlight, no inbox row). Spec-compliant servers that emit
31
+ notifications via their own sys_comment after-create hook can ignore
32
+ the client-side write — the bell de-dupes by id at the polling layer.
33
+
34
+ - 70b5570: `record:path` now distinguishes won/lost terminal stages. Stages can opt
35
+ in via the new `terminal: 'won' | 'lost'` property on each stage entry,
36
+ and the renderer also falls back to a value/label heuristic (matches
37
+ `closed_lost`, `lost`, `failed`, `cancelled`, `失败`, `流失`, `丢单`, etc.)
38
+ so existing CRM-style picklists get the treatment without migration.
39
+ - **Lost** stages render in a visually separated group with a left
40
+ border, destructive (red) tint, pill shape, and `✗` glyph — mirroring
41
+ the Salesforce / HubSpot alt-terminus pattern that signals "this
42
+ breaks the forward path, not steps past it."
43
+ - **Won** terminus (the last stage of the forward chevron) gets a subtle
44
+ emerald wash + 🏆 glyph to read as "the goal," even before the record
45
+ reaches it.
46
+ - Mobile pill row distinguishes lost via color, since the layout doesn't
47
+ have room to fork the row.
48
+
49
+ - 3216f8a: `buildDefaultPageSchema` now accepts a `slots.rightRail` override that
50
+ contributes nodes to the aside (right-rail) region. The aside region is
51
+ emitted whenever either the auto-detected reference rail OR
52
+ `slots.rightRail` is non-empty (previously: only when 2+ related lists
53
+ were declared). Slot contributions are appended after the canonical
54
+ `record:reference_rail` so the "related summary" stays anchored at the
55
+ top while plugins can drop activity feeds, workflow status cards,
56
+ presence lists, etc. beneath it.
57
+
58
+ No change for existing schemas — the aside region only renders if
59
+ something opts in.
60
+
61
+ ### Patch Changes
62
+
63
+ - a3cb88f: CRM UX polish batch:
64
+ - Kanban columns: drop the per-column rainbow top stripe. Lane border + header divider are sufficient; cards are now the loudest thing on screen (Linear / HubSpot pattern).
65
+ - Stage chevron (`record:path`): bump completed-stage contrast (emerald-800 text on emerald-500/15, was 700 on /10) and future-stage text from `foreground/70` to `foreground/85` for legibility.
66
+ - i18n: add `notifications.emptyUnread`, `notifications.filterUnread`, `notifications.filterAll` (en + zh) so the InboxPopover Unread/All sub-filter renders in the active locale.
67
+ - 5425608: CRM UX polish pass — calmer enterprise look across detail + kanban.
68
+ - **plugin-kanban**: column headers now use a 2px muted accent stripe with
69
+ neutral foreground titles + a quiet grey count pill instead of full
70
+ rainbow gradient + colored title + colored count. Pipeline boards
71
+ (Opportunity, Case, Task, Lead) look like Salesforce/Linear instead of
72
+ a toy. WIP-limit overflow remains destructive-red so urgency stays loud.
73
+ - **plugin-detail (`record:reference_rail`)**: new `hideEmpty` prop
74
+ (default true) collapses entries whose total === 0 into a single
75
+ `+ N empty (Quotes · Products …)` chip at the bottom of the rail.
76
+ Removes the 4–7 "No records" stack that dominated the aside.
77
+ - **plugin-detail (`record:path`)**: completed stages now render with an
78
+ emerald-tinted background + bold green check instead of low-contrast
79
+ `bg-muted text-muted-foreground` (which read as "light grey on white"
80
+ and was borderline unreadable).
81
+ - **app-shell (`RecordDetailView`)**: record-not-found short-circuit.
82
+ Previously a stale/missing recordId still rendered the page chrome
83
+ (rail, discussion, breadcrumb with the raw id), making invalid links
84
+ look like a partially broken page. Now renders a clean centered
85
+ `Empty` state with database icon + i18n'd "Record not found" copy.
86
+ - **i18n**: added `detail.showEmptyRelated_{one,other}` and
87
+ `empty.recordNotFound{,Description}` keys (en + zh).
88
+
89
+ - 5633edd: feat(detail,grid): tab + selection motion polish
90
+
91
+ **plugin-detail**
92
+ - `DetailTabs` and the auto-tabs path in `DetailView` (5 inline
93
+ `<TabsContent>` instances: details, related, activity, discussion,
94
+ history) now fade in when their tab becomes active, eliminating
95
+ the harsh flash when switching tabs.
96
+
97
+ **plugin-grid**
98
+ - `BulkActionBar` slides in from the bottom + fades in when a
99
+ selection is made, instead of popping into existence.
100
+ - The "N items selected" counter re-animates on every count change
101
+ (re-keyed on the count value with a small `zoom-in-90`), so users
102
+ see clear feedback as they tick/untick rows. `tabular-nums` keeps
103
+ the number from jittering during the animation.
104
+
105
+ All animations are wrapped in `motion-safe:` so prefers-reduced-motion
106
+ users keep the original instant UI. No new deps.
107
+
108
+ **Dialog / Sheet motion audit (informational, no code change)**
109
+
110
+ Verified `packages/components/src/ui/{dialog,alert-dialog,sheet}.tsx`:
111
+ Dialog + AlertDialog use a consistent `duration-200`. Sheet uses an
112
+ asymmetric `open:500ms / close:300ms` — this is the intentional
113
+ shadcn upstream default ("slower open feels purposeful"). No fixes
114
+ needed; these primitives live in the no-touch zone anyway.
115
+
116
+ - e919433: Stop silently assuming USD when a currency field has no `currency`
117
+ configured. For non-USD orgs (e.g. a CNY-based CRM seeded without an
118
+ explicit currency) the cells now render as plain locale-formatted
119
+ numbers (`150,000.00`) instead of `$150,000.00` — which was the #1
120
+ "why is my RMB showing as dollars?" bug.
121
+
122
+ Behavior change is opt-in via omission: when `currency` /
123
+ `defaultCurrency` is set on the field/column, formatting is unchanged.
124
+
125
+ Fixed call sites:
126
+ - `@object-ui/fields`: `formatCurrency`, `formatCompactCurrency`, and
127
+ `CurrencyCellRenderer` no longer default-param `'USD'`.
128
+ - `@object-ui/i18n`: `formatCurrency()` falls back to `formatNumber`
129
+ semantics when `currency` is omitted.
130
+ - `@object-ui/plugin-grid`: column-summary formatter (`Sum: 5,000,000`
131
+ instead of `Sum: $5,000,000.00`).
132
+ - `@object-ui/plugin-detail`: header-highlight currency formatter.
133
+ - `@object-ui/plugin-dashboard`: `ObjectMetricWidget` inferred
134
+ currency now resolves to `undefined` (not `'USD'`) for un-tagged
135
+ fields, so `MetricWidget`'s `isCurrency` heuristic falls through
136
+ to plain number formatting.
137
+
138
+ ## 5.1.1
139
+
140
+ ## 5.1.0
141
+
142
+ ### Minor Changes
143
+
144
+ - d1ec6a2: Fold inline-edit into the page-header overflow menu (HubSpot/Lightning
145
+ pattern) and remove the orphan "Edit fields" toolbar row that previously
146
+ floated between the tab strip and the first detail section.
147
+ - `@object-ui/app-shell` `RecordDetailView`: injects a new `sys_inline_edit`
148
+ system action that appears in the ⋯ overflow menu and dispatches a
149
+ `objectui:record:inline-edit-toggle` window CustomEvent (filtered by
150
+ recordId + objectName).
151
+ - `@object-ui/plugin-detail` `DetailView`: listens for that event to
152
+ toggle inline-edit mode; the in-page toolbar now renders only during
153
+ active editing / save error / locked states, so the idle layout flows
154
+ tabs → first section card with no orphan row.
155
+ - `@object-ui/components` layout containers: extended `KNOWN_LABEL_DICT`
156
+ with zh-CN + zh-TW translations for common CRM related-list labels
157
+ (Quotes / Products / Contacts / Accounts / Leads / Opportunities /
158
+ Cases / Campaigns / Approvals / Documents / Emails / Calls / Meetings
159
+ / Open Tasks / Closed Tasks), so authored English labels auto-translate
160
+ in `page:accordion` / `page:tabs` items.
161
+
162
+ - cf30cc2: Polish Lightning record detail page layout.
163
+ - `record:details` sections now render with Card chrome by default when a `title` is present, restoring visual grouping that was missing on pages like the opportunity detail page.
164
+ - Section labels can be translated via the `{ns}.objects.{objectName}._sections.{name}.label` convention. Author each section with a stable `name` (e.g. `info`, `forecast`) and the renderer picks up the locale-specific label automatically. Falls back to the literal `label` when no translation exists.
165
+ - The `page:header` action toolbar now collapses into a `⋯` overflow menu when more than two actions are present. The first business action stays inline; secondary system actions (Edit / Share / Delete) move into the menu, with destructive styling applied to Delete.
166
+ - Header action labels resolve via the `{ns}.objects.{objectName}._actions.{name}.label` convention.
167
+ - Removed the meaningless field-count Badge from collapsible section headers (the `2` chip next to "Description"). Field-count metadata wasn't useful in the header and added visual noise.
168
+ - Synth-path `sys_delete` now carries `variant: 'destructive'` so the overflow menu can color it appropriately.
169
+
170
+ - 32306e8: feat(plugin-detail): conflict-resolution dialog for OCC
171
+
172
+ When inline record-detail edits race a concurrent writer, the bound
173
+ DataSource now raises `ConcurrentUpdateError` (HTTP 409
174
+ `CONCURRENT_UPDATE`). `RecordDetailsRenderer` catches it and opens a
175
+ new `<ConcurrentUpdateDialog>` showing the user's pending value next
176
+ to the server's current value, with three resolution paths:
177
+ - **Reload latest** — discard the pending edit and refetch.
178
+ - **Overwrite anyway** — retry against the server's freshest version
179
+ (still OCC-checked, but acknowledges "I've seen the newer version").
180
+ - **Cancel** — close the dialog and leave the form untouched.
181
+
182
+ The renderer now forwards `record.updated_at` as `{ ifMatch }` to
183
+ `dataSource.update()`, so the server can detect stale writes. The
184
+ component is re-exported as `ConcurrentUpdateDialog` /
185
+ `isConcurrentUpdateError` from `@object-ui/plugin-detail` for hosts
186
+ that need to surface the same UX from custom save paths.
187
+
188
+ End-to-end OCC requires `@objectstack/client@>=4.2.0` (now wired) and
189
+ backend support in `@objectstack/rest@>=4.2.0`.
190
+
191
+ - 49b1760: Polish the ConcurrentUpdateDialog and add i18n.
192
+ - Internationalise all dialog strings (title, body, button labels, "your edit" / "current value" headings, audit-trail line) through `useDetailTranslation`. Locale strings added to `@object-ui/i18n` for English and Chinese.
193
+ - Replace the plain dialog header with an amber warning badge + `AlertTriangle` icon to communicate that this is a conflict, not a routine confirmation.
194
+ - Visually differentiate the two value blocks: amber tint for the user's pending edit, sky tint for the server's current value. Both wrap long values cleanly.
195
+ - Surface audit provenance for the racer's write (`updated_at`, plus `updated_by_name`/`updated_by_label` when supplied). Opaque ID-looking `updated_by` tokens are suppressed.
196
+ - Re-prioritise the action buttons: **Reload latest** is now the primary/recommended action (autofocused), **Overwrite anyway** is rendered as a destructive-outline button so the dangerous path requires deliberate intent, and **Cancel** falls back to a ghost variant.
197
+
198
+ - 8fd863e: Platform highlight + list polish:
199
+ - **deriveHighlightFields**: extended the preferred-field list (close_date, due_date, account, contact, …) and now skips fields whose declared type is not "highlight-friendly" (textarea, markdown, json, boolean, rich-text, etc.). Untyped legacy fields still pass through. Prevents long-form/structural fields from ending up in the highlight strip on objects with sparse metadata.
200
+ - **ListView bulk-action labels**: bulk-action buttons now resolve their labels through `actionLabel(objectName, action, fallback)` so they pick up app-supplied translations under `_actions.<name>.label`, matching the detail-page page-header overflow menu. Falls back to the previous title-cased string when no resource is found.
201
+
202
+ ### Patch Changes
203
+
204
+ - bd8447d: Three platform-wide detail polish items.
205
+
206
+ **Tighter page rhythm**
207
+ - Outer `PageRenderer` padding `p-4 md:p-6 lg:p-8` → `p-3 md:p-4 lg:p-6`
208
+ and outer body wrap `space-y-8` → `space-y-6` so list / detail / home
209
+ pages share the same edge rhythm. Cuts ~16px of edge slack on lg.
210
+
211
+ **Highlights KPI treatment**
212
+ - `HeaderHighlight` now renders numeric / currency / percent / decimal
213
+ values as KPI numbers (`text-xl md:text-2xl font-semibold tabular-nums`)
214
+ instead of the uniform `text-sm font-semibold`, so amount / probability
215
+ / count fields read as headline stats — Salesforce-style key facts.
216
+
217
+ **Discussion footer upgrade**
218
+ - `RecordActivityTimeline` now uses `RichTextCommentInput` (bold / italic /
219
+ list / code, `@`-mention autocomplete, preview toggle, Send) instead of
220
+ a bare `<textarea>`.
221
+ - `DiscussionContext` gains an optional `mentionSuggestions` array that
222
+ hosts can wire (e.g. team member directory). Falls back to free-text
223
+ `@mention` when omitted.
224
+ - `RecordChatterPanel` threads `mentionSuggestions` through both inline
225
+ and sidebar positions.
226
+
227
+ - fbd5052: Tighten record-detail visual rhythm. Section card titles were rendering at
228
+ Shadcn's default `text-2xl` which dominated the page; the related-list
229
+ accordion in flush mode dropped all per-item borders so the collapsed
230
+ "Quotes / Products / Open Tasks" triggers stacked with zero visual
231
+ separation.
232
+ - `@object-ui/plugin-detail` `DetailSection`: override the `CardTitle`
233
+ className to `text-base font-semibold tracking-tight`, slim down
234
+ `CardHeader` padding (`py-3 px-4 sm:py-4 sm:px-6`) and `CardContent`
235
+ vertical padding so titles + content read as a single tight block
236
+ rather than a billboard. Demoted the section description from `text-sm
237
+ mt-1.5` to `text-xs mt-1` for the same reason.
238
+ - `@object-ui/components` `PageAccordionRenderer`: in the default
239
+ `flush` variant restore a subtle `border-b last:border-b-0` divider
240
+ between accordion items so collapsed siblings get a separator, and
241
+ style the trigger as `text-sm font-semibold tracking-tight
242
+ hover:no-underline` (Shadcn's hover-underline default looks busy on
243
+ CRM-style related-list lists).
244
+
245
+ - d51a577: feat(platform): Discussion attachments + @mention directory + Reference Rail aside
246
+ - **Discussion attachments** — `RichTextCommentInput` now accepts an `extraSlot`
247
+ and a `canSubmitEmpty` flag so hosts can mount the existing
248
+ `CommentAttachment` composer beneath the editor without forking the toolbar.
249
+ `RecordActivityTimeline` plumbs the attachments through
250
+ `DiscussionContext.onUploadAttachments` and submits attachment-only comments.
251
+ - **@mention directory** — `DiscussionContext` gains a `mentionSuggestions`
252
+ field; `RecordDetailView` populates it from the host `sys_user` collection so
253
+ `@` autocomplete in the composer now resolves against real users.
254
+ - **Reference Rail** — New `record:reference_rail` renderer + a dedicated
255
+ `aside` region emitted by `buildDefaultPageSchema` whenever a record has
256
+ ≥ 2 related lists. The rail surfaces a Salesforce/HubSpot-style snapshot
257
+ of related collections (count badge + top 3 records) on `xl+` viewports.
258
+ - **Layout** — `PageRenderer`'s structured-layout `<aside>` wrappers now honor
259
+ `aside.className`, letting schemas attach responsive utilities like
260
+ `hidden xl:flex` to the rail region.
261
+
262
+ - a49f300: feat(detail): per-object Reference Rail opt-out via `objectDef.detail.hideReferenceRail`
263
+
264
+ The Record-detail Reference Rail (right-hand related-list summary cards)
265
+ can now be suppressed on a per-object basis without authoring a full
266
+ custom `Page`. Catalog-style objects (Product, Task) ship with the rail
267
+ off by default; hub objects (Account, Opportunity, Contact, Case) keep it
268
+ on.
269
+ - `RecordDetailView` now reads `(objectDef as any)?.detail?.hideReferenceRail`
270
+ and `…?.hideRelatedTab` and threads them to `buildDefaultPageSchema`.
271
+ - The Reference Rail renderer also accepts entries authored as either a
272
+ flat `entries` array or nested under `properties.entries`, so explicit
273
+ `Page` authors can opt-in via the standard spec shape.
274
+ - See `packages/plugin-detail/README.md` (Reference Rail decision matrix)
275
+ for the rationale and per-object guidance.
276
+
277
+ - 1cb6e21: feat(plugin-detail): suppress Related tab when Reference Rail is auto-emitted
278
+
279
+ When `buildDefaultPageSchema` decides to emit the Reference Rail (≥ 2
280
+ related lists), the duplicate `Related` tab is now suppressed by
281
+ default. The same data appeared in both places before, which is
282
+ visually noisy and risks confusing users when one surface refreshes
283
+ out-of-step with the other.
284
+
285
+ Behavior matches HubSpot / Microsoft Dynamics: the rail is the single
286
+ source of truth for related-list snapshots, and each rail card now
287
+ exposes a `View all` link that deep-links into the child object's
288
+ filtered list view. Authors can opt back into both surfaces via the
289
+ new `hideRelatedTab: false` option.
290
+
291
+ The change is gated on the same `≥ 2` heuristic that emits the rail,
292
+ so single-related-list pages keep the inline Related tab (where the
293
+ rail wouldn't have helped anyway).
294
+
295
+ - d548d6b: Unify empty-state visuals across timeline + registered `empty` renderer.
296
+ - `RecordActivityTimeline` and `ActivityTimeline` now use `DataEmptyState`
297
+ instead of a bare `<p>` so empty timelines match list/related-list visuals
298
+ (muted icon badge + centered copy).
299
+ - The `ui:empty` schema renderer now delegates to `DataEmptyState`, giving
300
+ schema-driven empty regions the same chrome as ad-hoc consumers.
301
+
3
302
  ## 5.0.2
4
303
 
5
304
  ## 5.0.1
package/README.md CHANGED
@@ -212,6 +212,80 @@ Displays related records in list, grid, or table format.
212
212
  - 🤝 [Contributing Guide](https://github.com/objectstack-ai/objectui/blob/main/CONTRIBUTING.md)
213
213
  - 🗺️ [Roadmap](https://github.com/objectstack-ai/objectui/blob/main/ROADMAP.md)
214
214
 
215
+ ## Reference Rail decision matrix
216
+
217
+ The "Reference Rail" is the right-hand column on the record detail page
218
+ that surfaces summary cards for related collections (similar to
219
+ Salesforce's **Related** rail and HubSpot's **About this record**
220
+ sidebar). It is rendered by the `record:reference_rail` component and
221
+ emits automatically when:
222
+
223
+ 1. The page is generated by the synth (`buildDefaultPageSchema`) — i.e.
224
+ no explicit `Page` overrides the object's detail view.
225
+ 2. The objectDef declares **≥2 related collections** (lookup/master-detail
226
+ inbound fields).
227
+ 3. The viewport is **≥ xl (1280 px)** — below that the rail collapses and
228
+ the **Related** tab keeps full coverage.
229
+ 4. The objectDef does **not** opt out via `detail.hideReferenceRail`.
230
+
231
+ When the rail emits, the synth automatically suppresses the **Related**
232
+ tab so the same information isn't shown twice.
233
+
234
+ ### Per-object opt-out
235
+
236
+ Add a `detail` block to the objectDef:
237
+
238
+ ```ts
239
+ ObjectSchema.create({
240
+ name: 'product',
241
+ // …
242
+ detail: {
243
+ hideReferenceRail: true, // hide the rail; restore the Related tab
244
+ hideRelatedTab: true, // (optional) force-hide the Related tab too
245
+ },
246
+ });
247
+ ```
248
+
249
+ ### CRM business-domain guidance
250
+
251
+ | Object type | Rail | Why |
252
+ |--------------------|--------|--------------------------------------------------------------|
253
+ | Hub objects | **on** | Account / Opportunity / Contact / Case — users browse laterally to quotes, contacts, activities |
254
+ | Transactional | **on** | Quote / Contract / Order — show line-items + related parties at a glance |
255
+ | Campaign / Event | **on** | Members, responses, child campaigns |
256
+ | Catalog | **off**| Product / Price Book — users edit attributes; lateral relationships are noise |
257
+ | Atomic action | **off**| Task / Note — focused single-column edit beats a related-list rail |
258
+ | Lead (unconverted) | **off**| Pre-conversion records have no children — keep it focused on the form |
259
+
260
+ ### Adding the rail to a custom `Page`
261
+
262
+ For explicit (non-synth) Pages, add an `aside` region after the `main`
263
+ region:
264
+
265
+ ```ts
266
+ {
267
+ name: 'aside',
268
+ width: 'small',
269
+ className: 'hidden xl:flex flex-col gap-4',
270
+ components: [
271
+ {
272
+ type: 'record:reference_rail',
273
+ id: 'opp_reference_rail',
274
+ properties: {
275
+ entries: [
276
+ { objectName: 'quote', relationshipField: 'opportunity', title: 'Quotes', limit: 3 },
277
+ { objectName: 'opportunity_line_item', relationshipField: 'opportunity', title: 'Products', limit: 3 },
278
+ { objectName: 'task', relationshipField: 'related_to_opportunity', title: 'Open Tasks', limit: 3 },
279
+ ],
280
+ },
281
+ },
282
+ ],
283
+ },
284
+ ```
285
+
286
+ The renderer reads `entries` from both `schema.entries` and
287
+ `schema.properties.entries` so either spec-style or flat authoring works.
288
+
215
289
  ## License
216
290
 
217
291
  MIT — see [LICENSE](./LICENSE).