diff --git a/backend/src/app/rpc/commands/profile.clj b/backend/src/app/rpc/commands/profile.clj index 631f84af58..59c72f69f6 100644 --- a/backend/src/app/rpc/commands/profile.clj +++ b/backend/src/app/rpc/commands/profile.clj @@ -47,6 +47,7 @@ (def schema:props [:map {:title "ProfileProps"} [:plugins {:optional true} schema:plugin-registry] + [:mcp-status {:optional true} ::sm/boolean] [:newsletter-updates {:optional true} ::sm/boolean] [:newsletter-news {:optional true} ::sm/boolean] [:onboarding-team-id {:optional true} ::sm/uuid] diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs index a247a982a8..41e18c846f 100644 --- a/frontend/src/app/main/ui.cljs +++ b/frontend/src/app/main/ui.cljs @@ -197,7 +197,7 @@ :settings-options :settings-feedback :settings-subscription - :settings-access-tokens + :settings-integrations :settings-notifications) (let [params (get params :query) error-report-id (some-> params :error-report-id uuid/parse*)] diff --git a/frontend/src/app/main/ui/ds/_sizes.scss b/frontend/src/app/main/ui/ds/_sizes.scss index 067bd0b416..9daa3a5ec7 100644 --- a/frontend/src/app/main/ui/ds/_sizes.scss +++ b/frontend/src/app/main/ui/ds/_sizes.scss @@ -18,6 +18,7 @@ $sz-32: px2rem(32); $sz-36: px2rem(36); $sz-40: px2rem(40); $sz-48: px2rem(48); +$sz-64: px2rem(64); $sz-88: px2rem(88); $sz-96: px2rem(96); $sz-120: px2rem(120); diff --git a/frontend/src/app/main/ui/routes.cljs b/frontend/src/app/main/ui/routes.cljs index e8159d3852..ca45bc5133 100644 --- a/frontend/src/app/main/ui/routes.cljs +++ b/frontend/src/app/main/ui/routes.cljs @@ -36,7 +36,7 @@ ["/feedback" :settings-feedback] ["/options" :settings-options] ["/subscriptions" :settings-subscription] - ["/access-tokens" :settings-access-tokens] + ["/integrations" :settings-integrations] ["/notifications" :settings-notifications]] ["/frame-preview" :frame-preview] diff --git a/frontend/src/app/main/ui/settings.cljs b/frontend/src/app/main/ui/settings.cljs index bc40ae20fa..2cb617c939 100644 --- a/frontend/src/app/main/ui/settings.cljs +++ b/frontend/src/app/main/ui/settings.cljs @@ -13,10 +13,10 @@ [app.main.store :as st] [app.main.ui.hooks :as hooks] [app.main.ui.modal :refer [modal-container*]] - [app.main.ui.settings.access-tokens :refer [access-tokens-page]] [app.main.ui.settings.change-email] [app.main.ui.settings.delete-account] [app.main.ui.settings.feedback :refer [feedback-page*]] + [app.main.ui.settings.integrations :refer [integrations-page*]] [app.main.ui.settings.notifications :refer [notifications-page*]] [app.main.ui.settings.options :refer [options-page]] [app.main.ui.settings.password :refer [password-page]] @@ -73,8 +73,8 @@ :settings-subscription [:> subscription-page* {:profile profile}] - :settings-access-tokens - [:& access-tokens-page] + :settings-integrations + [:> integrations-page*] :settings-notifications [:& notifications-page* {:profile profile}])]]]])) diff --git a/frontend/src/app/main/ui/settings/access_tokens.scss b/frontend/src/app/main/ui/settings/access_tokens.scss deleted file mode 100644 index 5e9f139765..0000000000 --- a/frontend/src/app/main/ui/settings/access_tokens.scss +++ /dev/null @@ -1,202 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. -// -// Copyright (c) KALEIDOS INC - -@use "refactor/common-refactor.scss" as deprecated; - -// ACCESS TOKENS PAGE -.dashboard-access-tokens { - display: grid; - grid-template-rows: auto 1fr; - margin: deprecated.$s-80 auto deprecated.$s-120 auto; - gap: deprecated.$s-32; - width: deprecated.$s-800; -} - -// hero -.access-tokens-hero { - display: grid; - grid-template-rows: auto auto 1fr; - gap: deprecated.$s-32; - width: deprecated.$s-500; - font-size: deprecated.$fs-14; - margin: deprecated.$s-16 auto 0 auto; -} - -.hero-title { - @include deprecated.bigTitleTipography; - color: var(--title-foreground-color-hover); -} - -.hero-desc { - color: var(--title-foreground-color); - margin-bottom: 0; - font-size: deprecated.$fs-14; -} - -.hero-btn { - @extend .button-primary; -} - -// table empty -.access-tokens-empty { - display: grid; - place-items: center; - align-content: center; - height: deprecated.$s-156; - max-width: deprecated.$s-1000; - width: 100%; - padding: deprecated.$s-32; - border: deprecated.$s-1 solid var(--panel-border-color); - border-radius: deprecated.$br-8; - color: var(--dashboard-list-text-foreground-color); -} - -// Access tokens table -.dashboard-table { - height: fit-content; -} - -.table-rows { - display: grid; - grid-auto-rows: deprecated.$s-64; - gap: deprecated.$s-16; - width: 100%; - height: 100%; - max-width: deprecated.$s-1000; - margin-top: deprecated.$s-16; - color: var(--title-foreground-color); -} - -.table-row { - display: grid; - grid-template-columns: 43% 1fr auto; - align-items: center; - height: deprecated.$s-64; - width: 100%; - padding: 0 deprecated.$s-16; - border-radius: deprecated.$br-8; - background-color: var(--dashboard-list-background-color); - color: var(--dashboard-list-foreground-color); -} - -.field-name { - @include deprecated.textEllipsis; - display: grid; - width: 43%; - min-width: deprecated.$s-300; -} - -.expiration-date { - @include deprecated.flexCenter; - min-width: deprecated.$s-76; - width: fit-content; - height: deprecated.$s-24; - border-radius: deprecated.$br-8; - color: var(--dashboard-list-text-foreground-color); -} - -.expired { - @include deprecated.headlineSmallTypography; - padding: 0 deprecated.$s-6; - color: var(--pill-foreground-color); - background-color: var(--status-widget-background-color-warning); -} - -.actions { - position: relative; -} -.menu-icon { - @extend .button-icon; - stroke: var(--icon-foreground); -} - -.menu-btn { - @include deprecated.buttonStyle; -} - -// Create access token modal -.modal-overlay { - @extend .modal-overlay-base; -} - -.modal-container { - @extend .modal-container-base; - min-width: deprecated.$s-408; -} - -.modal-header { - margin-bottom: deprecated.$s-24; -} - -.modal-title { - @include deprecated.uppercaseTitleTipography; - color: var(--modal-title-foreground-color); -} -.modal-close-btn { - @extend .modal-close-btn-base; -} - -.modal-content { - @include deprecated.flexColumn; - gap: deprecated.$s-24; - @include deprecated.bodySmallTypography; - margin-bottom: deprecated.$s-24; -} - -.select-title { - @include deprecated.bodySmallTypography; - color: var(--modal-title-foreground-color); -} - -.custon-input-wrapper { - @include deprecated.flexRow; - border-radius: deprecated.$br-8; - height: deprecated.$s-32; - background-color: var(--input-background-color); -} - -.custom-input-token { - @extend .input-element; - @include deprecated.bodySmallTypography; - margin: 0; - flex-grow: 1; - &:focus { - outline: none; - border: deprecated.$s-1 solid var(--input-border-color-active); - } -} - -.token-value { - @include deprecated.textEllipsis; - @include deprecated.bodySmallTypography; - flex-grow: 1; -} - -.copy-btn { - @include deprecated.flexCenter; - @extend .button-secondary; - height: deprecated.$s-28; - width: deprecated.$s-28; -} - -.clipboard-icon { - @extend .button-icon-small; -} - -.token-created-info { - color: var(--modal-text-foreground-color); -} - -.action-buttons { - @extend .modal-action-btns; - button { - @extend .modal-accept-btn; - } -} - -.cancel-button { - @extend .modal-cancel-btn; -} diff --git a/frontend/src/app/main/ui/settings/access_tokens.cljs b/frontend/src/app/main/ui/settings/integrations.cljs similarity index 55% rename from frontend/src/app/main/ui/settings/access_tokens.cljs rename to frontend/src/app/main/ui/settings/integrations.cljs index 29a09476b0..11eaaabd58 100644 --- a/frontend/src/app/main/ui/settings/access_tokens.cljs +++ b/frontend/src/app/main/ui/settings/integrations.cljs @@ -4,18 +4,27 @@ ;; ;; Copyright (c) KALEIDOS INC -(ns app.main.ui.settings.access-tokens +(ns app.main.ui.settings.integrations (:require-macros [app.main.style :as stl]) (:require + [app.common.data :as d] [app.common.schema :as sm] [app.common.time :as ct] + [app.config :as cf] [app.main.data.modal :as modal] [app.main.data.notifications :as ntf] [app.main.data.profile :as du] + [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.context-menu-a11y :refer [context-menu*]] [app.main.ui.components.forms :as fm] - [app.main.ui.icons :as deprecated-icon] + [app.main.ui.ds.buttons.button :refer [button*]] + [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] + [app.main.ui.ds.controls.switch :refer [switch*]] + [app.main.ui.ds.foundations.assets.icon :as i] + [app.main.ui.ds.foundations.typography :as t] + [app.main.ui.ds.foundations.typography.heading :refer [heading*]] + [app.main.ui.ds.foundations.typography.text :refer [text*]] [app.util.clipboard :as clipboard] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -23,15 +32,6 @@ [okulary.core :as l] [rumext.v2 :as mf])) -(def ^:private clipboard-icon - (deprecated-icon/icon-xref :clipboard (stl/css :clipboard-icon))) - -(def ^:private close-icon - (deprecated-icon/icon-xref :close (stl/css :close-icon))) - -(def ^:private menu-icon - (deprecated-icon/icon-xref :menu (stl/css :menu-icon))) - (def tokens-ref (l/derived :access-tokens st/state)) @@ -46,7 +46,7 @@ (def initial-data {:name "" :expiration-date "never"}) -(mf/defc access-token-modal +(mf/defc access-token-modal* {::mf/register modal/components ::mf/register-as :access-token} [] @@ -109,10 +109,10 @@ [:div {:class (stl/css :modal-header)} [:h2 {:class (stl/css :modal-title)} (tr "modals.create-access-token.title")] - - [:button {:class (stl/css :modal-close-btn) - :on-click on-close} - close-icon]] + [:> icon-button* {:variant "ghost" + :aria-label (tr "labels.close") + :on-click on-close + :icon i/close}]] [:div {:class (stl/css :modal-content)} [:div {:class (stl/css :fields-row)} @@ -149,10 +149,10 @@ :value (:token created "") :class (stl/css :custom-input-token) :read-only true}] - [:button {:title (tr "modals.create-access-token.copy-token") - :class (stl/css :copy-btn) - :on-click copy-token} - clipboard-icon]]) + [:> icon-button* {:variant "secondary" + :aria-label (tr "modals.create-access-token.copy-token") + :on-click copy-token + :icon i/clipboard}]]) #_(when @created? [:button {:class (stl/css :copy-btn) :title (tr "modals.create-access-token.copy-token") @@ -165,30 +165,38 @@ [:div {:class (stl/css :action-buttons)} (if @created? - [:input {:class (stl/css :cancel-button) - :type "button" - :value (tr "labels.close") - :on-click modal/hide!}] + [:> button* {:variant "secondary" + :on-click modal/hide!} + (tr "labels.close")] [:* - [:input {:class (stl/css :cancel-button) - :type "button" - :value (tr "labels.cancel") - :on-click modal/hide!}] - [:> fm/submit-button* - {:large? false :label (tr "modals.create-access-token.submit-label")}]])]]]]])) + [:> button* {:variant "secondary" + :on-click modal/hide!} + (tr "labels.cancel")] + [:> fm/submit-button* {:large? false + :label (tr "modals.create-access-token.submit-label")}]])]]]]])) -(mf/defc access-tokens-hero +(mf/defc access-tokens* + {::mf/private true} [] - (let [on-click (mf/use-fn #(st/emit! (modal/show :access-token {})))] - [:div {:class (stl/css :access-tokens-hero)} - [:h2 {:class (stl/css :hero-title)} (tr "dashboard.access-tokens.personal")] - [:p {:class (stl/css :hero-desc)} (tr "dashboard.access-tokens.personal.description")] + (let [on-click + (mf/use-fn + #(st/emit! (modal/show :access-token {})))] - [:button {:class (stl/css :hero-btn) - :on-click on-click} + [:div {:class (stl/css :access-tokens-hero)} + [:> heading* {:level 2 + :typography t/title-medium + :class (stl/css :mcp-title)} + (tr "dashboard.access-tokens.personal")] + [:> text* {:as "p" + :typography t/body-medium + :class (stl/css :mcp-description)} + (tr "dashboard.access-tokens.personal.description")] + [:> button* {:variant "primary" + :on-click on-click} (tr "dashboard.access-tokens.create")]])) -(mf/defc access-token-actions +(mf/defc token-actions* + {::mf/private true} [{:keys [on-delete]}] (let [local (mf/use-state {:menu-open false}) show? (:menu-open @local) @@ -200,7 +208,8 @@ menu-ref (mf/use-ref) on-menu-close - (mf/use-fn #(swap! local assoc :menu-open false)) + (mf/use-fn + #(swap! local assoc :menu-open false)) on-menu-click (mf/use-fn @@ -216,24 +225,27 @@ (dom/stop-propagation event) (on-menu-click event))))] - [:button {:class (stl/css :menu-btn) - :tab-index "0" - :ref menu-ref - :on-click on-menu-click - :on-key-down on-keydown} - menu-icon - [:> context-menu* - {:on-close on-menu-close - :show show? - :fixed true - :min-width true - :top "auto" - :left "auto" - :options options}]])) + [:* + [:> icon-button* {:variant "ghost" + :class (stl/css :item-button) + :ref menu-ref + :aria-pressed show? + :aria-label (tr "labels.options") + :on-click on-menu-click + :on-key-down on-keydown + :icon i/menu}] + [:> context-menu* {:on-close on-menu-close + :show show? + :fixed true + :min-width true + :top "auto" + :left "auto" + :options options}]])) -(mf/defc access-token-item - {::mf/wrap [mf/memo]} - [{:keys [token] :as props}] +(mf/defc token-item* + {::mf/private true + ::mf/wrap [mf/memo]} + [{:keys [token]}] (let [expires-at (:expires-at token) expires-txt (some-> expires-at (ct/format-inst "PPP")) expired? (and (some? expires-at) (> (ct/now) expires-at)) @@ -250,42 +262,106 @@ (mf/use-fn (mf/deps delete-fn) (fn [] - (st/emit! (modal/show - {:type :confirm - :title (tr "modals.delete-acces-token.title") - :message (tr "modals.delete-acces-token.message") - :accept-label (tr "modals.delete-acces-token.accept") - :on-accept delete-fn}))))] + (st/emit! (modal/show {:type :confirm + :title (tr "modals.delete-acces-token.title") + :message (tr "modals.delete-acces-token.message") + :accept-label (tr "modals.delete-acces-token.accept") + :on-accept delete-fn}))))] - [:div {:class (stl/css :table-row)} - [:div {:class (stl/css :table-field :field-name)} - (str (:name token))] + [:div {:class (stl/css :item)} + [:> text* {:as "div" + :typography t/body-medium + :title (:name token) + :class (stl/css :item-title)} + (:name token)] - [:div {:class (stl/css-case :expiration-date true - :expired expired?)} + [:> text* {:as "div" + :typography t/body-small + :class (stl/css-case :item-subtitle true + :warning expired?)} (cond (nil? expires-at) (tr "dashboard.access-tokens.no-expiration") - expired? (tr "dashboard.access-tokens.expired-on" expires-txt) - :else (tr "dashboard.access-tokens.expires-on" expires-txt))] - [:div {:class (stl/css :table-field :actions)} - [:& access-token-actions - {:on-delete on-delete}]]])) + expired? (tr "dashboard.access-tokens.expired-on" expires-txt) + :else (tr "dashboard.access-tokens.expires-on" expires-txt))] -(mf/defc access-tokens-page + [:div {:class (stl/css :table-field :actions)} + [:> token-actions* {:on-delete on-delete}]]])) + +(mf/defc mcp-config* + {::mf/private true} + [] + (let [profile (mf/deref refs/profile) + + active? (d/nilv (-> profile :props :mcp-status) false) + + handle-mcp-status-change + (mf/use-fn + (fn [value] + (st/emit! (du/update-profile-props {:mcp-status value}))))] + + [:div {:class (stl/css :mcp)} + + [:div + [:> heading* {:level 2 + :typography t/title-medium + :class (stl/css :mcp-title)} + "MCP Server"] + + [:> text* {:as "p" + :typography t/body-medium + :class (stl/css :mcp-description)} + "The Penpot MCP Server enables MCP clients to interact directly with Penpot design files."]] + + [:div + [:> text* {:as "h3" + :typography t/headline-small + :class (stl/css :mcp-headline)} + "Status"] + + [:> switch* {:label (if active? "Enabled" "Disabled") + :default-checked active? + :on-change handle-mcp-status-change}]] + + [:div + [:> text* {:as "h3" + :typography t/headline-small + :class (stl/css :mcp-headline)} + "MCP keys"] + + [:> button* {:variant "primary"} + "Regenerate MCP key"]]])) + +(mf/defc integrations-page* [] (let [tokens (mf/deref tokens-ref)] + (mf/with-effect [] (dom/set-html-title (tr "title.settings.access-tokens")) (st/emit! (du/fetch-access-tokens))) - [:div {:class (stl/css :dashboard-access-tokens)} - [:& access-tokens-hero] - (if (empty? tokens) - [:div {:class (stl/css :access-tokens-empty)} - [:div (tr "dashboard.access-tokens.empty.no-access-tokens")] - [:div (tr "dashboard.access-tokens.empty.add-one")]] - [:div {:class (stl/css :dashboard-table)} - [:div {:class (stl/css :table-rows)} - (for [token tokens] - [:& access-token-item {:token token :key (:id token)}])]])])) + [:div {:class (stl/css :integrations)} + [:> heading* {:level 1 + :typography t/title-large + :class (stl/css :integrations-title)} + "Integrations"] + + (when (contains? cf/flags :mcp-server) + [:> mcp-config*]) + + (when (contains? cf/flags :access-tokens) + [:* + [:> access-tokens*] + + (if (empty? tokens) + [:div {:class (stl/css :frame)} + [:> text* {:as "div" + :typography t/body-medium + :class (stl/css :frame-text-center)} + [:div (tr "dashboard.access-tokens.empty.no-access-tokens")] + [:div (tr "dashboard.access-tokens.empty.add-one")]]] + + [:div {:class (stl/css :list)} + (for [token tokens] + [:> token-item* {:key (:id token) + :token token}])])])])) diff --git a/frontend/src/app/main/ui/settings/integrations.scss b/frontend/src/app/main/ui/settings/integrations.scss new file mode 100644 index 0000000000..9ed7385b45 --- /dev/null +++ b/frontend/src/app/main/ui/settings/integrations.scss @@ -0,0 +1,185 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +@use "refactor/common-refactor.scss" as deprecated; + +@use "ds/_borders.scss" as *; +@use "ds/_sizes.scss" as *; +@use "ds/spacing.scss" as *; +@use "ds/mixins.scss" as *; + +.integrations { + display: grid; + grid-template-rows: auto 1fr; + margin: deprecated.$s-80 auto deprecated.$s-120 auto; + gap: deprecated.$s-32; + width: deprecated.$s-500; +} + +.integrations-title { + color: var(--color-foreground-primary); +} + +.mcp { + display: flex; + flex-direction: column; + gap: var(--sp-l); +} + +.mcp-title { + color: var(--color-foreground-primary); + margin: var(--sp-s) 0; +} + +.mcp-headline { + color: var(--color-foreground-primary); +} + +.mcp-description { + color: var(--color-foreground-secondary); +} + +.separator { + border: 1px solid var(--color-background-quaternary); +} + +.frame { + border: 1px solid var(--color-background-quaternary); + padding: var(--sp-m); + border-radius: $br-8; +} + +.frame-text-center { + text-align: center; + color: var(--color-foreground-secondary); +} + +.list { + display: grid; + grid-auto-rows: $sz-64; + gap: var(--sp-m); +} + +.item { + display: grid; + grid-template-columns: 40% 1fr auto; + align-items: center; + background-color: var(--color-background-tertiary); + border-radius: $br-8; +} + +.item-title { + @include textEllipsis; + align-content: center; + block-size: $sz-64; + padding: 0 var(--sp-l); + color: var(--color-foreground-primary); +} + +.item-subtitle { + align-content: center; + block-size: $sz-64; + padding: 0 var(--sp-l); + color: var(--color-foreground-secondary); + + &.warning { + padding: 0 var(--sp-m); + block-size: $sz-32; + inline-size: fit-content; + color: var(--pill-foreground-color); + background-color: var(--color-background-warning); + border: 1px solid var(--color-accent-warning); + border-radius: $br-8; + } +} + +.item-button { + block-size: $sz-64; + inline-size: $sz-48; +} + + + +// Create access token modal +.modal-overlay { + @extend .modal-overlay-base; +} + +.modal-container { + @extend .modal-container-base; + min-width: deprecated.$s-408; +} + +.modal-header { + margin-bottom: deprecated.$s-24; + display: flex; + justify-content: space-between; + align-items: center; +} + +.modal-title { + @include deprecated.uppercaseTitleTipography; + color: var(--modal-title-foreground-color); +} + +.modal-content { + @include deprecated.flexColumn; + gap: deprecated.$s-24; + @include deprecated.bodySmallTypography; + margin-bottom: deprecated.$s-24; +} + +// hero +.access-tokens-hero { + display: grid; + grid-template-rows: auto auto 1fr; + gap: deprecated.$s-32; + width: deprecated.$s-500; + font-size: deprecated.$fs-14; + margin: deprecated.$s-16 auto 0 auto; +} + +.actions { + position: relative; +} + +.action-buttons { + display: flex; + justify-content: right; +} + +.select-title { + @include deprecated.bodySmallTypography; + color: var(--modal-title-foreground-color); +} + +.custon-input-wrapper { + @include deprecated.flexRow; + border-radius: deprecated.$br-8; + height: deprecated.$s-32; + background-color: var(--input-background-color); +} + +.custom-input-token { + @extend .input-element; + @include deprecated.bodySmallTypography; + margin: 0; + flex-grow: 1; + &:focus { + outline: none; + border: deprecated.$s-1 solid var(--input-border-color-active); + } +} + +.token-value { + @include deprecated.textEllipsis; + @include deprecated.bodySmallTypography; + flex-grow: 1; +} + +.token-created-info { + color: var(--modal-text-foreground-color); +} diff --git a/frontend/src/app/main/ui/settings/sidebar.cljs b/frontend/src/app/main/ui/settings/sidebar.cljs index 0808e2299d..8ab3225ad1 100644 --- a/frontend/src/app/main/ui/settings/sidebar.cljs +++ b/frontend/src/app/main/ui/settings/sidebar.cljs @@ -43,8 +43,8 @@ (def ^:private go-settings-subscription #(st/emit! (rt/nav :settings-subscription))) -(def ^:private go-settings-access-tokens - #(st/emit! (rt/nav :settings-access-tokens))) +(def ^:private go-settings-integrations + #(st/emit! (rt/nav :settings-integrations))) (def ^:private go-settings-notifications #(st/emit! (rt/nav :settings-notifications))) @@ -66,7 +66,7 @@ options? (= section :settings-options) feedback? (= section :settings-feedback) subscription? (= section :settings-subscription) - access-tokens? (= section :settings-access-tokens) + integrations? (= section :settings-integrations) notifications? (= section :settings-notifications) team-id (or (dtm/get-last-team-id) (:default-team-id profile)) @@ -115,12 +115,13 @@ :data-testid "settings-subscription"} [:span {:class (stl/css :element-title)} (tr "subscription.labels")]]) - (when (contains? cf/flags :access-tokens) - [:li {:class (stl/css-case :current access-tokens? + (when (or (contains? cf/flags :access-tokens) + (contains? cf/flags :mcp-server)) + [:li {:class (stl/css-case :current integrations? :settings-item true) - :on-click go-settings-access-tokens - :data-testid "settings-access-tokens"} - [:span {:class (stl/css :element-title)} (tr "labels.access-tokens")]]) + :on-click go-settings-integrations + :data-testid "settings-integrations"} + [:span {:class (stl/css :element-title)} (tr "labels.integrations")]]) [:hr {:class (stl/css :sidebar-separator)}] diff --git a/frontend/translations/en.po b/frontend/translations/en.po index a514937354..a48888b33d 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -2468,6 +2468,10 @@ msgstr "Info" msgid "labels.installed-fonts" msgstr "Installed fonts" +#: src/app/main/ui/settings/sidebar.cljs:123 +msgid "labels.integrations" +msgstr "Integrations" + #: src/app/main/ui/static.cljs:396 msgid "labels.internal-error.desc-message-first" msgstr "Something bad happened." diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 2894156837..9ffb0f142c 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -2439,6 +2439,10 @@ msgstr "Información" msgid "labels.installed-fonts" msgstr "Fuentes instaladas" +#: src/app/main/ui/settings/sidebar.cljs:123 +msgid "labels.integrations" +msgstr "Integraciones" + #: src/app/main/ui/static.cljs:396 msgid "labels.internal-error.desc-message-first" msgstr "Ha ocurrido algo extraño."