-
Notifications
You must be signed in to change notification settings - Fork 5
fix: add coerceToSafeValue to cell renderers at source, use getCellRenderer in HeaderHighlight #1040
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: add coerceToSafeValue to cell renderers at source, use getCellRenderer in HeaderHighlight #1040
Changes from all commits
d33c135
6181108
1d751d8
ebb6775
7cf936a
d6d17bb
23350ed
9e2b980
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1414,7 +1414,34 @@ All 313 `@object-ui/fields` tests pass. | |
|
|
||
| --- | ||
|
|
||
| ### DetailView Rendering Optimization (March 2026) | ||
| ### DetailView/RecordDetailView SDUI Optimization (March 2026) | ||
|
|
||
| > Type-aware rendering, responsive layout, virtual scrolling, metadata-driven highlights, performance optimization, and activity panel collapse-when-empty. | ||
|
|
||
| **HeaderHighlight (`@object-ui/plugin-detail`):** | ||
| - [x] Use `getCellRenderer` for type-aware display (currency → `$250,000.00`, select → Badge, etc.) instead of raw `String(value)` | ||
| - [x] Add `objectSchema` prop for field metadata enrichment (type, options, currency, precision, format) | ||
|
|
||
| **autoLayout (`@object-ui/plugin-detail`):** | ||
| - [x] `inferDetailColumns` accepts optional `containerWidth` for responsive column capping (`<640px→1col`, `<900px→max 2col`) | ||
| - [x] `applyDetailAutoLayout` passes through `containerWidth` parameter | ||
|
|
||
| **RecordChatterPanel (`@object-ui/plugin-detail`):** | ||
| - [x] `collapseWhenEmpty` prop: auto-collapse panel when no feed items exist | ||
| - [x] Pass `collapseWhenEmpty` through to embedded `RecordActivityTimeline` | ||
|
|
||
| **DetailSection (`@object-ui/plugin-detail`):** | ||
| - [x] `virtualScroll` config (`VirtualScrollOptions`): progressive batch rendering for sections with many fields | ||
| - [x] Export `VirtualScrollOptions` type from package index | ||
|
|
||
| **RecordDetailView (`apps/console`):** | ||
| - [x] Wrap `detailSchema` construction with `useMemo` (deps: `objectDef`, `pureRecordId`, `related`, `childRelatedData`, `actionRefreshKey`) | ||
| - [x] Remove hardcoded `HIGHLIGHT_FIELD_NAMES`; read exclusively from `objectDef.views.detail.highlightFields` (no fallback) | ||
| - [x] Enable `collapseWhenEmpty` + `collapsible: true` on `RecordChatterPanel` | ||
|
|
||
| **Tests:** 125 plugin-detail tests passing (17 new) covering HeaderHighlight type-aware rendering, autoLayout responsive columns, RecordChatterPanel collapseWhenEmpty, DetailSection virtualScroll. | ||
|
||
|
|
||
| --- | ||
|
|
||
| > Platform-level DetailView enhancements: auto-grouping from form sections, empty value hiding, smart header with primaryField/summaryFields, responsive breakpoint fix, and activity timeline collapse. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,9 +30,6 @@ interface RecordDetailViewProps { | |
|
|
||
| const FALLBACK_USER = { id: 'current-user', name: 'Demo User' }; | ||
|
|
||
| /** Field names automatically promoted to the highlight banner when present. */ | ||
| const HIGHLIGHT_FIELD_NAMES = ['status', 'stage', 'priority', 'category', 'type', 'owner', 'amount']; | ||
|
|
||
| export function RecordDetailView({ dataSource, objects, onEdit }: RecordDetailViewProps) { | ||
| const { objectName, recordId } = useParams(); | ||
| const { showDebug } = useMetadataInspector(); | ||
|
|
@@ -398,16 +395,8 @@ export function RecordDetailView({ dataSource, objects, onEdit }: RecordDetailVi | |
| }); | ||
| })(); | ||
|
|
||
| // Build highlightFields: prefer explicit config, fallback to auto-detect key fields | ||
| const explicitHighlight: HighlightField[] | undefined = objectDef.views?.detail?.highlightFields; | ||
| const highlightFields: HighlightField[] = explicitHighlight | ||
| ?? Object.entries(objectDef.fields || {}) | ||
| .filter(([key]: [string, any]) => HIGHLIGHT_FIELD_NAMES.includes(key)) | ||
| .map(([key, def]: [string, any]) => ({ | ||
| name: key, | ||
| label: def.label || key, | ||
| ...(def.type && { type: def.type }), | ||
| })); | ||
| // Build highlightFields: exclusively from objectDef metadata (no hardcoded fallback) | ||
| const highlightFields: HighlightField[] = objectDef.views?.detail?.highlightFields ?? []; | ||
|
|
||
| // Build sectionGroups from objectDef detail/form config if available | ||
| const sectionGroups: SectionGroup[] | undefined = | ||
|
|
@@ -421,7 +410,7 @@ export function RecordDetailView({ dataSource, objects, onEdit }: RecordDetailVi | |
| data: childRelatedData[childObject] || [], | ||
| })); | ||
|
|
||
| const detailSchema: DetailViewSchema = { | ||
| const detailSchema: DetailViewSchema = useMemo(() => ({ | ||
| type: 'detail-view', | ||
| objectName: objectDef.name, | ||
| resourceId: pureRecordId, | ||
|
|
@@ -443,7 +432,8 @@ export function RecordDetailView({ dataSource, objects, onEdit }: RecordDetailVi | |
| actions: recordHeaderActions, | ||
| } as any], | ||
| }), | ||
| }; | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }), [objectDef.name, pureRecordId, childRelatedData, actionRefreshKey]); | ||
|
Comment on lines
+435
to
+436
|
||
|
|
||
| return ( | ||
| <div className="h-full bg-background overflow-hidden flex flex-col relative"> | ||
|
|
@@ -482,13 +472,14 @@ export function RecordDetailView({ dataSource, objects, onEdit }: RecordDetailVi | |
| <RecordChatterPanel | ||
| config={{ | ||
| position: 'bottom', | ||
| collapsible: false, | ||
| collapsible: true, | ||
| feed: { | ||
| enableReactions: true, | ||
| enableThreading: true, | ||
| showCommentInput: true, | ||
| }, | ||
| }} | ||
| collapseWhenEmpty | ||
| items={feedItems} | ||
| onAddComment={handleAddComment} | ||
| onAddReply={handleAddReply} | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ROADMAP documents the
useMemodeps asobjectDef, pureRecordId, related, childRelatedData, actionRefreshKeybut the actual implementation atRecordDetailView.tsx:436usesobjectDef.name, pureRecordId, childRelatedData, actionRefreshKey— neitherobjectDef(the whole object) norrelatedare in the real dependency array. Please update the ROADMAP to match the actual implementation (or fix the implementation to match the intended deps).