0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-21 06:02:32 -05:00

🔧 add groups handling

This commit is contained in:
Andrés Moya 2024-09-05 16:49:29 +02:00
parent 316d333c96
commit fa8f8ac54b
3 changed files with 200 additions and 9 deletions

View file

@ -12,10 +12,9 @@
[app.common.time :as dt]
[app.common.transit :as t]
[app.common.types.token :as cto]
[cuerdas.core :as str]
#?(:clj [app.common.fressian :as fres])))
;; #?(:clj (set! *warn-on-reflection* true))
;; === Token
(defrecord Token [name type value description modified-at])
@ -56,7 +55,8 @@
(defprotocol ITokenSet
(add-token [_ token] "add a token at the end of the list")
(update-token [_ token-name f] "update a token in the list")
(delete-token [_ token-name] "delete a token from the list"))
(delete-token [_ token-name] "delete a token from the list")
(get-tokens [_] "return an ordered sequence of all tokens in the set"))
(defrecord TokenSet [name description modified-at tokens]
ITokenSet
@ -87,7 +87,10 @@
(TokenSet. name
description
(dt/now)
(dissoc tokens token-name))))
(dissoc tokens token-name)))
(get-tokens [_]
(vals tokens)))
(def schema:token-set
[:and [:map {:title "TokenSet"}
@ -442,3 +445,90 @@
(let [sets (fres/read-object! r)
themes (fres/read-object! r)]
(->TokensLib sets themes)))}))
;; === Groups handling
(def schema:groupable-item
[:map {:title "Groupable item"}
[:name :string]])
(def valid-groupable-item?
(sm/validator schema:groupable-item))
(defn split-path
"Decompose a string in the form 'one.two.three' into a vector of strings, removing spaces."
[path]
(let [xf (comp (map str/trim)
(remove str/empty?))]
(->> (str/split path ".")
(into [] xf))))
(defn join-path
"Regenerate a path as a string, from a vector."
[path-vec]
(str/join "." path-vec))
(defn group-item
"Add a group to the item name, in the form group.name."
[item group-name]
(dm/assert!
"expected groupable item"
(valid-groupable-item? item))
(update item :name #(str group-name "." %)))
(defn ungroup-item
"Remove the first group from the item name."
[item]
(dm/assert!
"expected groupable item"
(valid-groupable-item? item))
(update item :name #(-> %
(split-path)
(rest)
(join-path))))
(defn get-path
"Get the groups part of the name. E.g. group.subgroup.name -> group.subrgoup"
[item]
(dm/assert!
"expected groupable item"
(valid-groupable-item? item))
(-> (:name item)
(split-path)
(butlast)
(join-path)))
(defn get-final-name
"Get the final part of the name. E.g. group.subgroup.name -> name"
[item]
(dm/assert!
"expected groupable item"
(valid-groupable-item? item))
(-> (:name item)
(split-path)
(last)))
(defn group-items
"Convert a sequence of items in a nested structure like this:
{'': [itemA itemB]
'group1': {'': [item1A item1B]
'subgroup11': {'': [item11A item11B item11C]}
'subgroup12': {'': [item12A]}}
'group2': {'subgroup21': {'': [item21A]}}}
"
[items & {:keys [reverse-sort?]}]
(when (seq items)
(reduce (fn [groups item]
(let [pathv (split-path (:name item))]
(update-in groups
pathv
(fn [group]
(if group
(cons group item)
item)))))
(sorted-map-by (fn [key1 key2] ;; TODO: this does not work well with ordered-map
(if reverse-sort? ;; we need to think a bit more of this
(compare key2 key1)
(compare key1 key2))))
items)))

View file

@ -409,3 +409,104 @@
(t/is (ctob/valid-tokens-lib? tokens-lib'))
(t/is (= (ctob/set-count tokens-lib') 1))
(t/is (= (ctob/theme-count tokens-lib') 1)))))
(t/testing "grouping"
(t/deftest split-and-join
(let [name "group.subgroup.name"
path (ctob/split-path name)
name' (ctob/join-path path)]
(t/is (= (first path) "group"))
(t/is (= (second path) "subgroup"))
(t/is (= (nth path 2) "name"))
(t/is (= name' name))))
(t/deftest remove-spaces
(let [name "group . subgroup . name"
path (ctob/split-path name)]
(t/is (= (first path) "group"))
(t/is (= (second path) "subgroup"))
(t/is (= (nth path 2) "name"))))
(t/deftest group-and-ungroup
(let [token1 (ctob/make-token :name "token1" :type :boolean :value true)
token2 (ctob/make-token :name "some group.token2" :type :boolean :value true)
token1' (ctob/group-item token1 "big group")
token2' (ctob/group-item token2 "big group")
token1'' (ctob/ungroup-item token1')
token2'' (ctob/ungroup-item token2')]
(t/is (= (:name token1') "big group.token1"))
(t/is (= (:name token2') "big group.some group.token2"))
(t/is (= (:name token1'') "token1"))
(t/is (= (:name token2'') "some group.token2"))))
(t/deftest get-path
(let [token1 (ctob/make-token :name "token1" :type :boolean :value true)
token2 (ctob/make-token :name "some-group.token2" :type :boolean :value true)
token3 (ctob/make-token :name "some-group.some-subgroup.token3" :type :boolean :value true)]
(t/is (= (ctob/get-path token1) ""))
(t/is (= (ctob/get-path token2) "some-group"))
(t/is (= (ctob/get-path token3) "some-group.some-subgroup"))))
(t/deftest get-final-name
(let [token1 (ctob/make-token :name "token1" :type :boolean :value true)
token2 (ctob/make-token :name "some-group.token2" :type :boolean :value true)
token3 (ctob/make-token :name "some-group.some-subgroup.token3" :type :boolean :value true)]
(t/is (= (ctob/get-final-name token1) "token1"))
(t/is (= (ctob/get-final-name token2) "token2"))
(t/is (= (ctob/get-final-name token3) "token3"))))
(t/deftest group-items
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :name "token-set1"))
(ctob/add-set (ctob/make-token-set :name "sgroup1.token-set2"))
(ctob/add-set (ctob/make-token-set :name "sgroup1.token-set3"))
(ctob/add-set (ctob/make-token-set :name "sgroup1.ssubgroup1.token-set4"))
(ctob/add-set (ctob/make-token-set :name "sgroup2.token-set5"))
(ctob/add-token-in-set "sgroup2.token-set5"
(ctob/make-token :name "tgroup1.tsubgroup1.token1"
:type :boolean
:value true))
(ctob/add-token-in-set "sgroup2.token-set5"
(ctob/make-token :name "tgroup1.tsubgroup1.token2"
:type :boolean
:value true)))
sets (ctob/get-sets tokens-lib)
set (ctob/get-set tokens-lib "sgroup2.token-set5")
tokens (ctob/get-tokens set)
set-groups (ctob/group-items sets)
token-set1 (get set-groups "token-set1")
sgroup1 (get set-groups "sgroup1")
token-set2 (get sgroup1 "token-set2")
token-set3 (get sgroup1 "token-set3")
ssubgroup1 (get sgroup1 "ssubgroup1")
token-set4 (get ssubgroup1 "token-set4")
sgroup2 (get set-groups "sgroup2")
token-set5 (get sgroup2 "token-set5")
token-groups (ctob/group-items tokens)
tgroup1 (get token-groups "tgroup1")
tsubgroup1 (get tgroup1 "tsubgroup1")
token1 (get tsubgroup1 "token1")
token2 (get tsubgroup1 "token2")]
;; {"sgroup1"
;; {"token-set2" {:name "sgroup1.token-set2" ...}
;; "token-set3" {:name "sgroup1.token-set3" ...}
;; "ssubgroup1"
;; {"token-set4" {:name "sgroup1.ssubgroup1.token-set4" ...}}}
;; "sgroup2"
;; {"token-set5" {:name "sgroup2.token-set5" ...}}
;; "token-set1" {:name "token-set1" ...}}
(t/is (= (:name token-set1) "token-set1"))
(t/is (= (:name token-set2) "sgroup1.token-set2"))
(t/is (= (:name token-set3) "sgroup1.token-set3"))
(t/is (= (:name token-set4) "sgroup1.ssubgroup1.token-set4"))
(t/is (= (:name token-set5) "sgroup2.token-set5"))
(t/is (= (:name token1) "tgroup1.tsubgroup1.token1"))
(t/is (= (:name token2) "tgroup1.tsubgroup1.token2")))))

View file

@ -69,11 +69,11 @@
(defn group-assets
"Convert a list of assets in a nested structure like this:
{'': [{assetA} {assetB}]
'group1': {'': [{asset1A} {asset1B}]
'subgroup11': {'': [{asset11A} {asset11B} {asset11C}]}
'subgroup12': {'': [{asset12A}]}}
'group2': {'subgroup21': {'': [{asset21A}}}}
{'': [assetA assetB]
'group1': {'': [asset1A asset1B]
'subgroup11': {'': [asset11A asset11B asset11C]}
'subgroup12': {'': [asset12A]}}
'group2': {'subgroup21': {'': [asset21A]}}}
"
[assets reverse-sort?]
(when-not (empty? assets)