Update multiple selected options as one
What does this MR do and why?
Collapse multiple selected decision options on text edit.
Currently, a resolved decision with several selected options is rendered with the selected options as a comma-separated string in the FE modal. We need a way to support editing of this comma-separated string in these cases.
Based on our discussion, for now we have decided to store the edit as one additional custom option, rather than try to update across the multiple selected options. The original options are then deselected and preserved.
Related thread: !256870 (comment 3895315261)
Related to #630642 (closed)
FE integration notes
Two arguments, two intents. One or the other at the moment; do not send both in one request.
Editing the decision text → selectedOptionContent
- For editing single decisions, use this new argument instead of the options array. Send it whenever the decision field changed.
- One option selected → that option's
contentis replaced (same id). - Otherwise (none selected, or more than one selected -> currently displayed as a comma-separated string) → any selected options are deselected and a new selected option is created with the text. The originals stay, as unselected options. This is also how a decision resolved by rejecting every option gets a written-in decision, if we want to open this path.
- Resolved decisions only. Can be combined with
title,description,resolutionRationale,sourceLink,discussionId,resolvedById,resolvingNoteIdin the same request.
Editing specific options → options (unchanged from 5b)
- Edits existing options by id:
content,description,selected(resolved only). Can be multiple. Up to 5 entries per request; unlisted options are untouched. - Cannot add or remove options.
- Deselecting every selected option without selecting another is a reject-all and needs a rationale (stored or in the same call).
selectedOptionContentnever needs one; it always leaves one option selected.- Note: The current gotcha: stored resolutionRationale is left as is and may become stale during this. As the BE cannot tell whether this rationale still applies, this may need some kind of UX guard on the FE side. It can be sent in the same request; when the decision text changes and a rationale exists, consider highlighting the "Why" field or asking whether it still applies.
GraphQL query using the new selectedOptionContent argument:
{
"workItemDecisionUpdateInput": {
"id": "gid://gitlab/WorkItems::Decision/246",
"selectedOptionContent": "Use PostgreSQL with Redis as a cache"
}
}DB review notes
Database review
No migrations. This MR adds one write path to WorkItems::Decisions::UpdateService and widens one model validation. All statements run inside a single decision's options (at most 6 rows), narrowed by index_work_item_decision_options_on_work_item_decision_id. No new indexes are needed.
Files
| File | Why |
|---|---|
ee/app/services/work_items/decisions/update_service.rb |
New update_selected_option_content!: one update_all (deselect), one INSERT (new selected option), one UPDATE by PK (in-place edit), plus the association load it reads the selection from. |
ee/app/models/work_items/decision_option.rb |
options_count_within_limit now allows MAX_OPTIONS_PER_DECISION + 1 rows when the inserted option is selected. Same COUNT query as before; only the compared limit changes. |
ee/app/graphql/mutations/work_items/decisions/update.rb |
New selectedOptionContent argument that reaches the service path above. |
Queries
Generated using local GDK as this is an experimental new feature
5. One option selected: edit its content in place — update_service.rb:209
UPDATE "work_item_decision_options" SET "updated_at" = '2026-09-24 21:48:02.337666', "content" = 'Edited in place' WHERE "work_item_decision_options"."id" = 48522Query plan: https://explain.depesz.com/s/7Nup
2. Collapse: deselect the selected options — update_service.rb:213
UPDATE "work_item_decision_options" SET "selected" = FALSE, "updated_at" = '2026-09-24 21:48:02.300158' WHERE ("work_item_decision_options"."id") IN (SELECT "work_item_decision_options"."id" FROM "work_item_decision_options" WHERE "work_item_decision_options"."work_item_decision_id" = 21381 AND "work_item_decision_options"."id" IN (48522, 48523) ORDER BY "work_item_decision_options"."id" ASC)Query plan: https://explain.depesz.com/s/PgaW
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to #630642 (closed)