From 316d333c9647ec56629d787d24edfff1ead82e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Wed, 4 Sep 2024 02:00:31 +0200 Subject: [PATCH 1/6] :wrench: Add token themes in tokens-lib custom type --- common/src/app/common/files/changes.cljc | 63 +- .../src/app/common/files/changes_builder.cljc | 10 +- common/src/app/common/fressian.clj | 8 +- common/src/app/common/types/tokens_lib.cljc | 149 ++++- .../app/common/types/tokens_theme_list.cljc | 5 +- .../common_tests/types/tokens_lib_test.cljc | 566 +++++++++++------- frontend/src/app/main/data/tokens.cljs | 3 +- 7 files changed, 565 insertions(+), 239 deletions(-) diff --git a/common/src/app/common/files/changes.cljc b/common/src/app/common/files/changes.cljc index ae9b6362fe..34b3a28e1d 100644 --- a/common/src/app/common/files/changes.cljc +++ b/common/src/app/common/files/changes.cljc @@ -263,7 +263,8 @@ [:delete-temporary-token-theme [:map {:title "DeleteTemporaryTokenThemeChange"} [:type [:= :delete-temporary-token-theme]] - [:id ::sm/uuid]]] + [:id ::sm/uuid] + [:name :string]]] [:add-token-theme [:map {:title "AddTokenThemeChange"} @@ -274,12 +275,14 @@ [:map {:title "ModTokenThemeChange"} [:type [:= :mod-token-theme]] [:id ::sm/uuid] + [:name :string] [:token-theme ::ctot/token-theme]]] [:del-token-theme [:map {:title "DelTokenThemeChange"} [:type [:= :del-token-theme]] - [:id ::sm/uuid]]] + [:id ::sm/uuid] + [:name :string]]] [:add-token-set [:map {:title "AddTokenSetChange"} @@ -822,29 +825,69 @@ set-name name))))) +(defn- set-ids->names + [data sets] + (let [lib-sets (:token-sets-index data) + set-id->name + (fn [set-id] + (dm/get-in lib-sets [set-id :name]))] + (map set-id->name sets))) + (defmethod process-change :add-temporary-token-theme [data {:keys [token-theme]}] - (ctotl/add-temporary-token-theme data token-theme)) + (-> data + (ctotl/add-temporary-token-theme token-theme) + (update :tokens-lib + #(-> % + (ctob/ensure-tokens-lib) + (ctob/add-theme (-> token-theme + (update :sets (partial set-ids->names data)) + (ctob/make-token-theme))))))) (defmethod process-change :update-active-token-themes [data {:keys [theme-ids]}] (ctotl/assoc-active-token-themes data theme-ids)) (defmethod process-change :delete-temporary-token-theme - [data {:keys [id]}] - (ctotl/delete-temporary-token-theme data id)) + [data {:keys [id name]}] + (-> data + (ctotl/delete-temporary-token-theme id) + (update :tokens-lib + #(-> % + (ctob/ensure-tokens-lib) + (ctob/delete-theme name))))) (defmethod process-change :add-token-theme [data {:keys [token-theme]}] - (ctotl/add-token-theme data token-theme)) + (-> data + (ctotl/add-token-theme token-theme) + (update :tokens-lib + #(-> % + (ctob/ensure-tokens-lib) + (ctob/add-theme (-> token-theme + (update :sets (partial set-ids->names data)) + (ctob/make-token-theme))))))) (defmethod process-change :mod-token-theme - [data {:keys [id token-theme]}] - (ctotl/update-token-theme data id merge token-theme)) + [data {:keys [id name token-theme]}] + (-> data + (ctotl/update-token-theme id merge token-theme) + (update :tokens-lib + #(-> % + (ctob/ensure-tokens-lib) + (ctob/update-theme name (fn [prev-theme] + (merge prev-theme + (-> token-theme + (update :sets (partial set-ids->names data)))))))))) (defmethod process-change :del-token-theme - [data {:keys [id]}] - (ctotl/delete-token-theme data id)) + [data {:keys [id name]}] + (-> data + (ctotl/delete-token-theme id) + (update :tokens-lib + #(-> % + (ctob/ensure-tokens-lib) + (ctob/delete-theme name))))) (defmethod process-change :add-token-set [data {:keys [token-set]}] diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc index 09148d5423..44f57464c3 100644 --- a/common/src/app/common/files/changes_builder.cljc +++ b/common/src/app/common/files/changes_builder.cljc @@ -699,7 +699,7 @@ [changes token-theme] (-> changes (update :redo-changes conj {:type :add-temporary-token-theme :token-theme token-theme}) - (update :undo-changes conj {:type :delete-temporary-token-theme :id (:id token-theme)}) + (update :undo-changes conj {:type :delete-temporary-token-theme :id (:id token-theme) :name (:name token-theme)}) (apply-changes-local))) (defn update-active-token-themes @@ -713,14 +713,14 @@ [changes token-theme] (-> changes (update :redo-changes conj {:type :add-token-theme :token-theme token-theme}) - (update :undo-changes conj {:type :del-token-theme :id (:id token-theme)}) + (update :undo-changes conj {:type :del-token-theme :id (:id token-theme) :name (:name token-theme)}) (apply-changes-local))) (defn update-token-theme [changes token-theme prev-token-theme] (-> changes - (update :redo-changes conj {:type :mod-token-theme :id (:id token-theme) :token-theme token-theme}) - (update :undo-changes conj {:type :mod-token-theme :id (:id token-theme) :token-theme (or prev-token-theme token-theme)}) + (update :redo-changes conj {:type :mod-token-theme :id (:id token-theme) :name (:name prev-token-theme) :token-theme token-theme}) + (update :undo-changes conj {:type :mod-token-theme :id (:id token-theme) :name (:name token-theme) :token-theme (or prev-token-theme token-theme)}) (apply-changes-local))) (defn delete-token-theme @@ -729,7 +729,7 @@ (let [library-data (::library-data (meta changes)) prev-token-theme (get-in library-data [:token-themes-index token-theme-id])] (-> changes - (update :redo-changes conj {:type :del-token-theme :id token-theme-id}) + (update :redo-changes conj {:type :del-token-theme :id token-theme-id :name (:name prev-token-theme)}) (update :undo-changes conj {:type :add-token-theme :token-theme prev-token-theme}) (apply-changes-local)))) diff --git a/common/src/app/common/fressian.clj b/common/src/app/common/fressian.clj index 4a640cd8cb..f75ece0bfc 100644 --- a/common/src/app/common/fressian.clj +++ b/common/src/app/common/fressian.clj @@ -16,6 +16,7 @@ java.time.OffsetDateTime java.util.List linked.map.LinkedMap + linked.set.LinkedSet org.fressian.Reader org.fressian.StreamingWriter org.fressian.Writer @@ -275,7 +276,12 @@ {:name "clj/seq" :class clojure.lang.ISeq :wfn write-list-like - :rfn (comp sequence read-object!)}) + :rfn (comp sequence read-object!)} + + {:name "linked/set" + :class LinkedSet + :wfn write-list-like + :rfn (comp #(into (d/ordered-set) %) read-object!)}) ;; --- PUBLIC API diff --git a/common/src/app/common/types/tokens_lib.cljc b/common/src/app/common/types/tokens_lib.cljc index 7e34404c43..3ba7aa5af3 100644 --- a/common/src/app/common/types/tokens_lib.cljc +++ b/common/src/app/common/types/tokens_lib.cljc @@ -94,7 +94,8 @@ [:name :string] [:description [:maybe :string]] [:modified-at ::sm/inst] - [:tokens [:map-of {:gen/max 5} :string ::token]]] + [:tokens [:and [:map-of {:gen/max 5} :string ::token] + [:fn d/ordered-map?]]]] [:fn (partial instance? TokenSet)]]) (sm/register! ::token-set schema:token-set) @@ -127,8 +128,7 @@ (delete-set [_ set-name] "delete a set in the library") (set-count [_] "get the total number if sets in the library") (get-sets [_] "get an ordered sequence of all sets in the library") - (get-set [_ set-name] "get one set looking for name") - (validate [_])) + (get-set [_ set-name] "get one set looking for name")) (def schema:token-sets [:and @@ -144,10 +144,79 @@ (def check-token-sets! (sm/check-fn ::token-sets)) +;; === TokenTheme + +(defprotocol ITokenTheme + (toggle-set [_ set-name] "togle a set used / not used in the theme")) + +(defrecord TokenTheme [name description is-source modified-at sets] + ITokenTheme + (toggle-set [_ set-name] + (TokenTheme. name + description + is-source + (dt/now) + (if (sets set-name) + (disj sets set-name) + (conj sets set-name))))) + +(def schema:token-theme + [:and [:map {:title "TokenTheme"} + [:name :string] + [:description [:maybe :string]] + [:is-source :boolean] + [:modified-at ::sm/inst] + [:sets [:and [:set {:gen/max 5} :string] + [:fn d/ordered-set?]]]] + [:fn (partial instance? TokenTheme)]]) + +(sm/register! ::token-theme schema:token-theme) + +(def valid-token-theme? + (sm/validator schema:token-theme)) + +(def check-token-theme! + (sm/check-fn ::token-theme)) + +(defn make-token-theme + [& {:keys [] :as params}] + (let [params (-> params + (dissoc :id) + (dissoc :group) + (update :is-source #(or % false)) + (update :modified-at #(or % (dt/now))) + (update :sets #(into (d/ordered-set) %))) + token-theme (map->TokenTheme params)] + + (dm/assert! + "expected valid token theme" + (check-token-theme! token-theme)) + + token-theme)) + ;; === TokenThemes (collection) +(defprotocol ITokenThemes + (add-theme [_ token-theme] "add a theme to the library, at the end") + (update-theme [_ theme-name f] "modify a theme in the ilbrary") + (delete-theme [_ theme-name] "delete a theme in the library") + (theme-count [_] "get the total number if themes in the library") + (get-themes [_] "get an ordered sequence of all themes in the library") + (get-theme [_ theme-name] "get one theme looking for name")) + +(def schema:token-themes + [:and + [:map-of {:title "TokenThemes"} + :string ::token-theme] + [:fn d/ordered-map?]]) + +(sm/register! ::token-themes schema:token-themes) + (def valid-token-themes? - (constantly true)) + (sm/validator schema:token-themes)) + +(def check-token-themes! + (sm/check-fn ::token-themes)) ;; === Tokens Lib @@ -155,7 +224,9 @@ "A library of tokens, sets and themes." (add-token-in-set [_ set-name token] "add token to a set") (update-token-in-set [_ set-name token-name f] "update a token in a set") - (delete-token-from-set [_ set-name token-name] "delete a token from a set")) + (delete-token-from-set [_ set-name token-name] "delete a token from a set") + (toggle-set-in-theme [_ theme-name set-name] "toggle a set used / not used in a theme") + (validate [_])) (deftype TokensLib [sets themes] ;; NOTE: This is only for debug purposes, pending to properly @@ -188,15 +259,11 @@ (d/addm-at-index index (:name set') set')))) themes)) this)) - + (delete-set [_ set-name] (TokensLib. (dissoc sets set-name) themes)) - (validate [_] - (and (valid-token-sets? sets) - (valid-token-themes? themes))) - (set-count [_] (count sets)) @@ -206,6 +273,39 @@ (get-set [_ set-name] (get sets set-name)) + ITokenThemes + (add-theme [_ token-theme] + (dm/assert! "expected valid token theme" (check-token-theme! token-theme)) + (TokensLib. sets + (assoc themes (:name token-theme) token-theme))) + + (update-theme [this theme-name f] + (if-let [theme (get themes theme-name)] + (let [theme' (-> (make-token-theme (f theme)) + (assoc :modified-at (dt/now)))] + (check-token-theme! theme') + (TokensLib. sets + (if (= (:name theme) (:name theme')) + (assoc themes (:name theme') theme') + (let [index (d/index-of (keys themes) (:name theme))] + (-> themes + (dissoc (:name theme)) + (d/addm-at-index index (:name theme') theme')))))) + this)) + + (delete-theme [_ theme-name] + (TokensLib. sets + (dissoc themes theme-name))) + + (theme-count [_] + (count themes)) + + (get-themes [_] + (vals themes)) + + (get-theme [_ theme-name] + (get themes theme-name)) + ITokensLib (add-token-in-set [this set-name token] (dm/assert! "expected valid token instance" (check-token! token)) @@ -226,7 +326,18 @@ (TokensLib. (update sets set-name #(delete-token % token-name)) themes) - this))) + this)) + + (toggle-set-in-theme [this theme-name set-name] + (if (contains? themes theme-name) + (TokensLib. sets + (update themes theme-name + #(toggle-set % set-name))) + this)) + + (validate [_] + (and (valid-token-sets? sets) + (valid-token-themes? themes)))) (defn valid-tokens-lib? [o] @@ -269,7 +380,7 @@ (sm/register! ::tokens-lib type:tokens-lib) -;; === Serialization handlers for RPC API and database +;; === Serialization handlers for RPC API (transit) and database (fressian) (t/add-handlers! {:id "penpot/tokens-lib" @@ -281,6 +392,11 @@ :class TokenSet :wfn #(into {} %) :rfn #(make-token-set %)} + + {:id "penpot/token-theme" + :class TokenTheme + :wfn #(into {} %) + :rfn #(make-token-theme %)} {:id "penpot/token" :class Token @@ -307,6 +423,15 @@ (let [obj (fres/read-object! r)] (map->TokenSet obj)))} + {:name "penpot/token-theme/v1" + :class TokenTheme + :wfn (fn [n w o] + (fres/write-tag! w n 1) + (fres/write-object! w (into {} o))) + :rfn (fn [r] + (let [obj (fres/read-object! r)] + (map->TokenTheme obj)))} + {:name "penpot/tokens-lib/v1" :class TokensLib :wfn (fn [n w o] diff --git a/common/src/app/common/types/tokens_theme_list.cljc b/common/src/app/common/types/tokens_theme_list.cljc index f9c3857ff2..971c96946c 100644 --- a/common/src/app/common/types/tokens_theme_list.cljc +++ b/common/src/app/common/types/tokens_theme_list.cljc @@ -19,16 +19,17 @@ (assoc file-data :token-active-themes theme-ids)) (defn add-temporary-token-theme - [file-data {:keys [id] :as token-theme}] + [file-data {:keys [id name] :as token-theme}] (-> file-data (d/dissoc-in [:token-themes-index (:token-theme-temporary-id file-data)]) (assoc :token-theme-temporary-id id) + (assoc :token-theme-temporary-name name) (update :token-themes-index assoc id token-theme))) (defn delete-temporary-token-theme [file-data token-theme-id] (cond-> file-data - (= (:token-theme-temporary-id file-data) token-theme-id) (dissoc :token-theme-temporary-id) + (= (:token-theme-temporary-id file-data) token-theme-id) (dissoc :token-theme-temporary-id :token-theme-temporary-name) :always (d/dissoc-in [:token-themes-index (:token-theme-temporary-id file-data)]))) (defn add-token-theme diff --git a/common/test/common_tests/types/tokens_lib_test.cljc b/common/test/common_tests/types/tokens_lib_test.cljc index 09ad19b177..3c24353da7 100644 --- a/common/test/common_tests/types/tokens_lib_test.cljc +++ b/common/test/common_tests/types/tokens_lib_test.cljc @@ -13,247 +13,399 @@ [app.common.types.tokens-lib :as ctob] [clojure.test :as t])) -(t/deftest make-token - (let [now (dt/now) - token1 (ctob/make-token :name "test-token-1" - :type :boolean - :value true) - token2 (ctob/make-token :name "test-token-2" - :type :numeric - :value 66 - :description "test description" - :modified-at now)] +(t/testing "token" + (t/deftest make-token + (let [now (dt/now) + token1 (ctob/make-token :name "test-token-1" + :type :boolean + :value true) + token2 (ctob/make-token :name "test-token-2" + :type :numeric + :value 66 + :description "test description" + :modified-at now)] - (t/is (= (:name token1) "test-token-1")) - (t/is (= (:type token1) :boolean)) - (t/is (= (:value token1) true)) - (t/is (nil? (:description token1))) - (t/is (some? (:modified-at token1))) - (t/is (ctob/valid-token? token1)) + (t/is (= (:name token1) "test-token-1")) + (t/is (= (:type token1) :boolean)) + (t/is (= (:value token1) true)) + (t/is (nil? (:description token1))) + (t/is (some? (:modified-at token1))) + (t/is (ctob/valid-token? token1)) - (t/is (= (:name token2) "test-token-2")) - (t/is (= (:type token2) :numeric)) - (t/is (= (:value token2) 66)) - (t/is (= (:description token2) "test description")) - (t/is (= (:modified-at token2) now)) - (t/is (ctob/valid-token? token2)))) + (t/is (= (:name token2) "test-token-2")) + (t/is (= (:type token2) :numeric)) + (t/is (= (:value token2) 66)) + (t/is (= (:description token2) "test description")) + (t/is (= (:modified-at token2) now)) + (t/is (ctob/valid-token? token2)))) -(t/deftest invalid-tokens - (let [args {:name 777 - :type :invalid}] - (t/is (thrown-with-msg? Exception #"expected valid token" - (apply ctob/make-token args))) - (t/is (false? (ctob/valid-token? {}))))) + (t/deftest invalid-tokens + (let [args {:name 777 + :type :invalid}] + (t/is (thrown-with-msg? Exception #"expected valid token" + (apply ctob/make-token args))) + (t/is (false? (ctob/valid-token? {})))))) -(t/deftest make-token-set - (let [now (dt/now) - token-set1 (ctob/make-token-set :name "test-token-set-1") - token-set2 (ctob/make-token-set :name "test-token-set-2" - :description "test description" - :modified-at now - :tokens [])] - (t/is (= (:name token-set1) "test-token-set-1")) - (t/is (nil? (:description token-set1))) - (t/is (some? (:modified-at token-set1))) - (t/is (empty? (:tokens token-set1))) +(t/testing "token-set" + (t/deftest make-token-set + (let [now (dt/now) + token-set1 (ctob/make-token-set :name "test-token-set-1") + token-set2 (ctob/make-token-set :name "test-token-set-2" + :description "test description" + :modified-at now + :tokens [])] - (t/is (= (:name token-set2) "test-token-set-2")) - (t/is (= (:description token-set2) "test description")) - (t/is (= (:modified-at token-set2) now)) - (t/is (empty? (:tokens token-set2))))) + (t/is (= (:name token-set1) "test-token-set-1")) + (t/is (nil? (:description token-set1))) + (t/is (some? (:modified-at token-set1))) + (t/is (empty? (:tokens token-set1))) -(t/deftest invalid-token-set - (let [args {:name 777 - :description 999}] - (t/is (thrown-with-msg? Exception #"expected valid token set" - (apply ctob/make-token-set args))))) + (t/is (= (:name token-set2) "test-token-set-2")) + (t/is (= (:description token-set2) "test description")) + (t/is (= (:modified-at token-set2) now)) + (t/is (empty? (:tokens token-set2))))) -(t/deftest make-tokens-lib - (let [tokens-lib (ctob/make-tokens-lib)] - (t/is (= (ctob/set-count tokens-lib) 0)))) + (t/deftest invalid-token-set + (let [args {:name 777 + :description 999}] + (t/is (thrown-with-msg? Exception #"expected valid token set" + (apply ctob/make-token-set args)))))) -(t/deftest add-token-set - (let [tokens-lib (ctob/make-tokens-lib) - token-set (ctob/make-token-set :name "test-token-set") - tokens-lib' (ctob/add-set tokens-lib token-set) - token-sets' (ctob/get-sets tokens-lib') - token-set' (ctob/get-set tokens-lib' "test-token-set")] +(t/testing "token-theme" + (t/deftest make-token-theme + (let [now (dt/now) + token-theme1 (ctob/make-token-theme :name "test-token-theme-1") + token-theme2 (ctob/make-token-theme :name "test-token-theme-2" + :description "test description" + :is-source true + :modified-at now + :sets #{})] - (t/is (= (ctob/set-count tokens-lib') 1)) - (t/is (= (first token-sets') token-set)) - (t/is (= token-set' token-set)))) + (t/is (= (:name token-theme1) "test-token-theme-1")) + (t/is (nil? (:description token-theme1))) + (t/is (false? (:is-source token-theme1))) + (t/is (some? (:modified-at token-theme1))) + (t/is (empty? (:sets token-theme1))) -(t/deftest update-token-set - (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-set (ctob/make-token-set :name "test-token-set"))) + (t/is (= (:name token-theme2) "test-token-theme-2")) + (t/is (= (:description token-theme2) "test description")) + (t/is (true? (:is-source token-theme2))) + (t/is (= (:modified-at token-theme2) now)) + (t/is (empty? (:sets token-theme2))))) - tokens-lib' (-> tokens-lib - (ctob/update-set "test-token-set" - (fn [token-set] - (assoc token-set - :name "updated-name" - :description "some description"))) - (ctob/update-set "not-existing-set" - (fn [token-set] - (assoc token-set - :name "no-effect")))) + (t/deftest invalid-token-theme + (let [args {:name 777 + :description 999 + :is-source 42}] + (t/is (thrown-with-msg? Exception #"expected valid token theme" + (apply ctob/make-token-theme args)))))) - token-set (ctob/get-set tokens-lib "test-token-set") - token-set' (ctob/get-set tokens-lib' "updated-name")] - (t/is (= (ctob/set-count tokens-lib') 1)) - (t/is (= (:name token-set') "updated-name")) - (t/is (= (:description token-set') "some description")) - (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))) +(t/testing "tokens-lib" + (t/deftest make-tokens-lib + (let [tokens-lib (ctob/make-tokens-lib)] + (t/is (= (ctob/set-count tokens-lib) 0)))) -(t/deftest delete-token-set - (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-set (ctob/make-token-set :name "test-token-set"))) + (t/deftest invalid-tokens-lib + (let [args {:sets nil + :themes nil}] + (t/is (thrown-with-msg? Exception #"expected valid tokens lib" + (apply ctob/make-tokens-lib args)))))) - tokens-lib' (-> tokens-lib - (ctob/delete-set "test-token-set") - (ctob/delete-set "not-existing-set")) - token-set' (ctob/get-set tokens-lib' "updated-name")] +(t/testing "token-set in a lib" + (t/deftest add-token-set + (let [tokens-lib (ctob/make-tokens-lib) + token-set (ctob/make-token-set :name "test-token-set") + tokens-lib' (ctob/add-set tokens-lib token-set) - (t/is (= (ctob/set-count tokens-lib') 0)) - (t/is (nil? token-set')))) + token-sets' (ctob/get-sets tokens-lib') + token-set' (ctob/get-set tokens-lib' "test-token-set")] -(t/deftest add-token - (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-set (ctob/make-token-set :name "test-token-set"))) - token (ctob/make-token :name "test-token" - :type :boolean - :value true) - tokens-lib' (-> tokens-lib - (ctob/add-token-in-set "test-token-set" token) - (ctob/add-token-in-set "not-existing-set" token)) + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (first token-sets') token-set)) + (t/is (= token-set' token-set)))) - token-set (ctob/get-set tokens-lib "test-token-set") - token-set' (ctob/get-set tokens-lib' "test-token-set") - token' (get-in token-set' [:tokens "test-token"])] + (t/deftest update-token-set + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set"))) - (t/is (= (ctob/set-count tokens-lib') 1)) - (t/is (= (count (:tokens token-set')) 1)) - (t/is (= (:name token') "test-token")) - (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))) + tokens-lib' (-> tokens-lib + (ctob/update-set "test-token-set" + (fn [token-set] + (assoc token-set + :description "some description"))) + (ctob/update-set "not-existing-set" + (fn [token-set] + (assoc token-set + :description "no-effect")))) -(t/deftest update-token - (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-set (ctob/make-token-set :name "test-token-set")) - (ctob/add-token-in-set "test-token-set" - (ctob/make-token :name "test-token-1" - :type :boolean - :value true)) - (ctob/add-token-in-set "test-token-set" - (ctob/make-token :name "test-token-2" - :type :boolean - :value true))) + token-set (ctob/get-set tokens-lib "test-token-set") + token-set' (ctob/get-set tokens-lib' "test-token-set")] - tokens-lib' (-> tokens-lib - (ctob/update-token-in-set "test-token-set" "test-token-1" - (fn [token] - (assoc token - :description "some description" - :value false))) - (ctob/update-token-in-set "not-existing-set" "test-token-1" - (fn [token] - (assoc token - :name "no-effect"))) - (ctob/update-token-in-set "test-token-set" "not-existing-token" - (fn [token] - (assoc token - :name "no-effect")))) + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (:name token-set') "test-token-set")) + (t/is (= (:description token-set') "some description")) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))) - token-set (ctob/get-set tokens-lib "test-token-set") - token-set' (ctob/get-set tokens-lib' "test-token-set") - token (get-in token-set [:tokens "test-token-1"]) - token' (get-in token-set' [:tokens "test-token-1"])] + (t/deftest rename-token-set + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set"))) - (t/is (= (ctob/set-count tokens-lib') 1)) - (t/is (= (count (:tokens token-set')) 2)) - (t/is (= (d/index-of (keys (:tokens token-set')) "test-token-1") 0)) - (t/is (= (:name token') "test-token-1")) - (t/is (= (:description token') "some description")) - (t/is (= (:value token') false)) - (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))) - (t/is (dt/is-after? (:modified-at token') (:modified-at token))))) + tokens-lib' (-> tokens-lib + (ctob/update-set "test-token-set" + (fn [token-set] + (assoc token-set + :name "updated-name")))) -(t/deftest rename-token - (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-set (ctob/make-token-set :name "test-token-set")) - (ctob/add-token-in-set "test-token-set" - (ctob/make-token :name "test-token-1" - :type :boolean - :value true)) - (ctob/add-token-in-set "test-token-set" - (ctob/make-token :name "test-token-2" - :type :boolean - :value true))) + token-set (ctob/get-set tokens-lib "test-token-set") + token-set' (ctob/get-set tokens-lib' "updated-name")] - tokens-lib' (-> tokens-lib - (ctob/update-token-in-set "test-token-set" "test-token-1" - (fn [token] - (assoc token - :name "updated-name")))) + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (:name token-set') "updated-name")) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))) - token-set (ctob/get-set tokens-lib "test-token-set") - token-set' (ctob/get-set tokens-lib' "test-token-set") - token (get-in token-set [:tokens "test-token-1"]) - token' (get-in token-set' [:tokens "updated-name"])] + (t/deftest delete-token-set + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set"))) - (t/is (= (ctob/set-count tokens-lib') 1)) - (t/is (= (count (:tokens token-set')) 2)) - (t/is (= (d/index-of (keys (:tokens token-set')) "updated-name") 0)) - (t/is (= (:name token') "updated-name")) - (t/is (= (:description token') nil)) - (t/is (= (:value token') true)) - (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))) - (t/is (dt/is-after? (:modified-at token') (:modified-at token))))) + tokens-lib' (-> tokens-lib + (ctob/delete-set "test-token-set") + (ctob/delete-set "not-existing-set")) -(t/deftest delete-token - (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-set (ctob/make-token-set :name "test-token-set")) - (ctob/add-token-in-set "test-token-set" - (ctob/make-token :name "test-token" - :type :boolean - :value true))) - tokens-lib' (-> tokens-lib - (ctob/delete-token-from-set "test-token-set" "test-token") - (ctob/delete-token-from-set "not-existing-set" "test-token") - (ctob/delete-token-from-set "test-set" "not-existing-token")) + token-set' (ctob/get-set tokens-lib' "updated-name")] - token-set (ctob/get-set tokens-lib "test-token-set") - token-set' (ctob/get-set tokens-lib' "test-token-set") - token' (get-in token-set' [:tokens "test-token"])] + (t/is (= (ctob/set-count tokens-lib') 0)) + (t/is (nil? token-set'))))) - (t/is (= (ctob/set-count tokens-lib') 1)) - (t/is (= (count (:tokens token-set')) 0)) - (t/is (nil? token')) - (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))) -(t/deftest transit-serialization - (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-set (ctob/make-token-set :name "test-token-set")) - (ctob/add-token-in-set "test-token-set" (ctob/make-token :name "test-token" - :type :boolean - :value true))) - encoded-str (tr/encode-str tokens-lib) - tokens-lib' (tr/decode-str encoded-str)] +(t/testing "token in a lib" + (t/deftest add-token + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set"))) + token (ctob/make-token :name "test-token" + :type :boolean + :value true) + tokens-lib' (-> tokens-lib + (ctob/add-token-in-set "test-token-set" token) + (ctob/add-token-in-set "not-existing-set" token)) - (t/is (ctob/valid-tokens-lib? tokens-lib')) - (t/is (= (ctob/set-count tokens-lib') 1)))) + token-set (ctob/get-set tokens-lib "test-token-set") + token-set' (ctob/get-set tokens-lib' "test-token-set") + token' (get-in token-set' [:tokens "test-token"])] -(t/deftest fressian-serialization - (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-set (ctob/make-token-set :name "test-token-set")) - (ctob/add-token-in-set "test-token-set" (ctob/make-token :name "test-token" - :type :boolean - :value true))) - encoded-blob (fres/encode tokens-lib) - tokens-lib' (fres/decode encoded-blob)] + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (count (:tokens token-set')) 1)) + (t/is (= (:name token') "test-token")) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))) - (t/is (ctob/valid-tokens-lib? tokens-lib')) - (t/is (= (ctob/set-count tokens-lib') 1)))) + (t/deftest update-token + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set")) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "test-token-1" + :type :boolean + :value true)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "test-token-2" + :type :boolean + :value true))) + + tokens-lib' (-> tokens-lib + (ctob/update-token-in-set "test-token-set" "test-token-1" + (fn [token] + (assoc token + :description "some description" + :value false))) + (ctob/update-token-in-set "not-existing-set" "test-token-1" + (fn [token] + (assoc token + :name "no-effect"))) + (ctob/update-token-in-set "test-token-set" "not-existing-token" + (fn [token] + (assoc token + :name "no-effect")))) + + token-set (ctob/get-set tokens-lib "test-token-set") + token-set' (ctob/get-set tokens-lib' "test-token-set") + token (get-in token-set [:tokens "test-token-1"]) + token' (get-in token-set' [:tokens "test-token-1"])] + + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (count (:tokens token-set')) 2)) + (t/is (= (d/index-of (keys (:tokens token-set')) "test-token-1") 0)) + (t/is (= (:name token') "test-token-1")) + (t/is (= (:description token') "some description")) + (t/is (= (:value token') false)) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))) + (t/is (dt/is-after? (:modified-at token') (:modified-at token))))) + + (t/deftest rename-token + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set")) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "test-token-1" + :type :boolean + :value true)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "test-token-2" + :type :boolean + :value true))) + + tokens-lib' (-> tokens-lib + (ctob/update-token-in-set "test-token-set" "test-token-1" + (fn [token] + (assoc token + :name "updated-name")))) + + token-set (ctob/get-set tokens-lib "test-token-set") + token-set' (ctob/get-set tokens-lib' "test-token-set") + token (get-in token-set [:tokens "test-token-1"]) + token' (get-in token-set' [:tokens "updated-name"])] + + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (count (:tokens token-set')) 2)) + (t/is (= (d/index-of (keys (:tokens token-set')) "updated-name") 0)) + (t/is (= (:name token') "updated-name")) + (t/is (= (:description token') nil)) + (t/is (= (:value token') true)) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))) + (t/is (dt/is-after? (:modified-at token') (:modified-at token))))) + + (t/deftest delete-token + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set")) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "test-token" + :type :boolean + :value true))) + tokens-lib' (-> tokens-lib + (ctob/delete-token-from-set "test-token-set" "test-token") + (ctob/delete-token-from-set "not-existing-set" "test-token") + (ctob/delete-token-from-set "test-set" "not-existing-token")) + + token-set (ctob/get-set tokens-lib "test-token-set") + token-set' (ctob/get-set tokens-lib' "test-token-set") + token' (get-in token-set' [:tokens "test-token"])] + + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (count (:tokens token-set')) 0)) + (t/is (nil? token')) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))))) + + +(t/testing "token-theme in a lib" + (t/deftest add-token-theme + (let [tokens-lib (ctob/make-tokens-lib) + token-theme (ctob/make-token-theme :name "test-token-theme") + tokens-lib' (ctob/add-theme tokens-lib token-theme) + + token-themes' (ctob/get-themes tokens-lib') + token-theme' (ctob/get-theme tokens-lib' "test-token-theme")] + + (prn "lib" tokens-lib') + (t/is (= (ctob/theme-count tokens-lib') 1)) + (t/is (= (first token-themes') token-theme)) + (t/is (= token-theme' token-theme)))) + + (t/deftest update-token-theme + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-theme (ctob/make-token-theme :name "test-token-theme"))) + + tokens-lib' (-> tokens-lib + (ctob/update-theme "test-token-theme" + (fn [token-theme] + (assoc token-theme + :description "some description"))) + (ctob/update-theme "not-existing-theme" + (fn [token-theme] + (assoc token-theme + :description "no-effect")))) + + token-theme (ctob/get-theme tokens-lib "test-token-theme") + token-theme' (ctob/get-theme tokens-lib' "test-token-theme")] + + (t/is (= (ctob/theme-count tokens-lib') 1)) + (t/is (= (:name token-theme') "test-token-theme")) + (t/is (= (:description token-theme') "some description")) + (t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme))))) + + (t/deftest rename-token-theme + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-theme (ctob/make-token-theme :name "test-token-theme"))) + + tokens-lib' (-> tokens-lib + (ctob/update-theme "test-token-theme" + (fn [token-theme] + (assoc token-theme + :name "updated-name")))) + + token-theme (ctob/get-theme tokens-lib "test-token-theme") + token-theme' (ctob/get-theme tokens-lib' "updated-name")] + + (t/is (= (ctob/theme-count tokens-lib') 1)) + (t/is (= (:name token-theme') "updated-name")) + (t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme))))) + + (t/deftest delete-token-theme + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-theme (ctob/make-token-theme :name "test-token-theme"))) + + tokens-lib' (-> tokens-lib + (ctob/delete-theme "test-token-theme") + (ctob/delete-theme "not-existing-theme")) + + token-theme' (ctob/get-theme tokens-lib' "updated-name")] + + (t/is (= (ctob/theme-count tokens-lib') 0)) + (t/is (nil? token-theme')))) + + (t/deftest toggle-set-in-theme + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "token-set-1")) + (ctob/add-set (ctob/make-token-set :name "token-set-2")) + (ctob/add-set (ctob/make-token-set :name "token-set-3")) + (ctob/add-theme (ctob/make-token-theme :name "test-token-theme"))) + tokens-lib' (-> tokens-lib + (ctob/toggle-set-in-theme "test-token-theme" "token-set-1") + (ctob/toggle-set-in-theme "test-token-theme" "token-set-2") + (ctob/toggle-set-in-theme "test-token-theme" "token-set-2")) + + token-theme (ctob/get-theme tokens-lib "test-token-theme") + token-theme' (ctob/get-theme tokens-lib' "test-token-theme")] + + (t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme)))))) + + +(t/testing "serialization" + (t/deftest transit-serialization + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set")) + (ctob/add-token-in-set "test-token-set" (ctob/make-token :name "test-token" + :type :boolean + :value true)) + (ctob/add-theme (ctob/make-token-theme :name "test-token-theme")) + (ctob/toggle-set-in-theme "test-token-theme" "test-token-set")) + encoded-str (tr/encode-str tokens-lib) + tokens-lib' (tr/decode-str encoded-str)] + + (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/deftest fressian-serialization + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set")) + (ctob/add-token-in-set "test-token-set" (ctob/make-token :name "test-token" + :type :boolean + :value true)) + (ctob/add-theme (ctob/make-token-theme :name "test-token-theme")) + (ctob/toggle-set-in-theme "test-token-theme" "test-token-set")) + encoded-blob (fres/encode tokens-lib) + tokens-lib' (fres/decode encoded-blob)] + + (t/is (ctob/valid-tokens-lib? tokens-lib')) + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (ctob/theme-count tokens-lib') 1))))) diff --git a/frontend/src/app/main/data/tokens.cljs b/frontend/src/app/main/data/tokens.cljs index 904811b804..820911b826 100644 --- a/frontend/src/app/main/data/tokens.cljs +++ b/frontend/src/app/main/data/tokens.cljs @@ -115,10 +115,9 @@ (ptk/reify ::update-token-theme ptk/WatchEvent (watch [it state _] - (let [prev-token-theme (wtts/get-workspace-token-theme state (:id token-theme)) + (let [prev-token-theme (wtts/get-workspace-token-theme (:id token-theme) state) changes (-> (pcb/empty-changes it) (pcb/update-token-theme token-theme prev-token-theme))] - (js/console.log "changes" changes) (rx/of (dch/commit-changes changes)))))) From fa8f8ac54b66944f7027a0c4b758e940877ce3c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Thu, 5 Sep 2024 16:49:29 +0200 Subject: [PATCH 2/6] :wrench: add groups handling --- common/src/app/common/types/tokens_lib.cljc | 98 ++++++++++++++++- .../common_tests/types/tokens_lib_test.cljc | 101 ++++++++++++++++++ .../ui/workspace/sidebar/assets/groups.cljs | 10 +- 3 files changed, 200 insertions(+), 9 deletions(-) diff --git a/common/src/app/common/types/tokens_lib.cljc b/common/src/app/common/types/tokens_lib.cljc index 3ba7aa5af3..aa7658b179 100644 --- a/common/src/app/common/types/tokens_lib.cljc +++ b/common/src/app/common/types/tokens_lib.cljc @@ -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))) diff --git a/common/test/common_tests/types/tokens_lib_test.cljc b/common/test/common_tests/types/tokens_lib_test.cljc index 3c24353da7..6d8d060f71 100644 --- a/common/test/common_tests/types/tokens_lib_test.cljc +++ b/common/test/common_tests/types/tokens_lib_test.cljc @@ -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"))))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/groups.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/groups.cljs index 82d97180d9..b8fa390584 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/groups.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/groups.cljs @@ -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) From e2ff6f7ba65e8c9c2d0fb3dcbe2c406b8de6bb48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Thu, 5 Sep 2024 17:51:02 +0200 Subject: [PATCH 3/6] :wrench: Add first draft of token set groups attributes --- common/src/app/common/types/tokens_lib.cljc | 61 ++++++++++++++----- .../common_tests/types/tokens_lib_test.cljc | 10 +++ 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/common/src/app/common/types/tokens_lib.cljc b/common/src/app/common/types/tokens_lib.cljc index aa7658b179..4de4d3ee8c 100644 --- a/common/src/app/common/types/tokens_lib.cljc +++ b/common/src/app/common/types/tokens_lib.cljc @@ -123,6 +123,16 @@ token-set)) +;; === TokenSetGroup + +(defrecord TokenSetGroup [attr1 attr2]) + +;; TODO schema, validators, etc. + +(defn make-token-set-group + [] + (TokenSetGroup. "one" "two")) + ;; === TokenSets (collection) (defprotocol ITokenSets @@ -131,7 +141,8 @@ (delete-set [_ set-name] "delete a set in the library") (set-count [_] "get the total number if sets in the library") (get-sets [_] "get an ordered sequence of all sets in the library") - (get-set [_ set-name] "get one set looking for name")) + (get-set [_ set-name] "get one set looking for name") + (get-set-group [_ set-group-path] "get the attributes of a set group")) (def schema:token-sets [:and @@ -231,23 +242,30 @@ (toggle-set-in-theme [_ theme-name set-name] "toggle a set used / not used in a theme") (validate [_])) -(deftype TokensLib [sets themes] +(declare get-path) + +(deftype TokensLib [sets set-groups themes] ;; NOTE: This is only for debug purposes, pending to properly ;; implement the toString and alternative printing. #?@(:clj [clojure.lang.IDeref - (deref [_] {:sets sets :themes themes})] + (deref [_] {:sets sets :set-groups set-groups :themes themes})] :cljs [cljs.core/IDeref - (-deref [_] {:sets sets :themes themes})]) + (-deref [_] {:sets sets :set-groups set-groups :themes themes})]) #?@(:cljs [cljs.core/IEncodeJS (-clj->js [_] (js-obj "sets" (clj->js sets) + "set-groups" (clj->js set-groups) "themes" (clj->js themes)))]) ITokenSets (add-set [_ token-set] (dm/assert! "expected valid token set" (check-token-set! token-set)) - (TokensLib. (assoc sets (:name token-set) token-set) - themes)) + (let [path (get-path token-set)] + (TokensLib. (assoc sets (:name token-set) token-set) + (cond-> set-groups + (seq path) + (assoc path (make-token-set-group))) + themes))) (update-set [this set-name f] (if-let [set (get sets set-name)] @@ -260,11 +278,13 @@ (-> sets (dissoc (:name set)) (d/addm-at-index index (:name set') set')))) + set-groups ;; TODO update set-groups as needed themes)) this)) - + (delete-set [_ set-name] (TokensLib. (dissoc sets set-name) + set-groups ;; TODO remove set-group if needed themes)) (set-count [_] @@ -276,10 +296,14 @@ (get-set [_ set-name] (get sets set-name)) + (get-set-group [_ set-group-path] + (get set-groups set-group-path)) + ITokenThemes (add-theme [_ token-theme] (dm/assert! "expected valid token theme" (check-token-theme! token-theme)) (TokensLib. sets + set-groups (assoc themes (:name token-theme) token-theme))) (update-theme [this theme-name f] @@ -288,6 +312,7 @@ (assoc :modified-at (dt/now)))] (check-token-theme! theme') (TokensLib. sets + set-groups (if (= (:name theme) (:name theme')) (assoc themes (:name theme') theme') (let [index (d/index-of (keys themes) (:name theme))] @@ -298,6 +323,7 @@ (delete-theme [_ theme-name] (TokensLib. sets + set-groups (dissoc themes theme-name))) (theme-count [_] @@ -314,6 +340,7 @@ (dm/assert! "expected valid token instance" (check-token! token)) (if (contains? sets set-name) (TokensLib. (update sets set-name add-token token) + set-groups themes) this)) @@ -321,6 +348,7 @@ (if (contains? sets set-name) (TokensLib. (update sets set-name #(update-token % token-name f)) + set-groups themes) this)) @@ -328,18 +356,20 @@ (if (contains? sets set-name) (TokensLib. (update sets set-name #(delete-token % token-name)) + set-groups themes) this)) (toggle-set-in-theme [this theme-name set-name] (if (contains? themes theme-name) (TokensLib. sets + set-groups (update themes theme-name #(toggle-set % set-name))) this)) (validate [_] - (and (valid-token-sets? sets) + (and (valid-token-sets? sets) ;; TODO: validate set-groups (valid-token-themes? themes)))) (defn valid-tokens-lib? @@ -362,10 +392,11 @@ ;; structure the data and the order separately as we already do ;; with pages and pages-index. (make-tokens-lib :sets (d/ordered-map) + :set-groups {} :themes (d/ordered-map))) - ([& {:keys [sets themes]}] - (let [tokens-lib (TokensLib. sets themes)] + ([& {:keys [sets set-groups themes]}] + (let [tokens-lib (TokensLib. sets set-groups themes)] (dm/assert! "expected valid tokens lib" @@ -438,13 +469,15 @@ {:name "penpot/tokens-lib/v1" :class TokensLib :wfn (fn [n w o] - (fres/write-tag! w n 2) + (fres/write-tag! w n 3) (fres/write-object! w (.-sets o)) + (fres/write-object! w (.-set-groups o)) (fres/write-object! w (.-themes o))) :rfn (fn [r] - (let [sets (fres/read-object! r) - themes (fres/read-object! r)] - (->TokensLib sets themes)))})) + (let [sets (fres/read-object! r) + set-groups (fres/read-object! r) + themes (fres/read-object! r)] + (->TokensLib sets set-groups themes)))})) ;; === Groups handling diff --git a/common/test/common_tests/types/tokens_lib_test.cljc b/common/test/common_tests/types/tokens_lib_test.cljc index 6d8d060f71..e96834c274 100644 --- a/common/test/common_tests/types/tokens_lib_test.cljc +++ b/common/test/common_tests/types/tokens_lib_test.cljc @@ -128,6 +128,16 @@ (t/is (= (first token-sets') token-set)) (t/is (= token-set' token-set)))) + (t/deftest add-token-set-with-group + (let [tokens-lib (ctob/make-tokens-lib) + token-set (ctob/make-token-set :name "test-group.test-token-set") + tokens-lib' (ctob/add-set tokens-lib token-set) + + set-group (ctob/get-set-group tokens-lib' "test-group")] + + (t/is (= (:attr1 set-group) "one")) + (t/is (= (:attr2 set-group) "two")))) + (t/deftest update-token-set (let [tokens-lib (-> (ctob/make-tokens-lib) (ctob/add-set (ctob/make-token-set :name "test-token-set"))) From 3a4ec32f8e3851b3385d098d619b97f484835a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Thu, 12 Sep 2024 10:04:03 +0200 Subject: [PATCH 4/6] :wrench: add groups handling v2 --- common/src/app/common/data.cljc | 49 ++ common/src/app/common/types/tokens_lib.cljc | 343 +++++----- .../common_tests/types/tokens_lib_test.cljc | 593 ++++++++++++++++-- 3 files changed, 766 insertions(+), 219 deletions(-) diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index 77e9af51b9..73d46576fa 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -57,6 +57,54 @@ #?(:cljs (instance? lkm/LinkedMap o) :clj (instance? LinkedMap o))) +(defn oassoc + [o & kvs] + (apply assoc (or o (ordered-map)) kvs)) + +(defn oassoc-in + [o [k & ks] v] + (if ks + (oassoc o k (oassoc-in (get o k) ks v)) + (oassoc o k v))) + +#_(defn oupdate-in + [m ks f & args] + (let [up (fn up [m ks f args] + (let [[k & ks] ks] + (if ks + (oassoc m k (up (get m k) ks f args)) + (oassoc m k (apply f (get m k) args)))))] + (up m ks f args))) + +(declare index-of) + +#_(defn oassoc-before + "Assoc a k v pair, in the order position just before the other key" + [o k v before-k] + (if-let [index (index-of (keys o) before-k)] + (-> (ordered-map) + (into (take index o)) + (assoc k v) + (into (drop index o))) + (oassoc o k v))) + +(defn oassoc-in-before + [o [old-k & old-ks] [k & ks] v] + (if-let [index (index-of (keys o) old-k)] + (let [new-v (if ks + (oassoc-in-before (get o k) old-ks ks v) + v)] + (if (= k old-k) + (-> (ordered-map) + (into (take index o)) + (assoc k new-v) + (into (drop (inc index) o))) + (-> (ordered-map) + (into (take index o)) + (assoc k new-v) + (into (drop index o))))) + (oassoc-in o (cons k ks) v))) + (defn vec2 "Creates a optimized vector compatible type of length 2 backed internally with MapEntry impl because it has faster access method @@ -564,6 +612,7 @@ new-elems (remove p? after)))) +;; TODO: remove this (defn addm-at-index "Insert an element in an ordered map at an arbitrary index" [coll index key element] diff --git a/common/src/app/common/types/tokens_lib.cljc b/common/src/app/common/types/tokens_lib.cljc index 4de4d3ee8c..e2a12733fe 100644 --- a/common/src/app/common/types/tokens_lib.cljc +++ b/common/src/app/common/types/tokens_lib.cljc @@ -15,6 +15,86 @@ [cuerdas.core :as str] #?(:clj [app.common.fressian :as fres]))) +;; === 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 separator] + (let [xf (comp (map str/trim) + (remove str/empty?))] + (->> (str/split path separator) + (into [] xf)))) + +(defn join-path + "Regenerate a path as a string, from a vector." + [path separator] + (str/join separator path)) + +(defn group-item + "Add a group to the item name, in the form group.name." + [item group-name separator] + (dm/assert! + "expected groupable item" + (valid-groupable-item? item)) + (update item :name #(str group-name separator %))) + +(defn ungroup-item + "Remove the first group from the item name." + [item separator] + (dm/assert! + "expected groupable item" + (valid-groupable-item? item)) + (update item :name #(-> % + (split-path separator) + (rest) + (join-path separator)))) + +(defn get-path + "Get the groups part of the name as a vector. E.g. group.subgroup.name -> ['group' 'subrgoup']" + [item separator] + (dm/assert! + "expected groupable item" + (valid-groupable-item? item)) + (split-path (:name item) separator)) + +(defn get-groups-str + "Get the groups part of the name. E.g. group.subgroup.name -> group.subrgoup" + [item separator] + (-> (get-path item separator) + (butlast) + (join-path separator))) + +(defn get-final-name + "Get the final part of the name. E.g. group.subgroup.name -> name" + [item separator] + (dm/assert! + "expected groupable item" + (valid-groupable-item? item)) + (-> (:name item) + (split-path separator) + (last))) + +(defn group? + "Check if a node of the grouping tree is a group or a final item." + [item] + (d/ordered-map? item)) + +(defn get-children + "Get all children of a group of a grouping tree. Each child is + a tuple [name item], where item " + [group] + (dm/assert! + "expected group node" + (group? group)) + (seq group)) + ;; === Token (defrecord Token [name type value description modified-at]) @@ -22,10 +102,10 @@ (def schema:token [:and [:map {:title "Token"} - [:name cto/token-name-ref] ;; not necessary to have uuid + [:name cto/token-name-ref] ;; not necessary to have uuid [:type [::sm/one-of cto/token-types]] [:value :any] - [:description [:maybe :string]] ;; defrecord always have the attributes, even with nil value + [:description [:maybe :string]] ;; defrecord always have the attributes, even with nil value [:modified-at ::sm/inst]] [:fn (partial instance? Token)]]) @@ -62,42 +142,56 @@ ITokenSet (add-token [_ token] (dm/assert! "expected valid token" (check-token! token)) - (TokenSet. name - description - (dt/now) - (assoc tokens (:name token) token))) + (let [path (split-path (:name token) ".")] + (TokenSet. name + description + (dt/now) + (d/oassoc-in tokens path token)))) (update-token [this token-name f] - (if-let [token (get tokens token-name)] - (let [token' (-> (make-token (f token)) - (assoc :modified-at (dt/now)))] - (check-token! token') - (TokenSet. name - description - (dt/now) - (if (= (:name token) (:name token')) - (assoc tokens (:name token') token') - (let [index (d/index-of (keys tokens) (:name token))] + (let [path (split-path token-name ".") + token (get-in tokens path)] + (if token + (let [token' (-> (make-token (f token)) + (assoc :modified-at (dt/now))) + path' (get-path token' ".")] + (check-token! token') + (TokenSet. name + description + (dt/now) + (if (= (:name token) (:name token')) + (d/oassoc-in tokens path token') (-> tokens - (dissoc (:name token)) - (d/addm-at-index index (:name token') token')))))) - this)) + (d/oassoc-in-before path path' token') + (d/dissoc-in path))))) + this))) (delete-token [_ token-name] - (TokenSet. name - description - (dt/now) - (dissoc tokens token-name))) + (let [path (split-path token-name ".")] + (TokenSet. name + description + (dt/now) + (d/dissoc-in tokens path)))) (get-tokens [_] - (vals tokens))) + (->> (tree-seq d/ordered-map? vals tokens) + (filter (partial instance? Token))))) + +(def schema:token-node + [:schema {:registry {::node [:or ::token + [:and + [:map-of {:gen/max 5} :string [:ref ::node]] + [:fn d/ordered-map?]]]}} + [:ref ::node]]) + +(sm/register! ::token-node schema:token-node) (def schema:token-set [:and [:map {:title "TokenSet"} [:name :string] [:description [:maybe :string]] [:modified-at ::sm/inst] - [:tokens [:and [:map-of {:gen/max 5} :string ::token] + [:tokens [:and [:map-of {:gen/max 5} :string ::token-node] [:fn d/ordered-map?]]]] [:fn (partial instance? TokenSet)]]) @@ -140,6 +234,7 @@ (update-set [_ set-name f] "modify a set in the ilbrary") (delete-set [_ set-name] "delete a set in the library") (set-count [_] "get the total number if sets in the library") + (get-set-tree [_] "get a nested tree of all sets in the library") (get-sets [_] "get an ordered sequence of all sets in the library") (get-set [_ set-name] "get one set looking for name") (get-set-group [_ set-group-path] "get the attributes of a set group")) @@ -215,6 +310,7 @@ (update-theme [_ theme-name f] "modify a theme in the ilbrary") (delete-theme [_ theme-name] "delete a theme in the library") (theme-count [_] "get the total number if themes in the library") + (get-theme-tree [_] "get a nested tree of all themes in the library") (get-themes [_] "get an ordered sequence of all themes in the library") (get-theme [_ theme-name] "get one theme looking for name")) @@ -242,8 +338,6 @@ (toggle-set-in-theme [_ theme-name set-name] "toggle a set used / not used in a theme") (validate [_])) -(declare get-path) - (deftype TokensLib [sets set-groups themes] ;; NOTE: This is only for debug purposes, pending to properly ;; implement the toString and alternative printing. @@ -260,41 +354,50 @@ ITokenSets (add-set [_ token-set] (dm/assert! "expected valid token set" (check-token-set! token-set)) - (let [path (get-path token-set)] - (TokensLib. (assoc sets (:name token-set) token-set) + (let [path (get-path token-set "/") + groups-str (get-groups-str token-set "/")] + (TokensLib. (d/oassoc-in sets path token-set) (cond-> set-groups - (seq path) - (assoc path (make-token-set-group))) + (not (str/empty? groups-str)) + (assoc groups-str (make-token-set-group))) themes))) (update-set [this set-name f] - (if-let [set (get sets set-name)] - (let [set' (-> (make-token-set (f set)) - (assoc :modified-at (dt/now)))] - (check-token-set! set') - (TokensLib. (if (= (:name set) (:name set')) - (assoc sets (:name set') set') - (let [index (d/index-of (keys sets) (:name set))] + (let [path (split-path set-name "/") + set (get-in sets path)] + (if set + (let [set' (-> (make-token-set (f set)) + (assoc :modified-at (dt/now))) + path' (get-path set' "/")] + (check-token-set! set') + (TokensLib. (if (= (:name set) (:name set')) + (d/oassoc-in sets path set') (-> sets - (dissoc (:name set)) - (d/addm-at-index index (:name set') set')))) - set-groups ;; TODO update set-groups as needed - themes)) - this)) + (d/oassoc-in-before path path' set') + (d/dissoc-in path))) + set-groups ;; TODO update set-groups as needed + themes)) + this))) (delete-set [_ set-name] - (TokensLib. (dissoc sets set-name) - set-groups ;; TODO remove set-group if needed - themes)) + (let [path (split-path set-name "/")] + (TokensLib. (d/dissoc-in sets path) + set-groups ;; TODO remove set-group if needed + themes))) - (set-count [_] - (count sets)) + (get-set-tree [_] + sets) (get-sets [_] - (vals sets)) + (->> (tree-seq d/ordered-map? vals sets) + (filter (partial instance? TokenSet)))) + + (set-count [this] + (count (get-sets this))) (get-set [_ set-name] - (get sets set-name)) + (let [path (split-path set-name "/")] + (get-in sets path))) (get-set-group [_ set-group-path] (get set-groups set-group-path)) @@ -302,38 +405,47 @@ ITokenThemes (add-theme [_ token-theme] (dm/assert! "expected valid token theme" (check-token-theme! token-theme)) - (TokensLib. sets - set-groups - (assoc themes (:name token-theme) token-theme))) + (let [path (get-path token-theme "/")] + (TokensLib. sets + set-groups + (d/oassoc-in themes path token-theme)))) (update-theme [this theme-name f] - (if-let [theme (get themes theme-name)] - (let [theme' (-> (make-token-theme (f theme)) - (assoc :modified-at (dt/now)))] - (check-token-theme! theme') - (TokensLib. sets - set-groups - (if (= (:name theme) (:name theme')) - (assoc themes (:name theme') theme') - (let [index (d/index-of (keys themes) (:name theme))] + (let [path (split-path theme-name "/") + theme (get-in themes path)] + (if theme + (let [theme' (-> (make-token-theme (f theme)) + (assoc :modified-at (dt/now))) + path' (get-path theme' "/")] + (check-token-theme! theme') + (TokensLib. sets + set-groups + (if (= (:name theme) (:name theme')) + (d/oassoc-in themes path theme') (-> themes - (dissoc (:name theme)) - (d/addm-at-index index (:name theme') theme')))))) - this)) + (d/oassoc-in-before path path' theme') + (d/dissoc-in path))))) + this))) (delete-theme [_ theme-name] - (TokensLib. sets - set-groups - (dissoc themes theme-name))) + (let [path (split-path theme-name "/")] + (TokensLib. sets + set-groups + (d/dissoc-in themes path)))) - (theme-count [_] - (count themes)) + (get-theme-tree [_] + themes) (get-themes [_] - (vals themes)) + (->> (tree-seq d/ordered-map? vals themes) + (filter (partial instance? TokenTheme)))) + + (theme-count [this] + (count (get-themes this))) (get-theme [_ theme-name] - (get themes theme-name)) + (let [path (split-path theme-name "/")] + (get-in themes path))) ITokensLib (add-token-in-set [this set-name token] @@ -478,90 +590,3 @@ set-groups (fres/read-object! r) themes (fres/read-object! r)] (->TokensLib sets set-groups 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))) diff --git a/common/test/common_tests/types/tokens_lib_test.cljc b/common/test/common_tests/types/tokens_lib_test.cljc index e96834c274..6a4418e830 100644 --- a/common/test/common_tests/types/tokens_lib_test.cljc +++ b/common/test/common_tests/types/tokens_lib_test.cljc @@ -130,10 +130,10 @@ (t/deftest add-token-set-with-group (let [tokens-lib (ctob/make-tokens-lib) - token-set (ctob/make-token-set :name "test-group.test-token-set") + token-set (ctob/make-token-set :name "test-group/test-token-set") tokens-lib' (ctob/add-set tokens-lib token-set) - set-group (ctob/get-set-group tokens-lib' "test-group")] + set-group (ctob/get-set-group tokens-lib' "test-group")] (t/is (= (:attr1 set-group) "one")) (t/is (= (:attr2 set-group) "two")))) @@ -423,8 +423,8 @@ (t/testing "grouping" (t/deftest split-and-join (let [name "group.subgroup.name" - path (ctob/split-path name) - name' (ctob/join-path path)] + 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")) @@ -432,7 +432,7 @@ (t/deftest remove-spaces (let [name "group . subgroup . name" - path (ctob/split-path name)] + path (ctob/split-path name ".")] (t/is (= (first path) "group")) (t/is (= (second path) "subgroup")) (t/is (= (nth path 2) "name")))) @@ -441,82 +441,555 @@ (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')] + 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 + (t/deftest get-groups-str (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/is (= (ctob/get-groups-str token1 ".") "")) + (t/is (= (ctob/get-groups-str token2 ".") "some-group")) + (t/is (= (ctob/get-groups-str 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" + (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/testing "grouped tokens" + (t/deftest grouped-tokens + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set")) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "token1" :type :boolean :value true)) - (ctob/add-token-in-set "sgroup2.token-set5" - (ctob/make-token :name "tgroup1.tsubgroup1.token2" + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "group1.token2" + :type :boolean + :value true)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "group1.token3" + :type :boolean + :value true)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "group1.subgroup11.token4" + :type :boolean + :value true)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "group2.token5" :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) + set (ctob/get-set tokens-lib "test-token-set") + tokens-list (ctob/get-tokens set) - 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") + tokens-tree (:tokens set) + [node-token1 node-group1 node-group2] + (ctob/get-children tokens-tree) - token-groups (ctob/group-items tokens) - tgroup1 (get token-groups "tgroup1") - tsubgroup1 (get tgroup1 "tsubgroup1") - token1 (get tsubgroup1 "token1") - token2 (get tsubgroup1 "token2")] + [node-token2 node-token3 node-subgroup11] + (ctob/get-children (second node-group1)) - ;; {"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" ...}} + [node-token4] + (ctob/get-children (second node-subgroup11)) - (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")) + [node-token5] + (ctob/get-children (second node-group2))] - (t/is (= (:name token1) "tgroup1.tsubgroup1.token1")) - (t/is (= (:name token2) "tgroup1.tsubgroup1.token2"))))) + (t/is (= (count tokens-list) 5)) + (t/is (= (:name (nth tokens-list 0)) "token1")) + (t/is (= (:name (nth tokens-list 1)) "group1.token2")) + (t/is (= (:name (nth tokens-list 2)) "group1.token3")) + (t/is (= (:name (nth tokens-list 3)) "group1.subgroup11.token4")) + (t/is (= (:name (nth tokens-list 4)) "group2.token5")) + + (t/is (= (first node-token1) "token1")) + (t/is (= (ctob/group? (second node-token1)) false)) + (t/is (= (:name (second node-token1)) "token1")) + + (t/is (= (first node-group1) "group1")) + (t/is (= (ctob/group? (second node-group1)) true)) + (t/is (= (count (second node-group1)) 3)) + + (t/is (= (first node-token2) "token2")) + (t/is (= (ctob/group? (second node-token2)) false)) + (t/is (= (:name (second node-token2)) "group1.token2")) + + (t/is (= (first node-token3) "token3")) + (t/is (= (ctob/group? (second node-token3)) false)) + (t/is (= (:name (second node-token3)) "group1.token3")) + + (t/is (= (first node-subgroup11) "subgroup11")) + (t/is (= (ctob/group? (second node-subgroup11)) true)) + (t/is (= (count (second node-subgroup11)) 1)) + + (t/is (= (first node-token4) "token4")) + (t/is (= (ctob/group? (second node-token4)) false)) + (t/is (= (:name (second node-token4)) "group1.subgroup11.token4")) + + (t/is (= (first node-token5) "token5")) + (t/is (= (ctob/group? (second node-token5)) false)) + (t/is (= (:name (second node-token5)) "group2.token5")))) + + (t/deftest update-token-in-groups + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set")) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "test-token-1" + :type :boolean + :value true)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "group1.test-token-2" + :type :boolean + :value true)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "group1.test-token-3" + :type :boolean + :value true))) + + tokens-lib' (-> tokens-lib + (ctob/update-token-in-set "test-token-set" "group1.test-token-2" + (fn [token] + (assoc token + :description "some description" + :value false)))) + + token-set (ctob/get-set tokens-lib "test-token-set") + token-set' (ctob/get-set tokens-lib' "test-token-set") + group1' (get-in token-set' [:tokens "group1"]) + token (get-in token-set [:tokens "group1" "test-token-2"]) + token' (get-in token-set' [:tokens "group1" "test-token-2"])] + + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (count group1') 2)) + (t/is (= (d/index-of (keys group1') "test-token-2") 0)) + (t/is (= (:name token') "group1.test-token-2")) + (t/is (= (:description token') "some description")) + (t/is (= (:value token') false)) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))) + (t/is (dt/is-after? (:modified-at token') (:modified-at token))))) + + (t/deftest rename-token-in-groups + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set")) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "test-token-1" + :type :boolean + :value true)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "group1.test-token-2" + :type :boolean + :value true)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "group1.test-token-3" + :type :boolean + :value true))) + + tokens-lib' (-> tokens-lib + (ctob/update-token-in-set "test-token-set" "group1.test-token-2" + (fn [token] + (assoc token + :name "group1.updated-name")))) + + token-set (ctob/get-set tokens-lib "test-token-set") + token-set' (ctob/get-set tokens-lib' "test-token-set") + group1' (get-in token-set' [:tokens "group1"]) + token (get-in token-set [:tokens "group1" "test-token-2"]) + token' (get-in token-set' [:tokens "group1" "updated-name"])] + + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (count group1') 2)) + (t/is (= (d/index-of (keys group1') "updated-name") 0)) + (t/is (= (:name token') "group1.updated-name")) + (t/is (= (:description token') nil)) + (t/is (= (:value token') true)) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))) + (t/is (dt/is-after? (:modified-at token') (:modified-at token))))) + + (t/deftest move-token-of-group + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set")) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "test-token-1" + :type :boolean + :value true)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "group1.test-token-2" + :type :boolean + :value true)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "group1.test-token-3" + :type :boolean + :value true))) + + tokens-lib' (-> tokens-lib + (ctob/update-token-in-set "test-token-set" "group1.test-token-2" + (fn [token] + (assoc token + :name "group2.updated-name")))) + + token-set (ctob/get-set tokens-lib "test-token-set") + token-set' (ctob/get-set tokens-lib' "test-token-set") + group1' (get-in token-set' [:tokens "group1"]) + group2' (get-in token-set' [:tokens "group2"]) + token (get-in token-set [:tokens "group1" "test-token-2"]) + token' (get-in token-set' [:tokens "group2" "updated-name"])] + + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (count group1') 1)) + (t/is (= (count group2') 1)) + (t/is (= (d/index-of (keys group2') "updated-name") 0)) + (t/is (= (:name token') "group2.updated-name")) + (t/is (= (:description token') nil)) + (t/is (= (:value token') true)) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))) + (t/is (dt/is-after? (:modified-at token') (:modified-at token))))) + + (t/deftest delete-token-in-group + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "test-token-set")) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "test-token-1" + :type :boolean + :value true)) + (ctob/add-token-in-set "test-token-set" + (ctob/make-token :name "group1.test-token-2" + :type :boolean + :value true))) + tokens-lib' (-> tokens-lib + (ctob/delete-token-from-set "test-token-set" "group1.test-token-2")) + + token-set (ctob/get-set tokens-lib "test-token-set") + token-set' (ctob/get-set tokens-lib' "test-token-set") + token' (get-in token-set' [:tokens "group1" "test-token-2"])] + + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (count (:tokens token-set')) 1)) + (t/is (nil? token')) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))))) + + (t/testing "grouped sets" + (t/deftest grouped-sets + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "token-set-1")) + (ctob/add-set (ctob/make-token-set :name "group1/token-set-2")) + (ctob/add-set (ctob/make-token-set :name "group1/token-set-3")) + (ctob/add-set (ctob/make-token-set :name "group1/subgroup11/token-set-4")) + (ctob/add-set (ctob/make-token-set :name "group2/token-set-5"))) + + sets-list (ctob/get-sets tokens-lib) + + sets-tree (ctob/get-set-tree tokens-lib) + + [node-set1 node-group1 node-group2] + (ctob/get-children sets-tree) + + [node-set2 node-set3 node-subgroup11] + (ctob/get-children (second node-group1)) + + [node-set4] + (ctob/get-children (second node-subgroup11)) + + [node-set5] + (ctob/get-children (second node-group2))] + + (t/is (= (count sets-list) 5)) + (t/is (= (:name (nth sets-list 0)) "token-set-1")) + (t/is (= (:name (nth sets-list 1)) "group1/token-set-2")) + (t/is (= (:name (nth sets-list 2)) "group1/token-set-3")) + (t/is (= (:name (nth sets-list 3)) "group1/subgroup11/token-set-4")) + (t/is (= (:name (nth sets-list 4)) "group2/token-set-5")) + + (t/is (= (first node-set1) "token-set-1")) + (t/is (= (ctob/group? (second node-set1)) false)) + (t/is (= (:name (second node-set1)) "token-set-1")) + + (t/is (= (first node-group1) "group1")) + (t/is (= (ctob/group? (second node-group1)) true)) + (t/is (= (count (second node-group1)) 3)) + + (t/is (= (first node-set2) "token-set-2")) + (t/is (= (ctob/group? (second node-set2)) false)) + (t/is (= (:name (second node-set2)) "group1/token-set-2")) + + (t/is (= (first node-set3) "token-set-3")) + (t/is (= (ctob/group? (second node-set3)) false)) + (t/is (= (:name (second node-set3)) "group1/token-set-3")) + + (t/is (= (first node-subgroup11) "subgroup11")) + (t/is (= (ctob/group? (second node-subgroup11)) true)) + (t/is (= (count (second node-subgroup11)) 1)) + + (t/is (= (first node-set4) "token-set-4")) + (t/is (= (ctob/group? (second node-set4)) false)) + (t/is (= (:name (second node-set4)) "group1/subgroup11/token-set-4")) + + (t/is (= (first node-set5) "token-set-5")) + (t/is (= (ctob/group? (second node-set5)) false)) + (t/is (= (:name (second node-set5)) "group2/token-set-5")))) + + (t/deftest update-set-in-groups + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "token-set-1")) + (ctob/add-set (ctob/make-token-set :name "group1/token-set-2")) + (ctob/add-set (ctob/make-token-set :name "group1/token-set-3")) + (ctob/add-set (ctob/make-token-set :name "group1/subgroup11/token-set-4")) + (ctob/add-set (ctob/make-token-set :name "group2/token-set-5"))) + + tokens-lib' (-> tokens-lib + (ctob/update-set "group1/token-set-2" + (fn [token-set] + (assoc token-set :description "some description")))) + + sets-tree (ctob/get-set-tree tokens-lib) + sets-tree' (ctob/get-set-tree tokens-lib') + group1' (get sets-tree' "group1") + token-set (get-in sets-tree ["group1" "token-set-2"]) + token-set' (get-in sets-tree' ["group1" "token-set-2"])] + + (t/is (= (ctob/set-count tokens-lib') 5)) + (t/is (= (count group1') 3)) + (t/is (= (d/index-of (keys group1') "token-set-2") 0)) + (t/is (= (:name token-set') "group1/token-set-2")) + (t/is (= (:description token-set') "some description")) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))) + + (t/deftest rename-set-in-groups + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "token-set-1")) + (ctob/add-set (ctob/make-token-set :name "group1/token-set-2")) + (ctob/add-set (ctob/make-token-set :name "group1/token-set-3")) + (ctob/add-set (ctob/make-token-set :name "group1/subgroup11/token-set-4")) + (ctob/add-set (ctob/make-token-set :name "group2/token-set-5"))) + + tokens-lib' (-> tokens-lib + (ctob/update-set "group1/token-set-2" + (fn [token-set] + (assoc token-set + :name "group1/updated-name")))) + + sets-tree (ctob/get-set-tree tokens-lib) + sets-tree' (ctob/get-set-tree tokens-lib') + group1' (get sets-tree' "group1") + token-set (get-in sets-tree ["group1" "token-set-2"]) + token-set' (get-in sets-tree' ["group1" "updated-name"])] + + (t/is (= (ctob/set-count tokens-lib') 5)) + (t/is (= (count group1') 3)) + (t/is (= (d/index-of (keys group1') "updated-name") 0)) + (t/is (= (:name token-set') "group1/updated-name")) + (t/is (= (:description token-set') nil)) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))) + + (t/deftest move-set-of-group + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "token-set-1")) + (ctob/add-set (ctob/make-token-set :name "group1/token-set-2")) + (ctob/add-set (ctob/make-token-set :name "group1/token-set-3")) + (ctob/add-set (ctob/make-token-set :name "group1/subgroup11/token-set-4")) + #_(ctob/add-set (ctob/make-token-set :name "group2/token-set-5"))) + + tokens-lib' (-> tokens-lib + (ctob/update-set "group1/token-set-2" + (fn [token-set] + (assoc token-set + :name "group2/updated-name")))) + + sets-tree (ctob/get-set-tree tokens-lib) + sets-tree' (ctob/get-set-tree tokens-lib') + group1' (get sets-tree' "group1") + group2' (get sets-tree' "group2") + token-set (get-in sets-tree ["group1" "token-set-2"]) + token-set' (get-in sets-tree' ["group2" "updated-name"])] + + (t/is (= (ctob/set-count tokens-lib') 4)) + (t/is (= (count group1') 2)) + (t/is (= (count group2') 1)) + (t/is (= (d/index-of (keys group2') "updated-name") 0)) + (t/is (= (:name token-set') "group2/updated-name")) + (t/is (= (:description token-set') nil)) + (t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))) + + (t/deftest delete-set-in-group + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-set (ctob/make-token-set :name "token-set-1")) + (ctob/add-set (ctob/make-token-set :name "group1/token-set-2"))) + + tokens-lib' (-> tokens-lib + (ctob/delete-set "group1/token-set-2")) + + sets-tree' (ctob/get-set-tree tokens-lib') + token-set' (get-in sets-tree' ["group1" "token-set-2"])] + + (t/is (= (ctob/set-count tokens-lib') 1)) + (t/is (= (count sets-tree') 1)) + (t/is (nil? token-set'))))) + + (t/testing "grouped themes" + (t/deftest grouped-themes + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-theme (ctob/make-token-theme :name "token-theme-1")) + (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2")) + (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-3")) + (ctob/add-theme (ctob/make-token-theme :name "group1/subgroup11/token-theme-4")) + (ctob/add-theme (ctob/make-token-theme :name "group2/token-theme-5"))) + + themes-list (ctob/get-themes tokens-lib) + + themes-tree (ctob/get-theme-tree tokens-lib) + + [node-theme1 node-group1 node-group2] + (ctob/get-children themes-tree) + + [node-theme2 node-theme3 node-subgroup11] + (ctob/get-children (second node-group1)) + + [node-theme4] + (ctob/get-children (second node-subgroup11)) + + [node-theme5] + (ctob/get-children (second node-group2))] + + (t/is (= (count themes-list) 5)) + (t/is (= (:name (nth themes-list 0)) "token-theme-1")) + (t/is (= (:name (nth themes-list 1)) "group1/token-theme-2")) + (t/is (= (:name (nth themes-list 2)) "group1/token-theme-3")) + (t/is (= (:name (nth themes-list 3)) "group1/subgroup11/token-theme-4")) + (t/is (= (:name (nth themes-list 4)) "group2/token-theme-5")) + + (t/is (= (first node-theme1) "token-theme-1")) + (t/is (= (ctob/group? (second node-theme1)) false)) + (t/is (= (:name (second node-theme1)) "token-theme-1")) + + (t/is (= (first node-group1) "group1")) + (t/is (= (ctob/group? (second node-group1)) true)) + (t/is (= (count (second node-group1)) 3)) + + (t/is (= (first node-theme2) "token-theme-2")) + (t/is (= (ctob/group? (second node-theme2)) false)) + (t/is (= (:name (second node-theme2)) "group1/token-theme-2")) + + (t/is (= (first node-theme3) "token-theme-3")) + (t/is (= (ctob/group? (second node-theme3)) false)) + (t/is (= (:name (second node-theme3)) "group1/token-theme-3")) + + (t/is (= (first node-subgroup11) "subgroup11")) + (t/is (= (ctob/group? (second node-subgroup11)) true)) + (t/is (= (count (second node-subgroup11)) 1)) + + (t/is (= (first node-theme4) "token-theme-4")) + (t/is (= (ctob/group? (second node-theme4)) false)) + (t/is (= (:name (second node-theme4)) "group1/subgroup11/token-theme-4")) + + (t/is (= (first node-theme5) "token-theme-5")) + (t/is (= (ctob/group? (second node-theme5)) false)) + (t/is (= (:name (second node-theme5)) "group2/token-theme-5")))) + + (t/deftest update-theme-in-groups + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-theme (ctob/make-token-theme :name "token-theme-1")) + (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2")) + (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-3")) + (ctob/add-theme (ctob/make-token-theme :name "group1/subgroup11/token-theme-4")) + (ctob/add-theme (ctob/make-token-theme :name "group2/token-theme-5"))) + + tokens-lib' (-> tokens-lib + (ctob/update-theme "group1/token-theme-2" + (fn [token-theme] + (assoc token-theme :description "some description")))) + + themes-tree (ctob/get-theme-tree tokens-lib) + themes-tree' (ctob/get-theme-tree tokens-lib') + group1' (get themes-tree' "group1") + token-theme (get-in themes-tree ["group1" "token-theme-2"]) + token-theme' (get-in themes-tree' ["group1" "token-theme-2"])] + + (t/is (= (ctob/theme-count tokens-lib') 5)) + (t/is (= (count group1') 3)) + (t/is (= (d/index-of (keys group1') "token-theme-2") 0)) + (t/is (= (:name token-theme') "group1/token-theme-2")) + (t/is (= (:description token-theme') "some description")) + (t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme))))) + + (t/deftest rename-theme-in-groups + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-theme (ctob/make-token-theme :name "token-theme-1")) + (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2")) + (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-3")) + (ctob/add-theme (ctob/make-token-theme :name "group1/subgroup11/token-theme-4")) + (ctob/add-theme (ctob/make-token-theme :name "group2/token-theme-5"))) + + tokens-lib' (-> tokens-lib + (ctob/update-theme "group1/token-theme-2" + (fn [token-theme] + (assoc token-theme + :name "group1/updated-name")))) + + themes-tree (ctob/get-theme-tree tokens-lib) + themes-tree' (ctob/get-theme-tree tokens-lib') + group1' (get themes-tree' "group1") + token-theme (get-in themes-tree ["group1" "token-theme-2"]) + token-theme' (get-in themes-tree' ["group1" "updated-name"])] + + (t/is (= (ctob/theme-count tokens-lib') 5)) + (t/is (= (count group1') 3)) + (t/is (= (d/index-of (keys group1') "updated-name") 0)) + (t/is (= (:name token-theme') "group1/updated-name")) + (t/is (= (:description token-theme') nil)) + (t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme))))) + + (t/deftest move-theme-of-group + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-theme (ctob/make-token-theme :name "token-theme-1")) + (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2")) + (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-3")) + (ctob/add-theme (ctob/make-token-theme :name "group1/subgroup11/token-theme-4")) + #_(ctob/add-theme (ctob/make-token-theme :name "group2/token-theme-5"))) + + tokens-lib' (-> tokens-lib + (ctob/update-theme "group1/token-theme-2" + (fn [token-theme] + (assoc token-theme + :name "group2/updated-name")))) + + themes-tree (ctob/get-theme-tree tokens-lib) + themes-tree' (ctob/get-theme-tree tokens-lib') + group1' (get themes-tree' "group1") + group2' (get themes-tree' "group2") + token-theme (get-in themes-tree ["group1" "token-theme-2"]) + token-theme' (get-in themes-tree' ["group2" "updated-name"])] + + (t/is (= (ctob/theme-count tokens-lib') 4)) + (t/is (= (count group1') 2)) + (t/is (= (count group2') 1)) + (t/is (= (d/index-of (keys group2') "updated-name") 0)) + (t/is (= (:name token-theme') "group2/updated-name")) + (t/is (= (:description token-theme') nil)) + (t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme))))) + + (t/deftest delete-theme-in-group + (let [tokens-lib (-> (ctob/make-tokens-lib) + (ctob/add-theme (ctob/make-token-theme :name "token-theme-1")) + (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2"))) + + tokens-lib' (-> tokens-lib + (ctob/delete-theme "group1/token-theme-2")) + + themes-tree' (ctob/get-theme-tree tokens-lib') + token-theme' (get-in themes-tree' ["group1" "token-theme-2"])] + + (t/is (= (ctob/theme-count tokens-lib') 1)) + (t/is (= (count themes-tree') 1)) + (t/is (nil? token-theme')))))) From 5f703d6a79e7281426a3124129021fb6c6d84392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Mon, 16 Sep 2024 17:47:05 +0200 Subject: [PATCH 5/6] :wrench: Make themes a two-level only tree --- common/src/app/common/data.cljc | 2 +- common/src/app/common/files/changes.cljc | 19 ++- common/src/app/common/types/tokens_lib.cljc | 62 +++---- .../common_tests/types/tokens_lib_test.cljc | 158 +++++++++--------- 4 files changed, 122 insertions(+), 119 deletions(-) diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index 73d46576fa..a67ee4b592 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -67,7 +67,7 @@ (oassoc o k (oassoc-in (get o k) ks v)) (oassoc o k v))) -#_(defn oupdate-in +(defn oupdate-in [m ks f & args] (let [up (fn up [m ks f args] (let [[k & ks] ks] diff --git a/common/src/app/common/files/changes.cljc b/common/src/app/common/files/changes.cljc index 34b3a28e1d..67353769a0 100644 --- a/common/src/app/common/files/changes.cljc +++ b/common/src/app/common/files/changes.cljc @@ -849,13 +849,13 @@ (ctotl/assoc-active-token-themes data theme-ids)) (defmethod process-change :delete-temporary-token-theme - [data {:keys [id name]}] + [data {:keys [id group name]}] (-> data (ctotl/delete-temporary-token-theme id) (update :tokens-lib #(-> % (ctob/ensure-tokens-lib) - (ctob/delete-theme name))))) + (ctob/delete-theme group name))))) (defmethod process-change :add-token-theme [data {:keys [token-theme]}] @@ -869,25 +869,26 @@ (ctob/make-token-theme))))))) (defmethod process-change :mod-token-theme - [data {:keys [id name token-theme]}] + [data {:keys [id name group token-theme]}] (-> data (ctotl/update-token-theme id merge token-theme) (update :tokens-lib #(-> % (ctob/ensure-tokens-lib) - (ctob/update-theme name (fn [prev-theme] - (merge prev-theme - (-> token-theme - (update :sets (partial set-ids->names data)))))))))) + (ctob/update-theme name group + (fn [prev-theme] + (merge prev-theme + (-> token-theme + (update :sets (partial set-ids->names data)))))))))) (defmethod process-change :del-token-theme - [data {:keys [id name]}] + [data {:keys [id group name]}] (-> data (ctotl/delete-token-theme id) (update :tokens-lib #(-> % (ctob/ensure-tokens-lib) - (ctob/delete-theme name))))) + (ctob/delete-theme group name))))) (defmethod process-change :add-token-set [data {:keys [token-set]}] diff --git a/common/src/app/common/types/tokens_lib.cljc b/common/src/app/common/types/tokens_lib.cljc index e2a12733fe..58fb928eac 100644 --- a/common/src/app/common/types/tokens_lib.cljc +++ b/common/src/app/common/types/tokens_lib.cljc @@ -258,10 +258,11 @@ (defprotocol ITokenTheme (toggle-set [_ set-name] "togle a set used / not used in the theme")) -(defrecord TokenTheme [name description is-source modified-at sets] +(defrecord TokenTheme [name group description is-source modified-at sets] ITokenTheme (toggle-set [_ set-name] (TokenTheme. name + group description is-source (dt/now) @@ -272,6 +273,7 @@ (def schema:token-theme [:and [:map {:title "TokenTheme"} [:name :string] + [:group :string] [:description [:maybe :string]] [:is-source :boolean] [:modified-at ::sm/inst] @@ -291,7 +293,7 @@ [& {:keys [] :as params}] (let [params (-> params (dissoc :id) - (dissoc :group) + (update :group #(or % "")) (update :is-source #(or % false)) (update :modified-at #(or % (dt/now))) (update :sets #(into (d/ordered-set) %))) @@ -307,17 +309,18 @@ (defprotocol ITokenThemes (add-theme [_ token-theme] "add a theme to the library, at the end") - (update-theme [_ theme-name f] "modify a theme in the ilbrary") - (delete-theme [_ theme-name] "delete a theme in the library") + (update-theme [_ group name f] "modify a theme in the ilbrary") + (delete-theme [_ group name] "delete a theme in the library") (theme-count [_] "get the total number if themes in the library") (get-theme-tree [_] "get a nested tree of all themes in the library") (get-themes [_] "get an ordered sequence of all themes in the library") - (get-theme [_ theme-name] "get one theme looking for name")) + (get-theme [_ group name] "get one theme looking for name")) (def schema:token-themes [:and [:map-of {:title "TokenThemes"} - :string ::token-theme] + :string [:and [:map-of :string ::token-theme] + [:fn d/ordered-map?]]] [:fn d/ordered-map?]]) (sm/register! ::token-themes schema:token-themes) @@ -335,7 +338,7 @@ (add-token-in-set [_ set-name token] "add token to a set") (update-token-in-set [_ set-name token-name f] "update a token in a set") (delete-token-from-set [_ set-name token-name] "delete a token from a set") - (toggle-set-in-theme [_ theme-name set-name] "toggle a set used / not used in a theme") + (toggle-set-in-theme [_ group-name theme-name set-name] "toggle a set used / not used in a theme") (validate [_])) (deftype TokensLib [sets set-groups themes] @@ -405,33 +408,31 @@ ITokenThemes (add-theme [_ token-theme] (dm/assert! "expected valid token theme" (check-token-theme! token-theme)) - (let [path (get-path token-theme "/")] - (TokensLib. sets - set-groups - (d/oassoc-in themes path token-theme)))) + (TokensLib. sets + set-groups + (update themes (:group token-theme) d/oassoc (:name token-theme) token-theme))) - (update-theme [this theme-name f] - (let [path (split-path theme-name "/") - theme (get-in themes path)] + (update-theme [this group name f] + (let [theme (dm/get-in themes [group name])] (if theme (let [theme' (-> (make-token-theme (f theme)) (assoc :modified-at (dt/now))) - path' (get-path theme' "/")] + group' (:group theme') + name' (:name theme')] (check-token-theme! theme') (TokensLib. sets set-groups - (if (= (:name theme) (:name theme')) - (d/oassoc-in themes path theme') + (if (and (= group group') (= name name')) + (update themes group' assoc name' theme') (-> themes - (d/oassoc-in-before path path' theme') - (d/dissoc-in path))))) + (d/oassoc-in-before [group name] [group' name'] theme') + (d/dissoc-in [group name]))))) this))) - (delete-theme [_ theme-name] - (let [path (split-path theme-name "/")] - (TokensLib. sets - set-groups - (d/dissoc-in themes path)))) + (delete-theme [_ group name] + (TokensLib. sets + set-groups + (d/dissoc-in themes [group name]))) (get-theme-tree [_] themes) @@ -443,9 +444,8 @@ (theme-count [this] (count (get-themes this))) - (get-theme [_ theme-name] - (let [path (split-path theme-name "/")] - (get-in themes path))) + (get-theme [_ group name] + (dm/get-in themes [group name])) ITokensLib (add-token-in-set [this set-name token] @@ -472,12 +472,12 @@ themes) this)) - (toggle-set-in-theme [this theme-name set-name] - (if (contains? themes theme-name) + (toggle-set-in-theme [this theme-group theme-name set-name] + (if-let [_theme (get-in themes theme-group theme-name)] (TokensLib. sets set-groups - (update themes theme-name - #(toggle-set % set-name))) + (d/oupdate-in themes [theme-group theme-name] + #(toggle-set % set-name))) this)) (validate [_] diff --git a/common/test/common_tests/types/tokens_lib_test.cljc b/common/test/common_tests/types/tokens_lib_test.cljc index 6a4418e830..358f17a93c 100644 --- a/common/test/common_tests/types/tokens_lib_test.cljc +++ b/common/test/common_tests/types/tokens_lib_test.cljc @@ -78,18 +78,21 @@ (let [now (dt/now) token-theme1 (ctob/make-token-theme :name "test-token-theme-1") token-theme2 (ctob/make-token-theme :name "test-token-theme-2" + :group "group-1" :description "test description" :is-source true :modified-at now :sets #{})] (t/is (= (:name token-theme1) "test-token-theme-1")) + (t/is (= (:group token-theme1) "")) (t/is (nil? (:description token-theme1))) (t/is (false? (:is-source token-theme1))) (t/is (some? (:modified-at token-theme1))) (t/is (empty? (:sets token-theme1))) (t/is (= (:name token-theme2) "test-token-theme-2")) + (t/is (= (:group token-theme2) "group-1")) (t/is (= (:description token-theme2) "test description")) (t/is (true? (:is-source token-theme2))) (t/is (= (:modified-at token-theme2) now)) @@ -97,6 +100,7 @@ (t/deftest invalid-token-theme (let [args {:name 777 + :group nil :description 999 :is-source 42}] (t/is (thrown-with-msg? Exception #"expected valid token theme" @@ -313,9 +317,8 @@ tokens-lib' (ctob/add-theme tokens-lib token-theme) token-themes' (ctob/get-themes tokens-lib') - token-theme' (ctob/get-theme tokens-lib' "test-token-theme")] + token-theme' (ctob/get-theme tokens-lib' "" "test-token-theme")] - (prn "lib" tokens-lib') (t/is (= (ctob/theme-count tokens-lib') 1)) (t/is (= (first token-themes') token-theme)) (t/is (= token-theme' token-theme)))) @@ -325,17 +328,17 @@ (ctob/add-theme (ctob/make-token-theme :name "test-token-theme"))) tokens-lib' (-> tokens-lib - (ctob/update-theme "test-token-theme" + (ctob/update-theme "" "test-token-theme" (fn [token-theme] (assoc token-theme :description "some description"))) - (ctob/update-theme "not-existing-theme" + (ctob/update-theme "" "not-existing-theme" (fn [token-theme] (assoc token-theme :description "no-effect")))) - token-theme (ctob/get-theme tokens-lib "test-token-theme") - token-theme' (ctob/get-theme tokens-lib' "test-token-theme")] + token-theme (ctob/get-theme tokens-lib "" "test-token-theme") + token-theme' (ctob/get-theme tokens-lib' "" "test-token-theme")] (t/is (= (ctob/theme-count tokens-lib') 1)) (t/is (= (:name token-theme') "test-token-theme")) @@ -347,13 +350,13 @@ (ctob/add-theme (ctob/make-token-theme :name "test-token-theme"))) tokens-lib' (-> tokens-lib - (ctob/update-theme "test-token-theme" + (ctob/update-theme "" "test-token-theme" (fn [token-theme] (assoc token-theme :name "updated-name")))) - token-theme (ctob/get-theme tokens-lib "test-token-theme") - token-theme' (ctob/get-theme tokens-lib' "updated-name")] + token-theme (ctob/get-theme tokens-lib "" "test-token-theme") + token-theme' (ctob/get-theme tokens-lib' "" "updated-name")] (t/is (= (ctob/theme-count tokens-lib') 1)) (t/is (= (:name token-theme') "updated-name")) @@ -364,10 +367,10 @@ (ctob/add-theme (ctob/make-token-theme :name "test-token-theme"))) tokens-lib' (-> tokens-lib - (ctob/delete-theme "test-token-theme") - (ctob/delete-theme "not-existing-theme")) + (ctob/delete-theme "" "test-token-theme") + (ctob/delete-theme "" "not-existing-theme")) - token-theme' (ctob/get-theme tokens-lib' "updated-name")] + token-theme' (ctob/get-theme tokens-lib' "" "updated-name")] (t/is (= (ctob/theme-count tokens-lib') 0)) (t/is (nil? token-theme')))) @@ -379,12 +382,12 @@ (ctob/add-set (ctob/make-token-set :name "token-set-3")) (ctob/add-theme (ctob/make-token-theme :name "test-token-theme"))) tokens-lib' (-> tokens-lib - (ctob/toggle-set-in-theme "test-token-theme" "token-set-1") - (ctob/toggle-set-in-theme "test-token-theme" "token-set-2") - (ctob/toggle-set-in-theme "test-token-theme" "token-set-2")) + (ctob/toggle-set-in-theme "" "test-token-theme" "token-set-1") + (ctob/toggle-set-in-theme "" "test-token-theme" "token-set-2") + (ctob/toggle-set-in-theme "" "test-token-theme" "token-set-2")) - token-theme (ctob/get-theme tokens-lib "test-token-theme") - token-theme' (ctob/get-theme tokens-lib' "test-token-theme")] + token-theme (ctob/get-theme tokens-lib "" "test-token-theme") + token-theme' (ctob/get-theme tokens-lib' "" "test-token-theme")] (t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme)))))) @@ -397,7 +400,7 @@ :type :boolean :value true)) (ctob/add-theme (ctob/make-token-theme :name "test-token-theme")) - (ctob/toggle-set-in-theme "test-token-theme" "test-token-set")) + (ctob/toggle-set-in-theme "" "test-token-theme" "test-token-set")) encoded-str (tr/encode-str tokens-lib) tokens-lib' (tr/decode-str encoded-str)] @@ -412,7 +415,7 @@ :type :boolean :value true)) (ctob/add-theme (ctob/make-token-theme :name "test-token-theme")) - (ctob/toggle-set-in-theme "test-token-theme" "test-token-set")) + (ctob/toggle-set-in-theme "" "test-token-theme" "test-token-set")) encoded-blob (fres/encode tokens-lib) tokens-lib' (fres/decode encoded-blob)] @@ -840,34 +843,40 @@ (t/testing "grouped themes" (t/deftest grouped-themes (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-theme (ctob/make-token-theme :name "token-theme-1")) - (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2")) - (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-3")) - (ctob/add-theme (ctob/make-token-theme :name "group1/subgroup11/token-theme-4")) - (ctob/add-theme (ctob/make-token-theme :name "group2/token-theme-5"))) + (ctob/add-theme (ctob/make-token-theme :group "" :name "token-theme-1")) + (ctob/add-theme (ctob/make-token-theme :group "group1" :name "token-theme-2")) + (ctob/add-theme (ctob/make-token-theme :group "group1" :name "token-theme-3")) + (ctob/add-theme (ctob/make-token-theme :group "group2" :name "token-theme-4"))) themes-list (ctob/get-themes tokens-lib) themes-tree (ctob/get-theme-tree tokens-lib) - [node-theme1 node-group1 node-group2] + [node-group0 node-group1 node-group2] (ctob/get-children themes-tree) - [node-theme2 node-theme3 node-subgroup11] + [node-theme1] + (ctob/get-children (second node-group0)) + + [node-theme2 node-theme3] (ctob/get-children (second node-group1)) [node-theme4] - (ctob/get-children (second node-subgroup11)) - - [node-theme5] (ctob/get-children (second node-group2))] - (t/is (= (count themes-list) 5)) + (t/is (= (count themes-list) 4)) (t/is (= (:name (nth themes-list 0)) "token-theme-1")) - (t/is (= (:name (nth themes-list 1)) "group1/token-theme-2")) - (t/is (= (:name (nth themes-list 2)) "group1/token-theme-3")) - (t/is (= (:name (nth themes-list 3)) "group1/subgroup11/token-theme-4")) - (t/is (= (:name (nth themes-list 4)) "group2/token-theme-5")) + (t/is (= (:name (nth themes-list 1)) "token-theme-2")) + (t/is (= (:name (nth themes-list 2)) "token-theme-3")) + (t/is (= (:name (nth themes-list 3)) "token-theme-4")) + (t/is (= (:group (nth themes-list 0)) "")) + (t/is (= (:group (nth themes-list 1)) "group1")) + (t/is (= (:group (nth themes-list 2)) "group1")) + (t/is (= (:group (nth themes-list 3)) "group2")) + + (t/is (= (first node-group0) "")) + (t/is (= (ctob/group? (second node-group0)) true)) + (t/is (= (count (second node-group0)) 1)) (t/is (= (first node-theme1) "token-theme-1")) (t/is (= (ctob/group? (second node-theme1)) false)) @@ -875,38 +884,29 @@ (t/is (= (first node-group1) "group1")) (t/is (= (ctob/group? (second node-group1)) true)) - (t/is (= (count (second node-group1)) 3)) + (t/is (= (count (second node-group1)) 2)) (t/is (= (first node-theme2) "token-theme-2")) (t/is (= (ctob/group? (second node-theme2)) false)) - (t/is (= (:name (second node-theme2)) "group1/token-theme-2")) + (t/is (= (:name (second node-theme2)) "token-theme-2")) (t/is (= (first node-theme3) "token-theme-3")) (t/is (= (ctob/group? (second node-theme3)) false)) - (t/is (= (:name (second node-theme3)) "group1/token-theme-3")) - - (t/is (= (first node-subgroup11) "subgroup11")) - (t/is (= (ctob/group? (second node-subgroup11)) true)) - (t/is (= (count (second node-subgroup11)) 1)) + (t/is (= (:name (second node-theme3)) "token-theme-3")) (t/is (= (first node-theme4) "token-theme-4")) (t/is (= (ctob/group? (second node-theme4)) false)) - (t/is (= (:name (second node-theme4)) "group1/subgroup11/token-theme-4")) - - (t/is (= (first node-theme5) "token-theme-5")) - (t/is (= (ctob/group? (second node-theme5)) false)) - (t/is (= (:name (second node-theme5)) "group2/token-theme-5")))) + (t/is (= (:name (second node-theme4)) "token-theme-4")))) (t/deftest update-theme-in-groups (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-theme (ctob/make-token-theme :name "token-theme-1")) - (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2")) - (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-3")) - (ctob/add-theme (ctob/make-token-theme :name "group1/subgroup11/token-theme-4")) - (ctob/add-theme (ctob/make-token-theme :name "group2/token-theme-5"))) + (ctob/add-theme (ctob/make-token-theme :group "" :name "token-theme-1")) + (ctob/add-theme (ctob/make-token-theme :group "group1" :name "token-theme-2")) + (ctob/add-theme (ctob/make-token-theme :group "group1" :name "token-theme-3")) + (ctob/add-theme (ctob/make-token-theme :group "group2" :name "token-theme-4"))) tokens-lib' (-> tokens-lib - (ctob/update-theme "group1/token-theme-2" + (ctob/update-theme "group1" "token-theme-2" (fn [token-theme] (assoc token-theme :description "some description")))) @@ -916,26 +916,26 @@ token-theme (get-in themes-tree ["group1" "token-theme-2"]) token-theme' (get-in themes-tree' ["group1" "token-theme-2"])] - (t/is (= (ctob/theme-count tokens-lib') 5)) - (t/is (= (count group1') 3)) + (t/is (= (ctob/theme-count tokens-lib') 4)) + (t/is (= (count group1') 2)) (t/is (= (d/index-of (keys group1') "token-theme-2") 0)) - (t/is (= (:name token-theme') "group1/token-theme-2")) + (t/is (= (:name token-theme') "token-theme-2")) + (t/is (= (:group token-theme') "group1")) (t/is (= (:description token-theme') "some description")) (t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme))))) (t/deftest rename-theme-in-groups (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-theme (ctob/make-token-theme :name "token-theme-1")) - (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2")) - (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-3")) - (ctob/add-theme (ctob/make-token-theme :name "group1/subgroup11/token-theme-4")) - (ctob/add-theme (ctob/make-token-theme :name "group2/token-theme-5"))) + (ctob/add-theme (ctob/make-token-theme :group "" :name "token-theme-1")) + (ctob/add-theme (ctob/make-token-theme :group "group1" :name "token-theme-2")) + (ctob/add-theme (ctob/make-token-theme :group "group1" :name "token-theme-3")) + (ctob/add-theme (ctob/make-token-theme :group "group2" :name "token-theme-4"))) tokens-lib' (-> tokens-lib - (ctob/update-theme "group1/token-theme-2" + (ctob/update-theme "group1" "token-theme-2" (fn [token-theme] (assoc token-theme - :name "group1/updated-name")))) + :name "updated-name")))) themes-tree (ctob/get-theme-tree tokens-lib) themes-tree' (ctob/get-theme-tree tokens-lib') @@ -943,26 +943,27 @@ token-theme (get-in themes-tree ["group1" "token-theme-2"]) token-theme' (get-in themes-tree' ["group1" "updated-name"])] - (t/is (= (ctob/theme-count tokens-lib') 5)) - (t/is (= (count group1') 3)) + (t/is (= (ctob/theme-count tokens-lib') 4)) + (t/is (= (count group1') 2)) (t/is (= (d/index-of (keys group1') "updated-name") 0)) - (t/is (= (:name token-theme') "group1/updated-name")) + (t/is (= (:name token-theme') "updated-name")) + (t/is (= (:group token-theme') "group1")) (t/is (= (:description token-theme') nil)) (t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme))))) (t/deftest move-theme-of-group (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-theme (ctob/make-token-theme :name "token-theme-1")) - (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2")) - (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-3")) - (ctob/add-theme (ctob/make-token-theme :name "group1/subgroup11/token-theme-4")) - #_(ctob/add-theme (ctob/make-token-theme :name "group2/token-theme-5"))) + (ctob/add-theme (ctob/make-token-theme :group "" :name "token-theme-1")) + (ctob/add-theme (ctob/make-token-theme :group "group1" :name "token-theme-2")) + (ctob/add-theme (ctob/make-token-theme :group "group1" :name "token-theme-3")) + #_(ctob/add-theme (ctob/make-token-theme :group "group2" :name "token-theme-4"))) tokens-lib' (-> tokens-lib - (ctob/update-theme "group1/token-theme-2" + (ctob/update-theme "group1" "token-theme-2" (fn [token-theme] (assoc token-theme - :name "group2/updated-name")))) + :name "updated-name" + :group "group2")))) themes-tree (ctob/get-theme-tree tokens-lib) themes-tree' (ctob/get-theme-tree tokens-lib') @@ -971,21 +972,22 @@ token-theme (get-in themes-tree ["group1" "token-theme-2"]) token-theme' (get-in themes-tree' ["group2" "updated-name"])] - (t/is (= (ctob/theme-count tokens-lib') 4)) - (t/is (= (count group1') 2)) + (t/is (= (ctob/theme-count tokens-lib') 3)) + (t/is (= (count group1') 1)) (t/is (= (count group2') 1)) (t/is (= (d/index-of (keys group2') "updated-name") 0)) - (t/is (= (:name token-theme') "group2/updated-name")) + (t/is (= (:name token-theme') "updated-name")) + (t/is (= (:group token-theme') "group2")) (t/is (= (:description token-theme') nil)) (t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme))))) (t/deftest delete-theme-in-group (let [tokens-lib (-> (ctob/make-tokens-lib) - (ctob/add-theme (ctob/make-token-theme :name "token-theme-1")) - (ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2"))) + (ctob/add-theme (ctob/make-token-theme :group "" :name "token-theme-1")) + (ctob/add-theme (ctob/make-token-theme :group "group1" :name "token-theme-2"))) tokens-lib' (-> tokens-lib - (ctob/delete-theme "group1/token-theme-2")) + (ctob/delete-theme "group1" "token-theme-2")) themes-tree' (ctob/get-theme-tree tokens-lib') token-theme' (get-in themes-tree' ["group1" "token-theme-2"])] From 0e15da5edea0362fe8c8ea10cea37c30a77eb8d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Tue, 17 Sep 2024 00:51:33 +0200 Subject: [PATCH 6/6] :wrench: Make tokens again a flat ordered map --- common/src/app/common/data.cljc | 12 +- common/src/app/common/types/tokens_lib.cljc | 72 +++++----- .../common_tests/types/tokens_lib_test.cljc | 126 +++++------------- 3 files changed, 76 insertions(+), 134 deletions(-) diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index a67ee4b592..2d0011be71 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -78,9 +78,9 @@ (declare index-of) -#_(defn oassoc-before +(defn oassoc-before "Assoc a k v pair, in the order position just before the other key" - [o k v before-k] + [o before-k k v] (if-let [index (index-of (keys o) before-k)] (-> (ordered-map) (into (take index o)) @@ -89,12 +89,12 @@ (oassoc o k v))) (defn oassoc-in-before - [o [old-k & old-ks] [k & ks] v] - (if-let [index (index-of (keys o) old-k)] + [o [before-k & before-ks] [k & ks] v] + (if-let [index (index-of (keys o) before-k)] (let [new-v (if ks - (oassoc-in-before (get o k) old-ks ks v) + (oassoc-in-before (get o k) before-ks ks v) v)] - (if (= k old-k) + (if (= k before-k) (-> (ordered-map) (into (take index o)) (assoc k new-v) diff --git a/common/src/app/common/types/tokens_lib.cljc b/common/src/app/common/types/tokens_lib.cljc index 58fb928eac..0a8b8d7d9e 100644 --- a/common/src/app/common/types/tokens_lib.cljc +++ b/common/src/app/common/types/tokens_lib.cljc @@ -142,56 +142,41 @@ ITokenSet (add-token [_ token] (dm/assert! "expected valid token" (check-token! token)) - (let [path (split-path (:name token) ".")] - (TokenSet. name - description - (dt/now) - (d/oassoc-in tokens path token)))) + (TokenSet. name + description + (dt/now) + (assoc tokens (:name token) token))) (update-token [this token-name f] - (let [path (split-path token-name ".") - token (get-in tokens path)] - (if token - (let [token' (-> (make-token (f token)) - (assoc :modified-at (dt/now))) - path' (get-path token' ".")] - (check-token! token') - (TokenSet. name - description - (dt/now) - (if (= (:name token) (:name token')) - (d/oassoc-in tokens path token') - (-> tokens - (d/oassoc-in-before path path' token') - (d/dissoc-in path))))) - this))) + (if-let [token (get tokens token-name)] + (let [token' (-> (make-token (f token)) + (assoc :modified-at (dt/now)))] + (check-token! token') + (TokenSet. name + description + (dt/now) + (if (= (:name token) (:name token')) + (assoc tokens (:name token') token') + (-> tokens + (d/oassoc-before (:name token) (:name token') token') + (dissoc (:name token)))))) + this)) (delete-token [_ token-name] - (let [path (split-path token-name ".")] - (TokenSet. name - description - (dt/now) - (d/dissoc-in tokens path)))) + (TokenSet. name + description + (dt/now) + (dissoc tokens token-name))) (get-tokens [_] - (->> (tree-seq d/ordered-map? vals tokens) - (filter (partial instance? Token))))) - -(def schema:token-node - [:schema {:registry {::node [:or ::token - [:and - [:map-of {:gen/max 5} :string [:ref ::node]] - [:fn d/ordered-map?]]]}} - [:ref ::node]]) - -(sm/register! ::token-node schema:token-node) + (vals tokens))) (def schema:token-set [:and [:map {:title "TokenSet"} [:name :string] [:description [:maybe :string]] [:modified-at ::sm/inst] - [:tokens [:and [:map-of {:gen/max 5} :string ::token-node] + [:tokens [:and [:map-of {:gen/max 5} :string ::token] [:fn d/ordered-map?]]]] [:fn (partial instance? TokenSet)]]) @@ -239,10 +224,19 @@ (get-set [_ set-name] "get one set looking for name") (get-set-group [_ set-group-path] "get the attributes of a set group")) +(def schema:token-set-node + [:schema {:registry {::node [:or ::token-set + [:and + [:map-of {:gen/max 5} :string [:ref ::node]] + [:fn d/ordered-map?]]]}} + [:ref ::node]]) + +(sm/register! ::token-set-node schema:token-set-node) + (def schema:token-sets [:and [:map-of {:title "TokenSets"} - :string ::token-set] + :string ::token-set-node] [:fn d/ordered-map?]]) (sm/register! ::token-sets schema:token-sets) diff --git a/common/test/common_tests/types/tokens_lib_test.cljc b/common/test/common_tests/types/tokens_lib_test.cljc index 358f17a93c..fd342c95c2 100644 --- a/common/test/common_tests/types/tokens_lib_test.cljc +++ b/common/test/common_tests/types/tokens_lib_test.cljc @@ -425,49 +425,49 @@ (t/testing "grouping" (t/deftest split-and-join - (let [name "group.subgroup.name" - path (ctob/split-path name ".") - name' (ctob/join-path path ".")] + (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 ".")] + (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) + (let [token-set1 (ctob/make-token-set :name "token-set1") + token-set2 (ctob/make-token-set :name "some group/token-set2") - 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")))) + token-set1' (ctob/group-item token-set1 "big group" "/") + token-set2' (ctob/group-item token-set2 "big group" "/") + token-set1'' (ctob/ungroup-item token-set1' "/") + token-set2'' (ctob/ungroup-item token-set2' "/")] + (t/is (= (:name token-set1') "big group/token-set1")) + (t/is (= (:name token-set2') "big group/some group/token-set2")) + (t/is (= (:name token-set1'') "token-set1")) + (t/is (= (:name token-set2'') "some group/token-set2")))) (t/deftest get-groups-str - (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-groups-str token1 ".") "")) - (t/is (= (ctob/get-groups-str token2 ".") "some-group")) - (t/is (= (ctob/get-groups-str token3 ".") "some-group.some-subgroup")))) + (let [token-set1 (ctob/make-token-set :name "token-set1") + token-set2 (ctob/make-token-set :name "some-group/token-set2") + token-set3 (ctob/make-token-set :name "some-group/some-subgroup/token-set3")] + (t/is (= (ctob/get-groups-str token-set1 "/") "")) + (t/is (= (ctob/get-groups-str token-set2 "/") "some-group")) + (t/is (= (ctob/get-groups-str token-set3 "/") "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")))) + (let [token-set1 (ctob/make-token-set :name "token-set1") + token-set2 (ctob/make-token-set :name "some-group/token-set2") + token-set3 (ctob/make-token-set :name "some-group/some-subgroup/token-set3")] + (t/is (= (ctob/get-final-name token-set1 "/") "token-set1")) + (t/is (= (ctob/get-final-name token-set2 "/") "token-set2")) + (t/is (= (ctob/get-final-name token-set3 "/") "token-set3")))) (t/testing "grouped tokens" (t/deftest grouped-tokens @@ -495,56 +495,14 @@ :value true))) set (ctob/get-set tokens-lib "test-token-set") - tokens-list (ctob/get-tokens set) - - tokens-tree (:tokens set) - - [node-token1 node-group1 node-group2] - (ctob/get-children tokens-tree) - - [node-token2 node-token3 node-subgroup11] - (ctob/get-children (second node-group1)) - - [node-token4] - (ctob/get-children (second node-subgroup11)) - - [node-token5] - (ctob/get-children (second node-group2))] + tokens-list (vals (:tokens set))] (t/is (= (count tokens-list) 5)) (t/is (= (:name (nth tokens-list 0)) "token1")) (t/is (= (:name (nth tokens-list 1)) "group1.token2")) (t/is (= (:name (nth tokens-list 2)) "group1.token3")) (t/is (= (:name (nth tokens-list 3)) "group1.subgroup11.token4")) - (t/is (= (:name (nth tokens-list 4)) "group2.token5")) - - (t/is (= (first node-token1) "token1")) - (t/is (= (ctob/group? (second node-token1)) false)) - (t/is (= (:name (second node-token1)) "token1")) - - (t/is (= (first node-group1) "group1")) - (t/is (= (ctob/group? (second node-group1)) true)) - (t/is (= (count (second node-group1)) 3)) - - (t/is (= (first node-token2) "token2")) - (t/is (= (ctob/group? (second node-token2)) false)) - (t/is (= (:name (second node-token2)) "group1.token2")) - - (t/is (= (first node-token3) "token3")) - (t/is (= (ctob/group? (second node-token3)) false)) - (t/is (= (:name (second node-token3)) "group1.token3")) - - (t/is (= (first node-subgroup11) "subgroup11")) - (t/is (= (ctob/group? (second node-subgroup11)) true)) - (t/is (= (count (second node-subgroup11)) 1)) - - (t/is (= (first node-token4) "token4")) - (t/is (= (ctob/group? (second node-token4)) false)) - (t/is (= (:name (second node-token4)) "group1.subgroup11.token4")) - - (t/is (= (first node-token5) "token5")) - (t/is (= (ctob/group? (second node-token5)) false)) - (t/is (= (:name (second node-token5)) "group2.token5")))) + (t/is (= (:name (nth tokens-list 4)) "group2.token5")))) (t/deftest update-token-in-groups (let [tokens-lib (-> (ctob/make-tokens-lib) @@ -571,13 +529,10 @@ token-set (ctob/get-set tokens-lib "test-token-set") token-set' (ctob/get-set tokens-lib' "test-token-set") - group1' (get-in token-set' [:tokens "group1"]) - token (get-in token-set [:tokens "group1" "test-token-2"]) - token' (get-in token-set' [:tokens "group1" "test-token-2"])] + token (get-in token-set [:tokens "group1.test-token-2"]) + token' (get-in token-set' [:tokens "group1.test-token-2"])] (t/is (= (ctob/set-count tokens-lib') 1)) - (t/is (= (count group1') 2)) - (t/is (= (d/index-of (keys group1') "test-token-2") 0)) (t/is (= (:name token') "group1.test-token-2")) (t/is (= (:description token') "some description")) (t/is (= (:value token') false)) @@ -608,13 +563,10 @@ token-set (ctob/get-set tokens-lib "test-token-set") token-set' (ctob/get-set tokens-lib' "test-token-set") - group1' (get-in token-set' [:tokens "group1"]) - token (get-in token-set [:tokens "group1" "test-token-2"]) - token' (get-in token-set' [:tokens "group1" "updated-name"])] + token (get-in token-set [:tokens "group1.test-token-2"]) + token' (get-in token-set' [:tokens "group1.updated-name"])] (t/is (= (ctob/set-count tokens-lib') 1)) - (t/is (= (count group1') 2)) - (t/is (= (d/index-of (keys group1') "updated-name") 0)) (t/is (= (:name token') "group1.updated-name")) (t/is (= (:description token') nil)) (t/is (= (:value token') true)) @@ -645,15 +597,11 @@ token-set (ctob/get-set tokens-lib "test-token-set") token-set' (ctob/get-set tokens-lib' "test-token-set") - group1' (get-in token-set' [:tokens "group1"]) - group2' (get-in token-set' [:tokens "group2"]) - token (get-in token-set [:tokens "group1" "test-token-2"]) - token' (get-in token-set' [:tokens "group2" "updated-name"])] + token (get-in token-set [:tokens "group1.test-token-2"]) + token' (get-in token-set' [:tokens "group2.updated-name"])] (t/is (= (ctob/set-count tokens-lib') 1)) - (t/is (= (count group1') 1)) - (t/is (= (count group2') 1)) - (t/is (= (d/index-of (keys group2') "updated-name") 0)) + (t/is (= (d/index-of (keys (:tokens token-set')) "group2.updated-name") 1)) (t/is (= (:name token') "group2.updated-name")) (t/is (= (:description token') nil)) (t/is (= (:value token') true)) @@ -676,7 +624,7 @@ token-set (ctob/get-set tokens-lib "test-token-set") token-set' (ctob/get-set tokens-lib' "test-token-set") - token' (get-in token-set' [:tokens "group1" "test-token-2"])] + token' (get-in token-set' [:tokens "group1.test-token-2"])] (t/is (= (ctob/set-count tokens-lib') 1)) (t/is (= (count (:tokens token-set')) 1))