Bind only declared props to GLQL field presenters
What does this MR do and why?
GLQL tables render each cell through FieldPresenter (app/assets/javascripts/glql/components/presenters/field.vue), which mounts the presenter resolved from the registry with <component :is="presenter">. It used to bind item (the whole row), data (the cell value) and parameters to every presenter unconditionally, so a presenter that didn't declare one of those props received it as a fallthrough attribute.
Under Vue 2 that was harmless - it just added a DOM attribute like item="[object Object]" on the presenter's root element.
Under Vue 3, fallthrough attrs are merged onto a component root and override its explicit props. GitLab serves the Vue 3 build of work item pages to users in the vue3_migrate_work_items rollout. The EE status presenter (ee/app/assets/javascripts/glql/components/presenters/status.vue) declares only data and renders <work-item-status-badge :item="data" />. The fallthrough item (the row) overwrote the badge's item. Result on gitlab.com: signed-in users on the Vue 3 build saw empty grey pills in the Status column - no icon (#undefined), no text. Anonymous visitors on the Vue 2 build saw it correctly.
Fix: FieldPresenter now computes presenterProps from the props the resolved presenter actually declares (object or array form) and binds only those with v-bind. Nothing falls through anymore, for item, data or parameters. This also removes the stray item="[object Object]" / parameters attributes flagged in an earlier review.
Added a spec asserting that a presenter declaring only data receives only data and has no attributes on its root. It fails without the fix.
Jest passes under both VUE_VERSION=2 and VUE_VERSION=3. Local verification matrix on GDK is below.
References
- Live report: gitlab-org#23300 (closed) (the "MCP Server GA Release Must-Have Issues" GLQL table, Status column)
- Vue 3 rollout for work items: #594426
- Earlier discussion of the same fallthrough: !254977 (comment 3825113761)
Screenshots or screen recordings
All four taken on GDK on the same work item, toggling the vue3_migrate_work_items flag and the fix. The badge count next to each cell is document.querySelectorAll('.md td [item]').length, i.e. how many cells carry a stray item attribute.
| Without fix | With fix | |
|---|---|---|
| Vue 2 (flag off) | Renders, 61 stray item attributes ![]() |
Renders, 0 stray attributes ![]() |
| Vue 3 (flag on) | Empty pills, 49 stray item attributes ![]() |
Renders, 0 stray attributes ![]() |
How to set up and validate locally
-
Create a work item in a group that has work items with statuses (Ultimate), with this description:
display: table fields: state, title, status, milestone, assignee query: type = Issue and group = "<your-group>" and includeSubgroups = true and state = opened -
Vue 2, without the fix (
master): open the work item. The Status column renders. In the console,document.querySelectorAll('.md td [item]').lengthis greater than 0. -
Vue 3, without the fix: in a Rails console run
Feature.enable(:vue3_migrate_work_items), reload. The Status column shows empty pills with no icon or text. -
Check out this branch and reload with the flag still on. The Status column renders and
document.querySelectorAll('.md td [item], .md td [parameters]').lengthis0. -
Feature.disable(:vue3_migrate_work_items), reload. Vue 2 with the fix renders the same, also with0stray attributes.
MR acceptance checklist
Evaluated against the MR acceptance checklist: no DB changes, no security-sensitive paths, no new user-facing strings, no docs impact. Changelog: fixed trailer is on the commit.



