From c4d2ca9cd10fba6635f6d51e66b95b22539ab318 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 7 Oct 2026 13:23:29 +0200 Subject: [PATCH] :sparkles: Move the dashboard MCP menu to the page headers Show the MCP menu next to the layout toggle in the header of the projects, files and deleted pages, instead of in the sidebar. It uses the secondary button style there and a visible dot colour while disconnected. Clicking the MCP button now toggles the menu instead of only opening it. Dashboard events report "dashboard:header" as their origin. --- docs/mcp/index.md | 2 +- .../src/app/main/ui/components/mcp_menu.cljs | 27 +++++++++++++------ .../src/app/main/ui/components/mcp_menu.scss | 10 +++---- .../src/app/main/ui/dashboard/deleted.cljs | 2 ++ frontend/src/app/main/ui/dashboard/files.cljs | 2 ++ .../src/app/main/ui/dashboard/projects.cljs | 2 ++ .../src/app/main/ui/dashboard/sidebar.cljs | 11 -------- 7 files changed, 31 insertions(+), 25 deletions(-) diff --git a/docs/mcp/index.md b/docs/mcp/index.md index cce812b516..fb9c927106 100644 --- a/docs/mcp/index.md +++ b/docs/mcp/index.md @@ -81,7 +81,7 @@ Some important concepts for users: Connect the tabs you want to use: -* **Remote MCP**: choose **MCP → Connect** in the dashboard sidebar or a file's toolbar. Use **Disconnect** in the same place to disconnect that tab. +* **Remote MCP**: choose **MCP → Connect** in the dashboard header or a file's toolbar. Use **Disconnect** in the same place to disconnect that tab. * **Local MCP**: run the plugin in each file and connect it to your local server. Each plugin connection has its own session ID. * Connecting or disconnecting one tab does not disconnect the others. * A connected tab stays connected while navigating between the dashboard and files. Its session ID stays the same; requests operate on the currently open file. diff --git a/frontend/src/app/main/ui/components/mcp_menu.cljs b/frontend/src/app/main/ui/components/mcp_menu.cljs index f38e4f377b..8e5091bfd3 100644 --- a/frontend/src/app/main/ui/components/mcp_menu.cljs +++ b/frontend/src/app/main/ui/components/mcp_menu.cljs @@ -7,9 +7,11 @@ (ns app.main.ui.components.mcp-menu (:require-macros [app.main.style :as stl]) (:require + [app.config :as cf] [app.main.data.event :as ev] [app.main.data.notifications :as ntf] [app.main.data.workspace.mcp :as mcp] + [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.dropdown-menu :refer [dropdown-menu* dropdown-menu-item*]] [app.main.ui.ds.buttons.button :refer [button*]] @@ -36,13 +38,13 @@ open-timer* (mf/use-ref nil) close-timer* (mf/use-ref nil) - on-open-menu + on-toggle-menu (mf/use-fn (fn [event] (dom/stop-propagation event) (cancel-timer! open-timer*) (cancel-timer! close-timer*) - (reset! menu-open* true))) + (swap! menu-open* not))) on-close-menu (mf/use-fn @@ -80,7 +82,7 @@ (mf/deps dashboard) #(st/emit! (mcp/connect-mcp) (ev/event {::ev/name "connect-mcp-plugin" - ::ev/origin (if dashboard "dashboard:sidebar" "workspace:toolbar")}))) + ::ev/origin (if dashboard "dashboard:header" "workspace:toolbar")}))) on-disconnect (mf/use-fn @@ -102,8 +104,8 @@ [:div {:class (stl/css-case :mcp-tool true :dashboard dashboard) :on-pointer-enter on-display-menu :on-pointer-leave on-hide-menu} - [:> button* {:variant "ghost" - :on-click on-open-menu + [:> button* {:variant (if dashboard "secondary" "ghost") + :on-click on-toggle-menu :aria-haspopup true :aria-expanded menu-open? :aria-pressed menu-open? @@ -115,9 +117,7 @@ :connected is-mcp-connected)}] [:span {:class (stl/css-case :toolbar-mcp-button-label true :connected is-mcp-connected)} - (if (and dashboard is-mcp-connected) - (tr "workspace.toolbar.mcp-connected") - (tr "workspace.toolbar.mcp"))]]] + (tr "workspace.toolbar.mcp")]]] [:div {:class (stl/css :toolbar-mcp-menu)} [:> dropdown-menu* {:show menu-open? @@ -139,3 +139,14 @@ (if is-connection-requested (tr "workspace.header.menu.mcp.plugin.status.disconnect") (tr "workspace.header.menu.mcp.plugin.status.connect"))]]]])) + +(mf/defc dashboard-mcp-menu* + [] + (let [mcp-state (mf/deref refs/mcp)] + (when (and (contains? cf/flags :mcp) + (:enabled mcp-state) + (:token-valid mcp-state)) + [:> mcp-menu* {:dashboard true + :is-mcp-connected (= "connected" (:connection-status mcp-state)) + :is-connection-requested (:connection-requested mcp-state) + :session-id (:session-id mcp-state)}]))) diff --git a/frontend/src/app/main/ui/components/mcp_menu.scss b/frontend/src/app/main/ui/components/mcp_menu.scss index f4c69ba4c8..fd466d4206 100644 --- a/frontend/src/app/main/ui/components/mcp_menu.scss +++ b/frontend/src/app/main/ui/components/mcp_menu.scss @@ -13,10 +13,10 @@ .mcp-tool { position: relative; -} -.dashboard { - margin-inline: var(--sp-l); + &.dashboard { + --mcp-disconnected-dot-color: var(--color-foreground-secondary); + } } .toolbar-mcp-button { @@ -38,7 +38,7 @@ inline-size: px2rem(6); block-size: px2rem(6); border-radius: 50%; - background-color: var(--color-background-disabled); + background-color: var(--mcp-disconnected-dot-color, var(--color-background-disabled)); &.connected { background-color: var(--color-accent-primary); @@ -72,6 +72,7 @@ .toolbar-mcp-menu { position: absolute; + z-index: var(--z-index-dropdown); left: 0; top: $sz-36; } @@ -85,7 +86,6 @@ display: flex; flex-direction: column; gap: var(--sp-xs); - z-index: var(--z-index-dropdown); margin: 0; padding: var(--sp-xs); border: $b-2 solid var(--panel-border-color); diff --git a/frontend/src/app/main/ui/dashboard/deleted.cljs b/frontend/src/app/main/ui/dashboard/deleted.cljs index 2f41c028e6..6bef519d98 100644 --- a/frontend/src/app/main/ui/dashboard/deleted.cljs +++ b/frontend/src/app/main/ui/dashboard/deleted.cljs @@ -16,6 +16,7 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.context-menu-a11y :refer [context-menu*]] + [app.main.ui.components.mcp-menu :refer [dashboard-mcp-menu*]] [app.main.ui.dashboard.grid :refer [grid*]] [app.main.ui.dashboard.layout-toggle :as lt :refer [layout-toggle*]] [app.main.ui.dashboard.subscription :refer [get-subscription-type]] @@ -64,6 +65,7 @@ [:div#dashboard-deleted-title {:class (stl/css :dashboard-title)} [:h1 (tr "dashboard.projects-title")]] [:div {:class (stl/css :dashboard-header-actions)} + [:> dashboard-mcp-menu*] [:> layout-toggle* {:layout layout :on-change on-change}]]]) (mf/defc project-context-menu* diff --git a/frontend/src/app/main/ui/dashboard/files.cljs b/frontend/src/app/main/ui/dashboard/files.cljs index b3318fc6f8..2d6a98f519 100644 --- a/frontend/src/app/main/ui/dashboard/files.cljs +++ b/frontend/src/app/main/ui/dashboard/files.cljs @@ -14,6 +14,7 @@ [app.main.data.project :as dpj] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.components.mcp-menu :refer [dashboard-mcp-menu*]] [app.main.ui.dashboard.grid :refer [grid*]] [app.main.ui.dashboard.import :as udi] [app.main.ui.dashboard.inline-edition :refer [inline-edition]] @@ -102,6 +103,7 @@ (:name project)]])) [:div {:class (stl/css :dashboard-header-actions)} + [:> dashboard-mcp-menu*] [:> layout-toggle* {:layout layout :on-change on-change}] diff --git a/frontend/src/app/main/ui/dashboard/projects.cljs b/frontend/src/app/main/ui/dashboard/projects.cljs index fef26f5b9b..2efbbefd21 100644 --- a/frontend/src/app/main/ui/dashboard/projects.cljs +++ b/frontend/src/app/main/ui/dashboard/projects.cljs @@ -17,6 +17,7 @@ [app.main.data.team :as dtm] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.components.mcp-menu :refer [dashboard-mcp-menu*]] [app.main.ui.dashboard.deleted :as deleted] [app.main.ui.dashboard.grid :refer [line-grid*]] [app.main.ui.dashboard.import :as udi] @@ -50,6 +51,7 @@ (tr "dashboard.personal-projects") (tr "dashboard.projects-title"))]] [:div {:class (stl/css :dashboard-header-actions)} + [:> dashboard-mcp-menu*] [:> layout-toggle* {:layout layout :on-change on-change}] (when can-edit diff --git a/frontend/src/app/main/ui/dashboard/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs index 8787c290ca..2f37187244 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.cljs +++ b/frontend/src/app/main/ui/dashboard/sidebar.cljs @@ -23,7 +23,6 @@ [app.main.ui.components.dropdown-menu :refer [dropdown-menu* dropdown-menu-item*]] [app.main.ui.components.link :refer [link*]] - [app.main.ui.components.mcp-menu :refer [mcp-menu*]] [app.main.ui.dashboard.check-updates :as dcu] [app.main.ui.dashboard.comments :refer [comments-icon* comments-section]] [app.main.ui.dashboard.inline-edition :refer [inline-edition]] @@ -256,7 +255,6 @@ (get default-project :id) team-id (get team :id) - mcp-state (mf/deref refs/mcp) projects? (= section :dashboard-recent) fonts? (= section :dashboard-fonts) @@ -384,15 +382,6 @@ [:span {:class (stl/css :element-title)} (tr "labels.shared-libraries")]]]]] - (when (and (contains? cf/flags :mcp) - (:enabled mcp-state) - (:token-valid mcp-state)) - [:div {:class (stl/css :sidebar-content-section)} - [:> mcp-menu* {:dashboard true - :is-mcp-connected (= "connected" (:connection-status mcp-state)) - :is-connection-requested (:connection-requested mcp-state) - :session-id (:session-id mcp-state)}]]) - [:div {:class (stl/css :sidebar-content-section) :data-testid "pinned-projects"} [:div {:class (stl/css :sidebar-section-title)}