Skip to content

Commit c167551

Browse files
Copilothotlong
andcommitted
docs: update Storybook stories and ROADMAP.md for DetailView optimization
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent f94dfee commit c167551

2 files changed

Lines changed: 108 additions & 1 deletion

File tree

ROADMAP.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ObjectUI Development Roadmap
22

3-
> **Last Updated:** February 27, 2026
3+
> **Last Updated:** March 1, 2026
44
> **Current Version:** v0.5.x
55
> **Spec Version:** @objectstack/spec v3.0.10
66
> **Client Version:** @objectstack/client v3.0.10
@@ -1272,6 +1272,37 @@ All 313 `@object-ui/fields` tests pass.
12721272

12731273
---
12741274

1275+
### DetailView Rendering Optimization (March 2026)
1276+
1277+
> Platform-level DetailView enhancements: auto-grouping from form sections, empty value hiding, smart header with primaryField/summaryFields, responsive breakpoint fix, and activity timeline collapse.
1278+
1279+
**Types (`@object-ui/types`):**
1280+
- [x] `DetailViewSection.hideEmpty?: boolean` — filter null/undefined/empty string fields; hide empty sections
1281+
- [x] `DetailViewSchema.primaryField?: string` — record-level title from data field
1282+
- [x] `DetailViewSchema.summaryFields?: string[]` — render key attributes as Badge in header
1283+
1284+
**DetailSection (`@object-ui/plugin-detail`):**
1285+
- [x] `hideEmpty` filtering: fields with null/undefined/empty string values are removed; section returns null when all fields hidden
1286+
- [x] Responsive breakpoint fix: `sm:grid-cols-2``md:grid-cols-2`, `sm:grid-cols-2 md:grid-cols-3``md:grid-cols-2 lg:grid-cols-3` (correct behavior on iPad+sidebar)
1287+
1288+
**DetailView Header (`@object-ui/plugin-detail`):**
1289+
- [x] Header renders `data[primaryField]` as h1 title (falls back to `schema.title`)
1290+
- [x] `summaryFields` rendered as `<Badge variant="secondary">` next to title
1291+
1292+
**RecordActivityTimeline (`@object-ui/plugin-detail`):**
1293+
- [x] `collapseWhenEmpty` prop: suppress "No activity recorded" message when true, showing only comment input
1294+
1295+
**RecordDetailView (`apps/console`):**
1296+
- [x] Read `objectDef.views?.form?.sections` for section grouping; fallback to flat field list
1297+
- [x] Remove `columns: 2` hardcode — let `autoLayout` infer optimal columns
1298+
- [x] Auto-detect `primaryField` from object fields (name/title)
1299+
1300+
**Tests:** 94 tests passing (11 new) covering hideEmpty filtering, empty section hiding, primaryField/summaryFields rendering, responsive breakpoints, collapseWhenEmpty, autoLayout undefined-columns regression.
1301+
1302+
**Storybook:** Added `PrimaryFieldWithBadges` and `HideEmptyFields` stories.
1303+
1304+
---
1305+
12751306
## ⚠️ Risk Management
12761307

12771308
| Risk | Mitigation |

packages/plugin-detail/src/DetailView.stories.tsx

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,79 @@ export const WithFieldCounts: Story = {
256256
],
257257
} as any,
258258
};
259+
260+
/**
261+
* Primary Field + Summary Badges — record name as header, key attributes as badges
262+
*/
263+
export const PrimaryFieldWithBadges: Story = {
264+
render: renderStory,
265+
args: {
266+
type: 'detail-view',
267+
title: 'Contact',
268+
primaryField: 'name',
269+
summaryFields: ['status', 'department'],
270+
objectName: 'Contact',
271+
resourceId: 'CNT-042',
272+
showBack: true,
273+
showEdit: true,
274+
data: {
275+
name: 'Sarah Johnson',
276+
email: 'sarah@example.com',
277+
phone: '+1 (555) 123-4567',
278+
status: 'Active',
279+
department: 'Engineering',
280+
title: 'Senior Engineer',
281+
},
282+
fields: [
283+
{ name: 'email', label: 'Email' },
284+
{ name: 'phone', label: 'Phone' },
285+
{ name: 'title', label: 'Job Title' },
286+
{ name: 'status', label: 'Status' },
287+
{ name: 'department', label: 'Department' },
288+
],
289+
} as any,
290+
};
291+
292+
/**
293+
* Hide Empty Fields — sections with hideEmpty filter out null/undefined/empty fields
294+
*/
295+
export const HideEmptyFields: Story = {
296+
render: renderStory,
297+
args: {
298+
type: 'detail-view',
299+
title: 'Contact',
300+
primaryField: 'name',
301+
showBack: true,
302+
data: {
303+
name: 'Mike Ross',
304+
email: 'mike@techcorp.io',
305+
phone: null,
306+
department: '',
307+
title: 'VP Engineering',
308+
website: undefined,
309+
linkedin: 'linkedin.com/in/mikeross',
310+
},
311+
sections: [
312+
{
313+
title: 'Contact Info',
314+
hideEmpty: true,
315+
fields: [
316+
{ name: 'email', label: 'Email' },
317+
{ name: 'phone', label: 'Phone' },
318+
{ name: 'title', label: 'Job Title' },
319+
{ name: 'department', label: 'Department' },
320+
{ name: 'website', label: 'Website' },
321+
{ name: 'linkedin', label: 'LinkedIn' },
322+
],
323+
},
324+
{
325+
title: 'Empty Section (hidden)',
326+
hideEmpty: true,
327+
fields: [
328+
{ name: 'fax', label: 'Fax' },
329+
{ name: 'pager', label: 'Pager' },
330+
],
331+
},
332+
],
333+
} as any,
334+
};

0 commit comments

Comments
 (0)