mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 11:18:36 +00:00
🎉 Add workspace menu for MCP server
This commit is contained in:
parent
0a5de10dff
commit
adc3fa41e9
10
.continue/mcpServers/new-mcp-server.yaml
Normal file
10
.continue/mcpServers/new-mcp-server.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
name: New MCP server
|
||||
version: 0.0.1
|
||||
schema: v1
|
||||
mcpServers:
|
||||
- name: New MCP server
|
||||
command: npx
|
||||
args:
|
||||
- -y
|
||||
- <your-mcp-server>
|
||||
env: {}
|
||||
@ -25,6 +25,7 @@
|
||||
[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]
|
||||
@ -214,7 +215,7 @@
|
||||
(watch [_ _ _]
|
||||
(rx/of (dp/check-open-plugin)
|
||||
(fdf/fix-deleted-fonts-for-local-library file-id)
|
||||
(mcp/init-mcp-connexion)))))
|
||||
(mcp/init-mcp-connection)))))
|
||||
|
||||
(defn- bundle-fetched
|
||||
[{:keys [file file-id thumbnails] :as bundle}]
|
||||
@ -370,6 +371,12 @@
|
||||
(rx/take 1)
|
||||
(rx/tap (fn [_] (perf/setup)))))
|
||||
|
||||
(when (contains? cf/flags :mcp)
|
||||
(->> mbc/stream
|
||||
(rx/filter (mbc/type? :mcp-enabled-change))
|
||||
(rx/map deref)
|
||||
(rx/map mcp/update-mcp-status)))
|
||||
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::dps/persistence-notification))
|
||||
(rx/take 1)
|
||||
|
||||
@ -34,6 +34,27 @@
|
||||
[event]
|
||||
(= (ptk/type event) :app.main.data.workspace/finalize-workspace))
|
||||
|
||||
(defn update-mcp-status
|
||||
[value]
|
||||
(ptk/reify ::update-mcp-status
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:profile :props] assoc :mcp-enabled value))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(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))))
|
||||
|
||||
(defn init-mcp!
|
||||
[stream]
|
||||
(->> (rp/cmd! :get-current-mcp-token)
|
||||
@ -52,8 +73,12 @@
|
||||
:getServerUrl #(str cf/mcp-ws-uri)
|
||||
:setMcpStatus
|
||||
(fn [status]
|
||||
;; TODO: Visual feedback
|
||||
(log/info :hint "MCP STATUS" :status status))
|
||||
(let [mcp-connected? (case status
|
||||
"connected" true
|
||||
"disconnected" false
|
||||
nil)]
|
||||
(st/emit! (update-mcp-connection mcp-connected?))
|
||||
(log/info :hint "MCP STATUS" :status status)))
|
||||
|
||||
:on
|
||||
(fn [event cb]
|
||||
@ -77,11 +102,11 @@
|
||||
[]
|
||||
(st/emit! (ptk/data-event ::connect)))
|
||||
|
||||
(defn init-mcp-connexion
|
||||
(defn init-mcp-connection
|
||||
[]
|
||||
(ptk/reify ::init-mcp-connexion
|
||||
(ptk/reify ::init-mcp-connection
|
||||
ptk/EffectEvent
|
||||
(effect [_ state stream]
|
||||
(when (and (contains? cf/flags :mcp)
|
||||
(-> state :profile :props :mcp-status))
|
||||
(-> state :profile :props :mcp-enabled))
|
||||
(init-mcp! stream)))))
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
[app.common.schema :as sm]
|
||||
[app.common.time :as ct]
|
||||
[app.config :as cf]
|
||||
[app.main.broadcast :as mbc]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.notifications :as ntf]
|
||||
@ -272,12 +273,13 @@
|
||||
on-created
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (du/update-profile-props {:mcp-status true})
|
||||
(st/emit! (du/update-profile-props {:mcp-enabled true})
|
||||
(ev/event {::ev/name "generate-mcp-key"
|
||||
::ev/origin "integrations"})
|
||||
(ev/event {::ev/name "enable-mcp"
|
||||
::ev/origin "integrations"
|
||||
:source "key-creation"}))
|
||||
(mbc/emit! :mcp-enabled-change true)
|
||||
(reset! created? true)))]
|
||||
|
||||
[:div {:class (stl/css :modal-overlay)}
|
||||
@ -315,9 +317,10 @@
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (du/delete-access-token {:id mcp-key-id})
|
||||
(du/update-profile-props {:mcp-status true})
|
||||
(du/update-profile-props {:mcp-enabled true})
|
||||
(ev/event {::ev/name "regenerate-mcp-key"
|
||||
::ev/origin "integrations"}))
|
||||
(mbc/emit! :mcp-enabled-change true)
|
||||
(reset! created? true)))]
|
||||
|
||||
[:div {:class (stl/css :modal-overlay)}
|
||||
@ -406,8 +409,8 @@
|
||||
(let [tokens (mf/deref tokens-ref)
|
||||
profile (mf/deref refs/profile)
|
||||
|
||||
mcp-key (some #(when (= (:type %) "mcp") %) tokens)
|
||||
mcp-active? (d/nilv (-> profile :props :mcp-status) false)
|
||||
mcp-key (some #(when (= (:type %) "mcp") %) tokens)
|
||||
mcp-enabled? (d/nilv (-> profile :props :mcp-enabled) false)
|
||||
|
||||
expires-at (:expires-at mcp-key)
|
||||
expired? (and (some? expires-at) (> (ct/now) expires-at))
|
||||
@ -415,21 +418,22 @@
|
||||
tooltip-id
|
||||
(mf/use-id)
|
||||
|
||||
handle-mcp-status-change
|
||||
handle-mcp-change
|
||||
(mf/use-fn
|
||||
(fn [mcp-status]
|
||||
(st/emit! (du/update-profile-props {:mcp-status mcp-status})
|
||||
(fn [value]
|
||||
(st/emit! (du/update-profile-props {:mcp-enabled value})
|
||||
(ntf/show {:level :info
|
||||
:type :toast
|
||||
:content (if (true? mcp-status)
|
||||
:content (if (true? value)
|
||||
(tr "integrations.notification.success.mcp-server-enabled")
|
||||
(tr "integrations.notification.success.mcp-server-disabled"))
|
||||
:timeout notification-timeout})
|
||||
(ev/event {::ev/name (if (true? mcp-status) "enable-mcp" "disable-mcp")
|
||||
(ev/event {::ev/name (if (true? value) "enable-mcp" "disable-mcp")
|
||||
::ev/origin "integrations"
|
||||
:source "toggle"}))))
|
||||
:source "toggle"}))
|
||||
(mbc/emit! :mcp-enabled-change value)))
|
||||
|
||||
handle-initial-mcp-status
|
||||
handle-generate-mcp-key
|
||||
(mf/use-fn
|
||||
#(st/emit! (modal/show {:type :generate-mcp-key})))
|
||||
|
||||
@ -444,7 +448,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-status false})))))
|
||||
(du/update-profile-props {:mcp-enabled false}))
|
||||
(mbc/emit! :mcp-enabled-change false))))
|
||||
|
||||
on-copy-to-clipboard
|
||||
(mf/use-fn
|
||||
@ -497,14 +502,14 @@
|
||||
(tr "integrations.mcp-server.status.expired.1")]]])
|
||||
|
||||
[:div {:class (stl/css :mcp-server-switch)}
|
||||
[:> switch* {:label (if mcp-active?
|
||||
[:> switch* {:label (if mcp-enabled?
|
||||
(tr "integrations.mcp-server.status.enabled")
|
||||
(tr "integrations.mcp-server.status.disabled"))
|
||||
:default-checked mcp-active?
|
||||
:on-change handle-mcp-status-change}]
|
||||
(when (and (false? mcp-active?) (nil? mcp-key))
|
||||
:default-checked mcp-enabled?
|
||||
:on-change handle-mcp-change}]
|
||||
(when (and (false? mcp-enabled?) (nil? mcp-key))
|
||||
[:div {:class (stl/css :mcp-server-switch-cover)
|
||||
:on-click handle-initial-mcp-status}])]]]
|
||||
:on-click handle-generate-mcp-key}])]]]
|
||||
|
||||
(when (some? mcp-key)
|
||||
[:div {:class (stl/css :mcp-server-key)}
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
[app.main.refs :as refs]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.main.ui.workspace.main-menu :as main-menu]
|
||||
[app.util.dom :as dom]
|
||||
@ -27,12 +26,10 @@
|
||||
;; --- Header Component
|
||||
|
||||
(mf/defc left-header*
|
||||
[{:keys [file layout project page-id class]}]
|
||||
(let [profile (mf/deref refs/profile)
|
||||
file-id (:id file)
|
||||
[{:keys [file layout project class]}]
|
||||
(let [file-id (:id file)
|
||||
file-name (:name file)
|
||||
project-id (:id project)
|
||||
team-id (:team-id project)
|
||||
shared? (:is-shared file)
|
||||
persistence
|
||||
(mf/deref refs/persistence)
|
||||
@ -40,8 +37,6 @@
|
||||
persistence-status
|
||||
(get persistence :status)
|
||||
|
||||
read-only? (mf/use-ctx ctx/workspace-read-only?)
|
||||
|
||||
editing* (mf/use-state false)
|
||||
editing? (deref editing*)
|
||||
input-ref (mf/use-ref nil)
|
||||
@ -137,10 +132,5 @@
|
||||
(when ^boolean shared?
|
||||
[:span {:class (stl/css :shared-badge)} deprecated-icon/library])
|
||||
[:div {:class (stl/css :menu-section)}
|
||||
[:& main-menu/menu
|
||||
{:layout layout
|
||||
:file file
|
||||
:profile profile
|
||||
:read-only? read-only?
|
||||
:team-id team-id
|
||||
:page-id page-id}]]]))
|
||||
[:> main-menu/menu* {:layout layout
|
||||
:file file}]]]))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -4,125 +4,174 @@
|
||||
//
|
||||
// Copyright (c) KALEIDOS INC
|
||||
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
@use "ds/typography.scss" as t;
|
||||
@use "ds/z-index.scss" as *;
|
||||
@use "ds/_borders.scss" as *;
|
||||
@use "ds/_sizes.scss" as *;
|
||||
@use "ds/_utils.scss" as *;
|
||||
|
||||
.base-menu {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sp-xs);
|
||||
padding: var(--sp-xs);
|
||||
border-radius: $br-8;
|
||||
z-index: var(--z-index-dropdown);
|
||||
background-color: var(--menu-background-color);
|
||||
border: $b-2 solid var(--panel-border-color);
|
||||
box-shadow: 0 0 $sz-12 0 var(--menu-shadow-color);
|
||||
}
|
||||
|
||||
.menu {
|
||||
@extend .menu-dropdown;
|
||||
top: deprecated.$s-48;
|
||||
left: calc(var(--right-sidebar-width, deprecated.$s-256) - deprecated.$s-16);
|
||||
width: deprecated.$s-192;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
@extend .menu-item-base;
|
||||
cursor: pointer;
|
||||
|
||||
.open-arrow {
|
||||
@include deprecated.flexCenter;
|
||||
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--menu-foreground-color-hover);
|
||||
|
||||
.open-arrow {
|
||||
svg {
|
||||
stroke: var(--menu-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.shortcut-key {
|
||||
color: var(--menu-shortcut-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.separator {
|
||||
border-top: deprecated.$s-1 solid var(--color-background-quaternary);
|
||||
height: deprecated.$s-4;
|
||||
left: calc(-1 * deprecated.$s-4);
|
||||
margin-top: deprecated.$s-8;
|
||||
position: relative;
|
||||
width: calc(100% + deprecated.$s-8);
|
||||
}
|
||||
|
||||
.shortcut {
|
||||
@extend .shortcut-base;
|
||||
}
|
||||
|
||||
.shortcut-key {
|
||||
@extend .shortcut-key-base;
|
||||
top: $sz-48;
|
||||
left: calc(var(--right-sidebar-width) - $sz-40);
|
||||
inline-size: $sz-192;
|
||||
}
|
||||
|
||||
.sub-menu {
|
||||
@extend .menu-dropdown;
|
||||
left: calc(var(--right-sidebar-width, deprecated.$s-256) + deprecated.$s-180);
|
||||
width: deprecated.$s-192;
|
||||
min-width: calc(deprecated.$s-272 - deprecated.$s-2);
|
||||
width: 110%;
|
||||
left: calc(var(--right-sidebar-width) + $sz-154);
|
||||
min-width: $sz-284;
|
||||
width: 115%;
|
||||
|
||||
.submenu-item {
|
||||
@extend .menu-item-base;
|
||||
|
||||
&:hover {
|
||||
color: var(--menu-foreground-color-hover);
|
||||
|
||||
.shortcut-key {
|
||||
color: var(--menu-shortcut-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
&.pos-1 {
|
||||
top: calc($sz-16 + $sz-32);
|
||||
}
|
||||
|
||||
.menu-disabled {
|
||||
color: var(--color-foreground-secondary);
|
||||
|
||||
&:hover {
|
||||
cursor: default;
|
||||
color: var(--color-foreground-secondary);
|
||||
background-color: var(--menu-background-color);
|
||||
}
|
||||
&.pos-2 {
|
||||
top: calc($sz-16 + (2 * $sz-32));
|
||||
}
|
||||
|
||||
&.file {
|
||||
top: deprecated.$s-48;
|
||||
&.pos-3 {
|
||||
top: calc($sz-16 + (3 * $sz-32));
|
||||
}
|
||||
|
||||
&.edit {
|
||||
top: deprecated.$s-76;
|
||||
&.pos-4 {
|
||||
top: calc($sz-16 + (4 * $sz-32));
|
||||
}
|
||||
|
||||
&.view {
|
||||
top: deprecated.$s-116;
|
||||
&.pos-5 {
|
||||
top: calc($sz-16 + (5 * $sz-32));
|
||||
}
|
||||
|
||||
&.preferences {
|
||||
top: deprecated.$s-148;
|
||||
&.pos-6 {
|
||||
top: calc($sz-16 + (6 * $sz-32));
|
||||
}
|
||||
|
||||
&.pos-final-5 {
|
||||
top: calc($sz-32 + (5 * $sz-32));
|
||||
}
|
||||
|
||||
&.pos-final-6 {
|
||||
top: calc($sz-32 + (6 * $sz-32));
|
||||
}
|
||||
|
||||
&.pos-final-7 {
|
||||
top: calc($sz-32 + (7 * $sz-32));
|
||||
}
|
||||
|
||||
&.plugins {
|
||||
top: deprecated.$s-180;
|
||||
max-height: calc(100vh - deprecated.$s-180);
|
||||
max-height: calc(100vh - $sz-200);
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.help-info {
|
||||
top: deprecated.$s-232;
|
||||
.base-menu-item {
|
||||
@include t.use-typography("body-small");
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: auto $sz-16 $sz-16;
|
||||
grid-template-areas: "name indicator arrow";
|
||||
block-size: $sz-28;
|
||||
inline-size: 100%;
|
||||
padding: $sz-6;
|
||||
border-radius: $br-8;
|
||||
color: var(--menu-foreground-color);
|
||||
background-color: var(--menu-background-color);
|
||||
|
||||
&:hover {
|
||||
--menu-foreground-color: var(--menu-foreground-color-hover);
|
||||
--menu-background-color: var(--menu-background-color-hover);
|
||||
--menu-shortcut-foreground-color: var(--menu-shortcut-foreground-color-hover);
|
||||
--menu-icon-foreground-color: var(--menu-foreground-color-hover);
|
||||
}
|
||||
|
||||
&.help-info-old {
|
||||
top: deprecated.$s-192;
|
||||
&.disabled {
|
||||
--menu-foreground-color: var(--color-foreground-secondary);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: auto $sz-16 $sz-16;
|
||||
grid-template-areas: "name indicator arrow";
|
||||
}
|
||||
|
||||
.submenu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
grid-area: name;
|
||||
}
|
||||
|
||||
.item-indicator {
|
||||
--menu-indicator-color: var(--color-foreground-secondary);
|
||||
grid-area: indicator;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
inline-size: px2rem(8);
|
||||
block-size: px2rem(8);
|
||||
border-radius: $br-circle;
|
||||
background-color: var(--menu-indicator-color);
|
||||
|
||||
&.active {
|
||||
--menu-indicator-color: var(--color-accent-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.item-arrow {
|
||||
grid-area: arrow;
|
||||
color: var(--menu-icon-foreground-color);
|
||||
}
|
||||
|
||||
.item-icon {
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
color: var(--menu-icon-foreground-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.separator {
|
||||
position: relative;
|
||||
block-size: var(--sp-xs);
|
||||
inline-size: calc(100% + var(--sp-s));
|
||||
border-top: $b-1 solid var(--color-background-quaternary);
|
||||
left: calc(-1 * var(--sp-xs));
|
||||
margin-top: var(--sp-s);
|
||||
}
|
||||
|
||||
.shortcut {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--sp-xxs);
|
||||
color: var(--menu-shortcut-foreground-color);
|
||||
}
|
||||
|
||||
.shortcut-key {
|
||||
@include t.use-typography("body-small");
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: px2rem(20);
|
||||
padding: var(--sp-xxs) px2rem(6);
|
||||
border-radius: $br-6;
|
||||
background-color: var(--menu-shortcut-background-color);
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@
|
||||
|
||||
(mf/defc left-sidebar*
|
||||
{::mf/memo true}
|
||||
[{:keys [layout file page-id tokens-lib active-tokens resolved-active-tokens]}]
|
||||
[{:keys [layout file tokens-lib active-tokens resolved-active-tokens]}]
|
||||
(let [options-mode (mf/deref refs/options-mode-global)
|
||||
project (mf/deref refs/project)
|
||||
file-id (get file :id)
|
||||
@ -185,12 +185,10 @@
|
||||
:class aside-class
|
||||
:style {:--left-sidebar-width (dm/str width "px")}}
|
||||
|
||||
[:> left-header*
|
||||
{:file file
|
||||
:layout layout
|
||||
:project project
|
||||
:page-id page-id
|
||||
:class (stl/css :left-header)}]
|
||||
[:> left-header* {:file file
|
||||
:layout layout
|
||||
:project project
|
||||
:class (stl/css :left-header)}]
|
||||
|
||||
[:div {:on-pointer-down on-pointer-down
|
||||
:on-lost-pointer-capture on-lost-pointer-capture
|
||||
|
||||
@ -5719,6 +5719,18 @@ msgstr "Hide rulers"
|
||||
msgid "workspace.header.menu.hide-textpalette"
|
||||
msgstr "Hide fonts palette"
|
||||
|
||||
msgid "workspace.header.menu.mcp.plugin.status.connect"
|
||||
msgstr "Connect"
|
||||
|
||||
msgid "workspace.header.menu.mcp.plugin.status.disconnect"
|
||||
msgstr "Disconnect"
|
||||
|
||||
msgid "workspace.header.menu.mcp.server.status.enabled"
|
||||
msgstr "Manage (Status: enabled)"
|
||||
|
||||
msgid "workspace.header.menu.mcp.server.status.disabled"
|
||||
msgstr "Manage (Status: disabled)"
|
||||
|
||||
#: src/app/main/ui/workspace/main_menu.cljs:884
|
||||
msgid "workspace.header.menu.option.edit"
|
||||
msgstr "Edit"
|
||||
@ -5731,6 +5743,9 @@ msgstr "File"
|
||||
msgid "workspace.header.menu.option.help-info"
|
||||
msgstr "Help & info"
|
||||
|
||||
msgid "workspace.header.menu.option.mcp"
|
||||
msgstr "MCP server"
|
||||
|
||||
#: src/app/main/ui/workspace/main_menu.cljs:916
|
||||
#, unused
|
||||
msgid "workspace.header.menu.option.power-up"
|
||||
|
||||
@ -5686,6 +5686,18 @@ msgstr "Ocultar reglas"
|
||||
msgid "workspace.header.menu.hide-textpalette"
|
||||
msgstr "Ocultar paleta de textos"
|
||||
|
||||
msgid "workspace.header.menu.mcp.plugin.status.connect"
|
||||
msgstr "Conectar"
|
||||
|
||||
msgid "workspace.header.menu.mcp.plugin.status.disconnect"
|
||||
msgstr "Desconectar"
|
||||
|
||||
msgid "workspace.header.menu.mcp.server.status.enabled"
|
||||
msgstr "Gestionar (estado: habilitado)"
|
||||
|
||||
msgid "workspace.header.menu.mcp.server.status.disabled"
|
||||
msgstr "Gestionar (estado: deshabilitado)"
|
||||
|
||||
#: src/app/main/ui/workspace/main_menu.cljs:884
|
||||
msgid "workspace.header.menu.option.edit"
|
||||
msgstr "Editar"
|
||||
@ -5698,6 +5710,9 @@ msgstr "Archivo"
|
||||
msgid "workspace.header.menu.option.help-info"
|
||||
msgstr "Ayuda e información"
|
||||
|
||||
msgid "workspace.header.menu.option.mcp"
|
||||
msgstr "Servidor MCP"
|
||||
|
||||
#: src/app/main/ui/workspace/main_menu.cljs:906
|
||||
msgid "workspace.header.menu.option.preferences"
|
||||
msgstr "Preferencias"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user