View
View protocol schemas
HTTP Method Enum & HTTP Request Schema Migrated to shared/http.zod.ts. Re-exported here for backward compatibility.
Source: packages/spec/src/ui/view.zod.ts
TypeScript Usage
import { AddRecordConfigSchema, AppearanceConfigSchema, CalendarConfigSchema, ColumnPrefixSchema, ColumnSummarySchema, ColumnSummaryConfigSchema, FormButtonConfigSchema, FormFieldSchema, FormFieldPublicPickerSchema, FormSectionSchema, FormViewSchema, GalleryConfigSchema, GanttConfigSchema, GanttQuickFilterSchema, GroupingConfigSchema, GroupingFieldSchema, HttpMethodSubsetSchema, HttpRequestSchema, KanbanConfigSchema, ListChartConfigSchema, ListColumnSchema, ListViewSchema, NavigationConfigSchema, NavigationModeSchema, ObjectListViewSchema, ObjectUserFiltersSchema, PaginationConfigSchema, RowColorConfigSchema, RowHeightSchema, SelectionConfigSchema, TimelineConfigSchema, TreeConfigSchema, UserActionsConfigSchema, UserFilterFieldSchema, UserFiltersSchema, ViewSchema, ViewDataSchema, ViewFilterRuleSchema, ViewItemSchema, ViewItemNameSchema, ViewItemWireSchema, ViewKindSchema, ViewScopeSchema, ViewSharingSchema, ViewTabSchema, VisualizationTypeSchema } from '@objectstack/spec/ui';
import type { AddRecordConfig, AppearanceConfig, CalendarConfig, ColumnPrefix, ColumnSummary, ColumnSummaryConfig, FormButtonConfig, FormField, FormFieldPublicPicker, FormSection, FormView, GalleryConfig, GanttConfig, GanttQuickFilter, GroupingConfig, HttpMethodSubset, HttpRequest, KanbanConfig, ListChartConfig, ListColumn, ListView, NavigationConfig, NavigationMode, PaginationConfig, RowColorConfig, RowHeight, SelectionConfig, TimelineConfig, TreeConfig, UserActionsConfig, UserFilterField, UserFilters, View, ViewData, ViewFilterRule, ViewItem, ViewItemName, ViewItemWire, ViewKind, ViewScope, ViewSharing, ViewTab, VisualizationType } from '@objectstack/spec/ui';
// Validate data
const result = AddRecordConfigSchema.parse(data);AddRecordConfig
Add record entry point configuration
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| enabled | boolean | ✅ | Show the add record entry point |
| position | Enum<'top' | 'bottom' | 'both'> | ✅ | Position of the add record button |
| mode | Enum<'inline' | 'form' | 'modal'> | ✅ | How to add a new record |
| formView | string | optional | Named form view to use when mode is "form" or "modal" |
AppearanceConfig
Appearance and visualization configuration
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| showDescription | boolean | ✅ | Show the view description text |
| allowedVisualizations | Enum<'grid' | 'kanban' | 'gallery' | 'calendar' | 'timeline' | 'gantt' | 'map' | 'chart' | 'tree'>[] | optional | Whitelist of visualization types users can switch between (e.g. ["grid", "gallery", "kanban"]) |
CalendarConfig
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| startDateField | string | ✅ | Field providing the event start date/time |
| endDateField | string | optional | Field providing the event end date/time (defaults to a single-day event) |
| titleField | string | ✅ | Field displayed as the event title |
| colorField | string | optional | Field whose value determines the event color |
ColumnPrefix
Compound-cell prefix configuration
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| field | string | ✅ | Field whose value renders before the cell value |
| type | Enum<'badge' | 'text'> | ✅ | How the prefix value is rendered |
ColumnSummary
Aggregation function for column footer summary
Allowed Values
nonecountcount_emptycount_filledcount_uniquepercent_emptypercent_filledsumavgminmax
ColumnSummaryConfig
Column footer summary configuration
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | Enum<'none' | 'count' | 'count_empty' | 'count_filled' | 'count_unique' | 'percent_empty' | 'percent_filled' | 'sum' | 'avg' | 'min' | 'max'> | ✅ | Aggregation function |
| field | string | optional | Field to aggregate (defaults to the column field) |
FormButtonConfig
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| show | boolean | optional | Whether the button is rendered (renderer default applies when omitted) |
| label | string | Record<string, string> | optional | Button label (i18n-capable; renderer default when omitted) |
FormField
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| field | string | ✅ | Field name (snake_case) |
| type | Enum<'text' | 'textarea' | 'email' | 'url' | 'phone' | 'password' | 'secret' | 'markdown' | 'html' | 'richtext' | 'number' | 'currency' | 'percent' | 'date' | … +35 more> | optional | Field type (auto-infers widget if omitted) |
| options | { label: string; value: string; color?: string; default?: boolean; … }[] | optional | Options for select/multiselect/radio/checkboxes fields |
| reference | string | optional | Target object name for lookup/master_detail fields |
| publicPicker | { displayFields?: string[]; maxResults?: integer; filter?: object[]; object?: string } | optional | Opt this field into the anonymous public-form lookup picker (GET /forms/:slug/lookup/:field). Without it the route answers 403 LOOKUP_NOT_PUBLIC and the field is stripped from the rendered public form. |
| maxLength | number | optional | Maximum character length (for text/textarea/email/url/phone) |
| minLength | number | optional | Minimum character length |
| min | number | optional | Minimum value (for number/currency/percent/slider) |
| max | number | optional | Maximum value |
| precision | number | optional | Total digits (for number/currency) |
| scale | number | optional | Decimal places |
| multiple | boolean | optional | Allow multiple values (for select/lookup/file/image) |
| label | string | Record<string, string> | optional | Display label override |
| placeholder | string | Record<string, string> | optional | Placeholder text |
| helpText | string | Record<string, string> | optional | Help/hint text |
| readonly | boolean | optional | Read-only override |
| immutable | boolean | optional | Editable on create, locked once the record exists (e.g. machine names). |
| required | boolean | optional | Required override |
| hidden | boolean | optional | Hidden override |
| colSpan | integer | optional | [legacy — prefer span] Absolute column span (1-4). Fragile when the column count is derived per surface (mobile 1 / modal 2 / page 3-4): a fixed span only lines up at the width the author imagined. The renderer clamps it to the current column count. Prefer span. |
| span | Enum<'auto' | 'full'> | optional | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count (wide widgets like textarea/richtext/json/file/subform take the whole row). 'full': whole row at any column count. Prefer this over the absolute colSpan. |
| widget | string | optional | Custom widget/component name (overrides type-based inference) |
| language | string | optional | Code editor language (for type=code) |
| keyField | { field?: string; label?: string | Record<string, string>; placeholder?: string | Record<string, string>; helpText?: string | Record<string, string>; … } | optional | Key column config for record-typed fields |
| dependsOn | string | optional | Parent field name for cascading |
| visibleWhen | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL) — field shown only when TRUE. Root: record (+ previous, parent) in runtime forms, or data in metadata forms. No current_user at field level — it is unbound here and the predicate would fault open (per-option visibleWhen is the surface that binds it). Inside a repeater data is the ROW, but it is still spelled data — a bare identifier is unbound and faults open too. e.g. Precord.priority == 'urgent' |
| visibleOn | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object } | optional | [DEPRECATED → visibleWhen] Visibility predicate (CEL). Normalized to visibleWhen at parse. |
| disclosure | Enum<'inline' | 'popover'> | optional | Composite rendering: inline bordered box (default) or a summary line + gear popover (progressive disclosure). |
| fields | [FormField](#formfield)[] | optional | Sub-fields for composite/repeater/record types |
Allowed Values: FormField.type
texttextareaemailurlphonepasswordsecretmarkdownhtmlrichtextnumbercurrencypercentdatedatetimetimebooleantoggleselectmultiselectradiocheckboxeslookupmaster_detailtreeuserimagefileavatarvideoaudioformulasummaryautonumbercompositerepeaterrecordlocationaddresscodejsoncolorratingslidersignatureqrcodeprogresstagsvector
FormFieldPublicPicker
Public-lookup opt-in: enables GET /forms/:slug/lookup/:field for this field on an anonymous public form (without it the route answers 403 LOOKUP_NOT_PUBLIC).
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| displayFields | string[] | optional | Fields projected into each picker result (with id); the visitor's search matches contains on the first entry. At most 5 (the route projects no more); omitted → ['name']. |
| maxResults | integer | optional | Maximum rows a lookup returns (default 20, hard ceiling 50 — the route clamps; anonymous visitors cannot paginate past it). |
| filter | { field: string; operator: Enum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'starts_with' | … +14 more>; value?: string | number | boolean | null | (string | number)[] }[] | optional | Static pre-filter rows ANDed ahead of the visitor's search (e.g. only active records are searchable). Same { field, operator, value } dialect as list-view filters. |
| object | string | optional | Referenced-object override for the picker search; omitted → resolved from the field definition (referenceTo). |
FormSection
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | optional | Stable section identifier for i18n lookup (snake_case) |
| label | string | Record<string, string> | optional | Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time |
| description | string | optional | Optional description rendered under the section header. |
| collapsible | boolean | optional | |
| collapsed | boolean | optional | |
| visibleWhen | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object } | optional | Visibility predicate (CEL) — section shown only when TRUE. Root: record (+ previous, parent) in runtime forms, or data in metadata forms. No current_user at section level — it is unbound here and the predicate would fault open. |
| visibleOn | string | { dialect: Enum<'cel' | 'cron' | 'template'>; source?: string; ast?: any; meta?: object } | optional | [DEPRECATED → visibleWhen] Visibility predicate (CEL). Hides the whole section when false. Normalized to visibleWhen at parse. |
| columns | Enum<'1' | '2' | '3' | '4'> | 1 | 2 | 3 | 4 | optional | |
| pane | Enum<'primary' | 'secondary'> | optional | Split pane this section renders in (split forms only; a parse error elsewhere). Omitted → first section 'primary', others 'secondary'. |
| fields | (string | { field: string; type?: Enum<'text' | 'textarea' | 'email' | 'url' | 'phone' | 'password' | 'secret' | … +42 more>; options?: object[]; reference?: string; … })[] | ✅ |
FormView
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | Enum<'simple' | 'tabbed' | 'wizard' | 'split' | 'drawer' | 'modal'> | optional | |
| layout | Enum<'vertical' | 'horizontal' | 'inline' | 'grid'> | optional | Field layout direction |
| columns | integer | optional | Number of columns for the form body |
| title | string | optional | Form title |
| description | string | optional | Form description |
| defaultTab | string | optional | Initially active tab (tabbed forms) |
| tabPosition | Enum<'top' | 'bottom' | 'left' | 'right'> | optional | Tab strip position (tabbed forms) |
| allowSkip | boolean | optional | Allow skipping steps (wizard forms) |
| showStepIndicator | boolean | optional | Show the step indicator (wizard forms) |
| splitDirection | Enum<'horizontal' | 'vertical'> | optional | Split orientation (split forms) |
| splitSize | number | optional | Primary split panel size, % (split forms) |
| splitResizable | boolean | optional | Whether the split is resizable (split forms) |
| drawerSide | Enum<'top' | 'bottom' | 'left' | 'right'> | optional | Drawer side (drawer forms) |
| drawerWidth | string | optional | [DEPRECATED → size buckets] Drawer width, e.g. "480px". A pixel width cannot be chosen without knowing the client viewport — the renderer derives it. |
| modalSize | Enum<'sm' | 'default' | 'lg' | 'xl' | 'full'> | optional | Modal size (modal forms) |
| data | { provider: 'object'; object: string } | { provider: 'api'; read?: object; write?: object } | { provider: 'value'; items: any[] } | { provider: 'schema'; schemaId: string; schema?: Record<string, any> } | optional | Data source configuration (defaults to "object" provider) |
| sections | { name?: string; label?: string | Record<string, string>; description?: string; collapsible?: boolean; … }[] | optional | |
| groups | { name?: string; label?: string | Record<string, string>; description?: string; collapsible?: boolean; … }[] | optional | [LEGACY ALIAS → sections] Accepted for back-compat and folded onto sections at parse; sections wins when both are present. Prefer sections. |
| subforms | { childObject: string; relationshipField?: string; columns?: any[]; amountField?: string; … }[] | optional | Inline master-detail child collections |
| defaultSort | never | optional | [REMOVED] form.defaultSort was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — nothing read it: a related list inside a form sorts by its own list view's sort. Delete the key and set the sort on the related list view instead. Run os migrate meta --from 16 to rewrite existing sources automatically. |
| sharing | { enabled?: boolean; publicLink?: string; password?: string; allowedDomains?: string[]; … } | optional | Public sharing configuration for this form |
| submitBehavior | { kind: 'thank-you'; title?: string; message?: string } | { kind: 'redirect'; url: string; delayMs?: integer } | { kind: 'continue' } | { kind: 'next-record' } | optional | Post-submit behavior. On the redirect arm, url is relative-only and interpolates only declared record fields as {{record.field_name}}, URL-escaped (ruled 2026-08-11, #7496). |
| buttons | { submit?: object; cancel?: object; reset?: object } | optional | Form action-button visibility & labels; folded onto the flat renderer props by ObjectUI ObjectForm (framework#1894 / #2998). |
| defaults | Record<string, any> | optional | Initial field values for create-mode forms (folded into ObjectUI ObjectForm initial values; framework#1894 / #2998). |
| aria | never | optional | [REMOVED] form.aria was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no form renderer ever applied it, so declared ARIA attributes silently did not reach the DOM. Delete the key. The form renderer emits its own semantic markup; report gaps as renderer issues rather than per-view attribute overrides. Run os migrate meta --from 16 to rewrite existing sources automatically. |
GalleryConfig
Gallery/card view configuration
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| coverField | string | optional | Attachment/image field to display as card cover |
| coverFit | Enum<'cover' | 'contain'> | ✅ | Image fit mode for card cover |
| cardSize | Enum<'small' | 'medium' | 'large'> | ✅ | Card size in gallery view |
| titleField | string | optional | Field to display as card title |
| visibleFields | string[] | optional | Fields to display on card body |
GanttConfig
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| startDateField | string | ✅ | Field providing the task start date |
| endDateField | string | ✅ | Field providing the task end date |
| titleField | string | ✅ | Field displayed as the task title |
| progressField | string | optional | Field providing the task completion percentage |
| dependenciesField | string | optional | Field listing the task's predecessor (dependency) record ids |
| colorField | string | optional | Field that drives the bar color |
| parentField | string | optional | Field holding the parent task id (builds the summary → step tree) |
| typeField | string | optional | Field whose value maps to task/summary/milestone |
| baselineStartField | string | optional | Baseline (planned) start field |
| baselineEndField | string | optional | Baseline (planned) end field |
| groupByField | string | optional | Field to group leaf tasks by (synthesized summary rows) |
| resourceView | boolean | optional | Render a per-resource workload histogram instead of the timeline |
| assigneeField | string | optional | Resource field to bucket load by (resource view) |
| effortField | string | optional | Per-task load units (resource view; default 1) |
| capacity | number | optional | Per-resource capacity ceiling; loads above this flag overload |
| tooltipFields | (string | { field: string; label?: string })[] | optional | Fields to surface in the hover tooltip, in display order |
| quickFilters | { field: string; label?: string; options?: (string | object)[] }[] | optional | Multi-select filter dropdowns rendered above the chart |
| autoZoomToFilter | boolean | optional | When true (default), filtering zooms the range to the filtered tasks |
GanttQuickFilter
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| field | string | ✅ | Record field / dot-path the dimension filters on |
| label | string | optional | Trigger label (falls back to the field label) |
| options | (string | { value: string | number; label?: string })[] | optional | Explicit option override for fixed enums |
GroupingConfig
Record grouping configuration
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| fields | { field: string; order: Enum<'asc' | 'desc'>; collapsed: boolean }[] | ✅ | Fields to group by, in nesting order — the first entry is the outermost group and each later entry nests one level deeper (at least one field) |
GroupingField
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| field | string | ✅ | Field name to group by |
| order | Enum<'asc' | 'desc'> | ✅ | Group sort order |
| collapsed | boolean | ✅ | Collapse groups by default |
HttpMethodSubset
HTTP methods a view data source may request — the subset of HttpMethod without HEAD/OPTIONS.
Allowed Values
GETPOSTPUTPATCHDELETE
HttpRequest
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| url | string | ✅ | API endpoint URL |
| method | Enum<'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'> | ✅ | HTTP method |
| headers | Record<string, string> | optional | Custom HTTP headers |
| params | Record<string, any> | optional | Query parameters |
| body | any | optional | Request body for POST/PUT/PATCH |
KanbanConfig
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| groupByField | string | ✅ | Field to group columns by (usually status/select) |
| summarizeField | string | optional | Field to sum at top of column (e.g. amount) |
| columns | string[] | ✅ | Fields to show on cards |
ListChartConfig
List chart view configuration
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| chartType | Enum<'bar' | 'line' | 'pie' | 'area' | 'scatter'> | ✅ | Chart visualisation type |
| dataset | string | ✅ | Dataset name to bind (ADR-0021) |
| dimensions | string[] | optional | Dimension names — X/group/split |
| values | string[] | ✅ | Measure names — Y (at least one) |
ListColumn
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| field | string | ✅ | Field name (snake_case) |
| label | string | Record<string, string> | optional | Display label override |
| width | number | optional | Column width in pixels |
| align | Enum<'left' | 'center' | 'right'> | optional | Text alignment |
| hidden | boolean | optional | Hide column by default |
| sortable | boolean | optional | Allow sorting by this column |
| resizable | boolean | optional | Allow resizing this column |
| wrap | boolean | optional | Allow text wrapping |
| type | string | optional | Renderer type override (e.g., "currency", "date") |
| pinned | Enum<'left' | 'right'> | optional | Pin/freeze column to left or right side |
| summary | Enum<'none' | 'count' | 'count_empty' | 'count_filled' | 'count_unique' | 'percent_empty' | 'percent_filled' | 'sum' | 'avg' | 'min' | 'max'> | { type: Enum<'none' | 'count' | 'count_empty' | 'count_filled' | 'count_unique' | … +6 more>; field?: string } | optional | Footer aggregation for this column — the function alone, or { type, field } to aggregate another field |
| prefix | { field: string; type: Enum<'badge' | 'text'> } | optional | Field rendered inline before this cell value |
| link | boolean | optional | Functions as the primary navigation link (triggers View navigation) |
| action | string | optional | Registered Action ID to execute when clicked |
ListView
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | optional | Internal view name (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time |
| type | Enum<'grid' | 'kanban' | 'gallery' | 'calendar' | 'timeline' | 'gantt' | 'map' | 'chart' | 'tree'> | optional | |
| data | { provider: 'object'; object: string } | { provider: 'api'; read?: object; write?: object } | { provider: 'value'; items: any[] } | { provider: 'schema'; schemaId: string; schema?: Record<string, any> } | optional | Data source configuration (defaults to "object" provider) |
| columns | string[] | { field: string; label?: string | Record<string, string>; width?: number; align?: Enum<'left' | 'center' | 'right'>; … }[] | ✅ | Fields to display as columns |
| filter | { field: string; operator?: Enum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'starts_with' | … +14 more>; value?: string | number | boolean | null | (string | number)[] }[] | optional | Filter criteria (JSON Rules) |
| sort | string | { field: string; order: Enum<'asc' | 'desc'> }[] | optional | |
| searchableFields | string[] | optional | Fields enabled for search |
| filterableFields | string[] | optional | Legacy shorthand for userFilters.fields — bare field names enabled for end-user filtering. Prefer userFilters |
| userFilters | { element?: Enum<'dropdown' | 'tabs' | 'toggle'>; fields?: object[]; tabs?: object[]; showAllRecords?: boolean; … } | optional | End-user quick-filter bar: dropdown/toggle fields or tab presets. Omit to let the renderer derive filters from select/boolean fields |
| resizable | boolean | optional | Enable column resizing |
| striped | boolean | optional | Striped row styling |
| bordered | boolean | optional | Show borders |
| compactToolbar | boolean | optional | Collapse Group/Color/Density/Hide-fields into a single View settings popover |
| selection | { type?: Enum<'none' | 'single' | 'multiple'> } | optional | Row selection configuration |
| navigation | { mode?: Enum<'page' | 'drawer' | 'modal' | 'split' | 'popover' | 'new_window' | 'none'>; view?: string; preventNavigation?: boolean; openNewTab?: boolean; … } | optional | Configuration for item click navigation (page, drawer, modal, etc.) |
| pagination | { pageSize?: integer; pageSizeOptions?: integer[] } | optional | Pagination configuration |
| kanban | { groupByField: string; summarizeField?: string; columns: string[] } | optional | Kanban-board configuration — applies when the view renders as a kanban layout |
| calendar | { startDateField: string; endDateField?: string; titleField: string; colorField?: string } | optional | Calendar configuration — applies when the view renders as a calendar layout |
| gantt | { startDateField: string; endDateField: string; titleField: string; progressField?: string; … } & Record<string, any> | optional | Gantt-timeline configuration — applies when the view renders as a gantt layout |
| gallery | { coverField?: string; coverFit?: Enum<'cover' | 'contain'>; cardSize?: Enum<'small' | 'medium' | 'large'>; titleField?: string; … } | optional | Gallery/card view configuration |
| timeline | { startDateField: string; endDateField?: string; titleField: string; groupByField?: string; … } | optional | Timeline view configuration |
| chart | { chartType?: Enum<'bar' | 'line' | 'pie' | 'area' | 'scatter'>; dataset: string; dimensions?: string[]; values: string[] } | optional | List chart view configuration |
| tree | { parentField?: string; labelField?: string; fields?: string[]; defaultExpandedDepth?: integer } & Record<string, any> | optional | Tree/hierarchy configuration — applies when the view renders as a tree layout |
| description | string | Record<string, string> | optional | View description for documentation/tooltips |
| sharing | { type?: Enum<'personal' | 'collaborative'>; lockedBy?: string } | optional | View sharing and access configuration |
| rowHeight | Enum<'compact' | 'short' | 'medium' | 'tall' | 'extra_tall'> | optional | Row height / density setting |
| grouping | { fields: object[] } | optional | Group records by one or more fields |
| rowColor | { field: string; colors?: Record<string, string> } | optional | Color rows based on field value |
| hiddenFields | string[] | optional | Fields to hide in this specific view |
| fieldOrder | string[] | optional | Explicit field display order for this view |
| rowActions | string[] | optional | Actions available for individual row items |
| bulkActions | string[] | optional | Actions available when multiple rows are selected |
| bulkActionDefs | { name: string; label?: string; icon?: string; variant?: Enum<'primary' | 'secondary' | 'danger' | 'ghost' | 'outline'>; … }[] | optional | Rich bulk action definitions (schema-driven, executed via BulkActionDialog). Use a def for a mass data-plane mutation ('update' with a patch / 'delete') that no action expresses, or for an operation: 'custom' + execution: 'aggregate' entry (objectui#3139) that dispatches the action it NAMES once for the whole selection — the renderer injects params._selectedIds: string[] (read that on the server, not recordId) so a single call can produce one aggregate artifact (zip of QR codes, merged PDF, batch print). Aggregate results are all-or-nothing: a handler that cannot cover the whole selection must reject, and per-row retry is replaced by re-running the action. batchSize does not apply (the call is never chunked); set maxRecords on defs whose server work is expensive. For the PER-RECORD dispatch use bulkActions: ['<name>'] instead — the bare-string form, promoted with the action's own label, params and visible; a 'custom' def without execution: 'aggregate' has no dispatcher and is refused at parse time (#4457). Toolbar url/api actions can also interpolate the current selection via ${ctx.selection.ids} / ${ctx.selection.count}. |
| virtualScroll | boolean | optional | Enable virtual scrolling for large datasets |
| conditionalFormatting | { condition: string | object; style: Record<string, string> }[] | optional | Conditional formatting rules for list rows |
| inlineEdit | boolean | optional | Allow inline editing of records directly in the list view |
| exportOptions | Enum<'csv' | 'xlsx' | 'pdf' | 'json'>[] | optional | Available export format options |
| userActions | { sort?: boolean; search?: boolean; filter?: boolean; refresh?: boolean; … } | optional | User action toggles for the view toolbar |
| appearance | { showDescription?: boolean; allowedVisualizations?: Enum<'grid' | 'kanban' | 'gallery' | 'calendar' | 'timeline' | 'gantt' | 'map' | 'chart' | 'tree'>[] } | optional | Appearance and visualization configuration |
| tabs | { name: string; label?: string | Record<string, string>; icon?: string; view?: string; … }[] | optional | Tab definitions for multi-tab view interface |
| addRecord | { enabled?: boolean; position?: Enum<'top' | 'bottom' | 'both'>; mode?: Enum<'inline' | 'form' | 'modal'>; formView?: string } | optional | Add record entry point configuration |
| showRecordCount | boolean | optional | Show record count at the bottom of the list |
| allowPrinting | boolean | optional | Allow users to print the view |
| emptyState | { title?: string | Record<string, string>; message?: string | Record<string, string>; icon?: string } | optional | Empty state configuration when no records found |
| aria | { ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string } | optional | ARIA accessibility attributes for the list view |
| responsive | never | optional | [REMOVED] view.responsive was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer ever read it; the grid is responsive by its own layout rules. Delete the key. Run os migrate meta --from 16 to rewrite existing sources automatically. |
| performance | never | optional | [REMOVED] view.performance was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; list-view performance tuning was never implemented. Delete the key. Run os migrate meta --from 16 to rewrite existing sources automatically. |
NavigationConfig
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| mode | Enum<'page' | 'drawer' | 'modal' | 'split' | 'popover' | 'new_window' | 'none'> | ✅ | |
| view | string | optional | Name of the form view to use for details (e.g. "summary_view", "edit_form") |
| preventNavigation | boolean | ✅ | Disable standard navigation entirely |
| openNewTab | boolean | ✅ | Force open in new tab (applies to page mode) |
| size | Enum<'auto' | 'sm' | 'md' | 'lg' | 'xl' | 'full'> | ✅ | [#2578] Overlay size bucket for drawer/modal detail: 'auto' (default — renderer derives from field count + viewport; AI writes nothing) or a coarse override sm/md/lg/xl/full. Prefer this over the pixel width; page mode ignores it. |
| width | string | number | optional | [DEPRECATED → size] Pixel/percent width of the drawer/modal (e.g. "600px"). A pixel width cannot be chosen at authoring time without knowing the client viewport — use the size bucket. |
NavigationMode
Allowed Values
pagedrawermodalsplitpopovernew_windownone
ObjectListView
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | optional | Internal view name (lowercase snake_case) |
| label | string | Record<string, string> | optional | Display label — the default-language string, or an inline locale map ({ en, "zh-CN" }) resolved at render time |
| type | Enum<'grid' | 'kanban' | 'gallery' | 'calendar' | 'timeline' | 'gantt' | 'map' | 'chart' | 'tree'> | optional | |
| data | { provider: 'object'; object: string } | { provider: 'api'; read?: object; write?: object } | { provider: 'value'; items: any[] } | { provider: 'schema'; schemaId: string; schema?: Record<string, any> } | optional | Data source configuration (defaults to "object" provider) |
| columns | string[] | { field: string; label?: string | Record<string, string>; width?: number; align?: Enum<'left' | 'center' | 'right'>; … }[] | ✅ | Fields to display as columns |
| filter | { field: string; operator?: Enum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'starts_with' | … +14 more>; value?: string | number | boolean | null | (string | number)[] }[] | optional | Filter criteria (JSON Rules) |
| sort | string | { field: string; order: Enum<'asc' | 'desc'> }[] | optional | |
| searchableFields | string[] | optional | Fields enabled for search |
| filterableFields | string[] | optional | Legacy shorthand for userFilters.fields — bare field names enabled for end-user filtering. Prefer userFilters |
| resizable | boolean | optional | Enable column resizing |
| striped | boolean | optional | Striped row styling |
| bordered | boolean | optional | Show borders |
| compactToolbar | boolean | optional | Collapse Group/Color/Density/Hide-fields into a single View settings popover |
| selection | { type?: Enum<'none' | 'single' | 'multiple'> } | optional | Row selection configuration |
| navigation | { mode?: Enum<'page' | 'drawer' | 'modal' | 'split' | 'popover' | 'new_window' | 'none'>; view?: string; preventNavigation?: boolean; openNewTab?: boolean; … } | optional | Configuration for item click navigation (page, drawer, modal, etc.) |
| pagination | { pageSize?: integer; pageSizeOptions?: integer[] } | optional | Pagination configuration |
| kanban | { groupByField: string; summarizeField?: string; columns: string[] } | optional | Kanban-board configuration — applies when the view renders as a kanban layout |
| calendar | { startDateField: string; endDateField?: string; titleField: string; colorField?: string } | optional | Calendar configuration — applies when the view renders as a calendar layout |
| gantt | { startDateField: string; endDateField: string; titleField: string; progressField?: string; … } & Record<string, any> | optional | Gantt-timeline configuration — applies when the view renders as a gantt layout |
| gallery | { coverField?: string; coverFit?: Enum<'cover' | 'contain'>; cardSize?: Enum<'small' | 'medium' | 'large'>; titleField?: string; … } | optional | Gallery/card view configuration |
| timeline | { startDateField: string; endDateField?: string; titleField: string; groupByField?: string; … } | optional | Timeline view configuration |
| chart | { chartType?: Enum<'bar' | 'line' | 'pie' | 'area' | 'scatter'>; dataset: string; dimensions?: string[]; values: string[] } | optional | List chart view configuration |
| tree | { parentField?: string; labelField?: string; fields?: string[]; defaultExpandedDepth?: integer } & Record<string, any> | optional | Tree/hierarchy configuration — applies when the view renders as a tree layout |
| description | string | Record<string, string> | optional | View description for documentation/tooltips |
| sharing | { type?: Enum<'personal' | 'collaborative'>; lockedBy?: string } | optional | View sharing and access configuration |
| rowHeight | Enum<'compact' | 'short' | 'medium' | 'tall' | 'extra_tall'> | optional | Row height / density setting |
| grouping | { fields: object[] } | optional | Group records by one or more fields |
| rowColor | { field: string; colors?: Record<string, string> } | optional | Color rows based on field value |
| hiddenFields | string[] | optional | Fields to hide in this specific view |
| fieldOrder | string[] | optional | Explicit field display order for this view |
| rowActions | string[] | optional | Actions available for individual row items |
| bulkActions | string[] | optional | Actions available when multiple rows are selected |
| bulkActionDefs | { name: string; label?: string; icon?: string; variant?: Enum<'primary' | 'secondary' | 'danger' | 'ghost' | 'outline'>; … }[] | optional | Rich bulk action definitions (schema-driven, executed via BulkActionDialog). Use a def for a mass data-plane mutation ('update' with a patch / 'delete') that no action expresses, or for an operation: 'custom' + execution: 'aggregate' entry (objectui#3139) that dispatches the action it NAMES once for the whole selection — the renderer injects params._selectedIds: string[] (read that on the server, not recordId) so a single call can produce one aggregate artifact (zip of QR codes, merged PDF, batch print). Aggregate results are all-or-nothing: a handler that cannot cover the whole selection must reject, and per-row retry is replaced by re-running the action. batchSize does not apply (the call is never chunked); set maxRecords on defs whose server work is expensive. For the PER-RECORD dispatch use bulkActions: ['<name>'] instead — the bare-string form, promoted with the action's own label, params and visible; a 'custom' def without execution: 'aggregate' has no dispatcher and is refused at parse time (#4457). Toolbar url/api actions can also interpolate the current selection via ${ctx.selection.ids} / ${ctx.selection.count}. |
| virtualScroll | boolean | optional | Enable virtual scrolling for large datasets |
| conditionalFormatting | { condition: string | object; style: Record<string, string> }[] | optional | Conditional formatting rules for list rows |
| inlineEdit | boolean | optional | Allow inline editing of records directly in the list view |
| exportOptions | Enum<'csv' | 'xlsx' | 'pdf' | 'json'>[] | optional | Available export format options |
| userActions | { sort?: boolean; search?: boolean; filter?: boolean; refresh?: boolean; … } | optional | User action toggles for the view toolbar |
| appearance | { showDescription?: boolean; allowedVisualizations?: Enum<'grid' | 'kanban' | 'gallery' | 'calendar' | 'timeline' | 'gantt' | 'map' | 'chart' | 'tree'>[] } | optional | Appearance and visualization configuration |
| tabs | { name: string; label?: string | Record<string, string>; icon?: string; view?: string; … }[] | optional | Tab definitions for multi-tab view interface |
| addRecord | { enabled?: boolean; position?: Enum<'top' | 'bottom' | 'both'>; mode?: Enum<'inline' | 'form' | 'modal'>; formView?: string } | optional | Add record entry point configuration |
| showRecordCount | boolean | optional | Show record count at the bottom of the list |
| allowPrinting | boolean | optional | Allow users to print the view |
| emptyState | { title?: string | Record<string, string>; message?: string | Record<string, string>; icon?: string } | optional | Empty state configuration when no records found |
| aria | { ariaLabel?: string | Record<string, string>; ariaDescribedBy?: string; role?: string } | optional | ARIA accessibility attributes for the list view |
| responsive | never | optional | [REMOVED] view.responsive was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer ever read it; the grid is responsive by its own layout rules. Delete the key. Run os migrate meta --from 16 to rewrite existing sources automatically. |
| performance | never | optional | [REMOVED] view.performance was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; list-view performance tuning was never implemented. Delete the key. Run os migrate meta --from 16 to rewrite existing sources automatically. |
| userFilters | { element?: Enum<'dropdown' | 'toggle'>; fields?: object[] } | optional |
ObjectUserFilters
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| element | Enum<'dropdown' | 'toggle'> | ✅ | Filter control style on object views: "dropdown" (per-field value chips). "toggle" is deprecated. "tabs" is page-only — use listViews for named presets. |
| fields | { field: string; label?: string | Record<string, string>; type?: Enum<'select' | 'multi-select' | 'boolean' | 'date-range' | 'text'>; options?: object[]; … }[] | optional | Fields exposed as quick filters (dropdown/toggle elements) |
PaginationConfig
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| pageSize | integer | ✅ | Number of records per page |
| pageSizeOptions | integer[] | optional | Available page size options |
RowColorConfig
Row color configuration based on field values
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| field | string | ✅ | Field to derive color from (typically a select/status field) |
| colors | Record<string, string> | optional | Map of field value to color (hex/token) |
RowHeight
Row height / density setting for list view
Allowed Values
compactshortmediumtallextra_tall
SelectionConfig
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | Enum<'none' | 'single' | 'multiple'> | ✅ | Selection mode |
TimelineConfig
Timeline view configuration
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| startDateField | string | ✅ | Field for timeline item start date |
| endDateField | string | optional | Field for timeline item end date |
| titleField | string | ✅ | Field to display as timeline item title |
| groupByField | string | optional | Field to group timeline rows |
| colorField | string | optional | Field to determine item color |
| scale | Enum<'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year'> | ✅ | Default timeline scale |
TreeConfig
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| parentField | string | optional | Single-parent pointer field (auto-detected from the object schema when omitted) |
| labelField | string | optional | Field rendered indented in the first column (defaults to "name") |
| fields | string[] | optional | Additional fields rendered as flat columns alongside the label |
| defaultExpandedDepth | integer | optional | Initial expansion depth (0 = roots only; omit = expand all) |
UserActionsConfig
User action toggles for the view toolbar
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| sort | boolean | ✅ | Allow users to sort records |
| search | boolean | ✅ | Allow users to search records |
| filter | boolean | ✅ | Allow users to filter records |
| refresh | boolean | ✅ | Allow users to reload the view data from the backend without a full page reload |
| rowHeight | boolean | ✅ | Allow users to toggle row height/density |
| addRecordForm | boolean | ✅ | Add records through a form instead of inline |
| editInline | boolean | ✅ | Allow users to edit records inline — click a cell to edit it with the field's type-aware widget (the same control the form uses). Off by default: the list is read-only unless the author opts in. |
| buttons | string[] | optional | Custom action button IDs to show in the toolbar |
UserFilterField
Quick-filter field configuration
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| field | string | ✅ | Field name on the source object (must exist — checked by reference diagnostics) |
| label | string | Record<string, string> | optional | Display label override (defaults to the field label) |
| type | Enum<'select' | 'multi-select' | 'boolean' | 'date-range' | 'text'> | optional | Filter control type. Omit to infer from the field definition |
| options | { value: string | number | boolean; label: string | Record<string, string>; color?: string }[] | optional | Static options. Omit to derive from the field definition (select options / lookup records) |
| showCount | boolean | optional | Show per-option record counts |
| defaultValues | (string | number | boolean)[] | optional | Pre-selected values when the view loads |
UserFilters
End-user quick-filter configuration (Airtable "User filters" parity)
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| element | Enum<'dropdown' | 'tabs' | 'toggle'> | ✅ | Filter control style: "dropdown" (per-field value selectors) or "tabs" (named presets). "toggle" is deprecated. |
| fields | { field: string; label?: string | Record<string, string>; type?: Enum<'select' | 'multi-select' | 'boolean' | 'date-range' | 'text'>; options?: object[]; … }[] | optional | Fields exposed as quick filters (dropdown/toggle elements) |
| tabs | { name: string; label?: string | Record<string, string>; icon?: string; view?: string; … }[] | optional | Named filter presets rendered as tabs (tabs element). Reuses ViewTabSchema |
| showAllRecords | boolean | optional | Show an "All records" tab before the presets (tabs element) |
| allowAddTab | boolean | optional | Let end users add their own tab after the presets (tabs element): the affordance asks for a name and snapshots the filters currently applied as a new tab. SESSION-SCOPED — an added tab lives only for the current mount, is never written back as metadata (ADR-0047), and carries a remove control the authored presets do not. Page lists only — object views use listViews for named presets |
View
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | optional | Item name — supplied by the metadata door; for an object-scoped container it is the object name. |
| label | string | Record<string, string> | optional | Human-readable label shown in metadata lists. |
| object | string | optional | Object this container binds to — how a stack-level views: [...] entry says which object its views belong to; read by getViewsByObject() / GET /meta/view?object=. |
| list | { name?: string; label?: string | Record<string, string>; type?: Enum<'grid' | 'kanban' | 'gallery' | 'calendar' | 'timeline' | 'gantt' | 'map' | 'chart' | 'tree'>; data?: object | … +3 more; … } | optional | |
| form | { type?: Enum<'simple' | 'tabbed' | 'wizard' | 'split' | 'drawer' | 'modal'>; layout?: Enum<'vertical' | 'horizontal' | 'inline' | 'grid'>; columns?: integer; title?: string; … } | optional | |
| listViews | Record<string, { name?: string; label?: string | Record<string, string>; type?: Enum<'grid' | 'kanban' | 'gallery' | 'calendar' | 'timeline' | 'gantt' | 'map' | 'chart' | 'tree'>; data?: object | … +3 more; … }> | optional | Additional named list views (views mode — dropdown userFilters allowed, no tabs; ADR-0047) |
| formViews | Record<string, { type?: Enum<'simple' | 'tabbed' | 'wizard' | 'split' | 'drawer' | 'modal'>; layout?: Enum<'vertical' | 'horizontal' | 'inline' | 'grid'>; columns?: integer; title?: string; … }> | optional | Additional named form views |
| protection | { lock: Enum<'none' | 'no-overlay' | 'no-delete' | 'full'>; reason: string; docsUrl?: string } | optional | Package author protection block — lock policy for this view. |
| _lock | Enum<'none' | 'no-overlay' | 'no-delete' | 'full'> | optional | Item-level lock — controls overlay & delete (ADR-0010). |
| _lockReason | string | optional | Human-readable reason shown when a write is refused by _lock. |
| _lockSource | Enum<'artifact' | 'package' | 'env-forced'> | optional | Layer that set _lock (artifact | package | env-forced). |
| _provenance | Enum<'package' | 'org' | 'env-forced'> | optional | Origin of the item (package | org | env-forced). |
| _packageId | string | optional | Owning package machine id. |
| _packageVersion | string | optional | Owning package version. |
| _lockDocsUrl | string | optional | Optional documentation link surfaced next to _lockReason. |
ViewData
Union Options
This schema accepts one of the following structures:
Option 1
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| provider | 'object' | ✅ | |
| object | string | ✅ | Target object name |
Option 2
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| provider | 'api' | ✅ | |
| read | { url: string; method: Enum<'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'>; headers?: Record<string, string>; params?: Record<string, any>; … } | optional | Configuration for fetching data |
| write | { url: string; method: Enum<'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'>; headers?: Record<string, string>; params?: Record<string, any>; … } | optional | Configuration for submitting data (for forms/editable tables) |
Option 3
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| provider | 'value' | ✅ | |
| items | any[] | ✅ | Static data array |
Option 4
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| provider | 'schema' | ✅ | |
| schemaId | string | ✅ | Schema identifier — typically the metadata type name |
| schema | Record<string, any> | optional | Inline JSON Schema (Draft 2020-12). Optional when schemaId is resolvable. |
ViewFilterRule
View filter rule
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| field | string | ✅ | Field name to filter on |
| operator | Enum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'starts_with' | 'ends_with' | 'greater_than' | 'less_than' | 'greater_than_or_equal' | … +10 more> | ✅ | Filter operator |
| value | string | number | boolean | null | (string | number)[] | optional | Filter value. The accepted SHAPE depends on the operator: in / not_in take an array (any length, including []), between takes exactly [min, max], every other operator takes a scalar. The unary operators (is_empty / is_not_empty / is_null / is_not_null) take their direction from the operator name and ignore this key. |
Allowed Values: ViewFilterRule.operator
equalsnot_equalscontainsnot_containsstarts_withends_withgreater_thanless_thangreater_than_or_equalless_than_or_equalinnot_inis_emptyis_not_emptyis_nullis_not_nullbeforeafterbetween
ViewItem
Union Options
This schema accepts one of the following structures:
Option 1
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| viewKind | 'list' | ✅ | |
| config | { name?: string; label?: string | Record<string, string>; type?: Enum<'grid' | 'kanban' | 'gallery' | 'calendar' | 'timeline' | 'gantt' | 'map' | 'chart' | 'tree'>; data?: object | … +3 more; … } | ✅ | List-family view configuration. |
| name | string | ✅ | Globally-unique view id, <object>.<viewKey>. |
| object | string | ✅ | Bound object name — the foreign key used to aggregate views. |
| label | string | Record<string, string> | optional | Display label (supports i18n). |
| isDefault | boolean | optional | Whether this is the object's default view in the switcher. |
| order | integer | optional | Sort order within the object's view switcher / left rail. |
| scope | Enum<'package' | 'shared' | 'personal'> | optional | Identity layer (defaults to package for source-loaded views). |
| owner | string | optional | Owner user id — set when scope is personal. |
| hidden | boolean | optional | Hidden from the switcher (per-user / per-org declutter). |
| protection | { lock: Enum<'none' | 'no-overlay' | 'no-delete' | 'full'>; reason: string; docsUrl?: string } | optional | Package author protection block — lock policy for this view. |
| _lock | Enum<'none' | 'no-overlay' | 'no-delete' | 'full'> | optional | Item-level lock — controls overlay & delete (ADR-0010). |
| _lockReason | string | optional | Human-readable reason shown when a write is refused by _lock. |
| _lockSource | Enum<'artifact' | 'package' | 'env-forced'> | optional | Layer that set _lock (artifact | package | env-forced). |
| _provenance | Enum<'package' | 'org' | 'env-forced'> | optional | Origin of the item (package | org | env-forced). |
| _packageId | string | optional | Owning package machine id. |
| _packageVersion | string | optional | Owning package version. |
| _lockDocsUrl | string | optional | Optional documentation link surfaced next to _lockReason. |
Option 2
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| viewKind | 'form' | ✅ | |
| config | { type?: Enum<'simple' | 'tabbed' | 'wizard' | 'split' | 'drawer' | 'modal'>; layout?: Enum<'vertical' | 'horizontal' | 'inline' | 'grid'>; columns?: integer; title?: string; … } | ✅ | Form view configuration. |
| name | string | ✅ | Globally-unique view id, <object>.<viewKey>. |
| object | string | ✅ | Bound object name — the foreign key used to aggregate views. |
| label | string | Record<string, string> | optional | Display label (supports i18n). |
| isDefault | boolean | optional | Whether this is the object's default view in the switcher. |
| order | integer | optional | Sort order within the object's view switcher / left rail. |
| scope | Enum<'package' | 'shared' | 'personal'> | optional | Identity layer (defaults to package for source-loaded views). |
| owner | string | optional | Owner user id — set when scope is personal. |
| hidden | boolean | optional | Hidden from the switcher (per-user / per-org declutter). |
| protection | { lock: Enum<'none' | 'no-overlay' | 'no-delete' | 'full'>; reason: string; docsUrl?: string } | optional | Package author protection block — lock policy for this view. |
| _lock | Enum<'none' | 'no-overlay' | 'no-delete' | 'full'> | optional | Item-level lock — controls overlay & delete (ADR-0010). |
| _lockReason | string | optional | Human-readable reason shown when a write is refused by _lock. |
| _lockSource | Enum<'artifact' | 'package' | 'env-forced'> | optional | Layer that set _lock (artifact | package | env-forced). |
| _provenance | Enum<'package' | 'org' | 'env-forced'> | optional | Origin of the item (package | org | env-forced). |
| _packageId | string | optional | Owning package machine id. |
| _packageVersion | string | optional | Owning package version. |
| _lockDocsUrl | string | optional | Optional documentation link surfaced next to _lockReason. |
ViewItemName
Globally-unique view id, <object>.<viewKey>.
Type: string
ViewItemWire
Union Options
This schema accepts one of the following structures:
Option 1
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| viewKind | 'list' | ✅ | |
| config | { name?: string; label?: string | Record<string, string>; type?: Enum<'grid' | 'kanban' | 'gallery' | 'calendar' | 'timeline' | 'gantt' | 'map' | 'chart' | 'tree'>; data?: object | … +3 more; … } | ✅ | List-family view configuration. |
| name | string | ✅ | Globally-unique view id, <object>.<viewKey>. |
| object | string | ✅ | Bound object name — the foreign key used to aggregate views. |
| label | string | Record<string, string> | optional | Display label (supports i18n). |
| isDefault | boolean | optional | Whether this is the object's default view in the switcher. |
| order | integer | optional | Sort order within the object's view switcher / left rail. |
| scope | Enum<'package' | 'shared' | 'personal'> | optional | Identity layer (defaults to package for source-loaded views). |
| owner | string | optional | Owner user id — set when scope is personal. |
| hidden | boolean | optional | Hidden from the switcher (per-user / per-org declutter). |
| protection | { lock: Enum<'none' | 'no-overlay' | 'no-delete' | 'full'>; reason: string; docsUrl?: string } | optional | Package author protection block — lock policy for this view. |
| _lock | Enum<'none' | 'no-overlay' | 'no-delete' | 'full'> | optional | Item-level lock — controls overlay & delete (ADR-0010). |
| _lockReason | string | optional | Human-readable reason shown when a write is refused by _lock. |
| _lockSource | Enum<'artifact' | 'package' | 'env-forced'> | optional | Layer that set _lock (artifact | package | env-forced). |
| _provenance | Enum<'package' | 'org' | 'env-forced'> | optional | Origin of the item (package | org | env-forced). |
| _packageId | string | optional | Owning package machine id. |
| _packageVersion | string | optional | Owning package version. |
| _lockDocsUrl | string | optional | Optional documentation link surfaced next to _lockReason. |
| isPinned | boolean | optional | Studio round-trip: view pinned in the switcher (per-user state, written by the console — not authored). |
| sortOrder | integer | optional | Studio round-trip: position within the switcher (per-user state, written by the console — not authored). |
Option 2
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| viewKind | 'form' | ✅ | |
| config | { type?: Enum<'simple' | 'tabbed' | 'wizard' | 'split' | 'drawer' | 'modal'>; layout?: Enum<'vertical' | 'horizontal' | 'inline' | 'grid'>; columns?: integer; title?: string; … } | ✅ | Form view configuration. |
| name | string | ✅ | Globally-unique view id, <object>.<viewKey>. |
| object | string | ✅ | Bound object name — the foreign key used to aggregate views. |
| label | string | Record<string, string> | optional | Display label (supports i18n). |
| isDefault | boolean | optional | Whether this is the object's default view in the switcher. |
| order | integer | optional | Sort order within the object's view switcher / left rail. |
| scope | Enum<'package' | 'shared' | 'personal'> | optional | Identity layer (defaults to package for source-loaded views). |
| owner | string | optional | Owner user id — set when scope is personal. |
| hidden | boolean | optional | Hidden from the switcher (per-user / per-org declutter). |
| protection | { lock: Enum<'none' | 'no-overlay' | 'no-delete' | 'full'>; reason: string; docsUrl?: string } | optional | Package author protection block — lock policy for this view. |
| _lock | Enum<'none' | 'no-overlay' | 'no-delete' | 'full'> | optional | Item-level lock — controls overlay & delete (ADR-0010). |
| _lockReason | string | optional | Human-readable reason shown when a write is refused by _lock. |
| _lockSource | Enum<'artifact' | 'package' | 'env-forced'> | optional | Layer that set _lock (artifact | package | env-forced). |
| _provenance | Enum<'package' | 'org' | 'env-forced'> | optional | Origin of the item (package | org | env-forced). |
| _packageId | string | optional | Owning package machine id. |
| _packageVersion | string | optional | Owning package version. |
| _lockDocsUrl | string | optional | Optional documentation link surfaced next to _lockReason. |
| isPinned | boolean | optional | Studio round-trip: view pinned in the switcher (per-user state, written by the console — not authored). |
| sortOrder | integer | optional | Studio round-trip: position within the switcher (per-user state, written by the console — not authored). |
ViewKind
Whether config is a ListView (list family) or a FormView.
Allowed Values
listform
ViewScope
View identity layer: package | shared | personal.
Allowed Values
packagesharedpersonal
ViewSharing
View sharing and access configuration
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| type | Enum<'personal' | 'collaborative'> | ✅ | View ownership type |
| lockedBy | string | optional | User who locked the view configuration |
ViewTab
Tab configuration for multi-tab view interface
Properties
| Property | Type | Required | Description |
|---|---|---|---|
| name | string | ✅ | Tab identifier (snake_case) |
| label | string | Record<string, string> | optional | Display label |
| icon | string | optional | Tab icon name |
| view | string | optional | Referenced list view name from listViews |
| filter | { field: string; operator: Enum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'starts_with' | … +14 more>; value?: string | number | boolean | null | (string | number)[] }[] | optional | Tab-specific filter criteria |
| order | integer | optional | Tab display order |
| pinned | boolean | ✅ | Pin tab (cannot be removed by users) |
| isDefault | boolean | ✅ | Set as the default active tab |
| visible | boolean | ✅ | Tab visibility |
VisualizationType
Visualization type that users can switch to
Allowed Values
gridkanbangallerycalendartimelineganttmapcharttree