Draft: Convert hand-written render bootstraps via normalizeRender and compatH
What does this MR do and why?
Stacked on !247299 (merged) (the boring initVueApp wave) — retarget to master when it merges. This MR carries the 64 bootstraps that the wave deliberately defers: files whose render functions do more than mount a component with static props, so the plain { component, props, events } shape cannot express them.
Why normalizeRender + compatH
Vue 3 render functions are zero-argument and take flat props; Vue 2 render functions receive h and pass a structured data object (props/on/class/scopedSlots). Two existing helpers (~/lib/utils/vue3compat/) bridge that for hand-written renders:
compatH(tag, data, children)— identityhon Vue 2; on Vue 3 it flattens the v2 data object into flat props, camelizeson:listeners toonX, and convertsscopedSlotsto slots. This keeps the render function written once in the familiar v2 shape.normalizeRender(options)— wraps component options so @vue/compat's legacy-render detection stays correct for zero-argument render functions.
What is in here beyond the mechanical wrap
Most files are the wrap alone. The bespoke ones are commented in place:
- Detached mounts (
render_math,render_kroki,render_image_lightbox,alert.js,vue_alerts): the Vue 2 idiomvm.$mount()+ insert$elhas no Vue 3 equivalent, so a placeholder element is inserted and mounted on; teardown pairsunmountVueApp(which removes the rendered DOM on Vue 3) with the manual removal that covers Vue 2. - Root-instance APIs (
toggles/index.js): callers read/write the root's reactive data. Subscribing via instance$onis Vue-2-only, so the contract is documented and change handlers pass through theeventsoption. import_entities/import_projectsandissues/showcarry review-flagged oddities (inheritAttrs,getNoteableDataat the bootstrap layer) — kept behavior-preserving here; the suggested refactors are follow-up material.
A second commit adds the version-branched hand-written renders deferred in the wave's second review round: filtered_search/recent_searches_root.js (root-level reactive data, RENDER_FUNCTION opt-out, Vue 2 version branch for the data-object h signature) and render_vue_component_for_legacy_js.js (the shared legacy-JS bridge with the same shape).
Two companion specs ride along (user_popovers_spec, init_duo_panel_spec) because they assert against the converted bootstrap shapes.
All conversions in this MR are the exact content that was CI-proven on the pre-split !247299 (merged) (full run-all-rspec + run-rspec-vue3 matrix, pipeline 2716536446 lineage).
MR acceptance checklist
- I have evaluated the MR acceptance checklist for this MR.