Skip to content

ListView Spec Protocol Gap — Implement 18 unimplemented properties - #737

Merged
hotlong merged 4 commits into
mainfrom
copilot/complete-properties-checklist
Feb 23, 2026
Merged

ListView Spec Protocol Gap — Implement 18 unimplemented properties#737
hotlong merged 4 commits into
mainfrom
copilot/complete-properties-checklist

Conversation

CopilotAI commented Feb 23, 2026

Copy link
Copy Markdown
Contributor

Gap analysis identified 42 spec properties on ListView with only 33% fully implemented. This PR closes 18 of the typed-only/stub/missing items and adds a ROADMAP section for the remaining complex ones.

ListView.tsx — New rendering behaviors

  • showRecordCount — record count bar now conditionally hidden when false
  • description — rendered below toolbar, gated by appearance.showDescription
  • allowPrinting — print button calls window.print()
  • addRecord — "+ Add Record" button from addRecord.enabled
  • tabs — tab bar UI with icon resolution, ordering, visibility filtering
  • pageSizeOptions — page size <select> in status bar

Toolbar control via userActions

userActions.sort/search/filter/rowHeight now override showSort/showSearch/showFilters/showDensity:

// userActions takes precedence over showX flagsconsttoolbarFlags={showSearch: ua?.search!==undefined ? ua.search : schema.showSearch!==false,showSort: ua?.sort!==undefined ? ua.sort : schema.showSort!==false,// ...};

Spec config alignment (kanban/calendar/gantt/gallery/timeline)

All five view-type configs now read from spec-level typed properties with legacy options.* fallback:

// Before: only legacy path
groupBy: schema.options?.kanban?.groupField||'status'// After: spec config takes precedence
groupBy: schema.kanban?.groupField||schema.options?.kanban?.groupField||'status'
  • gallerycoverField, coverFit, cardSize, titleField, visibleFields
  • timelinestartDateField, endDateField, titleField, groupByField, colorField, scale
  • appearance.allowedVisualizations — restricts ViewSwitcher to whitelist

Data query improvements

  • searchableFields — passes $search + $searchFields to dataSource.find()
  • filterableFields — restricts FilterBuilder field list to whitelist
  • virtualScroll — forwarded to grid view schema

Type changes (objectql.ts)

  • rowHeight expanded: 'compact' | 'short' | 'medium' | 'tall' | 'extra_tall'
  • sort accepts legacy string format: Array<{ field; order } | string>
  • Added typed gallery and timeline configs to ListViewSchema

Bridge (list-view.ts)

  • mapDensity handles short → compact, tall/extra_tall → spacious
  • Passes through filterableFields, resizable, striped, bordered, navigation, and all five view-type configs

ROADMAP P2.6

Remaining complex items deferred: data ViewDataSchema provider, grouping rendering, rowColor rendering, quickFilters structure reconciliation, column pinned/summary/link/action, rowActions/bulkActions UI.

Tests

39 new tests (32 ListView + 7 bridge), 522 total passing across 24 files.

Original prompt

This section details on the original issue you should resolve

<issue_title>ListView Spec Protocol Gap — Complete Unimplemented Properties Checklist</issue_title>
<issue_description>## ListView Spec Protocol — Complete Implementation Gap Analysis

A thorough comparison between @objectstack/spec View protocol (view.zod.ts) and the ObjectUI ListView implementation across packages/types, packages/plugin-list, packages/plugin-grid, and packages/react/src/spec-bridge.

Legend

StatusMeaning
✅ ImplementedProperty is typed, bridged, AND rendered with real UI behavior
⚠️ Typed-only / StubProperty exists in types or bridge, but has NO real rendering logic (disabled button, passthrough, no UI)
❌ Not ImplementedProperty is defined in spec but has no corresponding type, bridge, or rendering at all

1. ListView Top-Level Properties (42 total)

