From e99b6ec213ce80cfdbe2852d8d24a9acc5726a11 Mon Sep 17 00:00:00 2001 From: Luis de Dios Date: Tue, 7 Apr 2026 10:58:04 +0200 Subject: [PATCH] :bug: Fix MCP active tab switching (#8856) --- frontend/src/app/main/broadcast.cljs | 5 +- frontend/src/app/main/data/workspace.cljs | 306 +++++++++--------- frontend/src/app/main/data/workspace/mcp.cljs | 223 +++++++++---- .../main/data/workspace/notifications.cljs | 8 +- frontend/src/app/main/refs.cljs | 3 + .../app/main/ui/settings/integrations.cljs | 18 +- .../src/app/main/ui/workspace/main_menu.cljs | 10 +- 7 files changed, 330 insertions(+), 243 deletions(-) diff --git a/frontend/src/app/main/broadcast.cljs b/frontend/src/app/main/broadcast.cljs index 33e12f12a6..0a4ccf1070 100644 --- a/frontend/src/app/main/broadcast.cljs +++ b/frontend/src/app/main/broadcast.cljs @@ -57,5 +57,6 @@ [type data] (ptk/reify ::event ptk/EffectEvent - (effect [_ _ _] - (emit! type data)))) + (effect [_ state _] + (let [session-id (get state :session-id)] + (emit! session-id type data))))) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index dd03d7601e..5fce5c0217 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -25,7 +25,6 @@ [app.common.types.variant :as ctv] [app.common.uuid :as uuid] [app.config :as cf] - [app.main.broadcast :as mbc] [app.main.data.changes :as dch] [app.main.data.comments :as dcmt] [app.main.data.common :as dcm] @@ -213,9 +212,11 @@ ptk/WatchEvent (watch [_ _ _] - (rx/of (dp/check-open-plugin) - (fdf/fix-deleted-fonts-for-local-library file-id) - (mcp/init-mcp-connection))))) + (rx/merge + (rx/of (dp/check-open-plugin) + (fdf/fix-deleted-fonts-for-local-library file-id)) + (when (contains? cf/flags :mcp) + (rx/of (mcp/init))))))) (defn- bundle-fetched [{:keys [file file-id thumbnails] :as bundle}] @@ -319,180 +320,169 @@ :team-id (dm/str team-id) :file-id (dm/str file-id)) - (->> (rx/merge - (rx/concat - ;; Fetch all essential data that should be loaded before the file - (rx/merge - (if ^boolean render-wasm? - (->> (rx/from @wasm/module) - (rx/filter true?) - (rx/tap (fn [_] - (let [event (ug/event "penpot:wasm:loaded")] - (ug/dispatch! event)))) - (rx/ignore)) - (rx/empty)) + (rx/concat + (->> (rx/merge + (rx/concat + ;; Fetch all essential data that should be loaded before the file + (rx/merge + (if ^boolean render-wasm? + (->> (rx/from @wasm/module) + (rx/filter true?) + (rx/tap (fn [_] + (let [event (ug/event "penpot:wasm:loaded")] + (ug/dispatch! event)))) + (rx/ignore)) + (rx/empty)) - (->> stream - (rx/filter (ptk/type? ::df/fonts-loaded)) - (rx/take 1) - (rx/ignore)) + (->> stream + (rx/filter (ptk/type? ::df/fonts-loaded)) + (rx/take 1) + (rx/ignore)) - (rx/of (ntf/hide) - (dcmt/retrieve-comment-threads file-id) - (dcmt/fetch-profiles) - (df/fetch-fonts team-id)) + (rx/of (ntf/hide) + (dcmt/retrieve-comment-threads file-id) + (dcmt/fetch-profiles) + (df/fetch-fonts team-id)) - (when (contains? cf/flags :mcp) - (rx/of (du/fetch-access-tokens)))) + (when (contains? cf/flags :mcp) + (rx/of (du/fetch-access-tokens)))) - ;; Once the essential data is fetched, lets proceed to - ;; fetch teh file bunldle - (rx/of (fetch-bundle file-id features))) + ;; Once the essential data is fetched, lets proceed to + ;; fetch teh file bunldle + (rx/of (fetch-bundle file-id features))) - (->> stream - (rx/filter (ptk/type? ::bundle-fetched)) - (rx/take 1) - (rx/map deref) - (rx/mapcat - (fn [{:keys [file]}] - (log/debug :hint "bundle fetched" - :team-id (dm/str team-id) - :file-id (dm/str file-id)) + (->> stream + (rx/filter (ptk/type? ::bundle-fetched)) + (rx/take 1) + (rx/map deref) + (rx/mapcat + (fn [{:keys [file]}] + (log/debug :hint "bundle fetched" + :team-id (dm/str team-id) + :file-id (dm/str file-id)) - (rx/of (dpj/initialize-project (:project-id file)) - (dwn/initialize team-id file-id) - (dwsl/initialize-shape-layout) - (fetch-libraries file-id features) - (-> (workspace-initialized file-id) - (with-meta {:team-id team-id - :file-id file-id})))))) + (rx/of (dpj/initialize-project (:project-id file)) + (dwn/initialize team-id file-id) + (dwsl/initialize-shape-layout) + (fetch-libraries file-id features) + (-> (workspace-initialized file-id) + (with-meta {:team-id team-id + :file-id file-id})))))) - ;; Install dev perf observers once the workspace is ready - (when (contains? cf/flags :perf-logs) - (->> stream - (rx/filter (ptk/type? ::workspace-initialized)) - (rx/take 1) - (rx/tap (fn [_] (perf/setup))))) + ;; Install dev perf observers once the workspace is ready + (when (contains? cf/flags :perf-logs) + (->> stream + (rx/filter (ptk/type? ::workspace-initialized)) + (rx/take 1) + (rx/tap (fn [_] (perf/setup))))) - (when (contains? cf/flags :mcp) - (->> mbc/stream - (rx/filter (mbc/type? :mcp-enabled-change-connection)) - (rx/map deref) - (rx/mapcat (fn [value] - (rx/of (mcp/update-mcp-connection value) - (mcp/user-disconnect-mcp)))))) + (->> stream + (rx/filter (ptk/type? ::dps/persistence-notification)) + (rx/take 1) + (rx/map dwc/set-workspace-visited)) - (when (contains? cf/flags :mcp) - (->> mbc/stream - (rx/filter (mbc/type? :mcp-enabled-change-status)) - (rx/map deref) - (rx/map mcp/update-mcp-status))) + (when-let [component-id (some-> rparams :component-id uuid/parse)] + (->> stream + (rx/filter (ptk/type? ::workspace-initialized)) + (rx/observe-on :async) + (rx/take 1) + (rx/map #(dwl/go-to-local-component :id component-id :update-layout? (:update-layout rparams))))) - (->> stream - (rx/filter (ptk/type? ::dps/persistence-notification)) - (rx/take 1) - (rx/map dwc/set-workspace-visited)) + (when (:board-id rparams) + (->> stream + (rx/filter (ptk/type? ::dwv/initialize-viewport)) + (rx/take 1) + (rx/map zoom-to-frame))) - (when-let [component-id (some-> rparams :component-id uuid/parse)] - (->> stream - (rx/filter (ptk/type? ::workspace-initialized)) - (rx/observe-on :async) - (rx/take 1) - (rx/map #(dwl/go-to-local-component :id component-id :update-layout? (:update-layout rparams))))) + (when-let [comment-id (some-> rparams :comment-id uuid/parse)] + (->> stream + (rx/filter (ptk/type? ::workspace-initialized)) + (rx/observe-on :async) + (rx/take 1) + (rx/map #(dwcm/navigate-to-comment-id comment-id)))) - (when (:board-id rparams) - (->> stream - (rx/filter (ptk/type? ::dwv/initialize-viewport)) - (rx/take 1) - (rx/map zoom-to-frame))) + (when render-wasm? + (->> stream + (rx/filter dch/commit?) + (rx/map deref) + (rx/mapcat + (fn [{:keys [redo-changes]}] + (let [added (->> redo-changes + (filter #(= (:type %) :add-obj)) + (map :id))] + (->> (rx/from added) + (rx/map process-wasm-object))))))) - (when-let [comment-id (some-> rparams :comment-id uuid/parse)] - (->> stream - (rx/filter (ptk/type? ::workspace-initialized)) - (rx/observe-on :async) - (rx/take 1) - (rx/map #(dwcm/navigate-to-comment-id comment-id)))) + (when render-wasm? + (let [local-commits-s + (->> stream + (rx/filter dch/commit?) + (rx/map deref) + (rx/filter #(and (= :local (:source %)) + (not (contains? (:tags %) :position-data)))) + (rx/filter (complement empty?))) - (when render-wasm? - (->> stream - (rx/filter dch/commit?) - (rx/map deref) - (rx/mapcat - (fn [{:keys [redo-changes]}] - (let [added (->> redo-changes - (filter #(= (:type %) :add-obj)) - (map :id))] - (->> (rx/from added) - (rx/map process-wasm-object))))))) + notifier-s + (rx/merge + (->> local-commits-s (rx/debounce 1000)) + (->> stream (rx/filter dps/force-persist?))) - (when render-wasm? - (let [local-commits-s - (->> stream - (rx/filter dch/commit?) - (rx/map deref) - (rx/filter #(and (= :local (:source %)) - (not (contains? (:tags %) :position-data)))) - (rx/filter (complement empty?))) + objects-s + (rx/from-atom refs/workspace-page-objects {:emit-current-value? true}) - notifier-s - (rx/merge - (->> local-commits-s (rx/debounce 1000)) - (->> stream (rx/filter dps/force-persist?))) + current-page-id-s + (rx/from-atom refs/current-page-id {:emit-current-value? true})] - objects-s - (rx/from-atom refs/workspace-page-objects {:emit-current-value? true}) + (->> local-commits-s + (rx/buffer-until notifier-s) + (rx/with-latest-from objects-s) + (rx/map + (fn [[commits objects]] + (->> commits + (mapcat :redo-changes) + (filter #(contains? #{:mod-obj :add-obj} (:type %))) + (filter #(cfh/text-shape? objects (:id %))) + (map #(vector + (:id %) + (wasm.api/calculate-position-data (get objects (:id %)))))))) - current-page-id-s - (rx/from-atom refs/current-page-id {:emit-current-value? true})] + (rx/with-latest-from current-page-id-s) + (rx/map + (fn [[text-position-data page-id]] + (let [changes + (->> text-position-data + (mapv (fn [[id position-data]] + {:type :mod-obj + :id id + :page-id page-id + :operations + [{:type :set + :attr :position-data + :val position-data + :ignore-touched true + :ignore-geometry true}]})))] + (when (d/not-empty? changes) + (dch/commit-changes + {:redo-changes changes :undo-changes [] + :save-undo? false + :tags #{:position-data}}))))) + (rx/take-until stoper-s)))) - (->> local-commits-s - (rx/buffer-until notifier-s) - (rx/with-latest-from objects-s) - (rx/map - (fn [[commits objects]] - (->> commits - (mapcat :redo-changes) - (filter #(contains? #{:mod-obj :add-obj} (:type %))) - (filter #(cfh/text-shape? objects (:id %))) - (map #(vector - (:id %) - (wasm.api/calculate-position-data (get objects (:id %)))))))) + (->> stream + (rx/filter dch/commit?) + (rx/map deref) + (rx/mapcat + (fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo?]}] + (if (and save-undo? (seq undo-changes)) + (let [entry {:undo-changes undo-changes + :redo-changes redo-changes + :undo-group undo-group + :tags tags}] + (rx/of (dwu/append-undo entry stack-undo?))) + (rx/empty)))))) + (rx/take-until stoper-s)) - (rx/with-latest-from current-page-id-s) - (rx/map - (fn [[text-position-data page-id]] - (let [changes - (->> text-position-data - (mapv (fn [[id position-data]] - {:type :mod-obj - :id id - :page-id page-id - :operations - [{:type :set - :attr :position-data - :val position-data - :ignore-touched true - :ignore-geometry true}]})))] - (when (d/not-empty? changes) - (dch/commit-changes - {:redo-changes changes :undo-changes [] - :save-undo? false - :tags #{:position-data}}))))) - (rx/take-until stoper-s)))) - - (->> stream - (rx/filter dch/commit?) - (rx/map deref) - (rx/mapcat - (fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo?]}] - (if (and save-undo? (seq undo-changes)) - (let [entry {:undo-changes undo-changes - :redo-changes redo-changes - :undo-group undo-group - :tags tags}] - (rx/of (dwu/append-undo entry stack-undo?))) - (rx/empty)))))) - (rx/take-until stoper-s)))) + (rx/of (mcp/notify-other-tabs-disconnect))))) ptk/EffectEvent (effect [_ _ _] diff --git a/frontend/src/app/main/data/workspace/mcp.cljs b/frontend/src/app/main/data/workspace/mcp.cljs index 50b70fee43..f4a9c9bacc 100644 --- a/frontend/src/app/main/data/workspace/mcp.cljs +++ b/frontend/src/app/main/data/workspace/mcp.cljs @@ -48,7 +48,7 @@ (ptk/reify ::set-mcp-active ptk/UpdateEvent (update [_ state] - (assoc-in state [:workspace-local :mcp :active] value)))) + (assoc-in state [:mcp :active] value)))) (defn start-reconnect-watcher! [] @@ -61,7 +61,7 @@ (fn [] ;; Try to reconnect if active and not connected (when-not (contains? #{"connecting" "connected"} - (-> @st/state :workspace-local :mcp :connection)) + (-> @st/state :mcp :connection-status)) (.log js/console "Reconnecting to MCP...") (st/emit! (ptk/data-event ::connect)))))))) @@ -72,55 +72,46 @@ (rx/dispose! @interval-sub) (reset! interval-sub nil))) -;; This event will arrive when the user selects disconnect on the menu -;; or there is a broadcast message for disconnection -(defn user-disconnect-mcp - [] - (ptk/reify ::remote-disconnect-mcp +(declare manage-mcp-notification) + +(defn handle-pong + [{:keys [id data]}] + (ptk/reify ::handle-pong + ptk/UpdateEvent + (update [_ state] + (let [mcp-state (get state :mcp)] + (cond + (= "connected" (:connection-status data)) + (update state :mcp assoc :connected-tab id) + + (and (= "disconnected" (:connection-status data)) + (= id (:connection-status mcp-state))) + (update state :mcp dissoc :connected-tab) + + :else + state))) + ptk/WatchEvent (watch [_ _ _] - (rx/of (ptk/data-event ::disconnect))) + (rx/of (manage-mcp-notification))))) - ptk/EffectEvent - (effect [_ _ _] - (stop-reconnect-watcher!)))) - -(defn connect-mcp +;; This event will arrive when a new workspace is open in another tab +(defn handle-ping [] - (ptk/reify ::connect-mcp - ptk/WatchEvent - (watch [_ _ stream] - (mbc/emit! :mcp-enabled-change-connection false) - (->> stream - (rx/filter (ptk/type? ::disconnect)) - (rx/take 1) - (rx/map #(ptk/data-event ::connect)))))) - -(defn manage-mcp-notification - [] - (ptk/reify ::manage-mcp-notification + (ptk/reify ::handle-ping ptk/WatchEvent (watch [_ state _] - (let [mcp-connected? (= "connected" (-> state :workspace-local :mcp :connection)) - mcp-enabled? (true? (-> state :profile :props :mcp-enabled)) - num-sessions (-> state :workspace-presence count) - multi-session? (> num-sessions 1) - mcp-active? (-> state :workspace-local :mcp :active)] - (if (and mcp-enabled? multi-session?) - (if (or mcp-connected? mcp-active?) - (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))))))) + (let [conn-status (get-in state [:mcp :connection-status])] + (rx/of (mbc/event :mcp/pong {:connection-status conn-status})))))) -;; This event will arrive when the mcp is enabled in the main menu +(defn notify-other-tabs-disconnect + [] + (ptk/reify ::notify-other-tabs-disconnect + ptk/WatchEvent + (watch [_ _ _] + (rx/of (mbc/event :mcp/pong {:connection-status "disconnected"}))))) + +;; This event will arrive when the mcp is enabled in the dashboard (defn update-mcp-status [value] (ptk/reify ::update-mcp-status @@ -131,27 +122,81 @@ ptk/WatchEvent (watch [_ _ _] (rx/merge - (rx/of (manage-mcp-notification))) - (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 +(defn update-mcp-connection-status [value] (ptk/reify ::update-mcp-plugin-connection ptk/UpdateEvent (update [_ state] - (update-in state [:workspace-local :mcp] assoc :connection value)) + (update state :mcp assoc :connection-status value)) ptk/WatchEvent (watch [_ _ _] - (rx/of (manage-mcp-notification))))) + (rx/of (manage-mcp-notification) + (mbc/event :mcp/pong {:connection-status value}))))) -(defn init-mcp! +(defn connect-mcp + [] + (ptk/reify ::connect-mcp + ptk/UpdateEvent + (update [_ state] + (update state :mcp assoc :connected-tab (:session-id state))) + + ptk/WatchEvent + (watch [_ _ _] + (rx/of (mbc/event :mcp/force-disconect {}) + (ptk/data-event ::connect))))) + +;; This event will arrive when the user selects disconnect on the menu +;; or there is a broadcast message for disconnection +(defn user-disconnect-mcp + [] + (ptk/reify ::user-disconnect-mcp + ptk/WatchEvent + (watch [_ _ _] + (rx/of (ptk/data-event ::disconnect) + (update-mcp-connection-status "disconnected"))) + + ptk/EffectEvent + (effect [_ _ _] + (stop-reconnect-watcher!)))) + +(defn- manage-mcp-notification + [] + (ptk/reify ::manage-mcp-notification + ptk/WatchEvent + (watch [_ state _] + (let [mcp-state (get state :mcp) + + mcp-enabled? (-> state :profile :props :mcp-enabled) + + current-tab-id (get state :session-id) + connected-tab-id (get mcp-state :connected-tab)] + + (if mcp-enabled? + (if (= connected-tab-id current-tab-id) + (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) + (ev/event {::ev/name "confirm-mcp-tab-switch" + ::ev/origin "workspace-notification"}))} + :accept {:label (tr "labels.switch") + :callback #(st/emit! (connect-mcp) + (ev/event {::ev/name "dismiss-mcp-tab-switch" + ::ev/origin "workspace-notification"}))}}))) + (rx/of (ntf/hide))))))) + +(defn init-mcp [stream] (->> (rp/cmd! :get-current-mcp-token) - (rx/subs! + (rx/tap (fn [{:keys [token]}] (when token (dp/start-plugin! @@ -168,7 +213,7 @@ (fn [status] (when (= status "connected") (start-reconnect-watcher!)) - (st/emit! (update-mcp-connection status)) + (st/emit! (update-mcp-connection-status status)) (log/info :hint "MCP STATUS" :status status)) :on @@ -183,13 +228,65 @@ (->> stream (rx/filter (ptk/type? event)) (rx/take-until stopper) - (rx/subs! #(cb))))))}})))))) + (rx/subs! #(cb))))))}})))) + (rx/ignore))) -(defn init-mcp-connection +(defn init [] - (ptk/reify ::init-mcp-connection - ptk/EffectEvent - (effect [_ state stream] - (when (and (contains? cf/flags :mcp) - (-> state :profile :props :mcp-enabled)) - (init-mcp! stream))))) + (ptk/reify ::init + ptk/UpdateEvent + (update [_ state] + (update state :mcp assoc :connected-tab (:session-id state) :active true)) + + ptk/WatchEvent + (watch [_ state stream] + (let [stoper-s (rx/merge + (rx/filter (ptk/type? :app.main.data.workspace/finalize-workspace) stream) + (rx/filter (ptk/type? ::init) stream)) + session-id (get state :session-id) + enabled? (-> state :profile :props :mcp-enabled)] + + (->> (rx/merge + (if enabled? + (rx/merge + (init-mcp stream) + + (rx/of (mbc/event :mcp/ping {})) + + (->> mbc/stream + (rx/filter (mbc/type? :mcp/ping)) + (rx/filter (fn [{:keys [id]}] + (not= session-id id))) + (rx/map handle-ping)) + + (->> mbc/stream + (rx/filter (mbc/type? :mcp/pong)) + (rx/filter (fn [{:keys [id]}] + (not= session-id id))) + (rx/map handle-pong)) + + (->> mbc/stream + (rx/filter (mbc/type? :mcp/force-disconect)) + (rx/filter (fn [{:keys [id]}] + (not= session-id id))) + (rx/map deref) + (rx/map (fn [] (user-disconnect-mcp))))) + (rx/empty)) + + (->> mbc/stream + (rx/filter (mbc/type? :mcp/enable)) + (rx/mapcat (fn [_] + ;; NOTE: we don't need an explicit + ;; connect because the plugin has + ;; auto-connect + (rx/of (update-mcp-status true) + (init))))) + + (->> mbc/stream + (rx/filter (mbc/type? :mcp/disable)) + (rx/mapcat (fn [_] + (rx/of (update-mcp-status false) + (init) + (user-disconnect-mcp)))))) + + (rx/take-until stoper-s)))))) diff --git a/frontend/src/app/main/data/workspace/notifications.cljs b/frontend/src/app/main/data/workspace/notifications.cljs index ebbf8ce916..5e01fd4486 100644 --- a/frontend/src/app/main/data/workspace/notifications.cljs +++ b/frontend/src/app/main/data/workspace/notifications.cljs @@ -12,7 +12,6 @@ [app.common.schema :as sm] [app.common.time :as ct] [app.common.uuid :as uuid] - [app.config :as cf] [app.main.data.changes :as dch] [app.main.data.common :as dc] [app.main.data.helpers :as dsh] @@ -24,7 +23,6 @@ [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]] @@ -214,12 +212,8 @@ (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 [_ _ _] - (when (contains? cf/flags :mcp) - (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/refs.cljs b/frontend/src/app/main/refs.cljs index 124ee35b6e..20074c584b 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -150,6 +150,9 @@ (def workspace-global (l/derived :workspace-global st/state)) +(def mcp + (l/derived :mcp st/state)) + (def workspace-drawing (l/derived :workspace-drawing st/state)) diff --git a/frontend/src/app/main/ui/settings/integrations.cljs b/frontend/src/app/main/ui/settings/integrations.cljs index fc1316ce97..780f9918e3 100644 --- a/frontend/src/app/main/ui/settings/integrations.cljs +++ b/frontend/src/app/main/ui/settings/integrations.cljs @@ -285,8 +285,8 @@ ::ev/origin "integrations"}) (ev/event {::ev/name "enable-mcp" ::ev/origin "integrations" - :source "key-creation"})) - (mbc/emit! :mcp-enabled-change-status true) + :source "key-creation"}) + (mbc/event :mcp/enable {})) (reset! created? true)))] [:div {:class (stl/css :modal-overlay)} @@ -326,8 +326,8 @@ (st/emit! (du/delete-access-token {:id mcp-key-id}) (du/update-profile-props {:mcp-enabled true}) (ev/event {::ev/name "regenerate-mcp-key" - ::ev/origin "integrations"})) - (mbc/emit! :mcp-enabled-change-status true) + ::ev/origin "integrations"}) + (mbc/event :mcp/enable {})) (reset! created? true)))] [:div {:class (stl/css :modal-overlay)} @@ -437,8 +437,10 @@ :timeout notification-timeout}) (ev/event {::ev/name (if (true? value) "enable-mcp" "disable-mcp") ::ev/origin "integrations" - :source "toggle"})) - (mbc/emit! :mcp-enabled-change-status value))) + :source "toggle"}) + (if value + (mbc/event :mcp/enable {}) + (mbc/event :mcp/disable {}))))) handle-generate-mcp-key (mf/use-fn @@ -455,8 +457,8 @@ (let [params {:id (:id mcp-key)} mdata {:on-success #(st/emit! (du/fetch-access-tokens))}] (st/emit! (du/delete-access-token (with-meta params mdata)) - (du/update-profile-props {:mcp-enabled false})) - (mbc/emit! :mcp-enabled-change-status false)))) + (du/update-profile-props {:mcp-enabled false}) + (mbc/event :mcp/disable {}))))) on-copy-to-clipboard (mf/use-fn diff --git a/frontend/src/app/main/ui/workspace/main_menu.cljs b/frontend/src/app/main/ui/workspace/main_menu.cljs index 135ed716e4..4d16c79646 100644 --- a/frontend/src/app/main/ui/workspace/main_menu.cljs +++ b/frontend/src/app/main/ui/workspace/main_menu.cljs @@ -752,10 +752,10 @@ (let [plugins? (features/active-feature? @st/state "plugins/runtime") profile (mf/deref refs/profile) - workspace-local (mf/deref refs/workspace-local) + mcp (mf/deref refs/mcp) mcp-enabled? (true? (-> profile :props :mcp-enabled)) - mcp-connected? (= "connected" (-> workspace-local :mcp :connection)) + mcp-connected? (= "connected" (get mcp :connection-status)) on-nav-to-integrations (mf/use-fn @@ -815,8 +815,8 @@ (mf/defc menu* [{:keys [layout file]}] - (let [profile (mf/deref refs/profile) - workspace-local (mf/deref refs/workspace-local) + (let [profile (mf/deref refs/profile) + mcp (mf/deref refs/mcp) show-menu* (mf/use-state false) show-menu? (deref show-menu*) @@ -990,7 +990,7 @@ (> (ct/now))) mcp-enabled? (true? (-> profile :props :mcp-enabled)) - mcp-connection (-> workspace-local :mcp :connection) + mcp-connection (get mcp :connection-status) mcp-connected? (= mcp-connection "connected") mcp-error? (= mcp-connection "error")