🐛 Fix MCP notifications when there is only one tab

This commit is contained in:
Luis de Dios 2026-03-18 15:06:06 +01:00 committed by Alonso Torres
parent 93de83c427
commit 9e9c28fe3c
7 changed files with 62 additions and 40 deletions

View File

@ -53,21 +53,28 @@
(rx/take 1) (rx/take 1)
(rx/map #(ptk/data-event ::connect)))))) (rx/map #(ptk/data-event ::connect))))))
(defn manage-notification (defn manage-mcp-notification
[mcp-enabled? mcp-connected?] []
(if mcp-enabled? (ptk/reify ::manage-mcp-notification
(if mcp-connected? ptk/WatchEvent
(rx/of (ntf/hide)) (watch [_ state _]
(rx/of (ntf/dialog :content (tr "notifications.mcp.active-tab-switching.text") (let [mcp-connected? (true? (-> state :workspace-local :mcp :connection))
:cancel {:label (tr "labels.dismiss") mcp-enabled? (true? (-> state :profile :props :mcp-enabled))
:callback #(st/emit! (ntf/hide) num-sessions (-> state :workspace-presence vals count)
(ptk/event ::ev/event {::ev/name "confirm-mcp-tab-switch" multi-session? (> num-sessions 1)]
::ev/origin "workspace-notification"}))} (if (and mcp-enabled? multi-session?)
:accept {:label (tr "labels.switch") (if mcp-connected?
:callback #(st/emit! (connect-mcp) (rx/of (ntf/hide))
(ptk/event ::ev/event {::ev/name "dismiss-mcp-tab-switch" (rx/of (ntf/dialog :content (tr "notifications.mcp.active-in-another-tab")
::ev/origin "workspace-notification"}))}))) :cancel {:label (tr "labels.dismiss")
(rx/of (ntf/hide)))) :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 (defn update-mcp-status
[value] [value]
@ -77,26 +84,24 @@
(update-in state [:profile :props] assoc :mcp-enabled value)) (update-in state [:profile :props] assoc :mcp-enabled value))
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ _ _]
(rx/merge (rx/merge
(let [mcp-connected? (-> state :workspace-local :mcp :connected)] (rx/of (manage-mcp-notification)))
(manage-notification value mcp-connected?)) (case value
(case value true (rx/of (ptk/data-event ::connect))
true (rx/of (ptk/data-event ::connect)) false (rx/of (ptk/data-event ::disconnect))
false (rx/of (ptk/data-event ::disconnect)) nil))))
nil)))))
(defn update-mcp-connection (defn update-mcp-connection
[value] [value]
(ptk/reify ::update-mcp-plugin-connection (ptk/reify ::update-mcp-plugin-connection
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(update-in state [:workspace-local :mcp] assoc :connected value)) (update-in state [:workspace-local :mcp] assoc :connection value))
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ _ _]
(let [mcp-enabled? (-> state :profile :props :mcp-enabled)] (rx/of (manage-mcp-notification)))))
(manage-notification mcp-enabled? value)))))
(defn init-mcp! (defn init-mcp!
[stream] [stream]
@ -116,11 +121,12 @@
:getServerUrl #(str cf/mcp-ws-uri) :getServerUrl #(str cf/mcp-ws-uri)
:setMcpStatus :setMcpStatus
(fn [status] (fn [status]
(let [mcp-connected? (case status (let [mcp-connection (case status
"connected" true "connected" true
"disconnected" false "disconnected" false
nil)] "error" nil
(st/emit! (update-mcp-connection mcp-connected?)) "")]
(st/emit! (update-mcp-connection mcp-connection))
(log/info :hint "MCP STATUS" :status status))) (log/info :hint "MCP STATUS" :status status)))
:on :on

View File

@ -23,6 +23,7 @@
[app.main.data.workspace.edition :as dwe] [app.main.data.workspace.edition :as dwe]
[app.main.data.workspace.layout :as dwly] [app.main.data.workspace.layout :as dwly]
[app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.mcp :as mcp]
[app.main.data.workspace.texts :as dwt] [app.main.data.workspace.texts :as dwt]
[app.main.router :as rt] [app.main.router :as rt]
[app.util.globals :refer [global]] [app.util.globals :refer [global]]
@ -212,7 +213,11 @@
(update [_ state] (update [_ state]
(if (or (= :disconnect type) (= :leave-file type)) (if (or (= :disconnect type) (= :leave-file type))
(update state :workspace-presence dissoc session-id) (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 (defn handle-pointer-update
[{:keys [page-id session-id position zoom zoom-inverse vbox vport] :as msg}] [{:keys [page-id session-id position zoom zoom-inverse vbox vport] :as msg}]

View File

@ -7,7 +7,6 @@
(ns app.main.ui.settings.integrations (ns app.main.ui.settings.integrations
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.schema :as sm] [app.common.schema :as sm]
[app.common.time :as ct] [app.common.time :as ct]
@ -410,7 +409,7 @@
profile (mf/deref refs/profile) profile (mf/deref refs/profile)
mcp-key (some #(when (= (:type %) "mcp") %) tokens) 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) expires-at (:expires-at mcp-key)
expired? (and (some? expires-at) (> (ct/now) expires-at)) expired? (and (some? expires-at) (> (ct/now) expires-at))

View File

@ -749,8 +749,8 @@
profile (mf/deref refs/profile) profile (mf/deref refs/profile)
workspace-local (mf/deref refs/workspace-local) workspace-local (mf/deref refs/workspace-local)
mcp-enabled? (-> profile :props :mcp-enabled) mcp-enabled? (true? (-> profile :props :mcp-enabled))
mcp-connected? (-> workspace-local :mcp :connected) mcp-connected? (true? (-> workspace-local :mcp :connection))
on-nav-to-integrations on-nav-to-integrations
(mf/use-fn (mf/use-fn
@ -978,9 +978,10 @@
:class (stl/css :item-arrow)}]]) :class (stl/css :item-arrow)}]])
(when (contains? cf/flags :mcp) (when (contains? cf/flags :mcp)
(let [mcp-enabled? (-> profile :props :mcp-enabled) (let [mcp-enabled? (true? (-> profile :props :mcp-enabled))
mcp-connected? (-> workspace-local :mcp :connected) mcp-connection (-> workspace-local :mcp :connection)
mcp-active? (and mcp-enabled? mcp-connected?)] mcp-connected? (true? mcp-connection)
mcp-error? (nil? mcp-connection)]
[:> dropdown-menu-item* {:class (stl/css :base-menu-item :menu-item) [:> dropdown-menu-item* {:class (stl/css :base-menu-item :menu-item)
:on-click on-menu-click :on-click on-menu-click
:on-key-down (fn [event] :on-key-down (fn [event]
@ -992,7 +993,8 @@
[:span {:class (stl/css :item-name)} [:span {:class (stl/css :item-name)}
(tr "workspace.header.menu.option.mcp")] (tr "workspace.header.menu.option.mcp")]
[:span {:class (stl/css-case :item-indicator true [: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 [:> icon* {:icon-id i/arrow-right
:class (stl/css :item-arrow)}]])) :class (stl/css :item-arrow)}]]))

View File

@ -134,6 +134,10 @@
&.active { &.active {
--menu-indicator-color: var(--color-accent-primary); --menu-indicator-color: var(--color-accent-primary);
} }
&.failed {
--menu-indicator-color: var(--color-foreground-error);
}
} }
.item-arrow { .item-arrow {

View File

@ -3833,9 +3833,12 @@ msgstr "Invitation sent successfully"
msgid "notifications.invitation-link-copied" msgid "notifications.invitation-link-copied"
msgstr "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?" 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 #: src/app/main/ui/settings/delete_account.cljs:24
msgid "notifications.profile-deletion-not-allowed" msgid "notifications.profile-deletion-not-allowed"
msgstr "You can't delete your profile. Reassign your teams before proceed." msgstr "You can't delete your profile. Reassign your teams before proceed."

View File

@ -3790,9 +3790,12 @@ msgstr "Invitación enviada con éxito"
msgid "notifications.invitation-link-copied" msgid "notifications.invitation-link-copied"
msgstr "Enlace de invitacion copiado" 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?" 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 #: src/app/main/ui/settings/delete_account.cljs:24
msgid "notifications.profile-deletion-not-allowed" msgid "notifications.profile-deletion-not-allowed"
msgstr "No puedes borrar tu perfil. Reasigna tus equipos antes de seguir." msgstr "No puedes borrar tu perfil. Reasigna tus equipos antes de seguir."