mirror of
https://github.com/penpot/penpot.git
synced 2026-09-18 18:06:14 +00:00
✨ Add organization selection for nitrate (#8619)
This commit is contained in:
parent
3eabbffb0e
commit
08845ad2d4
@ -82,8 +82,9 @@
|
|||||||
|
|
||||||
(def ^:private schema:organization
|
(def ^:private schema:organization
|
||||||
[:map
|
[:map
|
||||||
[:id ::sm/text]
|
[:id ::sm/uuid]
|
||||||
[:name ::sm/text]])
|
[:name ::sm/text]
|
||||||
|
[:slug ::sm/text]])
|
||||||
|
|
||||||
;; TODO Unify with schemas on backend/src/app/http/management.clj
|
;; TODO Unify with schemas on backend/src/app/http/management.clj
|
||||||
(def ^:private schema:timestamp
|
(def ^:private schema:timestamp
|
||||||
@ -189,6 +190,9 @@
|
|||||||
|
|
||||||
|
|
||||||
(defn add-nitrate-licence-to-profile
|
(defn add-nitrate-licence-to-profile
|
||||||
|
"Enriches a profile map with subscription information from Nitrate.
|
||||||
|
Adds a :subscription field containing the user's license details.
|
||||||
|
Returns the original profile unchanged if the request fails."
|
||||||
[cfg profile]
|
[cfg profile]
|
||||||
(try
|
(try
|
||||||
(let [subscription (call cfg :get-subscription {:profile-id (:id profile)})]
|
(let [subscription (call cfg :get-subscription {:profile-id (:id profile)})]
|
||||||
@ -199,11 +203,26 @@
|
|||||||
:cause cause)
|
:cause cause)
|
||||||
profile)))
|
profile)))
|
||||||
|
|
||||||
(defn add-org-to-team
|
(defn add-org-info-to-team
|
||||||
|
"Enriches a team map with organization information from Nitrate.
|
||||||
|
Adds organization-id, organization-name, organization-slug, and your-penpot fields.
|
||||||
|
Returns the original team unchanged if the request fails or org data is nil."
|
||||||
[cfg team params]
|
[cfg team params]
|
||||||
(let [params (assoc (or params {}) :team-id (:id team))
|
(try
|
||||||
org (call cfg :get-team-org params)]
|
(let [params (assoc (or params {}) :team-id (:id team))
|
||||||
(assoc team :organization-id (:id org) :organization-name (:name org))))
|
org (call cfg :get-team-org params)]
|
||||||
|
(if (some? org)
|
||||||
|
(assoc team
|
||||||
|
:organization-id (:id org)
|
||||||
|
:organization-name (:name org)
|
||||||
|
:organization-slug (:slug org)
|
||||||
|
:is-default (or (:is-default team) (true? (:isYourPenpot org))))
|
||||||
|
team))
|
||||||
|
(catch Throwable cause
|
||||||
|
(l/error :hint "failed to get team organization info"
|
||||||
|
:team-id (:id team)
|
||||||
|
:cause cause)
|
||||||
|
team)))
|
||||||
|
|
||||||
(defn connectivity
|
(defn connectivity
|
||||||
[cfg]
|
[cfg]
|
||||||
|
|||||||
@ -193,7 +193,7 @@
|
|||||||
(dm/with-open [conn (db/open pool)]
|
(dm/with-open [conn (db/open pool)]
|
||||||
(cond->> (get-teams conn profile-id)
|
(cond->> (get-teams conn profile-id)
|
||||||
(contains? cf/flags :nitrate)
|
(contains? cf/flags :nitrate)
|
||||||
(map #(nitrate/add-org-to-team cfg % params)))))
|
(map #(nitrate/add-org-info-to-team cfg % params)))))
|
||||||
|
|
||||||
(def ^:private sql:get-owned-teams
|
(def ^:private sql:get-owned-teams
|
||||||
"SELECT t.id, t.name,
|
"SELECT t.id, t.name,
|
||||||
|
|||||||
@ -122,8 +122,7 @@
|
|||||||
(set/difference cfeat/no-team-inheritable-features))
|
(set/difference cfeat/no-team-inheritable-features))
|
||||||
params {:profile-id profile-id
|
params {:profile-id profile-id
|
||||||
:name "Default"
|
:name "Default"
|
||||||
:features features
|
:features features}
|
||||||
:is-default true}
|
|
||||||
team (db/tx-run! cfg teams/create-team params)]
|
team (db/tx-run! cfg teams/create-team params)]
|
||||||
(select-keys team [:id])))
|
(select-keys team [:id])))
|
||||||
|
|
||||||
|
|||||||
3
frontend/resources/images/icons/arrow-up-right.svg
Normal file
3
frontend/resources/images/icons/arrow-up-right.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M2.667 13.333 13.333 2.667m0 0H2.667m10.666 0v10.666"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 184 B |
@ -17,12 +17,17 @@
|
|||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
(->> (rp/cmd! ::get-nitrate-connectivity {})
|
(->> (rp/cmd! ::get-nitrate-connectivity {})
|
||||||
(rx/map (fn [connectivity]
|
(rx/map (fn [connectivity]
|
||||||
(prn "connectivity" connectivity)
|
|
||||||
(modal/show popup-type (or connectivity {}))))))))
|
(modal/show popup-type (or connectivity {}))))))))
|
||||||
|
|
||||||
(defn go-to-nitrate-cc
|
(defn go-to-nitrate-cc
|
||||||
[]
|
([]
|
||||||
(st/emit! (rt/nav-raw :href "/control-center/")))
|
(st/emit! (rt/nav-raw :href "/control-center/")))
|
||||||
|
([{:keys [organization-id organization-slug]}]
|
||||||
|
(let [href (dm/str "/control-center/org/"
|
||||||
|
(u/percent-encode organization-slug)
|
||||||
|
"/"
|
||||||
|
(u/percent-encode (str organization-id)))]
|
||||||
|
(st/emit! (rt/nav-raw :href href)))))
|
||||||
|
|
||||||
(defn go-to-nitrate-billing
|
(defn go-to-nitrate-billing
|
||||||
[]
|
[]
|
||||||
|
|||||||
@ -78,6 +78,12 @@
|
|||||||
(def ^:private exit-icon
|
(def ^:private exit-icon
|
||||||
(deprecated-icon/icon-xref :exit (stl/css :exit-icon)))
|
(deprecated-icon/icon-xref :exit (stl/css :exit-icon)))
|
||||||
|
|
||||||
|
(def ^:private add-org-icon
|
||||||
|
(deprecated-icon/icon-xref :add (stl/css :add-org-icon)))
|
||||||
|
|
||||||
|
(def ^:private arrow-up-right-icon
|
||||||
|
(deprecated-icon/icon-xref :arrow-up-right (stl/css :arrow-up-right-icon)))
|
||||||
|
|
||||||
(def ^:private ^:svg-id penpot-logo-icon "penpot-logo-icon")
|
(def ^:private ^:svg-id penpot-logo-icon "penpot-logo-icon")
|
||||||
|
|
||||||
(mf/defc sidebar-project*
|
(mf/defc sidebar-project*
|
||||||
@ -285,13 +291,10 @@
|
|||||||
:on-click on-clear-click}
|
:on-click on-clear-click}
|
||||||
search-icon])]))
|
search-icon])]))
|
||||||
|
|
||||||
(mf/defc teams-selector-dropdown*
|
(mf/defc organizations-selector-dropdown*
|
||||||
{::mf/private true}
|
{::mf/private true}
|
||||||
[{:keys [team profile teams show-default-team allow-create-teams allow-create-org] :rest props}]
|
[{:keys [organization organizations profile] :rest props}]
|
||||||
(let [on-create-team-click
|
(let [on-org-click
|
||||||
(mf/use-fn #(st/emit! (modal/show :team-form {})))
|
|
||||||
|
|
||||||
on-team-click
|
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [team-id (-> (dom/get-current-target event)
|
(let [team-id (-> (dom/get-current-target event)
|
||||||
@ -301,23 +304,93 @@
|
|||||||
|
|
||||||
on-create-org-click
|
on-create-org-click
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
(mf/deps profile)
|
||||||
(fn []
|
(fn []
|
||||||
(if (dnt/is-valid-license? profile)
|
(if (dnt/is-valid-license? profile)
|
||||||
(dnt/go-to-nitrate-cc)
|
(dnt/go-to-nitrate-cc)
|
||||||
(st/emit! (dnt/show-nitrate-popup :nitrate-form)))))]
|
(st/emit! (dnt/show-nitrate-popup :nitrate-form)))))
|
||||||
|
|
||||||
|
on-go-to-cc-click
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps organization)
|
||||||
|
(fn []
|
||||||
|
(dnt/go-to-nitrate-cc organization)))
|
||||||
|
|
||||||
|
default-team-id (or (->> organizations
|
||||||
|
vals
|
||||||
|
(filter :is-default)
|
||||||
|
first
|
||||||
|
:id)
|
||||||
|
(:default-team-id profile))
|
||||||
|
organizations (dissoc organizations default-team-id)]
|
||||||
|
|
||||||
[:> dropdown-menu* props
|
[:> dropdown-menu* props
|
||||||
|
|
||||||
(when show-default-team
|
[:> dropdown-menu-item* {:on-click on-org-click
|
||||||
[:> dropdown-menu-item* {:on-click on-team-click
|
:data-value default-team-id
|
||||||
:data-value (:default-team-id profile)
|
:class (stl/css :org-dropdown-item)}
|
||||||
:class (stl/css :team-dropdown-item)}
|
[:span {:class (stl/css :nitrate-org-icon)}
|
||||||
[:span {:class (stl/css :penpot-icon)} deprecated-icon/logo-icon]
|
[:> raw-svg* {:id penpot-logo-icon}]]
|
||||||
|
"Penpot"
|
||||||
|
(when (= default-team-id (:id organization))
|
||||||
|
tick-icon)]
|
||||||
|
|
||||||
[:span {:class (stl/css :team-text)} (tr "dashboard.your-penpot")]
|
(for [org-item (remove :is-default (vals organizations))]
|
||||||
(when (= (:default-team-id profile) (:id team))
|
[:> dropdown-menu-item* {:on-click on-org-click
|
||||||
|
:data-value (:id org-item)
|
||||||
|
:class (stl/css :org-dropdown-item)
|
||||||
|
:key (str (:id org-item))}
|
||||||
|
;; TODO org pictures
|
||||||
|
[:img {:src (cf/resolve-team-photo-url org-item)
|
||||||
|
:class (stl/css :team-picture)
|
||||||
|
:alt (:name org-item)}]
|
||||||
|
[:span {:class (stl/css :team-text)
|
||||||
|
:title (:name org-item)} (:name org-item)]
|
||||||
|
(when (= (:id org-item) (:id organization))
|
||||||
tick-icon)])
|
tick-icon)])
|
||||||
|
|
||||||
|
[:hr {:role "separator" :class (stl/css :team-separator)}]
|
||||||
|
[:> dropdown-menu-item* {:on-click on-create-org-click
|
||||||
|
:class (stl/css :org-dropdown-item :action)}
|
||||||
|
[:span {:class (stl/css :icon-wrapper)} add-org-icon]
|
||||||
|
[:span {:class (stl/css :team-text)} (tr "dashboard.create-new-org")]]
|
||||||
|
[:> dropdown-menu-item* {:on-click on-go-to-cc-click
|
||||||
|
:class (stl/css :org-dropdown-item :action)}
|
||||||
|
[:span {:class (stl/css :icon-wrapper)} arrow-up-right-icon]
|
||||||
|
[:span {:class (stl/css :team-text)} (tr "dashboard.go-to-control-center")]]]))
|
||||||
|
|
||||||
|
(mf/defc teams-selector-dropdown*
|
||||||
|
{::mf/private true}
|
||||||
|
[{:keys [team profile teams] :rest props}]
|
||||||
|
(let [default-team-id (or (->> teams
|
||||||
|
vals
|
||||||
|
(filter :is-default)
|
||||||
|
first
|
||||||
|
:id)
|
||||||
|
(:default-team-id profile))
|
||||||
|
|
||||||
|
teams (dissoc teams default-team-id)
|
||||||
|
on-create-team-click
|
||||||
|
(mf/use-fn #(st/emit! (modal/show :team-form {})))
|
||||||
|
|
||||||
|
on-team-click
|
||||||
|
(mf/use-fn
|
||||||
|
(fn [event]
|
||||||
|
(let [team-id (-> (dom/get-current-target event)
|
||||||
|
(dom/get-data "value")
|
||||||
|
(uuid/parse))]
|
||||||
|
(st/emit! (dcm/go-to-dashboard-recent :team-id team-id)))))]
|
||||||
|
|
||||||
|
[:> dropdown-menu* props
|
||||||
|
[:> dropdown-menu-item* {:on-click on-team-click
|
||||||
|
:data-value (:default-team-id profile)
|
||||||
|
:class (stl/css :team-dropdown-item)}
|
||||||
|
[:span {:class (stl/css :penpot-icon)} deprecated-icon/logo-icon]
|
||||||
|
|
||||||
|
[:span {:class (stl/css :team-text)} (tr "dashboard.your-penpot")]
|
||||||
|
(when (= (:default-team-id profile) (:id team))
|
||||||
|
tick-icon)]
|
||||||
|
|
||||||
(for [team-item (remove :is-default (vals teams))]
|
(for [team-item (remove :is-default (vals teams))]
|
||||||
[:> dropdown-menu-item* {:on-click on-team-click
|
[:> dropdown-menu-item* {:on-click on-team-click
|
||||||
:data-value (:id team-item)
|
:data-value (:id team-item)
|
||||||
@ -337,19 +410,12 @@
|
|||||||
(when (= (:id team-item) (:id team))
|
(when (= (:id team-item) (:id team))
|
||||||
tick-icon)])
|
tick-icon)])
|
||||||
|
|
||||||
(when allow-create-teams
|
|
||||||
[:hr {:role "separator" :class (stl/css :team-separator)}]
|
|
||||||
[:> dropdown-menu-item* {:on-click on-create-team-click
|
|
||||||
:class (stl/css :team-dropdown-item :action)}
|
|
||||||
[:span {:class (stl/css :icon-wrapper)} add-icon]
|
|
||||||
[:span {:class (stl/css :team-text)} (tr "dashboard.create-new-team")]])
|
|
||||||
|
|
||||||
(when allow-create-org
|
[:hr {:role "separator" :class (stl/css :team-separator)}]
|
||||||
[:hr {:role "separator" :class (stl/css :team-separator)}]
|
[:> dropdown-menu-item* {:on-click on-create-team-click
|
||||||
[:> dropdown-menu-item* {:on-click on-create-org-click
|
:class (stl/css :team-dropdown-item :action)}
|
||||||
:class (stl/css :team-dropdown-item :action)}
|
[:span {:class (stl/css :icon-wrapper)} add-icon]
|
||||||
[:span {:class (stl/css :icon-wrapper)} add-icon]
|
[:span {:class (stl/css :team-text)} (tr "dashboard.create-new-team")]]]))
|
||||||
[:span {:class (stl/css :team-text)} (tr "dashboard.create-new-org")]])]))
|
|
||||||
|
|
||||||
(mf/defc team-options-dropdown*
|
(mf/defc team-options-dropdown*
|
||||||
{::mf/private true}
|
{::mf/private true}
|
||||||
@ -500,39 +566,41 @@
|
|||||||
(tr "dashboard.delete-team")])]))
|
(tr "dashboard.delete-team")])]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn- team->org [team]
|
||||||
|
(assoc (dm/select-keys team [:id :organization-id :organization-slug])
|
||||||
|
:name (:organization-name team)))
|
||||||
|
|
||||||
(mf/defc sidebar-org-switch*
|
(mf/defc sidebar-org-switch*
|
||||||
[{:keys [team profile]}]
|
[{:keys [team profile]}]
|
||||||
(let [teams (mf/deref refs/teams)
|
(let [teams (mf/deref refs/teams)
|
||||||
|
|
||||||
|
;; Find the "your-penpot" teams, and transform them in orgs
|
||||||
orgs (mf/with-memo [teams]
|
orgs (mf/with-memo [teams]
|
||||||
(let [orgs (->> teams
|
(->> teams
|
||||||
vals
|
vals
|
||||||
(group-by :organization-id)
|
(filter :is-default)
|
||||||
(map (fn [[_group entries]] (first entries)))
|
(map team->org)
|
||||||
vec
|
(d/index-by :id)))
|
||||||
(d/index-by :id))]
|
|
||||||
(update-vals orgs
|
|
||||||
(fn [t]
|
|
||||||
(assoc t :name (str "ORG: " (:organization-name t)))))))
|
|
||||||
|
|
||||||
empty? (= (count orgs) 1)
|
no-orgs? (= (count orgs) 0)
|
||||||
|
|
||||||
|
current-org (team->org team)
|
||||||
|
|
||||||
current-org (mf/with-memo [team]
|
default-org? (= (:default-team-id profile) (:id current-org))
|
||||||
(assoc team :name (str "ORG: " (:organization-name team))))
|
|
||||||
|
|
||||||
show-teams-menu*
|
show-orgs-menu*
|
||||||
(mf/use-state false)
|
(mf/use-state false)
|
||||||
|
|
||||||
show-teams-menu?
|
show-orgs-menu?
|
||||||
(deref show-teams-menu*)
|
(deref show-orgs-menu*)
|
||||||
|
|
||||||
on-show-teams-click
|
on-show-orgs-click
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(swap! show-teams-menu* not)))
|
(swap! show-orgs-menu* not)))
|
||||||
|
|
||||||
on-show-teams-keydown
|
on-show-orgs-keydown
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(when (or (kbd/space? event)
|
(when (or (kbd/space? event)
|
||||||
@ -541,51 +609,58 @@
|
|||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(some-> (dom/get-current-target event)
|
(some-> (dom/get-current-target event)
|
||||||
(dom/click)))))
|
(dom/click)))))
|
||||||
close-teams-menu
|
close-orgs-menu
|
||||||
(mf/use-fn #(reset! show-teams-menu* false))
|
(mf/use-fn #(reset! show-orgs-menu* false))
|
||||||
|
|
||||||
on-create-org-click
|
on-create-org-click
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
(mf/deps profile)
|
||||||
(fn []
|
(fn []
|
||||||
(if (dnt/is-valid-license? profile)
|
(if (dnt/is-valid-license? profile)
|
||||||
(dnt/go-to-nitrate-cc)
|
(dnt/go-to-nitrate-cc)
|
||||||
(st/emit! (dnt/show-nitrate-popup :nitrate-form)))))]
|
(st/emit! (dnt/show-nitrate-popup :nitrate-form)))))]
|
||||||
(if empty?
|
(if no-orgs?
|
||||||
[:div {:class (stl/css :nitrate-orgs-empty)}
|
[:div {:class (stl/css :nitrate-selected-org)}
|
||||||
[:span {:class (stl/css :nitrate-penpot-icon)}
|
[:span {:class (stl/css :nitrate-penpot-icon)}
|
||||||
[:> raw-svg* {:id penpot-logo-icon}]]
|
[:> raw-svg* {:id penpot-logo-icon}]]
|
||||||
"Penpot"
|
"Penpot"
|
||||||
[:> button* {:variant "ghost"
|
[:> button* {:variant "ghost"
|
||||||
:type "button"
|
:type "button"
|
||||||
:class (stl/css :nitrate-create-org)
|
:class (stl/css :nitrate-create-org)
|
||||||
:on-click on-create-org-click} (tr "dashboard.create-new-org")]]
|
:on-click on-create-org-click} (tr "dashboard.plus-create-new-org")]]
|
||||||
|
|
||||||
[:div {:class (stl/css :sidebar-team-switch)}
|
[:div {:class (stl/css :sidebar-org-switch)}
|
||||||
[:div {:class (stl/css :switch-content)}
|
|
||||||
[:button {:class (stl/css :current-team)
|
|
||||||
:on-click on-show-teams-click
|
|
||||||
:on-key-down on-show-teams-keydown}
|
|
||||||
|
|
||||||
[:div {:class (stl/css :team-name)}
|
[:button {:class (stl/css :current-org)
|
||||||
[:img {:src (cf/resolve-team-photo-url current-org)
|
:on-click on-show-orgs-click
|
||||||
:class (stl/css :team-picture)
|
:on-key-down on-show-orgs-keydown
|
||||||
:alt (:name current-org)}]
|
:aria-expanded show-orgs-menu?
|
||||||
[:span {:class (stl/css :team-text) :title (:name current-org)} (:name current-org)]]
|
:aria-haspopup "menu"}
|
||||||
|
[:div {:class (stl/css :team-name)}
|
||||||
|
(if default-org?
|
||||||
|
[:*
|
||||||
|
[:span {:class (stl/css :nitrate-penpot-icon)}
|
||||||
|
[:> raw-svg* {:id penpot-logo-icon}]]
|
||||||
|
[:span {:class (stl/css :team-text)}
|
||||||
|
"Penpot"]]
|
||||||
|
[:*
|
||||||
|
[:span {:class (stl/css :nitrate-penpot-icon)}
|
||||||
|
;; TODO org pictures
|
||||||
|
[:img {:src (cf/resolve-team-photo-url current-org)
|
||||||
|
:class (stl/css :team-picture)
|
||||||
|
:alt (:name current-org)}]]
|
||||||
|
[:span {:class (stl/css :team-text)}
|
||||||
|
(:name current-org)]])]
|
||||||
|
arrow-icon]
|
||||||
|
|
||||||
arrow-icon]]
|
;; Orgs Dropdown
|
||||||
|
[:> organizations-selector-dropdown* {:show show-orgs-menu?
|
||||||
;; Teams Dropdown
|
:on-close close-orgs-menu
|
||||||
|
:id "organizations-list"
|
||||||
[:> teams-selector-dropdown* {:show show-teams-menu?
|
:class (stl/css :dropdown :teams-dropdown)
|
||||||
:on-close close-teams-menu
|
:organization current-org
|
||||||
:id "organizations-list"
|
:profile profile
|
||||||
:class (stl/css :dropdown :teams-dropdown)
|
:organizations orgs}]])))
|
||||||
:team current-org
|
|
||||||
:profile profile
|
|
||||||
:teams orgs
|
|
||||||
:show-default-team false
|
|
||||||
:allow-create-teams false
|
|
||||||
:allow-create-org true}]])))
|
|
||||||
|
|
||||||
(mf/defc sidebar-team-switch*
|
(mf/defc sidebar-team-switch*
|
||||||
[{:keys [team profile]}]
|
[{:keys [team profile]}]
|
||||||
@ -593,7 +668,9 @@
|
|||||||
org-id (when nitrate? (:organization-id team))
|
org-id (when nitrate? (:organization-id team))
|
||||||
teams (cond->> (mf/deref refs/teams)
|
teams (cond->> (mf/deref refs/teams)
|
||||||
nitrate?
|
nitrate?
|
||||||
(filter #(= (-> % val :organization-id) org-id)))
|
(filter #(= (-> % val :organization-id) org-id))
|
||||||
|
nitrate?
|
||||||
|
(into {}))
|
||||||
|
|
||||||
subscription
|
subscription
|
||||||
(get team :subscription)
|
(get team :subscription)
|
||||||
@ -613,6 +690,9 @@
|
|||||||
show-teams-menu?
|
show-teams-menu?
|
||||||
(deref show-teams-menu*)
|
(deref show-teams-menu*)
|
||||||
|
|
||||||
|
is-default?
|
||||||
|
(:is-default team)
|
||||||
|
|
||||||
on-show-teams-click
|
on-show-teams-click
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
@ -656,15 +736,17 @@
|
|||||||
[:div {:class (stl/css :switch-content)}
|
[:div {:class (stl/css :switch-content)}
|
||||||
[:button {:class (stl/css :current-team)
|
[:button {:class (stl/css :current-team)
|
||||||
:on-click on-show-teams-click
|
:on-click on-show-teams-click
|
||||||
:on-key-down on-show-teams-keydown}
|
:on-key-down on-show-teams-keydown
|
||||||
|
:aria-expanded show-teams-menu?
|
||||||
|
:aria-haspopup "menu"}
|
||||||
(cond
|
(cond
|
||||||
(:is-default team)
|
is-default?
|
||||||
[:div {:class (stl/css :team-name)}
|
[:div {:class (stl/css :team-name)}
|
||||||
[:span {:class (stl/css :penpot-icon)} deprecated-icon/logo-icon]
|
[:span {:class (stl/css :penpot-icon)} deprecated-icon/logo-icon]
|
||||||
[:span {:class (stl/css :team-text)} (tr "dashboard.default-team-name")]]
|
[:span {:class (stl/css :team-text)} (tr "dashboard.default-team-name")]]
|
||||||
|
|
||||||
(and (contains? cf/flags :subscriptions)
|
(and (contains? cf/flags :subscriptions)
|
||||||
(not (:is-default team))
|
(not is-default?)
|
||||||
(or (= "unlimited" subscription-type) (= "enterprise" subscription-type)))
|
(or (= "unlimited" subscription-type) (= "enterprise" subscription-type)))
|
||||||
[:div {:class (stl/css :team-name)}
|
[:div {:class (stl/css :team-name)}
|
||||||
[:img {:src (cf/resolve-team-photo-url team)
|
[:img {:src (cf/resolve-team-photo-url team)
|
||||||
@ -675,7 +757,7 @@
|
|||||||
[:> menu-team-icon* {:subscription-type subscription-type}]]]
|
[:> menu-team-icon* {:subscription-type subscription-type}]]]
|
||||||
|
|
||||||
|
|
||||||
(and (not (:is-default team))
|
(and (not is-default?)
|
||||||
(or (not= "unlimited" subscription-type) (not= "enterprise" subscription-type)))
|
(or (not= "unlimited" subscription-type) (not= "enterprise" subscription-type)))
|
||||||
[:div {:class (stl/css :team-name)}
|
[:div {:class (stl/css :team-name)}
|
||||||
[:img {:src (cf/resolve-team-photo-url team)
|
[:img {:src (cf/resolve-team-photo-url team)
|
||||||
@ -685,7 +767,7 @@
|
|||||||
|
|
||||||
arrow-icon]
|
arrow-icon]
|
||||||
|
|
||||||
(when-not (:is-default team)
|
(when-not is-default?
|
||||||
[:button {:class (stl/css :switch-options)
|
[:button {:class (stl/css :switch-options)
|
||||||
:on-click on-show-options-click
|
:on-click on-show-options-click
|
||||||
:aria-label "team-management"
|
:aria-label "team-management"
|
||||||
@ -701,10 +783,7 @@
|
|||||||
:class (stl/css :dropdown :teams-dropdown)
|
:class (stl/css :dropdown :teams-dropdown)
|
||||||
:team team
|
:team team
|
||||||
:profile profile
|
:profile profile
|
||||||
:teams teams
|
:teams teams}]
|
||||||
:show-default-team true
|
|
||||||
:allow-create-teams true
|
|
||||||
:allow-create-org false}]
|
|
||||||
|
|
||||||
[:> team-options-dropdown* {:show show-team-options-menu?
|
[:> team-options-dropdown* {:show show-team-options-menu?
|
||||||
:on-close close-team-options-menu
|
:on-close close-team-options-menu
|
||||||
|
|||||||
@ -172,6 +172,14 @@
|
|||||||
height: $sz-40;
|
height: $sz-40;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.org-dropdown-item {
|
||||||
|
@extend .menu-item-base;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: var(--sp-xxxl) 1fr auto;
|
||||||
|
gap: var(--sp-s);
|
||||||
|
height: $sz-40;
|
||||||
|
}
|
||||||
|
|
||||||
.action {
|
.action {
|
||||||
--sidebar-action-icon-color: var(--icon-foreground);
|
--sidebar-action-icon-color: var(--icon-foreground);
|
||||||
--sidebar-icon-backgroun-color: var(--color-background-secondary);
|
--sidebar-icon-backgroun-color: var(--color-background-secondary);
|
||||||
@ -492,6 +500,20 @@
|
|||||||
stroke: var(--icon-foreground);
|
stroke: var(--icon-foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.add-org-icon {
|
||||||
|
@extend .button-icon;
|
||||||
|
width: var(--sp-l);
|
||||||
|
height: var(--sp-l);
|
||||||
|
stroke: var(--sidebar-action-icon-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow-up-right-icon {
|
||||||
|
@extend .button-icon;
|
||||||
|
width: var(--sp-m);
|
||||||
|
height: var(--sp-m);
|
||||||
|
stroke: var(--sidebar-action-icon-color);
|
||||||
|
}
|
||||||
|
|
||||||
.upgrade-plan-section {
|
.upgrade-plan-section {
|
||||||
@include deprecated.buttonStyle;
|
@include deprecated.buttonStyle;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -530,7 +552,7 @@
|
|||||||
// border-block-end: $b-1 solid var(--color-background-quaternary);
|
// border-block-end: $b-1 solid var(--color-background-quaternary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nitrate-orgs-empty {
|
.nitrate-selected-org {
|
||||||
@include t.use-typography("body-medium");
|
@include t.use-typography("body-medium");
|
||||||
color: var(--color-foreground-primary);
|
color: var(--color-foreground-primary);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -560,3 +582,35 @@
|
|||||||
height: var(--sp-xxl);
|
height: var(--sp-xxl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nitrate-org-icon {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
height: var(--sp-xxl);
|
||||||
|
width: var(--sp-xxl);
|
||||||
|
background-color: var(--color-foreground-primary);
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: var(--icon-stroke-color);
|
||||||
|
width: var(--sp-xl);
|
||||||
|
height: var(--sp-xl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-org-switch {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-org {
|
||||||
|
@include deprecated.buttonStyle;
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
gap: var(--sp-s);
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 var(--sp-m);
|
||||||
|
}
|
||||||
|
|||||||
@ -54,6 +54,7 @@
|
|||||||
(def ^:icon-id arrow-left "arrow-left")
|
(def ^:icon-id arrow-left "arrow-left")
|
||||||
(def ^:icon-id arrow-right "arrow-right")
|
(def ^:icon-id arrow-right "arrow-right")
|
||||||
(def ^:icon-id arrow-up "arrow-up")
|
(def ^:icon-id arrow-up "arrow-up")
|
||||||
|
(def ^:icon-id arrow-up-right "arrow-up-right")
|
||||||
(def ^:icon-id asc-sort "asc-sort")
|
(def ^:icon-id asc-sort "asc-sort")
|
||||||
(def ^:icon-id at "at")
|
(def ^:icon-id at "at")
|
||||||
(def ^:icon-id board "board")
|
(def ^:icon-id board "board")
|
||||||
|
|||||||
@ -359,9 +359,15 @@ msgid "dashboard.copy-suffix"
|
|||||||
msgstr "(copy)"
|
msgstr "(copy)"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/sidebar.cljs:347
|
#: src/app/main/ui/dashboard/sidebar.cljs:347
|
||||||
msgid "dashboard.create-new-org"
|
msgid "dashboard.plus-create-new-org"
|
||||||
msgstr "+ Create org"
|
msgstr "+ Create org"
|
||||||
|
|
||||||
|
msgid "dashboard.create-new-org"
|
||||||
|
msgstr "Create org"
|
||||||
|
|
||||||
|
msgid "dashboard.go-to-control-center"
|
||||||
|
msgstr "Go to Control Center"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/sidebar.cljs:340
|
#: src/app/main/ui/dashboard/sidebar.cljs:340
|
||||||
msgid "dashboard.create-new-team"
|
msgid "dashboard.create-new-team"
|
||||||
msgstr "Create new team"
|
msgstr "Create new team"
|
||||||
|
|||||||
@ -368,9 +368,15 @@ msgid "dashboard.copy-suffix"
|
|||||||
msgstr "(copia)"
|
msgstr "(copia)"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/sidebar.cljs:347
|
#: src/app/main/ui/dashboard/sidebar.cljs:347
|
||||||
msgid "dashboard.create-new-org"
|
msgid "dashboard.plus-create-new-org"
|
||||||
msgstr "+ Crear org"
|
msgstr "+ Crear org"
|
||||||
|
|
||||||
|
msgid "dashboard.create-new-org"
|
||||||
|
msgstr "Crear org"
|
||||||
|
|
||||||
|
msgid "dashboard.go-to-control-center"
|
||||||
|
msgstr "Ir al centro de control"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/sidebar.cljs:340
|
#: src/app/main/ui/dashboard/sidebar.cljs:340
|
||||||
msgid "dashboard.create-new-team"
|
msgid "dashboard.create-new-team"
|
||||||
msgstr "Crear nuevo equipo"
|
msgstr "Crear nuevo equipo"
|
||||||
@ -2171,7 +2177,7 @@ msgstr "La clave MCP utilizada para conectarse al servidor MCP ha expirado. Como
|
|||||||
|
|
||||||
#: src/app/main/ui/settings/integrations.cljs:368
|
#: src/app/main/ui/settings/integrations.cljs:368
|
||||||
msgid "integrations.mcp-server.status.expired.1"
|
msgid "integrations.mcp-server.status.expired.1"
|
||||||
msgstr "Por favor, regenera la clave MCP y actualiza la configuración de tu cliente con la nueva clave."
|
msgstr "Por favor, regenera la clave MCP y actualiza la configuración de tu cliente con la nueva clave."
|
||||||
|
|
||||||
#: src/app/main/ui/settings/integrations.cljs:415
|
#: src/app/main/ui/settings/integrations.cljs:415
|
||||||
msgid "integrations.mcp-server.mcp-keys.copy"
|
msgid "integrations.mcp-server.mcp-keys.copy"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user