mirror of
https://github.com/open-webui/open-webui.git
synced 2026-07-18 02:04:06 -05:00
[PR #24865] [CLOSED] feat(chat): citation modal as global singleton via store #131562
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/open-webui/open-webui/pull/24865
Author: @julenlurnova
Created: 5/18/2026
Status: ❌ Closed
Base:
dev← Head:feat/citation-modal-store📝 Commits (3)
328474cfeat(chat): add citation modal store9f89645feat(chat): mount global citation modal in layoutab57a0arefactor(chat): dispatch citation modal via store📊 Changes
3 files changed (+48 additions, -20 deletions)
View changed files
📝
src/lib/components/chat/Messages/Citations.svelte(+4 -20)➕
src/lib/stores/citations.ts(+31 -0)📝
src/routes/(app)/+layout.svelte(+13 -0)📄 Description
Before submitting, make sure you've checked the following:
devembed/showEmbedsstore pattern. No new settings, no UX change.devfeatChangelog Entry
Description
Citations.sveltemounts<CitationModal>per instance. A chat with N RAG responses has N modal state machines in the DOM, idle until clicked.This PR applies the same singleton pattern already used by
embed/showEmbeds/showControls(writable stores in$lib/stores, sink mounted once at app level, any caller dispatches via store action). Three benefits:openCitation()directly — nobind:thisref hacks back into the right<Citations>instance.citationModal, render alongside the modal).Added
src/lib/stores/citations.ts—citationModalwritable store +openCitation/closeCitationactions.<CitationModal>mount insrc/routes/(app)/+layout.sveltesubscribed to the store.Changed
src/lib/components/chat/Messages/Citations.svelte— dispatches viaopenCitation()instead of a local<CitationModal bind:show>mount.showSourceModalexport kept as a thin wrapper for back-compat with external callers (e.g.ResponseMessage.sveltewhich still callscitationsElement.showSourceModal(id)from a Markdown click handler).Deprecated
N/A
Removed
showCitationModal,selectedCitation) inCitations.svelte.Fixed
N/A — pure refactor, no bug fix.
Security
N/A
Breaking Changes
None. Existing consumers of
Citations.sveltekeep working without modification;showSourceModalexternal API preserved.Additional Information
Bridge note. The
+layoutbridge between the store and<CitationModal bind:show={local}>uses one-way sync (store → local) plus a close-back handler:The naive
if ($store.show !== local) { sync }form races itself: the X click writesfalsetolocalviabind:show, then the reactive immediately re-syncs from the store (stilltrue), undoing the close. The split form above avoids the loop because the first$:only writeslocal, never reads it; the second$:only triggers whenlocaltransitions tofalsewhile the store is still open.Manual tests performed.
[n]marker click → modal opens (viashowSourceModalwrapper, the existing path throughResponseMessage.svelte).embed_urlcitation → opens right-side embed panel (unchanged path, theshowSourceModalwrapper preserves the embed branch).readOnlymode (shared chat) → opens link in new tab (unchanged).Follow-ups. The same pattern fits
ImagePreview(Image.sveltecurrently mounts one per image — 7+ call sites in the chat tree) andCodeExecutionModal. Happy to open those as separate small PRs after this is reviewed.Screenshots or Videos
Refactor with no UX change; visual behavior is identical to current
main.Contributor License Agreement
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.