Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/app-showcase/src/pages/task-workbench.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ export const TaskWorkbenchPage: Page = {
addRecordForm: false,
},

// Toolbar buttons ARE object actions (ADR-0047) — referenced by name from
// the showcase_task object's ActionSchema, not free text.
buttons: ['showcase_bulk_reassign', 'showcase_mark_done'],

showRecordCount: true,
},
};
8 changes: 5 additions & 3 deletions packages/spec/src/ui/page.form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,18 @@ export const pageForm = defineForm({
{ field: 'filterBy', type: 'repeater', helpText: 'Always-on base filter for the page' },
{ field: 'levels', helpText: 'Hierarchy levels to display (tree-like sources)' },
// ── Appearance ──
{ field: 'appearance', type: 'composite', helpText: 'Allowed visualizations (Grid / Kanban / Calendar / …) and description visibility' },
{ field: 'appearance', type: 'composite', disclosure: 'popover', helpText: 'Allowed visualizations (Grid / Kanban / Calendar / …) and description visibility' },
// ── User filters ──
{
field: 'userFilters',
widget: 'filter-mode',
helpText: 'End-user filter bar: None (no bar) / Tabs (named presets) / Dropdown (per-field). None removes the config.',
},
// ── User actions ──
{ field: 'userActions', type: 'composite', helpText: 'Toolbar toggles (search, sort, filter, row height)' },
{ field: 'addRecord', type: 'composite', helpText: 'Add-record entry point' },
{ field: 'userActions', type: 'composite', disclosure: 'popover', helpText: 'Toolbar toggles (search, sort, filter, row height)' },
{ field: 'addRecord', type: 'composite', disclosure: 'popover', helpText: 'Add-record entry point' },
// Buttons ARE object actions — pick from the source object's actions.
{ field: 'buttons', widget: 'action-multi', dependsOn: 'source', helpText: "Toolbar buttons — pick from this object's actions" },
{ field: 'showRecordCount', helpText: 'Show the record count bar' },
{ field: 'allowPrinting', helpText: 'Allow users to print this page' },
],
Expand Down
4 changes: 4 additions & 0 deletions packages/spec/src/ui/page.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ export const InterfacePageConfigSchema = lazySchema(() => z.object({
/** Add record */
addRecord: AddRecordConfigSchema.optional().describe('Add record entry point configuration'),

/** Toolbar buttons — references to the source object's actions (ActionSchema).
* Buttons ARE object actions (not free text): correct-by-construction. */
buttons: z.array(z.string()).optional().describe("Toolbar buttons — names of the source object's actions to surface in the page toolbar"),

/** Record count */
showRecordCount: z.boolean().optional().describe('Show record count at page bottom'),

Expand Down
1 change: 1 addition & 0 deletions packages/spec/src/ui/view.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ export const FormFieldSchema: z.ZodType<any> = lazySchema(() => z.object({

dependsOn: z.string().optional().describe('Parent field name for cascading'),
visibleOn: ExpressionInputSchema.optional().describe('Visibility predicate (CEL).'),
disclosure: z.enum(['inline', 'popover']).optional().describe('Composite rendering: inline bordered box (default) or a summary line + gear popover (progressive disclosure).'),
}));

/**
Expand Down
Loading