From 64e6ba58df0cd8a10df1d4c6c7459f37f509cc40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=85=E5=91=A8=E6=B6=9B?= Date: Fri, 3 Jul 2026 18:35:41 -0700 Subject: [PATCH 1/2] demo(app-showcase): bulk multi-select edit on the Project grid (#2185) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exercises the objectui BulkActionDialog multi-select fix (objectstack-ai/objectui#2186) end-to-end in a real running app: - project.object.ts: add `labels` (multiselect, fixed options) and `team_members` (multi-user) — the two shapes the bulk dialog could not set before #2185 (its picker collapsed to a single value / overwrote the array). - project.view.ts: add the two columns and three `bulkActionDefs`: • set_labels → multi-select on a `select` param (array patch) • assign_team → multi-select on a `lookup` param (sys_user) • reschedule → the new `date` control + a single-select Verified in objectstack dev: select rows → each action writes an array (or date) patch to all selected records; labels/team_members/end_date persist server-side. --- .../src/objects/project.object.ts | 18 +++++ .../app-showcase/src/views/project.view.ts | 71 +++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/examples/app-showcase/src/objects/project.object.ts b/examples/app-showcase/src/objects/project.object.ts index adae2c88fe..8007c7c4e5 100644 --- a/examples/app-showcase/src/objects/project.object.ts +++ b/examples/app-showcase/src/objects/project.object.ts @@ -56,6 +56,24 @@ export const Project = ObjectSchema.create({ start_date: Field.date({ label: 'Start Date' }), end_date: Field.date({ label: 'Target End Date' }), owner: Field.text({ label: 'Owner', maxLength: 200 }), + // Multi-value fields — the payload for the grid's *bulk-edit* showcase. A + // multiselect (fixed options) and a multi-user field are exactly the two + // shapes that, before #2185, the bulk dialog could not set: its people / + // select picker collapsed to a single value and overwrote the array. The + // list view's `bulkActionDefs` below now sets both with real multi-select + // controls, writing an array patch. + labels: { + type: 'multiselect', + label: 'Labels', + options: [ + { label: 'Frontend', value: 'frontend', color: '#3B82F6' }, + { label: 'Backend', value: 'backend', color: '#8B5CF6' }, + { label: 'Design', value: 'design', color: '#EC4899' }, + { label: 'QA', value: 'qa', color: '#F59E0B' }, + { label: 'DevOps', value: 'devops', color: '#10B981' }, + ], + }, + team_members: Field.user({ label: 'Team Members', multiple: true }), // Roll-up summaries — recomputed server-side whenever a child task is // inserted / updated / deleted (FK auto-detected: showcase_task.project). task_count: Field.summary({ diff --git a/examples/app-showcase/src/views/project.view.ts b/examples/app-showcase/src/views/project.view.ts index 1e656ab5ec..085106761f 100644 --- a/examples/app-showcase/src/views/project.view.ts +++ b/examples/app-showcase/src/views/project.view.ts @@ -15,10 +15,81 @@ export const ProjectViews = defineView({ { field: 'account' }, { field: 'status' }, { field: 'health' }, + { field: 'labels' }, + { field: 'team_members' }, { field: 'budget' }, { field: 'budget_remaining' }, { field: 'end_date' }, ], + // Rich bulk-edit definitions (#2185) — select rows, then "set the same + // value on all of them" through the BulkActionDialog. Each def exercises a + // control the dialog gained in #2185: + // • set_labels → multi-select on a `select` param (fixed options) + // • assign_team → multi-select on a `lookup` param (users; array patch) + // • reschedule → the new `date` control + a single-select together + // A def with no `multiple` still renders a single-select, unchanged. + bulkActionDefs: [ + { + name: 'set_labels', + label: 'Set Labels', + operation: 'update', + confirmText: 'Set these labels on every selected project?', + params: [ + { + name: 'labels', + label: 'Labels', + type: 'select', + multiple: true, + required: true, + options: [ + { label: 'Frontend', value: 'frontend' }, + { label: 'Backend', value: 'backend' }, + { label: 'Design', value: 'design' }, + { label: 'QA', value: 'qa' }, + { label: 'DevOps', value: 'devops' }, + ], + }, + ], + }, + { + name: 'assign_team', + label: 'Assign Team', + operation: 'update', + confirmText: 'Assign these team members to every selected project?', + params: [ + { + name: 'team_members', + label: 'Team Members', + type: 'lookup', + object: 'sys_user', + multiple: true, + labelField: 'name', + required: true, + }, + ], + }, + { + name: 'reschedule', + label: 'Reschedule', + operation: 'update', + confirmText: 'Apply this schedule/status to every selected project?', + params: [ + { name: 'end_date', label: 'Target End Date', type: 'date' }, + { + name: 'status', + label: 'Status', + type: 'select', + options: [ + { label: 'Planned', value: 'planned' }, + { label: 'Active', value: 'active' }, + { label: 'On Hold', value: 'on_hold' }, + { label: 'Completed', value: 'completed' }, + { label: 'Cancelled', value: 'cancelled' }, + ], + }, + ], + }, + ], }, listViews: { by_status: { From 8c859b102cc33fa9e95ac78445c416bf94df58dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=85=E5=91=A8=E6=B6=9B?= Date: Fri, 3 Jul 2026 18:47:01 -0700 Subject: [PATCH 2/2] demo(app-showcase): add single-lookup bulk action (reassign_account) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exercises the searchable single-lookup picker (objectui#2186): a `lookup` param with no `multiple` now renders a searchable reference combobox over showcase_account, not a bare dropdown. Verified in objectstack dev — select rows → Reassign Account → search/pick one → every selected project's `account` is set to the single chosen id. --- .../app-showcase/src/views/project.view.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/examples/app-showcase/src/views/project.view.ts b/examples/app-showcase/src/views/project.view.ts index 085106761f..51aa1933bc 100644 --- a/examples/app-showcase/src/views/project.view.ts +++ b/examples/app-showcase/src/views/project.view.ts @@ -26,8 +26,9 @@ export const ProjectViews = defineView({ // control the dialog gained in #2185: // • set_labels → multi-select on a `select` param (fixed options) // • assign_team → multi-select on a `lookup` param (users; array patch) + // • reassign_account → single-select on a `lookup` param (searchable + // reference picker, not a bare dropdown) // • reschedule → the new `date` control + a single-select together - // A def with no `multiple` still renders a single-select, unchanged. bulkActionDefs: [ { name: 'set_labels', @@ -68,6 +69,22 @@ export const ProjectViews = defineView({ }, ], }, + { + name: 'reassign_account', + label: 'Reassign Account', + operation: 'update', + confirmText: 'Move every selected project to this account?', + params: [ + { + name: 'account', + label: 'Account', + type: 'lookup', + object: 'showcase_account', + labelField: 'name', + required: true, + }, + ], + }, { name: 'reschedule', label: 'Reschedule',