diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc index 5401304555..20746bd2e2 100644 --- a/common/src/app/common/files/changes_builder.cljc +++ b/common/src/app/common/files/changes_builder.cljc @@ -1091,10 +1091,10 @@ (defn set-tokens-source [changes library-id] - (assert-file-data! changes) - (let [file-data (::file-data (meta changes)) - file-id (:id file-data) - prev-val (:tokens-source file-data)] + (assert-library! changes) + (let [library-data (::library-data (meta changes)) + file-id (:id library-data) + prev-val (:tokens-source library-data)] (-> changes (update :redo-changes conj {:type :set-tokens-source :file-id file-id diff --git a/common/src/app/common/files/tokens.cljc b/common/src/app/common/files/tokens.cljc index 3f58147859..1dab687905 100644 --- a/common/src/app/common/files/tokens.cljc +++ b/common/src/app/common/files/tokens.cljc @@ -463,13 +463,43 @@ (update :tokens-status #(or % (ctos/make-tokens-status))))) (defn get-tokens-source + "Return the current tokens source of the file. When there is no explicit :tokens-source attribute, + the source is the file itself." [file-data] - (:tokens-source file-data)) + (or (:tokens-source file-data) (:id file-data))) (defn set-tokens-source [file-data tokens-source] (assoc file-data :tokens-source tokens-source)) +(defn tokens-source? + "Returns true if the given id is the current tokens source of the file-data. + When no tokens-source is set, the file's own id is considered the source if there are any tokens in it." + [file-data id] + (assert (uuid? id) "expected valid uuid") + (let [source (:tokens-source file-data) + tokens-lib (:tokens-lib file-data) + has-tokens? (and (some? tokens-lib) + (not (ctob/empty-lib? tokens-lib)))] + (if (= id (:id file-data)) + (and has-tokens? + (or (nil? source) (= source id))) + (= source id)))) + +(defn tokens-provider? + "Returns true if the file MAY become a tokens source. This is if the file has tokens and has + not configured another tokens source." + [file-data] + (and (some? (:tokens-lib file-data)) + (or (nil? (:tokens-source file-data)) + (= (:tokens-source file-data) (:id file-data))))) + +(defn editable-tokens? + "Returns true if the file-data owns its tokens (no external source or source is itself)." + [file-data] + (let [source (:tokens-source file-data)] + (or (nil? source) (= source (:id file-data))))) + (defn get-tokens-lib [file-data] (:tokens-lib file-data)) @@ -656,7 +686,9 @@ (conj force-set-id))] (reduce (fn [tokens set-id] (let [set (ctob/get-set tokens-lib set-id)] - (merge tokens (ctob/get-tokens- set)))) + (if set + (merge tokens (ctob/get-tokens- set)) + tokens))) (d/ordered-map) ordered-active))) diff --git a/common/test/common_tests/files/tokens_test.cljc b/common/test/common_tests/files/tokens_test.cljc index 8a96f908b4..86c9b01731 100644 --- a/common/test/common_tests/files/tokens_test.cljc +++ b/common/test/common_tests/files/tokens_test.cljc @@ -14,7 +14,6 @@ [app.common.types.tokens-lib :as ctob] [app.common.types.tokens-status :as ctos] [app.common.uuid :as uuid] - [clojure.datafy :refer [datafy]] [clojure.test :as t])) ;; Helper functions @@ -235,25 +234,25 @@ (t/is (ctos/tokens-status? (:tokens-status file-data'))))) (t/testing "ensure-tokens-lib should not add a tokens-lib if there is a tokens-source" - (let [tokens-source (uuid/next) + (let [source-id (uuid/next) tokens-status (ctos/make-tokens-status) file (-> (thf/sample-file :file1) - (assoc-in [:data :tokens-source] tokens-source) + (assoc-in [:data :tokens-source] source-id) (assoc-in [:data :tokens-status] tokens-status)) file-data (ctf/file-data file) file-data' (cfo/ensure-tokens-lib file-data)] (t/is (not (contains? file-data' :tokens-lib))) - (t/is (= tokens-source (:tokens-source file-data'))) + (t/is (= source-id (:tokens-source file-data'))) (t/is (= tokens-status (:tokens-status file-data'))))) (t/testing "ensure-tokens-lib should not add a tokens-lib if there is a tokens-source, but should add a tokens-status if it's missing" - (let [tokens-source (uuid/next) + (let [source-id (uuid/next) file (-> (thf/sample-file :file1) - (assoc-in [:data :tokens-source] tokens-source)) + (assoc-in [:data :tokens-source] source-id)) file-data (ctf/file-data file) file-data' (cfo/ensure-tokens-lib file-data)] (t/is (not (contains? file-data' :tokens-lib))) - (t/is (= tokens-source (:tokens-source file-data'))) + (t/is (= source-id (:tokens-source file-data'))) (t/is (contains? file-data' :tokens-status)) (t/is (ctos/tokens-status? (:tokens-status file-data')))))) @@ -268,20 +267,224 @@ (t/deftest test-get-tokens-source (t/testing "returns tokens-source from file data" - (let [file-id (thi/new-id! :tokens-source) - file-data {:tokens-source file-id}] - (t/is (= file-id (cfo/get-tokens-source file-data))))) + (let [source-id (thi/new-id! :tokens-source) + file (-> (thf/sample-file :file1) + (assoc-in [:data :tokens-source] source-id))] + (t/is (= source-id (cfo/get-tokens-source (:data file)))))) - (t/testing "returns nil when no tokens-source" - (t/is (nil? (cfo/get-tokens-source {}))))) + (t/testing "returns file id when no tokens-source" + (let [file (thf/sample-file :file1)] + (t/is (= (:id file) (cfo/get-tokens-source file)))))) (t/deftest test-set-tokens-source (t/testing "sets tokens-source on file data" - (let [file-id (thi/new-id! :tokens-source) - file-data {:other :data} - file-data' (cfo/set-tokens-source file-data file-id)] - (t/is (= file-id (:tokens-source file-data'))) - (t/is (= :data (:other file-data')))))) + (let [source-id (thi/new-id! :tokens-source) + file (thf/sample-file :file1) + file-data (:data file) + file-data' (cfo/set-tokens-source file-data source-id)] + (t/is (= source-id (:tokens-source file-data')))))) + +(t/deftest test-tokens-source? + (t/testing "no tokens, no tokens-source, ask for file id -> false" + (let [file (thf/sample-file :file1) + file-data (:data file)] + (t/is (false? (cfo/tokens-source? file-data (:id file-data)))))) + + (t/testing "empty tokens-lib, no tokens-source, ask for file id -> false" + (let [file (-> (thf/sample-file :file1) + (tht/add-tokens-lib)) + file-data (:data file)] + (t/is (false? (cfo/tokens-source? file-data (:id file-data)))))) + + (t/testing "tokens, no tokens-source, ask for file id -> true" + (let [file (-> (thf/sample-file :file1) + (tht/add-tokens-lib) + (tht/update-tokens-lib + #(-> % + (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) + (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) + file-data (:data file)] + (t/is (true? (cfo/tokens-source? file-data (:id file-data)))))) + + (t/testing "no tokens, no tokens source, ask for other id -> false" + (let [file (thf/sample-file :file1) + file-data (:data file)] + (t/is (false? (cfo/tokens-source? file-data (uuid/next)))))) + + (t/testing "empty tokens-lib, no tokens source, ask for other id -> false" + (let [file (-> (thf/sample-file :file1) + (tht/add-tokens-lib)) + file-data (:data file)] + (t/is (false? (cfo/tokens-source? file-data (uuid/next)))))) + + (t/testing "tokens, no tokens source, ask for other id -> false" + (let [file (-> (thf/sample-file :file1) + (tht/add-tokens-lib) + (tht/update-tokens-lib + #(-> % + (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) + (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) + file-data (:data file)] + (t/is (false? (cfo/tokens-source? file-data (uuid/next)))))) + + ;; --- + + (t/testing "no tokens, tokens source = file id, ask for file id -> false" ;; This case should not occur + (let [file (thf/sample-file :file1) + file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] + (t/is (false? (cfo/tokens-source? file-data (:id file-data)))))) + + (t/testing "empty tokens-lib, tokens source = file id, ask for file id -> false" ;; This case should not occur + (let [file (-> (thf/sample-file :file1) + (tht/add-tokens-lib)) + file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] + (t/is (false? (cfo/tokens-source? file-data (:id file-data)))))) + + (t/testing "tokens, tokens source = file id, ask for file id -> true" + (let [file (-> (thf/sample-file :file1) + (tht/add-tokens-lib) + (tht/update-tokens-lib + #(-> % + (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) + (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) + file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] + (t/is (true? (cfo/tokens-source? file-data (:id file-data)))))) + + (t/testing "no tokens, tokens source = file id, ask for other id -> false" ;; This case should not occur + (let [file (thf/sample-file :file1) + file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] + (t/is (false? (cfo/tokens-source? file-data (uuid/next)))))) + + (t/testing "empty tokens-lib, tokens source = file id, ask for other id -> false" ;; This case should not occur + (let [file (-> (thf/sample-file :file1) + (tht/add-tokens-lib)) + file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] + (t/is (false? (cfo/tokens-source? file-data (uuid/next)))))) + + (t/testing "tokens, tokens source = file id, ask for other id -> false" + (let [file (-> (thf/sample-file :file1) + (tht/add-tokens-lib) + (tht/update-tokens-lib + #(-> % + (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) + (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) + file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] + (t/is (false? (cfo/tokens-source? file-data (uuid/next)))))) + + ;; --- + + (t/testing "no tokens, tokens source = other id, ask for file id -> false" + (let [source-id (thi/new-id! :tokens-source) + file (thf/sample-file :file1) + file-data (cfo/set-tokens-source (:data file) source-id)] + (t/is (false? (cfo/tokens-source? file-data (:id file-data)))))) + + (t/testing "empty tokens-lib, tokens source = other id, ask for file id -> false" + (let [source-id (thi/new-id! :tokens-source) + file (-> (thf/sample-file :file1) + (tht/add-tokens-lib)) + file-data (cfo/set-tokens-source (:data file) source-id)] + (t/is (false? (cfo/tokens-source? file-data (:id file-data)))))) + + (t/testing "tokens, tokens source = other id, ask for file id -> false" + (let [source-id (thi/new-id! :tokens-source) + file (-> (thf/sample-file :file1) + (tht/add-tokens-lib) + (tht/update-tokens-lib + #(-> % + (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) + (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) + file-data (cfo/set-tokens-source (:data file) source-id)] + (t/is (false? (cfo/tokens-source? file-data (:id file-data)))))) + + (t/testing "no tokens, tokens source = other id, ask for this same id -> true" + (let [source-id (thi/new-id! :tokens-source) + file (thf/sample-file :file1) + file-data (cfo/set-tokens-source (:data file) source-id)] + (t/is (true? (cfo/tokens-source? file-data source-id))))) + + (t/testing "empty tokens-lib, tokens source = other id, ask for this same id -> true" + (let [source-id (thi/new-id! :tokens-source) + file (-> (thf/sample-file :file1) + (tht/add-tokens-lib)) + file-data (cfo/set-tokens-source (:data file) source-id)] + (t/is (true? (cfo/tokens-source? file-data source-id))))) + + (t/testing "tokens, tokens source = other id, ask for this same id -> true" + (let [source-id (thi/new-id! :tokens-source) + file (-> (thf/sample-file :file1) + (tht/add-tokens-lib) + (tht/update-tokens-lib + #(-> % + (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) + (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) + file-data (cfo/set-tokens-source (:data file) source-id)] + (t/is (true? (cfo/tokens-source? file-data source-id))))) + + (t/testing "no tokens, tokens source = other id, ask for a different id -> false" + (let [source-id (thi/new-id! :tokens-source) + file (thf/sample-file :file1) + file-data (cfo/set-tokens-source (:data file) source-id)] + (t/is (false? (cfo/tokens-source? file-data (uuid/next)))))) + + (t/testing "empty tokens-lib, tokens source = other id, ask for a different id -> false" + (let [source-id (thi/new-id! :tokens-source) + file (-> (thf/sample-file :file1) + (tht/add-tokens-lib)) + file-data (cfo/set-tokens-source (:data file) source-id)] + (t/is (false? (cfo/tokens-source? file-data (uuid/next)))))) + + (t/testing "tokens, tokens source = other id, ask for a different id -> false" + (let [source-id (thi/new-id! :tokens-source) + file (-> (thf/sample-file :file1) + (tht/add-tokens-lib) + (tht/update-tokens-lib + #(-> % + (ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-a) :name "set-a")) + (ctob/add-token (thi/id :set-a) (ctob/make-token :id (thi/new-id! :tok1) :name "spacing" :type :spacing :value "8px"))))) + file-data (cfo/set-tokens-source (:data file) source-id)] + (t/is (false? (cfo/tokens-source? file-data (uuid/next))))))) + +(t/deftest test-tokens-provider? + (t/testing "returns false if it has no tokens" + (let [file (thf/sample-file :file1) + file-data (:data file)] + (t/is (false? (cfo/tokens-provider? file-data))))) + + (t/testing "returns true if it has tokens and no tokens-source" + (let [file (-> (thf/sample-file :file1) + (tht/add-tokens-lib)) + file-data (:data file)] + (t/is (true? (cfo/tokens-provider? file-data))))) + + (t/testing "returns true if it has tokens and tokens-source is its own id" + (let [file (-> (thf/sample-file :file1) + (tht/add-tokens-lib)) + file-data (cfo/set-tokens-source (:data file) (:id file))] + (t/is (true? (cfo/tokens-provider? file-data))))) + + (t/testing "returns false if it has tokens and tokens-source is other id" + (let [file (-> (thf/sample-file :file1) + (tht/add-tokens-lib)) + file-data (cfo/set-tokens-source (:data file) (uuid/next))] + (t/is (false? (cfo/tokens-provider? file-data)))))) + +(t/deftest test-editable-tokens? + (t/testing "returns true when file-data has no tokens-source" + (let [file (thf/sample-file :file1) + file-data (:data file)] + (t/is (true? (cfo/editable-tokens? file-data))))) + + (t/testing "returns true when tokens-source is the file's own id" + (let [file (thf/sample-file :file1) + file-data (cfo/set-tokens-source (:data file) (:id (:data file)))] + (t/is (true? (cfo/editable-tokens? file-data))))) + + (t/testing "returns false when tokens-source is a different uuid" + (let [source-id (thi/new-id! :tokens-source) + file (thf/sample-file :file1) + file-data (cfo/set-tokens-source (:data file) source-id)] + (t/is (false? (cfo/editable-tokens? file-data)))))) (t/deftest test-get-tokens-status (t/testing "returns tokens-status from file data" diff --git a/frontend/src/app/main/data/helpers.cljs b/frontend/src/app/main/data/helpers.cljs index be8f798d5d..467f3bc9ef 100644 --- a/frontend/src/app/main/data/helpers.cljs +++ b/frontend/src/app/main/data/helpers.cljs @@ -38,10 +38,11 @@ ([state file-id] (dm/get-in state [:files file-id :data]))) +;; TODO perhaps this is not necessary, lookup-tokens-lib should be enough (defn lookup-tokens-source-data [state] (let [current-file-data (lookup-file-data state) - tokens-source-id (or (cfo/get-tokens-source current-file-data) (:id current-file-data))] + tokens-source-id (cfo/get-tokens-source current-file-data)] (lookup-file-data state tokens-source-id))) (defn lookup-tokens-lib diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 5ebdd1f9a9..fe24540fa9 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -1628,10 +1628,6 @@ (map first) set)] (rx/concat - (when (contains? cf/flags :token-lib-sync) - (rx/of (dch/commit-changes (-> (pcb/empty-changes nil) - (pcb/with-file-data file-data) - (pcb/set-tokens-source library-id))))) (->> (rp/cmd! :link-file-to-library {:file-id file-id :library-id library-id}) (rx/merge-map (fn [libraries-to-load] (as-> libraries-to-load $ diff --git a/frontend/src/app/main/data/workspace/tokens/library_edit.cljs b/frontend/src/app/main/data/workspace/tokens/library_edit.cljs index b0b8d6f951..3339ea934c 100644 --- a/frontend/src/app/main/data/workspace/tokens/library_edit.cljs +++ b/frontend/src/app/main/data/workspace/tokens/library_edit.cljs @@ -420,6 +420,17 @@ (rx/of (dch/commit-changes changes) (dwtp/propagate-workspace-tokens)))))) +(defn set-tokens-source + [library-id] + (ptk/reify ::set-tokens-source + ptk/WatchEvent + (watch [it state _] + (let [data (dsh/lookup-file-data state) + changes (-> (pcb/empty-changes it) + (pcb/with-library-data data) + (pcb/set-tokens-source library-id))] + (rx/of (dch/commit-changes changes)))))) + (defn delete-token-set [id] (ptk/reify ::delete-token-set diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index 0a2f5908f2..7c2707111e 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -9,6 +9,7 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.files.tokens :as cfo] [app.common.files.variant :as cfv] [app.common.types.components-list :as ctkl] [app.common.types.file :as ctf] @@ -24,6 +25,7 @@ [app.main.data.team :as dtm] [app.main.data.workspace.colors :as mdc] [app.main.data.workspace.libraries :as dwl] + [app.main.data.workspace.tokens.library-edit :as dwtl] [app.main.refs :as refs] [app.main.render :refer [component-svg]] [app.main.store :as st] @@ -262,7 +264,7 @@ unlink-library (mf/use-fn - (mf/deps file-id) + (mf/deps file-id local-library) (fn [event] (let [library-id (some-> (dom/get-current-target event) (dom/get-data "library-id") @@ -270,7 +272,11 @@ (when (= library-id @selected) (reset! selected :file)) (st/emit! (dwl/unlink-file-from-library file-id library-id) - (dwl/sync-file file-id library-id))))) + (dwl/sync-file file-id library-id)) + ;; When the unlinked library is the current tokens source, + ;; we must reset it to the local library. + (when (cfo/tokens-source? local-library library-id) + (st/emit! (dwtl/set-tokens-source (:id local-library))))))) import-tokens (mf/use-fn @@ -283,6 +289,14 @@ :tokens/import-from-library {:file-id file-id :library-id library-id}))))) + set-as-tokens-source + (mf/use-fn + (fn [event] + (let [library-id (some-> (dom/get-current-target event) + (dom/get-data "library-id") + (uuid/parse))] + (st/emit! (dwtl/set-tokens-source library-id))))) + on-delete-accept (mf/use-fn (mf/deps file-id) @@ -335,7 +349,16 @@ [:div {:class (stl/css :item-content)} [:div {:class (stl/css :item-title)} (tr "workspace.libraries.file-library")] [:ul {:class (stl/css :item-contents)} - [:> library-description* {:summary summary}]]] + [:> library-description* {:summary summary}]] + (when (contains? cf/flags :token-lib-sync) + (if (cfo/tokens-source? local-library (:id local-library)) + [:div (tr "workspace.libraries.tokens-source")] + (when (not= (cfo/get-tokens-source local-library) (:id local-library)) + [:> button* {:variant "secondary" + :type "button" + :data-library-id (dm/str (:id local-library)) + :on-click set-as-tokens-source} + (tr "workspace.libraries.set-as-tokens-source")])))] (if ^boolean is-shared [:> button* {:variant "secondary" @@ -366,16 +389,28 @@ [:div {:class (stl/css :connected-to-wrapper)} [:span "(" (tr "workspace.libraries.connected-to") " "] [:span {:class (stl/css :connected-to-values)} (str/join ", " connected-to-names)] - [:span ")"]])])]] + [:span ")"]])])] + (when (contains? cf/flags :token-lib-sync) + (when (cfo/tokens-source? local-library id) + [:div (tr "workspace.libraries.tokens-source")]))] + [:div {:class (stl/css :library-actions)} - (when ^boolean has-tokens? - [:> icon-button* - {:type "button" - :aria-label (tr "workspace.tokens.import-tokens") - :icon i/import-export - :data-library-id (dm/str id) - :variant "secondary" - :on-click import-tokens}]) + (if (contains? cf/flags :token-lib-sync) + (when (and (cfo/tokens-provider? (:data library)) + (not (cfo/tokens-source? local-library id))) + [:> button* {:variant "secondary" + :type "button" + :data-library-id (dm/str id) + :on-click set-as-tokens-source} + (tr "workspace.libraries.set-as-tokens-source")]) + (when ^boolean has-tokens? + [:> icon-button* + {:type "button" + :aria-label (tr "workspace.tokens.import-tokens") + :icon i/import-export + :data-library-id (dm/str id) + :variant "secondary" + :on-click import-tokens}])) [:> icon-button* {:type "button" :aria-label (tr "workspace.libraries.unlink-library-btn") diff --git a/frontend/test/frontend_tests/tokens/helpers/state.cljs b/frontend/test/frontend_tests/tokens/helpers/state.cljs index 5bb61696b1..beab3d2b8c 100644 --- a/frontend/test/frontend_tests/tokens/helpers/state.cljs +++ b/frontend/test/frontend_tests/tokens/helpers/state.cljs @@ -8,8 +8,10 @@ (:require [app.common.files.tokens :as cfo] [app.common.types.tokens-lib :as ctob] + [app.main.data.changes :as dch] [app.main.data.helpers :as dsh] [app.main.data.style-dictionary :as sd] + [app.main.data.workspace.undo :as dwu] [beicon.v2.core :as rx] [potok.v2.core :as ptk])) @@ -53,6 +55,31 @@ "Stops on `send-update-indices` function being called, which should be the last function of an event chain." (stop-on ::end)) +(defn watch-undo-stack + "Maintain the workspace undo stack by watching for commit events. + Must be emitted before the events under test so undo entries are populated." + [] + (ptk/reify ::watch-undo-stack + ptk/WatchEvent + (watch [_ _ stream] + (let [stopper-s (->> stream (rx/filter (ptk/type? ::watch-undo-stack)))] + (->> stream + (rx/filter dch/commit?) + (rx/map deref) + (rx/filter #(= :local (:source %))) + (rx/mapcat + (fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo? selected-before]}] + (if (and save-undo? (seq undo-changes)) + (rx/of (dwu/append-undo + {:undo-changes undo-changes + :redo-changes redo-changes + :undo-group undo-group + :tags tags + :selected-before selected-before} + stack-undo?)) + (rx/empty)))) + (rx/take-until stopper-s)))))) + ;; Support for async events in tests ;; https://chat.kaleidos.net/penpot-partners/pl/tz1yoes3w3fr9qanxqpuhoz3ch (defn run-store diff --git a/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs b/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs index 9eb0be8dfa..a0c9eb3632 100644 --- a/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs +++ b/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs @@ -6,7 +6,6 @@ (ns frontend-tests.tokens.logic.token-actions-test (:require - [app.common.files.tokens :as cfo] [app.common.test-helpers.compositions :as ctho] [app.common.test-helpers.files :as cthf] [app.common.test-helpers.ids-map :as cthi] diff --git a/frontend/test/frontend_tests/tokens/logic/token_data_test.cljs b/frontend/test/frontend_tests/tokens/logic/token_data_test.cljs index 98a3b02bff..449e91bb91 100644 --- a/frontend/test/frontend_tests/tokens/logic/token_data_test.cljs +++ b/frontend/test/frontend_tests/tokens/logic/token_data_test.cljs @@ -13,6 +13,7 @@ [app.common.types.tokens-status :as ctos] [app.common.uuid :as uuid] [app.main.data.workspace.tokens.library-edit :as dwtl] + [app.main.data.workspace.undo :as dwu] [cljs.test :as t :include-macros true] [frontend-tests.helpers.pages :as thp] [frontend-tests.helpers.state :as ths] @@ -123,4 +124,32 @@ sets' (ctob/get-sets tokens-lib')] (t/testing "Set has been deleted" - (t/is (= (count sets') 0))))))))) \ No newline at end of file + (t/is (= (count sets') 0))))))))) + +(t/deftest set-tokens-source + (t/async + done + (let [file (setup-file-with-token-lib) + store (ths/setup-store file) + library-id (uuid/next)] + + ;; Phase 1: set tokens-source with undo watcher active + (tohs/run-store + store identity + [(tohs/watch-undo-stack) + (dwtl/set-tokens-source library-id)] + (fn [new-state] + (let [file-data' (-> (ths/get-file-from-state new-state) :data)] + (t/testing "tokens-source is set to the library id" + (t/is (= library-id (:tokens-source file-data')))))) + (tohs/stop-on ::dwtl/set-tokens-source)) + + ;; Phase 2: undo and verify restoration + (tohs/run-store + store done + [dwu/undo] + (fn [undone-state] + (let [file-data'' (-> (ths/get-file-from-state undone-state) :data)] + (t/testing "tokens-source is restored to nil" + (t/is (nil? (:tokens-source file-data'')))))) + (tohs/stop-on ::dwu/undo))))) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index fe5aa1e2e2..4f79a11209 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -7239,6 +7239,14 @@ msgstr "some templates in here" msgid "workspace.libraries.file-library" msgstr "File library" +#: src/app/main/ui/workspace/libraries.cljs:336 +msgid "workspace.libraries.tokens-source" +msgstr "Tokens source" + +#: src/app/main/ui/workspace/libraries.cljs:336 +msgid "workspace.libraries.set-as-tokens-source" +msgstr "Set as tokens source" + #: src/app/main/ui/workspace/libraries.cljs:100, src/app/main/ui/workspace/libraries.cljs:124 msgid "workspace.libraries.graphics" msgid_plural "workspace.libraries.graphics" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 0ba6b9c1db..db00b6ce63 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -7072,6 +7072,14 @@ msgstr "algunas plantillas aquĆ­" msgid "workspace.libraries.file-library" msgstr "Biblioteca del archivo" +#: src/app/main/ui/workspace/libraries.cljs:336 +msgid "workspace.libraries.tokens-source" +msgstr "Fuente de tokens" + +#: src/app/main/ui/workspace/libraries.cljs:336 +msgid "workspace.libraries.set-as-tokens-source" +msgstr "Activar fuente de tokens" + #: src/app/main/ui/workspace/libraries.cljs:100, src/app/main/ui/workspace/libraries.cljs:124 msgid "workspace.libraries.graphics" msgid_plural "workspace.libraries.graphics"