Add notification for nitrate when creating a team inside an organization (#8639)

This commit is contained in:
Pablo Alba
2026-03-16 10:36:32 +01:00
committed by GitHub
parent 6e19548bac
commit 8f35e451e6
6 changed files with 102 additions and 30 deletions

View File

@@ -18,16 +18,16 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- request-builder
[cfg method uri shared-key profile-id]
[cfg method uri shared-key profile-id request-params]
(fn []
(http/req! cfg {:method method
:headers {"content-type" "application/json"
"accept" "application/json"
"x-shared-key" shared-key
"x-profile-id" (str profile-id)}
:uri uri
:version :http1.1})))
(http/req! cfg (cond-> {:method method
:headers {"content-type" "application/json"
"accept" "application/json"
"x-shared-key" shared-key
"x-profile-id" (str profile-id)}
:uri uri
:version :http1.1}
(= method :post) (assoc :body (json/encode request-params))))))
(defn- with-retries
[handler max-retries]
@@ -60,9 +60,9 @@
nil)))))
(defn- request-to-nitrate
[cfg method uri schema {:keys [::rpc/profile-id] :as params}]
[cfg method uri schema {:keys [::rpc/profile-id request-params] :as params}]
(let [shared-key (-> cfg ::setup/shared-keys :nitrate)
full-http-call (-> (request-builder cfg method uri shared-key profile-id)
full-http-call (-> (request-builder cfg method uri shared-key profile-id request-params)
(with-retries 3)
(with-validate uri schema))]
(full-http-call)))
@@ -86,6 +86,12 @@
[:name ::sm/text]
[:slug ::sm/text]])
(def ^:private schema:team
[:map
[:id ::sm/uuid]
[:organizationId ::sm/uuid]
[:yourPenpot :boolean]])
;; TODO Unify with schemas on backend/src/app/http/management.clj
(def ^:private schema:timestamp
(sm/type-schema
@@ -161,17 +167,40 @@
(defn- get-team-org
[cfg {:keys [team-id] :as params}]
(let [baseuri (cf/get :nitrate-backend-uri)]
(request-to-nitrate cfg :get (str baseuri "/api/teams/" (str team-id)) schema:organization params)))
(request-to-nitrate cfg :get
(str baseuri
"/api/teams/"
team-id)
schema:organization params)))
(defn- set-team-org
[cfg {:keys [organization-id team-id is-default] :as params}]
(let [baseuri (cf/get :nitrate-backend-uri)
params (assoc params :request-params {:teamId team-id
:yourPenpot (true? is-default)})]
(request-to-nitrate cfg :post
(str baseuri
"/api/organizations/"
organization-id
"/addTeam")
schema:team params)))
(defn- get-subscription
[cfg {:keys [profile-id] :as params}]
(let [baseuri (cf/get :nitrate-backend-uri)]
(request-to-nitrate cfg :get (str baseuri "/api/subscriptions/" (str profile-id)) schema:subscription params)))
(request-to-nitrate cfg :get
(str baseuri
"/api/subscriptions/"
profile-id)
schema:subscription params)))
(defn- get-connectivity
[cfg params]
(let [baseuri (cf/get :nitrate-backend-uri)]
(request-to-nitrate cfg :get (str baseuri "/api/connectivity") schema:connectivity params)))
(request-to-nitrate cfg :get
(str baseuri
"/api/connectivity")
schema:connectivity params)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INITIALIZATION
@@ -181,6 +210,7 @@
[_ cfg]
(when (contains? cf/flags :nitrate)
{:get-team-org (partial get-team-org cfg)
:set-team-org (partial set-team-org cfg)
:get-subscription (partial get-subscription cfg)
:connectivity (partial get-connectivity cfg)}))
@@ -224,6 +254,22 @@
:cause cause)
team)))
(defn set-team-organization
"Associates a team with an organization in Nitrate.
Requires organization-id and is-default in params.
Throws an exception if the request fails."
[cfg team params]
(let [params (assoc (or params {})
:team-id (:id team)
:organization-id (:organization-id params)
:is-default (:is-default params))
result (call cfg :set-team-org params)]
(when (nil? result)
(throw (ex-info "Failed to set team organization"
{:team-id (:id team)
:organization-id (:organization-id params)})))
team))
(defn connectivity
[cfg]
(call cfg :connectivity {}))

View File

