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
6 changes: 5 additions & 1 deletion examples/app-showcase/src/objects/task.object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ export const Task = ObjectSchema.create({
project: Field.masterDetail('showcase_project', {
label: 'Project',
required: true,
inlineEdit: true,
// Pin the editable-grid form factor (fast bulk line-item entry, with the
// column chooser + per-row expand). Left at `true`, the smart default
// would pick `form` for this fat child — the right call for many apps;
// here we keep the grid demo. Use `'form'` to force the per-row form.
inlineEdit: 'grid',
inlineTitle: 'Tasks',
relatedListTitle: 'Tasks',
relatedListColumns: ['title', 'status', 'priority', 'assignee', 'due_date'],
Expand Down
25 changes: 17 additions & 8 deletions packages/spec/src/data/field.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,15 +405,24 @@ export const FieldSchema = lazySchema(() => z.object({
deleteBehavior: z.enum(['set_null', 'cascade', 'restrict']).optional().default('set_null').describe('What happens if referenced record is deleted'),
/**
* Master-detail INLINE EDITING. On a child's `master_detail`/`lookup` field
* (whose `reference` is the parent object), set `inlineEdit: true` to declare
* "this child is entered/edited inline within the parent's form". The
* parent's standard create/edit form then renders an editable grid for these
* children and saves parent + children in ONE atomic transaction — no form
* view config and no bespoke page. The intent lives here in the data model;
* forms derive the UI. Use for true line-item/composition children (invoice
* lines, order items); leave off for associations (comments, attachments).
* (whose `reference` is the parent object), declare that "this child is
* entered/edited inline within the parent's form". The parent's standard
* create/edit form then renders the children and saves parent + children in
* ONE atomic transaction — no form view config and no bespoke page. The intent
* lives here in the data model; forms derive the UI.
*
* The value also selects the EDITING FORM FACTOR:
* - `true` → auto: the UI picks `grid` or `form` from the child's shape
* (rich types / many fields → `form`, else `grid`).
* - `'grid'` → an editable line-item grid (fast bulk entry; thin children
* like invoice lines / order items).
* - `'form'` → a compact read-only list; "Add" / per-row edit opens the
* child's FULL form (fat children with rich types, e.g. long
* text, attachments, many fields).
* Use for true line-item/composition children; leave off for associations
* (comments, attachments) — surface those as detail-page related lists.
*/
inlineEdit: z.boolean().optional().describe('Edit these child records inline within the parent object\'s form (atomic master-detail).'),
inlineEdit: z.union([z.boolean(), z.enum(['grid', 'form'])]).optional().describe('Edit these child records inline within the parent\'s form (atomic master-detail). true = auto-pick grid/form by child shape; \'grid\' = editable line-item grid; \'form\' = list + per-row full form.'),
/** Optional section title for the inline grid (defaults to the child object label). */
inlineTitle: z.string().optional().describe('Title for the inline master-detail grid'),
/** Optional explicit grid columns for the inline editor (derived from the child object when omitted). */
Expand Down
19 changes: 19 additions & 0 deletions skills/objectstack-data/rules/relationships.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,25 @@ A form view may still set `subforms` to override the derived columns/order, but
the relationship `inlineEdit` is the primary, zero-config path. See the
objectstack-ui skill (Master-Detail Forms) for the rendering side.

#### Inline-edit form factor (`grid` vs `form`)

`inlineEdit` also picks how the children are entered:

```typescript
inlineEdit: true // auto — pick grid/form from the child's shape (default)
inlineEdit: 'grid' // editable line-item grid (fast bulk entry; thin children)
inlineEdit: 'form' // read-only list; "Add" / per-row edit opens the FULL form
```

- **`'grid'`** — spreadsheet-like editable grid. Best for *thin* line items
(invoice/order lines): few columns, high volume, keyboard-fast.
- **`'form'`** — compact read-only list; Add / per-row edit opens the child's
complete form. Best for *fat* children (long text, attachments, many fields)
that don't fit a narrow grid cell.
- **`true`** / omitted — **smart default**: picks `form` when the child has
rich/form-only fields (textarea, file, image, json, location…) or more than ~8
editable fields, else `grid`. Set the string to override.

### Detail-page related lists (the read-side mirror)

Where `inlineEdit` is the **write** side (child pulled into the parent's entry
Expand Down
8 changes: 6 additions & 2 deletions skills/objectstack-ui/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,12 @@ custom page or form config. Prefer, in order:
DATA MODEL — set `inlineEdit: true` on the child's `master_detail` field that
references the parent (see the objectstack-data skill → Relationships →
Inline Editing). Every standard New/Edit form for the parent (modal, drawer,
full-page) then auto-renders an editable child grid and saves parent +
children in one atomic `/api/v1/batch`. **No view metadata needed.**
full-page) then auto-renders the children and saves parent + children in one
atomic `/api/v1/batch`. **No view metadata needed.** The value picks the
form factor: `'grid'` (editable line-item grid — thin children), `'form'`
(read-only list whose Add / per-row edit opens the child's FULL form — fat
children with rich types), or `true` (smart default: `form` when the child
has rich/form-only fields or >~8 fields, else `grid`).

2. **Form view `subforms` (override / tuning).** Add to a form view only when you
need to override the derived columns/order, or expose a child the
Expand Down