Repository navigation
fix(invite): guard against JS double-mount - #1576
Merged
Merged
Conversation
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
icewind1991
approved these changes
May 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1555. Modal not opening when clicking "Invite guest" in the share dialog on production NC 32.x.
Root cause
guests-init.mjswas evaluating twice in production. NC'sUtil::addScriptappends a?v=<hash>cache-buster to the script-tag URL, but the bundledimportinsideguests-main.mjsuses the bare relative path. Different URLs, the browser keys ES modules by URL, so the file runs twice andcreateApp(GuestForm).mount('#guest-root')happens twice.The visible Vue instance is the last-evaluated one.
OCA.Guests.openGuestDialogis reassigned during both evaluations and ends up bound to that visible instance, so Talk and contacts integrations work fine. Butmain.tsdoesimport { guestForm } from './init.ts', which resolves to the bare-path module record, i.e. the orphaned first instance. The share-dialog handler then writesisOpened = trueon a detached vnode and nothing visible happens.Didn't reproduce on docker-dev because
TemplateLayout::getVersionHashSuffix()returns an empty string whendebug => true(which docker-dev sets by default), so both URLs match and the module loads once. Reproduces on the officialnextcloud:32.0.9Docker image and every real production install.Fix
Make
init.tsidempotent. The first evaluation creates the Vue app and stashes it onOCA.Guests._guestForm. The second evaluation reuses it instead of mounting a second app on#guest-root.openGuestDialogis assigned once after the if/else so its presence doesn't depend on which branch ran. No behavioral change for callers.Related
The server-side fix for this exact bug already exists in NC33+: nextcloud/server#56941 added
emit_import_map(), which emits an ES module importmap aliasing the bare path to the cache-busted URL. Single module record, double-mount becomes impossible. Backported tostable33andstable34, notstable32. Asking for that backport separately. Other community apps with multi-entry bundles probably hit the same latent issue on NC32.Test plan
nextcloud:32.0.9with guests v4.7.4 from app store, matches v4.7.1 no new guests can be added #1555 stack traceBackport
stable-4.7