@@ -499,7 +499,9 @@
[:map {:title "create-team"}
[:name [:string {:max 250}]]
[:features {:optional true} ::cfeat/features]
[:id {:optional true} ::sm/uuid]])
[:id {:optional true} ::sm/uuid]
[:organization-id {:optional true} ::sm/uuid]
[:is-default {:optional true} :boolean]])
(sv/defmethod ::create-team
{::doc/added "1.17"
@@ -531,6 +533,9 @@
:role :owner)
project (create-team-default-project conn params)]
(create-team-role conn params)
;; Set team organization in Nitrate if organization-id is provided
(when (and (contains? cf/flags :nitrate) (:organization-id params))
(nitrate/set-team-organization cfg-or-conn team params))
(assoc team :default-project-id (:id project))))
(defn- create-team*

View File

@@ -113,7 +113,7 @@
{::doc/added "2.14"
::sm/params schema:notify-user-added-to-organization
::rpc/auth false}
[cfg {:keys [profile-id]}]
[cfg {:keys [profile-id organization-id]}]
(quotes/check! cfg {::quotes/id ::quotes/teams-per-profile
::quotes/profile-id profile-id})
@@ -122,7 +122,9 @@
(set/difference cfeat/no-team-inheritable-features))
params {:profile-id profile-id
:name "Default"
:features features}
:features features
:organization-id organization-id
:is-default true}
team (db/tx-run! cfg teams/create-team params)]
(select-keys team [:id])))

View File

@@ -255,7 +255,7 @@
(-deref [_] team)))
(defn create-team
[{:keys [name] :as params}]
[{:keys [name organization-id] :as params}]
(dm/assert! (string? name))
(ptk/reify ::create-team
ptk/WatchEvent
@@ -264,7 +264,8 @@
:or {on-success identity
on-error rx/throw}} (meta params)
features features/global-enabled-features
params {:name name :features features}]
params (cond-> {:name name :features features}
organization-id (assoc :organization-id organization-id))]
(->> (rp/cmd! :create-team (with-meta params (meta it)))
(rx/tap on-success)
(rx/map team-created)

View File

@@ -314,7 +314,9 @@
(mf/use-fn
(mf/deps organization)
(fn []
(dnt/go-to-nitrate-cc organization)))
(if (:organization-id organization)
(dnt/go-to-nitrate-cc organization)
(dnt/go-to-nitrate-cc))))
default-team-id (or (->> organizations
vals
@@ -371,7 +373,13 @@
teams (dissoc teams default-team-id)
on-create-team-click
(mf/use-fn #(st/emit! (modal/show :team-form {})))
(mf/use-fn
(mf/deps team)
(fn []
(let [params (if (and (contains? cf/flags :nitrate) (:organization-id team))
{:organization-id (:organization-id team)}
{})]
(st/emit! (modal/show :team-form params)))))
on-team-click
(mf/use-fn
@@ -383,12 +391,12 @@
[:> dropdown-menu* props
[:> dropdown-menu-item* {:on-click on-team-click
:data-value (:default-team-id profile)
:data-value default-team-id
: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))
(when (= default-team-id (:id team))
tick-icon)]
(for [team-item (remove :is-default (vals teams))]

View File

@@ -24,7 +24,8 @@
(def ^:private schema:team-form
[:map {:title "TeamForm"}
[:name [::sm/text {:max 250}]]])
[:name [::sm/text {:max 250}]]
[:organization-id {:optional true} [:maybe ::sm/uuid]]])
(defn- on-create-success
[_form response]
@@ -50,7 +51,9 @@
[form]
(let [mdata {:on-success (partial on-create-success form)
:on-error (partial on-error form)}
params {:name (get-in @form [:clean-data :name])}]
data (:clean-data @form)
params (cond-> {:name (:name data)}
(:organization-id data) (assoc :organization-id (:organization-id data)))]
(st/emit! (-> (dtm/create-team (with-meta params mdata))
(with-meta {::ev/origin :dashboard})))))
@@ -58,7 +61,8 @@
[form]
(let [mdata {:on-success (partial on-update-success form)
:on-error (partial on-error form)}
team (get @form :clean-data)]
data (:clean-data @form)
team (select-keys data [:id :name])] ;; Only send name and id for updates
(st/emit! (dtm/update-team (with-meta team mdata))
(modal/hide))))
@@ -72,10 +76,16 @@
(mf/defc team-form-modal
{::mf/register modal/components
::mf/register-as :team-form}
[{:keys [team] :as props}]
(let [initial (mf/use-memo (fn []
(or (some-> team (select-keys [:name :id]))
{})))
[{:keys [team organization-id] :as props}]
(let [initial (mf/use-memo
(mf/deps team organization-id)
(fn []
(if team
;; For existing teams, only include name and id (no organization changes)
(select-keys team [:name :id])
;; For new teams, include organization-id if provided
(cond-> {}
organization-id (assoc :organization-id organization-id)))))
form (fm/use-form :schema schema:team-form
:initial initial)
handle-keydown