#Spec PropertyType (Spec)StatusDetails
1namestring?Used as view identifier
2labelI18nLabel?Displayed in title; but i18n object form { en, zh } is NOT resolved — only plain string works
3typeenumMapped to viewType
4dataViewDataSchema?⚠️ Typed-onlyListView.tsx ignores data entirely — always uses dataSource.find(objectName). provider: api/value modes not consumed
5columnsstring[] | ListColumn[]Supports both simple strings and detailed column configs
6filterany[]?Used as base filter in data fetching
7sortstring | SortConfig[]?✅ PartialOnly array form supported; legacy string format "field desc" NOT parsed
8searchableFieldsstring[]?⚠️ Typed-onlySearch UI exists but does NOT scope queries to these fields
9filterableFieldsstring[]?⚠️ Typed-onlyFilterBuilder does NOT restrict fields to this whitelist
10quickFiltersQuickFilter[]?⚠️ IncompatibleStructure mismatch: spec uses { field, operator, value }, ObjectUI uses { id, label, filters[] }
11resizableboolean?Passed to ObjectGrid
12stripedboolean?Forwarded to child views
13borderedboolean?Forwarded to child views
14selectionSelectionConfig?Fully implemented
15navigationNavigationConfig?drawer/modal/page/popover all supported
16paginationPaginationConfig?⚠️ PartialpageSize works; pageSizeOptions has no UI selector for users to switch
17kanbanKanbanConfig?⚠️ PartialUses legacy schema.options?.kanban?.groupField instead of spec kanban config
18calendarCalendarConfig?⚠️ PartialUses legacy schema.options?.calendar instead of spec structure
19ganttGanttConfig?⚠️ PartialUses legacy schema.options?.gantt instead of spec structure
20galleryGalleryConfig?❌ Not ImplementedSpec GalleryConfigSchema (coverField, coverFit, cardSize, titleField, visibleFields) is NOT typed or consumed
21timelineTimelineConfig?❌ Not ImplementedSpec TimelineConfigSchema (startDateField, endDateField, titleField, groupByField, colorField, scale) is NOT typed or consumed
22descriptionI18nLabel?⚠️ Typed-onlyBridge passes through, no UI renders view description
23sharingViewSharing?⚠️ Schema MismatchSpec: { type: personal/collaborative, lockedBy } vs ObjectUI: { visibility, enabled } — Share button renders but is non-functional
24rowHeightRowHeight enum?⚠️ PartialOnly compact/medium/tall mapped; spec short and extra_tall are NOT handled
25groupingGroupingConfig?⚠️ StubGroup button renders but is disabled — zero grouping rendering logic
26rowColorRowColorConfig?⚠️ StubColor button renders but is disabled — zero row coloring logic
27hiddenFieldsstring[]?Implemented with hide/show popover UI
28fieldOrderstring[]?Sorts fields by order map
29rowActionsstring[]?⚠️ Typed-onlyNo row-level action menu UI rendered
30bulkActionsstring[]?⚠️ Typed-onlyNo bulk action bar UI on multi-select
31virtualScrollboolean?⚠️ Typed-onlyVirtualGrid exists but ListView does NOT toggle it based on this flag
32conditionalFormattingArray<{condition, style}>?⚠️ Schema MismatchSpec uses expression-based { condition, style }, ObjectUI uses field/operator/value rules
33inlineEditboolean?Mapped to editable on ObjectGrid
34exportOptionsenum[]?⚠️ Schema MismatchSpec: simple string[], ObjectUI: { formats, maxRecords, includeHeaders, fileNamePrefix } object
35`...

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

@vercel

vercelBot commented Feb 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
objectuiReadyReadyPreview, CommentFeb 23, 2026 4:13am
objectui-demoReadyReadyPreview, CommentFeb 23, 2026 4:13am
objectui-storybookErrorErrorFeb 23, 2026 4:13am

Request Review

- #39 showRecordCount: conditionally show/hide record count bar
- #24 rowHeight: add short and extra_tall mapping in ListView + bridge
- #7 sort: parse legacy string format "field desc"
- #22 description: render view description below toolbar
- #40 allowPrinting: add print button with window.print()
- #31 virtualScroll: forward flag to grid view schema
- #35 userActions: wire sort/search/filter/rowHeight to toolbar visibility
- #38 addRecord: render "+ Add Record" button from spec config
- #37 tabs: render tab bar UI for view tabs
- #9 filterableFields: restrict FilterBuilder to whitelist fields
- #8 searchableFields: scope search queries to specified fields
- #36 appearance: wire showDescription and allowedVisualizations
- #16 pageSizeOptions: add page size selector UI in status bar
- #17-21: use spec kanban/calendar/gantt/gallery/timeline configs
- #20 gallery: add typed GalleryConfig to ListViewSchema
- #21 timeline: add typed TimelineConfig to ListViewSchema
- Bridge: add short/extra_tall density mapping, filterableFields pass-through
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
CopilotAIand others added 2 commits February 23, 2026 04:03
- Add 32 new ListView tests covering: showRecordCount, rowHeight short/extra_tall,
sort legacy string, description, allowPrinting, addRecord, tabs, userActions,
appearance.allowedVisualizations, spec config usage (kanban/gallery/timeline/
calendar/gantt), pageSizeOptions, searchableFields scoping
- Add 7 new bridge tests: short/extra_tall density mapping, filterableFields,
resizable/striped/bordered, view-type configs, navigation
- Update ROADMAP with P2.6 ListView Spec Protocol Gaps (remaining complex items)
- Total: 81 ListView tests (was 49), 43 bridge tests (was 36)
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…t, use defaultValue for page size
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
CopilotAI changed the title [WIP] Complete implementation gap analysis for ListView specListView Spec Protocol Gap — Implement 18 unimplemented propertiesFeb 23, 2026
CopilotAI requested a review from hotlongFebruary 23, 2026 04:10
@hotlong
hotlong marked this pull request as ready for review February 23, 2026 04:19
CopilotAI review requested due to automatic review settings February 23, 2026 04:19
@hotlong
hotlong merged commit 1341bef into mainFeb 23, 2026
5 of 6 checks passed

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements additional @objectstack/spec ListView protocol properties across types, the SpecBridge, and the ListView renderer, plus adds tests and documents remaining gaps in the roadmap.

Changes:

  • Expanded ListViewSchema typing (sort legacy strings, rowHeight enum, gallery/timeline configs).
  • Updated ListView renderer behaviors (toolbar flags via userActions, search scoping, filterable fields restriction, tabs/description/printing/add-record/page-size UI).
  • Added SpecBridge passthrough + density mapping tests and new ListView unit tests; documented remaining gaps in ROADMAP.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
FileDescription
packages/types/src/objectql.tsExtends ListView schema types (sort, rowHeight, gallery/timeline configs).
packages/react/src/spec-bridge/bridges/list-view.tsBridges additional ListView properties and improves density mapping for new rowHeight values.
packages/react/src/spec-bridge/tests/P1SpecBridge.test.tsAdds coverage for new bridge mappings and density conversion.
packages/plugin-list/src/ListView.tsxImplements new UI/behavior for multiple spec properties (tabs, description, printing, add record, search scoping, pageSizeOptions, view-type config precedence).
packages/plugin-list/src/tests/ListView.test.tsxAdds tests for newly implemented ListView behaviors.
ROADMAP.mdUpdates exec summary and adds a new section documenting remaining ListView protocol gaps.

Comment on lines +1304 to +1316
<select
className="ml-auto h-6 rounded border border-input bg-background px-1 text-xs"
defaultValue={schema.pagination.pageSize}
onChange={(e) => {
const newSize = Number(e.target.value);
if (props.onPageSizeChange) props.onPageSizeChange(newSize);
}}
data-testid="page-size-selector"
>
{schema.pagination.pageSizeOptions.map(size => (
<option key={size} value={size}>{size} / page</option>
))}
</select>

CopilotAIFeb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The page size <select> is uncontrolled (defaultValue) and has no accessible label. If schema.pagination.pageSize changes after mount, the UI won't reflect it; prefer a controlled value tied to state/props, and add an aria-label (or an associated <label>) so screen readers can identify the control.

Copilot uses AI. Check for mistakes.
objectName: 'contacts',
viewType: 'grid',
fields: ['name', 'email'],
sort: ['name desc' as any],

CopilotAIFeb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sort type now allows legacy string entries, so the as any cast in this test is no longer needed. Removing the cast will keep the test aligned with the public typing and catch regressions if the type changes again.

Suggested change
sort: ['name desc'asany],
sort: ['name desc'],

Copilot uses AI. Check for mistakes.
Comment threadROADMAP.md
ObjectUI is a universal Server-Driven UI (SDUI) engine built on React + Tailwind + Shadcn. It renders JSON metadata from the @objectstack/spec protocol into pixel-perfect, accessible, and interactive enterprise interfaces.

**Where We Are:** Foundation is **solid and shipping** — 35 packages, 99+ components, 5,618+ tests, 78 Storybook stories, 42/42 builds passing, ~85% protocol alignment. SpecBridge, Expression Engine, Action Engine, data binding, all view plugins (Grid/Kanban/Calendar/Gantt/Timeline/Map/Gallery), Record components, Report engine, Dashboard BI features, mobile UX, i18n (11 locales), WCAG AA accessibility, Designer Phase 1 (ViewDesigner drag-to-reorder ✅), Console through Phase 20 (L3), **AppShell Navigation Renderer** (P0.1), **Flow Designer** (P2.4), and **Feed/Chatter UI** (P1.5) — all ✅ complete.
**Where We Are:** Foundation is **solid and shipping** — 35 packages, 99+ components, 5,618+ tests, 78 Storybook stories, 42/42 builds passing, ~88% protocol alignment. SpecBridge, Expression Engine, Action Engine, data binding, all view plugins (Grid/Kanban/Calendar/Gantt/Timeline/Map/Gallery), Record components, Report engine, Dashboard BI features, mobile UX, i18n (11 locales), WCAG AA accessibility, Designer Phase 1 (ViewDesigner drag-to-reorder ✅), Console through Phase 20 (L3), **AppShell Navigation Renderer** (P0.1), **Flow Designer** (P2.4), **Feed/Chatter UI** (P1.5), and **ListView Spec Protocol Gap Fixes** (P2.6 partial) — all ✅ complete.

CopilotAIFeb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ROADMAP claims "i18n (11 locales)", but packages/i18n/src/locales currently contains 10 locale files (en, zh, de, ru, ja, fr, ar, pt, es, ko). Update the locale count (or add the missing locale) to keep the executive summary accurate.

Suggested change
**Where We Are:** Foundation is **solid and shipping** — 35 packages, 99+ components, 5,618+ tests, 78 Storybook stories, 42/42 builds passing, ~88% protocol alignment. SpecBridge, Expression Engine, Action Engine, data binding, all view plugins (Grid/Kanban/Calendar/Gantt/Timeline/Map/Gallery), Record components, Report engine, Dashboard BI features, mobile UX, i18n (11 locales), WCAG AA accessibility, Designer Phase 1 (ViewDesigner drag-to-reorder ✅), Console through Phase 20 (L3), **AppShell Navigation Renderer** (P0.1), **Flow Designer** (P2.4), **Feed/Chatter UI** (P1.5), and **ListView Spec Protocol Gap Fixes** (P2.6 partial) — all ✅ complete.
**Where We Are:** Foundation is **solid and shipping** — 35 packages, 99+ components, 5,618+ tests, 78 Storybook stories, 42/42 builds passing, ~88% protocol alignment. SpecBridge, Expression Engine, Action Engine, data binding, all view plugins (Grid/Kanban/Calendar/Gantt/Timeline/Map/Gallery), Record components, Report engine, Dashboard BI features, mobile UX, i18n (10 locales), WCAG AA accessibility, Designer Phase 1 (ViewDesigner drag-to-reorder ✅), Console through Phase 20 (L3), **AppShell Navigation Renderer** (P0.1), **Flow Designer** (P2.4), **Feed/Chatter UI** (P1.5), and **ListView Spec Protocol Gap Fixes** (P2.6 partial) — all ✅ complete.

Copilot uses AI. Check for mistakes.
Comment on lines +1235 to +1236
/** Sort order. Supports array of objects or legacy string format "field desc" */
sort?: Array<{ field: string; order: 'asc' | 'desc' } | string>;

CopilotAIFeb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ListViewSchema type now allows legacy string sort items, but the corresponding Zod schema still validates sort as an array of SortConfig objects only. This will cause runtime validation/parsing to reject valid schemas using the new legacy sort format unless the Zod schema is updated to accept string entries as well.

Copilot uses AI. Check for mistakes.
Comment on lines 1427 to +1430
* Row height for list/grid view rows.
* Aligned with @objectstack/spec ListViewSchema.rowHeight.
* Aligned with @objectstack/spec RowHeight enum.
*/
rowHeight?: 'compact' | 'medium' | 'tall';
rowHeight?: 'compact' | 'short' | 'medium' | 'tall' | 'extra_tall';

CopilotAIFeb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ListViewSchema adds gallery/timeline typed configs and extends rowHeight to include short/extra_tall, but packages/types/src/zod/objectql.zod.ts ListViewSchema is still missing these properties/enum values. This creates a mismatch where TS accepts the schema but Zod validation will fail at runtime; please update the Zod ListViewSchema accordingly.

Copilot uses AI. Check for mistakes.
Comment on lines +887 to +890
{schema.tabs
// Spec defines visible as string (expression), but also handle boolean false for convenience
.filter(tab => tab.visible !== 'false' && tab.visible !== (false as any))
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))

CopilotAIFeb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tabs[].visible is documented as an expression string, but the current filter only treats the literal string "false" (or boolean false) as hidden. Any other expression (e.g. "${user.role==='admin'}") will be treated as visible. Consider evaluating visible via useCondition/ExpressionEvaluator (with appropriate context) and also handling common literals like "true"/"false" robustly.

Copilot uses AI. Check for mistakes.
variant="ghost"
size="sm"
className="h-7 px-2 text-muted-foreground hover:text-primary text-xs"
onClick={() => window.print()}

CopilotAIFeb 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onClick={() => window.print()} will throw in non-browser environments (SSR) and can be undefined in some WebViews/test runners. Guard with typeof window !== 'undefined' and call window.print?.() (or route through a prop callback) so the button is safe across runtimes.

Suggested change
onClick={()=>window.print()}
onClick={()=>{
if(typeofwindow!=='undefined'){
window.print?.();
}
}}

Copilot uses AI. Check for mistakes.
CopilotAI added a commit that referenced this pull request Feb 23, 2026
)
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ListView Spec Protocol Gap — Complete Unimplemented Properties Checklist

3 participants

@hotlong