mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 05:50:35 +00:00
✨ Add get-file-tokens RPC to read a file's design tokens (#12172)
Clients that only need a file's design tokens, such as a CI job that syncs them to a git repository after an update-file webhook, had to download the whole file with get-file. get-file-tokens returns the file's tokens as a DTCG document, the same format the token export produces, or nil when the file has none. Active themes and sets come from the file's tokens status, so they reflect what is currently active. The document is returned as a plain map. A bare TokensLib is not a collection, so the response middleware would hand it to ring unencoded. Relates to #7091 Signed-off-by: Filip Sajdak <filip.sajdak@siili.com> Signed-off-by: Andrey Antukh <niwi@niwi.nz> Co-authored-by: Andrey Antukh <niwi@niwi.nz>
This commit is contained in:
parent
fa5e5b6176
commit
10955f17e2
@ -746,6 +746,28 @@
|
||||
(select-keys plugin-data [namespace])
|
||||
(or plugin-data {}))))
|
||||
|
||||
;; --- COMMAND QUERY: get-file-tokens
|
||||
|
||||
(def ^:private schema:get-file-tokens
|
||||
[:map {:title "get-file-tokens"}
|
||||
[:file-id ::sm/uuid]])
|
||||
|
||||
(sv/defmethod ::get-file-tokens
|
||||
"Return the design tokens of a file as a DTCG document, or nil when
|
||||
the file has none. Active themes and sets come from the file's
|
||||
tokens status. Cheap alternative to `get-file` when only the tokens
|
||||
are needed."
|
||||
{::doc/added "2.20"
|
||||
::sm/params schema:get-file-tokens
|
||||
::sm/result [:maybe [:map-of :string :any]]}
|
||||
[cfg {:keys [::rpc/profile-id file-id]}]
|
||||
(bfc/check-file-exists cfg file-id)
|
||||
(check-read-permissions! cfg profile-id file-id)
|
||||
(let [{:keys [data]} (bfc/get-file cfg file-id)]
|
||||
(binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg file-id)]
|
||||
(when-let [tokens-lib (cfo/get-tokens-lib data)]
|
||||
(ctob/export-dtcg-json tokens-lib (cfo/get-tokens-status data))))))
|
||||
|
||||
|
||||
;; --- COMMAND QUERY: get-file-libraries
|
||||
|
||||
|
||||
@ -2929,3 +2929,68 @@
|
||||
(t/is (not (nil? (:error out))))
|
||||
(let [edata (-> out :error ex-data)]
|
||||
(t/is (= :not-found (:type edata))))))
|
||||
|
||||
(t/deftest get-file-tokens-without-tokens
|
||||
(let [profile (th/create-profile* 1 {:is-active true})
|
||||
file (th/create-file* 1 {:profile-id (:id profile)
|
||||
:project-id (:default-project-id profile)
|
||||
:is-shared false})
|
||||
out (th/command! {::th/type :get-file-tokens
|
||||
::rpc/profile-id (:id profile)
|
||||
:file-id (:id file)})]
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (nil? (:result out)))))
|
||||
|
||||
(t/deftest get-file-tokens-with-tokens
|
||||
(let [profile (th/create-profile* 1 {:is-active true})
|
||||
file (th/create-file* 1 {:profile-id (:id profile)
|
||||
:project-id (:default-project-id profile)
|
||||
:is-shared false})
|
||||
set-id (uuid/next)
|
||||
token-id (uuid/next)]
|
||||
|
||||
(update-file!
|
||||
:file-id (:id file)
|
||||
:profile-id (:id profile)
|
||||
:changes
|
||||
[{:type :set-token-set
|
||||
:id set-id
|
||||
:attrs {:id set-id :name "brand-core"}}
|
||||
{:type :set-token
|
||||
:set-id set-id
|
||||
:token-id token-id
|
||||
:attrs {:id token-id
|
||||
:name "color.primary-base"
|
||||
:type :color
|
||||
:value "#ff0000"}}])
|
||||
|
||||
(update-file!
|
||||
:file-id (:id file)
|
||||
:profile-id (:id profile)
|
||||
:revn 1
|
||||
:changes
|
||||
[{:type :set-tokens-status
|
||||
:theme-ids #{}
|
||||
:set-ids #{set-id}}])
|
||||
|
||||
(let [out (th/command! {::th/type :get-file-tokens
|
||||
::rpc/profile-id (:id profile)
|
||||
:file-id (:id file)})
|
||||
dtcg (:result out)]
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (= "#ff0000" (get-in dtcg ["brand-core" "color" "primary-base" "$value"])))
|
||||
(t/is (= "color" (get-in dtcg ["brand-core" "color" "primary-base" "$type"])))
|
||||
(t/is (= ["brand-core"] (get-in dtcg ["$metadata" "tokenSetOrder"])))
|
||||
(t/is (= #{"brand-core"} (set (get-in dtcg ["$metadata" "activeSets"])))))))
|
||||
|
||||
(t/deftest get-file-tokens-forbidden
|
||||
(let [owner (th/create-profile* 1 {:is-active true})
|
||||
other (th/create-profile* 2 {:is-active true})
|
||||
file (th/create-file* 1 {:profile-id (:id owner)
|
||||
:project-id (:default-project-id owner)
|
||||
:is-shared false})
|
||||
out (th/command! {::th/type :get-file-tokens
|
||||
::rpc/profile-id (:id other)
|
||||
:file-id (:id file)})]
|
||||
(t/is (th/ex-info? (:error out)))
|
||||
(t/is (th/ex-of-type? (:error out) :not-found))))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user