Skip to content

Commit dc65fc0

Browse files
committed
fix(spec): declare summaryOperations sub-fields in the Field metadata form (#3257)
`fieldForm` declared `summaryOperations` as a bare `composite` (no sub-fields), so the protocol-driven form renderer fell back to a raw JSON editor. Declare the inner shape explicitly — object (ref:object), function (select), field, relationshipField, and filter (widget: 'filter-condition') — mirroring the `summaryOperations` Zod schema and surfacing the roll-up filter from #1868. Gate the block to `data.type == 'summary'`. Small step toward #3257 (metadata-driven Studio field designer); the live objectui inspector already edits these fields. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HbK4FqcHwp9jSwdhTtxYuC
1 parent 611402f commit dc65fc0

2 files changed

Lines changed: 45 additions & 1 deletion

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
fix(spec): declare `summaryOperations` sub-fields in the Field metadata form (#3257)
6+
7+
`fieldForm` (the registered metadata form for editing a Field) previously
8+
declared `summaryOperations` as a bare `composite` with no sub-fields, so a
9+
protocol-driven renderer had to fall back to a raw JSON editor. It now declares
10+
the inner shape explicitly — `object` (`ref:object`), `function` (select),
11+
`field`, `relationshipField`, and `filter` (bound to `widget: 'filter-condition'`)
12+
— mirroring the `summaryOperations` Zod schema and surfacing the roll-up `filter`
13+
added in #1868. Also gates the block to `data.type == 'summary'`.
14+
15+
Small step toward #3257 (making the Studio field designer metadata-driven rather
16+
than hand-coded); the live objectui inspector already edits these fields.

packages/spec/src/data/field.form.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,35 @@ export const fieldForm = defineForm({
5656
collapsed: true,
5757
fields: [
5858
{ field: 'expression', widget: 'textarea', helpText: 'CEL expression to calculate this field (makes it read-only)' },
59-
{ field: 'summaryOperations', type: 'composite', helpText: 'Roll-up summary configuration (for parent-child relationships)' },
59+
{
60+
field: 'summaryOperations',
61+
type: 'composite',
62+
visibleWhen: "data.type == 'summary'",
63+
helpText: 'Roll-up summary configuration (for parent-child relationships)',
64+
// Declare the composite's inner shape so the protocol-driven form
65+
// renders structured sub-fields (not a raw JSON blob). Mirrors the
66+
// `summaryOperations` Zod schema in field.zod.ts; `filter` is bound to
67+
// the FilterCondition widget so only matching child rows aggregate.
68+
fields: [
69+
{ field: 'object', widget: 'ref:object', required: true, helpText: 'Child object to aggregate' },
70+
{
71+
field: 'function',
72+
type: 'select',
73+
required: true,
74+
options: [
75+
{ label: 'Count', value: 'count' },
76+
{ label: 'Sum', value: 'sum' },
77+
{ label: 'Min', value: 'min' },
78+
{ label: 'Max', value: 'max' },
79+
{ label: 'Average', value: 'avg' },
80+
],
81+
helpText: 'Aggregation function',
82+
},
83+
{ field: 'field', required: true, helpText: 'Child field to aggregate (ignored for count)' },
84+
{ field: 'relationshipField', helpText: 'Child FK back to this parent (auto-detected when omitted)' },
85+
{ field: 'filter', widget: 'filter-condition', helpText: 'Only child rows matching this predicate are aggregated (e.g. status == received)' },
86+
],
87+
},
6088
],
6189
},
6290
{

0 commit comments

Comments
 (0)