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

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 vue2_without_fix Renders, 0 stray attributes vue2_with_fix
Vue 3 (flag on) Empty pills, 49 stray item attributes vue3_without_fix Renders, 0 stray attributes vue3_with_fix

How to set up and validate locally

  1. 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
  2. Vue 2, without the fix (master): open the work item. The Status column renders. In the console, document.querySelectorAll('.md td [item]').length is greater than 0.

  3. 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.

  4. Check out this branch and reload with the flag still on. The Status column renders and document.querySelectorAll('.md td [item], .md td [parameters]').length is 0.

  5. Feature.disable(:vue3_migrate_work_items), reload. Vue 2 with the fix renders the same, also with 0 stray 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.

Edited by Daniele Rossetti

Merge request reports

Loading
Loading