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
16 changes: 16 additions & 0 deletions .changeset/field-form-summary-subfields.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
'@objectstack/spec': patch
---

fix(spec): declare `summaryOperations` sub-fields in the Field metadata form (#3257)

`fieldForm` (the registered metadata form for editing a Field) previously
declared `summaryOperations` as a bare `composite` with no sub-fields, so a
protocol-driven renderer had to fall back to a raw JSON editor. It now declares
the inner shape explicitly — `object` (`ref:object`), `function` (select),
`field`, `relationshipField`, and `filter` (bound to `widget: 'filter-condition'`)
— mirroring the `summaryOperations` Zod schema and surfacing the roll-up `filter`
added in #1868. Also gates the block to `data.type == 'summary'`.

Small step toward #3257 (making the Studio field designer metadata-driven rather
than hand-coded); the live objectui inspector already edits these fields.
30 changes: 29 additions & 1 deletion packages/spec/src/data/field.form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,35 @@ export const fieldForm = defineForm({
collapsed: true,
fields: [
{ field: 'expression', widget: 'textarea', helpText: 'CEL expression to calculate this field (makes it read-only)' },
{ field: 'summaryOperations', type: 'composite', helpText: 'Roll-up summary configuration (for parent-child relationships)' },
{
field: 'summaryOperations',
type: 'composite',
visibleWhen: "data.type == 'summary'",
helpText: 'Roll-up summary configuration (for parent-child relationships)',
// Declare the composite's inner shape so the protocol-driven form
// renders structured sub-fields (not a raw JSON blob). Mirrors the
// `summaryOperations` Zod schema in field.zod.ts; `filter` is bound to
// the FilterCondition widget so only matching child rows aggregate.
fields: [
{ field: 'object', widget: 'ref:object', required: true, helpText: 'Child object to aggregate' },
{
field: 'function',
type: 'select',
required: true,
options: [
{ label: 'Count', value: 'count' },
{ label: 'Sum', value: 'sum' },
{ label: 'Min', value: 'min' },
{ label: 'Max', value: 'max' },
{ label: 'Average', value: 'avg' },
],
helpText: 'Aggregation function',
},
{ field: 'field', required: true, helpText: 'Child field to aggregate (ignored for count)' },
{ field: 'relationshipField', helpText: 'Child FK back to this parent (auto-detected when omitted)' },
{ field: 'filter', widget: 'filter-condition', helpText: 'Only child rows matching this predicate are aggregated (e.g. status == received)' },
],
},
],
},
{
Expand Down