Skip to content

Commit 5c4a8c8

Browse files
os-zhuangclaude
andauthored
feat(spec): RecordRelatedListProps.add — add-existing-via-picker (generic m2m/junction) (#2324)
* feat(spec): RecordRelatedListProps.add — add-existing-via-picker (generic m2m/junction) A related list could only '+ New' (create+navigate). Add an optional `add` config so a related list can LINK existing records via a picker: pick from `add.picker.object` (the far side) → create a link row in `objectName` as {[relationshipField]: parentId, [add.linkField]: pickedId} (junction), or omit linkField to re-parent a 1:m child. Generic over any relationship; the canonical use is 'Assigned Users' on a permission set (assign sys_user → ai_seat etc.), with server-side insert rules (e.g. the AI-seat cap) surfacing inline. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(changeset): related-list add-by-picker --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 3afaeed commit 5c4a8c8

2 files changed

Lines changed: 28 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@objectstack/spec': minor
3+
---
4+
5+
feat(spec): RecordRelatedListProps.add — add-existing-via-picker (generic m2m/junction assignment). A related list can now link existing records via a picker, not just create+navigate. Powers a generic "Assigned Users" / Manage Assignments UI on permission sets.

packages/spec/src/ui/component.zod.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,29 @@ export const RecordRelatedListProps = z.object({
8484
title: I18nLabelSchema.optional().describe('Custom title for the related list'),
8585
showViewAll: z.boolean().default(true).describe('Show "View All" link to see all related records'),
8686
actions: z.array(z.string()).optional().describe('Action IDs available for related records'),
87+
/**
88+
* Enable an "Add" affordance that links EXISTING records via a picker, rather
89+
* than only "+ New" (create-and-navigate). Generic over m2m / junction
90+
* relationships: pick records from `add.picker.object` (the far side) and
91+
* create a link row in `objectName` with `{[relationshipField]: <parentId>,
92+
* [add.linkField]: <pickedId>}`. Omit `linkField` for a plain 1:m re-parent
93+
* (the picked child's `relationshipField` is set to the parent id instead).
94+
* Server-side rules still apply on insert (e.g. the AI-seat cap), and their
95+
* errors surface in the dialog. The canonical use is "Assigned Users" on a
96+
* permission set (objectName=`sys_user_permission_set`,
97+
* relationshipField=`permission_set_id`, picker.object=`sys_user`,
98+
* linkField=`user_id`).
99+
*/
100+
add: z.object({
101+
picker: z.object({
102+
object: z.string().describe('Object to pick records from (the far side of an m2m, or the child object for a 1:m re-parent).'),
103+
valueField: z.string().default('id').describe('Field on the picked record used as the link value (default `id`).'),
104+
labelField: z.string().optional().describe('Field shown in the picker rows (defaults to the object title field).'),
105+
filter: z.array(ViewFilterRuleSchema).optional().describe('Restrict which records the picker offers.'),
106+
}).describe('Where the Add affordance sources records from.'),
107+
linkField: z.string().optional().describe('Field on `objectName` that stores the picked record id (junction case). Omit for a 1:m re-parent.'),
108+
label: I18nLabelSchema.optional().describe('Label for the Add button (default "Add").'),
109+
}).optional().describe('Add-existing-via-picker config (generic m2m/junction assignment).'),
87110
/** ARIA accessibility */
88111
aria: AriaPropsSchema.optional().describe('ARIA accessibility attributes'),
89112
});

0 commit comments

Comments
 (0)