From 9e9c28fe3c5b08b7560194e8bf78040a65efeb18 Mon Sep 17 00:00:00 2001 From: Luis de Dios Date: Wed, 18 Mar 2026 15:06:06 +0100 Subject: [PATCH] :bug: Fix MCP notifications when there is only one tab --- frontend/src/app/main/data/workspace/mcp.cljs | 64 ++++++++++--------- .../main/data/workspace/notifications.cljs | 7 +- .../app/main/ui/settings/integrations.cljs | 3 +- .../src/app/main/ui/workspace/main_menu.cljs | 14 ++-- .../src/app/main/ui/workspace/main_menu.scss | 4 ++ frontend/translations/en.po | 5 +- frontend/translations/es.po | 5 +- 7 files changed, 62 insertions(+), 40 deletions(-) diff --git a/frontend/src/app/main/data/workspace/mcp.cljs b/frontend/src/app/main/data/workspace/mcp.cljs index 63e7de7516..d8ce546c85 100644 --- a/frontend/src/app/main/data/workspace/mcp.cljs +++ b/frontend/src/app/main/data/workspace/mcp.cljs @@ -53,21 +53,28 @@ (rx/take 1) (rx/map #(ptk/data-event ::connect)))))) -(defn manage-notification - [mcp-enabled? mcp-connected?] - (if mcp-enabled? - (if mcp-connected? - (rx/of (ntf/hide)) - (rx/of (ntf/dialog :content (tr "notifications.mcp.active-tab-switching.text") - :cancel {:label (tr "labels.dismiss") - :callback #(st/emit! (ntf/hide) - (ptk/event ::ev/event {::ev/name "confirm-mcp-tab-switch" - ::ev/origin "workspace-notification"}))} - :accept {:label (tr "labels.switch") - :callback #(st/emit! (connect-mcp) - (ptk/event ::ev/event {::ev/name "dismiss-mcp-tab-switch" - ::ev/origin "workspace-notification"}))}))) - (rx/of (ntf/hide)))) +(defn manage-mcp-notification + [] + (ptk/reify ::manage-mcp-notification + ptk/WatchEvent + (watch [_ state _] + (let [mcp-connected? (true? (-> state :workspace-local :mcp :connection)) + mcp-enabled? (true? (-> state :profile :props :mcp-enabled)) + num-sessions (-> state :workspace-presence vals count) + multi-session? (> num-sessions 1)] + (if (and mcp-enabled? multi-session?) + (if mcp-connected? + (rx/of (ntf/hide)) + (rx/of (ntf/dialog :content (tr "notifications.mcp.active-in-another-tab") + :cancel {:label (tr "labels.dismiss") + :callback #(st/emit! (ntf/hide) + (ptk/event ::ev/event {::ev/name "confirm-mcp-tab-switch" + ::ev/origin "workspace-notification"}))} + :accept {:label (tr "labels.switch") + :callback #(st/emit! (connect-mcp) + (ptk/event ::ev/event {::ev/name "dismiss-mcp-tab-switch" + ::ev/origin "workspace-notification"}))}))) + (rx/of (ntf/hide))))))) (defn update-mcp-status [value] @@ -77,26 +84,24 @@ (update-in state [:profile :props] assoc :mcp-enabled value)) ptk/WatchEvent - (watch [_ state _] + (watch [_ _ _] (rx/merge - (let [mcp-connected? (-> state :workspace-local :mcp :connected)] - (manage-notification value mcp-connected?)) - (case value - true (rx/of (ptk/data-event ::connect)) - false (rx/of (ptk/data-event ::disconnect)) - nil))))) + (rx/of (manage-mcp-notification))) + (case value + true (rx/of (ptk/data-event ::connect)) + false (rx/of (ptk/data-event ::disconnect)) + nil)))) (defn update-mcp-connection [value] (ptk/reify ::update-mcp-plugin-connection ptk/UpdateEvent (update [_ state] - (update-in state [:workspace-local :mcp] assoc :connected value)) + (update-in state [:workspace-local :mcp] assoc :connection value)) ptk/WatchEvent - (watch [_ state _] - (let [mcp-enabled? (-> state :profile :props :mcp-enabled)] - (manage-notification mcp-enabled? value))))) + (watch [_ _ _] + (rx/of (manage-mcp-notification))))) (defn init-mcp! [stream] @@ -116,11 +121,12 @@ :getServerUrl #(str cf/mcp-ws-uri) :setMcpStatus (fn [status] - (let [mcp-connected? (case status + (let [mcp-connection (case status "connected" true "disconnected" false - nil)] - (st/emit! (update-mcp-connection mcp-connected?)) + "error" nil + "")] + (st/emit! (update-mcp-connection mcp-connection)) (log/info :hint "MCP STATUS" :status status))) :on diff --git a/frontend/src/app/main/data/workspace/notifications.cljs b/frontend/src/app/main/data/workspace/notifications.cljs index 9bfc7ac8a2..743fecd850 100644 --- a/frontend/src/app/main/data/workspace/notifications.cljs +++ b/frontend/src/app/main/data/workspace/notifications.cljs @@ -23,6 +23,7 @@ [app.main.data.workspace.edition :as dwe] [app.main.data.workspace.layout :as dwly] [app.main.data.workspace.libraries :as dwl] + [app.main.data.workspace.mcp :as mcp] [app.main.data.workspace.texts :as dwt] [app.main.router :as rt] [app.util.globals :refer [global]] @@ -212,7 +213,11 @@ (update [_ state] (if (or (= :disconnect type) (= :leave-file type)) (update state :workspace-presence dissoc session-id) - (update state :workspace-presence update-presence)))))) + (update state :workspace-presence update-presence))) + + ptk/WatchEvent + (watch [_ _ _] + (rx/of (mcp/manage-mcp-notification)))))) (defn handle-pointer-update [{:keys [page-id session-id position zoom zoom-inverse vbox vport] :as msg}] diff --git a/frontend/src/app/main/ui/settings/integrations.cljs b/frontend/src/app/main/ui/settings/integrations.cljs index f4b820e0b3..a54b43d2b9 100644 --- a/frontend/src/app/main/ui/settings/integrations.cljs +++ b/frontend/src/app/main/ui/settings/integrations.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.settings.integrations (:require-macros [app.main.style :as stl]) (:require - [app.common.data :as d] [app.common.data.macros :as dm] [app.common.schema :as sm] [app.common.time :as ct] @@ -410,7 +409,7 @@ profile (mf/deref refs/profile) mcp-key (some #(when (= (:type %) "mcp") %) tokens) - mcp-enabled? (d/nilv (-> profile :props :mcp-enabled) false) + mcp-enabled? (true? (-> profile :props :mcp-enabled)) expires-at (:expires-at mcp-key) expired? (and (some? expires-at) (> (ct/now) expires-at)) diff --git a/frontend/src/app/main/ui/workspace/main_menu.cljs b/frontend/src/app/main/ui/workspace/main_menu.cljs index aa320694c7..223e30ce50 100644 --- a/frontend/src/app/main/ui/workspace/main_menu.cljs +++ b/frontend/src/app/main/ui/workspace/main_menu.cljs @@ -749,8 +749,8 @@ profile (mf/deref refs/profile) workspace-local (mf/deref refs/workspace-local) - mcp-enabled? (-> profile :props :mcp-enabled) - mcp-connected? (-> workspace-local :mcp :connected) + mcp-enabled? (true? (-> profile :props :mcp-enabled)) + mcp-connected? (true? (-> workspace-local :mcp :connection)) on-nav-to-integrations (mf/use-fn @@ -978,9 +978,10 @@ :class (stl/css :item-arrow)}]]) (when (contains? cf/flags :mcp) - (let [mcp-enabled? (-> profile :props :mcp-enabled) - mcp-connected? (-> workspace-local :mcp :connected) - mcp-active? (and mcp-enabled? mcp-connected?)] + (let [mcp-enabled? (true? (-> profile :props :mcp-enabled)) + mcp-connection (-> workspace-local :mcp :connection) + mcp-connected? (true? mcp-connection) + mcp-error? (nil? mcp-connection)] [:> dropdown-menu-item* {:class (stl/css :base-menu-item :menu-item) :on-click on-menu-click :on-key-down (fn [event] @@ -992,7 +993,8 @@ [:span {:class (stl/css :item-name)} (tr "workspace.header.menu.option.mcp")] [:span {:class (stl/css-case :item-indicator true - :active mcp-active?)}] + :active (and mcp-enabled? mcp-connected?) + :failed (and mcp-enabled? mcp-error?))}] [:> icon* {:icon-id i/arrow-right :class (stl/css :item-arrow)}]])) diff --git a/frontend/src/app/main/ui/workspace/main_menu.scss b/frontend/src/app/main/ui/workspace/main_menu.scss index d69b09e61a..1b12e2cdbf 100644 --- a/frontend/src/app/main/ui/workspace/main_menu.scss +++ b/frontend/src/app/main/ui/workspace/main_menu.scss @@ -134,6 +134,10 @@ &.active { --menu-indicator-color: var(--color-accent-primary); } + + &.failed { + --menu-indicator-color: var(--color-foreground-error); + } } .item-arrow { diff --git a/frontend/translations/en.po b/frontend/translations/en.po index c36e440412..4e52ddd5ee 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -3833,9 +3833,12 @@ msgstr "Invitation sent successfully" msgid "notifications.invitation-link-copied" msgstr "Invitation link copied" -msgid "notifications.mcp.active-tab-switching.text" +msgid "notifications.mcp.active-in-another-tab" msgstr "MCP is active in another tab. Switch here?" +msgid "notifications.mcp.active-in-this-tab" +msgstr "MCP is now active in this tab." + #: src/app/main/ui/settings/delete_account.cljs:24 msgid "notifications.profile-deletion-not-allowed" msgstr "You can't delete your profile. Reassign your teams before proceed." diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 4d58a6dc7f..a2d6277640 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -3790,9 +3790,12 @@ msgstr "Invitación enviada con éxito" msgid "notifications.invitation-link-copied" msgstr "Enlace de invitacion copiado" -msgid "notifications.mcp.active-tab-switching.text" +msgid "notifications.mcp.active-in-another-tab" msgstr "MCP está activo en otra pestaña. ¿Cambiar a esta?" +msgid "notifications.mcp.active-in-this-tab" +msgstr "MCP está ahora activo en esta pestaña." + #: src/app/main/ui/settings/delete_account.cljs:24 msgid "notifications.profile-deletion-not-allowed" msgstr "No puedes borrar tu perfil. Reasigna tus equipos antes de seguir."