[PR #24864] [CLOSED] feat(chat): citation modal as global singleton via store #131561

Closed
opened 2026-05-21 17:13:16 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/24864
Author: @julenlurnova
Created: 5/18/2026
Status: Closed

Base: mainHead: feat/citation-modal-store


📝 Commits (3)

  • 86932af feat(chat): add citation modal store
  • 1956616 feat(chat): mount global citation modal in layout
  • c486904 refactor(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

Citations.svelte mounts per instance. A chat with N RAG responses has N modal state machines in the DOM, idle until clicked.

Same shape as the embed/showEmbeds pattern already in $lib/stores. Applied to citations:

  • Removes N-instances cost (memory, listeners, lifecycle).
  • Markdown citation-marker clicks can call openCitation() directly — no bind:this ref hacks into the right instance.
  • Gives forks an extension point (subscribe to citationModal, render alongside).

Changes

  • NEW src/lib/stores/citations.ts — writable + openCitation/closeCitation
  • src/routes/(app)/+layout.svelte — mount once, subscribed to store
  • src/lib/components/chat/Messages/Citations.svelte — dispatch via store instead of local mount; showSourceModal export kept as thin wrapper for back-compat

Bridge note

The +layout bridge is one-way sync (store→local) + close-back handler. The naive if ($store.show !== local) { sync } form races itself: the X click writes false to local via bind:show, the reactive immediately re-syncs from store (still true), undoes the close. The split form (one $: writes local from store, a separate $: writes store-close when local goes false) avoids the loop.

Tested

  • Click chip pill → modal opens; X / Esc / backdrop close
  • Inline Markdown [n] marker click → modal opens (via showSourceModal wrapper)
  • embed_url citation → opens right-side embed panel (unchanged path)
  • readOnly mode (shared chat) → opens link in new tab (unchanged)
  • Multiple chats in tabs → single global modal, no cross-chat leakage

Follow-ups (separate PRs if this lands)

Same pattern fits ImagePreview (Image.svelte mounts one per image — 7+ call sites in the chat tree) and CodeExecutionModal. Happy to open those as small PRs after this is reviewed.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/open-webui/pull/24864 **Author:** [@julenlurnova](https://github.com/julenlurnova) **Created:** 5/18/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `feat/citation-modal-store` --- ### 📝 Commits (3) - [`86932af`](https://github.com/open-webui/open-webui/commit/86932af9c40000b82145707fef36fb5cad38e1dc) feat(chat): add citation modal store - [`1956616`](https://github.com/open-webui/open-webui/commit/1956616d8e407cfbb63a7818d43a77a4a3ab20cc) feat(chat): mount global citation modal in layout - [`c486904`](https://github.com/open-webui/open-webui/commit/c48690426b7ee0952e383b0d7bb4ce71a6e53255) refactor(chat): dispatch citation modal via store ### 📊 Changes **3 files changed** (+48 additions, -20 deletions) <details> <summary>View changed files</summary> 📝 `src/lib/components/chat/Messages/Citations.svelte` (+4 -20) ➕ `src/lib/stores/citations.ts` (+31 -0) 📝 `src/routes/(app)/+layout.svelte` (+13 -0) </details> ### 📄 Description Citations.svelte mounts <CitationModal> per instance. A chat with N RAG responses has N modal state machines in the DOM, idle until clicked. Same shape as the embed/showEmbeds pattern already in $lib/stores. Applied to citations: - Removes N-instances cost (memory, listeners, lifecycle). - Markdown citation-marker clicks can call openCitation() directly — no `bind:this` ref hacks into the right <Citations> instance. - Gives forks an extension point (subscribe to citationModal, render alongside). ### Changes - NEW `src/lib/stores/citations.ts` — writable + openCitation/closeCitation - `src/routes/(app)/+layout.svelte` — mount <CitationModal> once, subscribed to store - `src/lib/components/chat/Messages/Citations.svelte` — dispatch via store instead of local mount; `showSourceModal` export kept as thin wrapper for back-compat ### Bridge note The +layout bridge is one-way sync (store→local) + close-back handler. The naive `if ($store.show !== local) { sync }` form races itself: the X click writes false to local via `bind:show`, the reactive immediately re-syncs from store (still true), undoes the close. The split form (one `$:` writes local from store, a separate `$:` writes store-close when local goes false) avoids the loop. ### Tested - Click chip pill → modal opens; X / Esc / backdrop close - Inline Markdown [n] marker click → modal opens (via showSourceModal wrapper) - embed_url citation → opens right-side embed panel (unchanged path) - readOnly mode (shared chat) → opens link in new tab (unchanged) - Multiple chats in tabs → single global modal, no cross-chat leakage ### Follow-ups (separate PRs if this lands) Same pattern fits ImagePreview (Image.svelte mounts one per image — 7+ call sites in the chat tree) and CodeExecutionModal. Happy to open those as small PRs after this is reviewed. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-05-21 17:13:16 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#131561