mirror of
https://github.com/penpot/penpot.git
synced 2026-06-26 09:12:06 +00:00
Merge remote-tracking branch 'origin/main' into staging
This commit is contained in:
commit
9259b596dc
@ -487,7 +487,13 @@
|
||||
:fn (mg/resource "app/migrations/sql/0149-mod-file-library-rel-synced-at.sql")}
|
||||
|
||||
{:name "0150-mod-http-session-v2"
|
||||
:fn (mg/resource "app/migrations/sql/0150-mod-http-session-v2.sql")}])
|
||||
:fn (mg/resource "app/migrations/sql/0150-mod-http-session-v2.sql")}
|
||||
|
||||
{:name "0150-mod-storage-object-table"
|
||||
:fn (mg/resource "app/migrations/sql/0150-mod-storage-object-table.sql")}
|
||||
|
||||
{:name "0151-mod-file-tagged-object-thumbnail-table"
|
||||
:fn (mg/resource "app/migrations/sql/0151-mod-file-tagged-object-thumbnail-table.sql")}])
|
||||
|
||||
(defn apply-migrations!
|
||||
[pool name migrations]
|
||||
|
||||
@ -0,0 +1 @@
|
||||
CREATE INDEX IF NOT EXISTS storage_object__metadata_upload_id__idx ON storage_object ((metadata->>'~:upload-id')) WHERE deleted_at IS NULL;
|
||||
@ -0,0 +1 @@
|
||||
CREATE INDEX IF NOT EXISTS file_tagged_object_thumbnail__object_id__idx ON file_tagged_object_thumbnail (object_id);
|
||||
@ -9,7 +9,7 @@
|
||||
data resources."
|
||||
(:refer-clojure :exclude [read-string hash-map merge name update-vals
|
||||
parse-double group-by iteration concat mapcat
|
||||
parse-uuid max min regexp? array?])
|
||||
parse-uuid max min regexp? array? empty?])
|
||||
#?(:cljs
|
||||
(:require-macros [app.common.data]))
|
||||
|
||||
@ -175,11 +175,17 @@
|
||||
(.isArray (class o))
|
||||
false)))
|
||||
|
||||
(defn empty?
|
||||
[val]
|
||||
(if (or (coll? val) (string? val))
|
||||
(clojure.core/empty? val)
|
||||
(nil? val)))
|
||||
|
||||
(defn not-empty?
|
||||
[coll]
|
||||
(if (coll? coll)
|
||||
(boolean (seq coll))
|
||||
(not (nil? coll))))
|
||||
[val]
|
||||
(if (or (coll? val) (string? val))
|
||||
(boolean (seq val))
|
||||
(some? val)))
|
||||
|
||||
(defn editable-collection?
|
||||
[m]
|
||||
|
||||
@ -6,12 +6,14 @@
|
||||
|
||||
(ns app.common.test-helpers.tokens
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.test-helpers.files :as thf]
|
||||
[app.common.test-helpers.shapes :as ths]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.types.text :as ctt]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.tokens-lib :as ctob]))
|
||||
|
||||
@ -81,11 +83,16 @@
|
||||
:token {:name token-name}
|
||||
:attributes token-attrs})
|
||||
(reduce (fn [shape attr]
|
||||
(case attr
|
||||
:stroke-width (set-stroke-width shape resolved-value)
|
||||
:stroke-color (set-stroke-color shape resolved-value)
|
||||
:fill (set-fill-color shape resolved-value)
|
||||
(ctn/set-shape-attr shape attr resolved-value {:ignore-touched true})))
|
||||
(if (ctt/text-node-attr? attr)
|
||||
(let [value (if (sequential? resolved-value) (first resolved-value) resolved-value)]
|
||||
(ctt/update-text-content shape
|
||||
ctt/is-content-node?
|
||||
d/txt-merge {attr value}))
|
||||
(case attr
|
||||
:stroke-width (set-stroke-width shape resolved-value)
|
||||
:stroke-color (set-stroke-color shape resolved-value)
|
||||
:fill (set-fill-color shape resolved-value)
|
||||
(ctn/set-shape-attr shape attr resolved-value {:ignore-touched true}))))
|
||||
$
|
||||
shape-attrs)))]
|
||||
|
||||
|
||||
@ -78,6 +78,10 @@
|
||||
text-transform-attrs
|
||||
text-fills))
|
||||
|
||||
(defn text-node-attr?
|
||||
[attr]
|
||||
(d/index-of text-node-attrs attr))
|
||||
|
||||
(def text-all-attrs (d/concat-set shape-attrs root-attrs paragraph-attrs text-node-attrs))
|
||||
|
||||
(def text-style-attrs
|
||||
@ -201,6 +205,27 @@
|
||||
[text]
|
||||
(subs text 0 (min 280 (count text))))
|
||||
|
||||
(defn- compare-text-attr
|
||||
"Compare two attribute values and return true if they are different.
|
||||
Take into account the following:
|
||||
- Only process keys that belong to text node attrs (ignore deprecated
|
||||
attributes or other things that may be attached).
|
||||
- Consider nil values, empty strings or empty lists all equal.
|
||||
- Normalize numeric values (legacy) into strings.
|
||||
- No value is equal than the default value."
|
||||
[key value1 value2]
|
||||
(when (text-node-attr? key)
|
||||
(let [default-value (get default-text-attrs key)
|
||||
normalize-value (fn [value]
|
||||
(as-> value $
|
||||
(if (number? $) (str $) $)
|
||||
(if (or (d/empty? $) (= $ default-value))
|
||||
nil
|
||||
$)))
|
||||
value1' (normalize-value value1)
|
||||
value2' (normalize-value value2)]
|
||||
(not= value1' value2'))))
|
||||
|
||||
(defn- compare-text-content
|
||||
"Given two content text structures, conformed by maps and vectors,
|
||||
compare them, and returns a set with the differences info.
|
||||
@ -245,8 +270,7 @@
|
||||
;; If the key is not :text, and they are different, it is an attribute difference.
|
||||
;; Take into account that some processes remove empty attributes, so in some
|
||||
;; cases we will compare [] with nil, and this is not a difference.
|
||||
(if (and (not= v1 v2)
|
||||
(or (d/not-empty? v1) (d/not-empty? v2)))
|
||||
(if (compare-text-attr k v1 v2)
|
||||
(attribute-cb acc k)
|
||||
acc))))
|
||||
#{}
|
||||
|
||||
@ -111,8 +111,8 @@
|
||||
(tht/apply-token-to-shape :frame1 "token-color" [:stroke-color] [:stroke-color] "#00ff00")
|
||||
(tht/apply-token-to-shape :frame1 "token-color" [:fill] [:fill] "#00ff00")
|
||||
(tht/apply-token-to-shape :frame1 "token-dimensions" [:width :height] [:width :height] 100)
|
||||
(tht/apply-token-to-shape :text1 "token-font-size" [:font-size] [:font-size] 24)
|
||||
(tht/apply-token-to-shape :text1 "token-letter-spacing" [:letter-spacing] [:letter-spacing] 2)
|
||||
(tht/apply-token-to-shape :text1 "token-font-size" [:font-size] [:font-size] "24")
|
||||
(tht/apply-token-to-shape :text1 "token-letter-spacing" [:letter-spacing] [:letter-spacing] "2")
|
||||
(tht/apply-token-to-shape :text1 "token-font-family" [:font-family] [:font-family] ["Helvetica" "Arial" "sans-serif"])
|
||||
(tht/apply-token-to-shape :circle1
|
||||
"token-sizing"
|
||||
@ -331,7 +331,7 @@
|
||||
d/txt-merge
|
||||
{:fills (ths/sample-fills-color :fill-color "#fabada")
|
||||
:font-size "1"
|
||||
:letter-spacing "0"
|
||||
:letter-spacing "3"
|
||||
:font-family "Arial"}))
|
||||
(:objects page)
|
||||
{})
|
||||
@ -360,3 +360,40 @@
|
||||
(t/is (= (count applied-tokens-frame') 0))
|
||||
(t/is (= (count applied-tokens-text') 0))
|
||||
(t/is (= (count applied-tokens-circle') 0))))
|
||||
|
||||
(t/deftest dont-unapply-automatic-when-null-change
|
||||
(let [;; ==== Setup
|
||||
file (-> (setup-file)
|
||||
(tht/apply-token-to-shape :text1 "token-font-size" [:font-size] [:font-size] "14")
|
||||
(tht/apply-token-to-shape :text1 "token-letter-spacing" [:letter-spacing] [:letter-spacing] "2")
|
||||
(tht/apply-token-to-shape :text1 "token-font-family" [:font-family] [:font-family] ["Helvetica" "Arial" "sans-serif"]))
|
||||
page (thf/current-page file)
|
||||
text1 (ths/get-shape file :text1)
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page page)
|
||||
(pcb/with-objects (:objects page)))
|
||||
;; Some changes in text content are not semantic changes
|
||||
;; and thus they don't unapply tokens (e.g. adding an attribute
|
||||
;; with value nil or with the default value).
|
||||
(cls/generate-update-shapes [(:id text1)]
|
||||
(fn [shape]
|
||||
(txt/update-text-content
|
||||
shape
|
||||
txt/is-content-node?
|
||||
d/txt-merge
|
||||
{:font-size nil
|
||||
:line-height "3"
|
||||
:nonexistent-attr "sample value"}))
|
||||
(:objects page)
|
||||
{}))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
text1' (ths/get-shape file' :text1)
|
||||
applied-tokens-text' (:applied-tokens text1')]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (count applied-tokens-text') 3))))
|
||||
@ -16,6 +16,8 @@
|
||||
(get :content)
|
||||
(cttx/change-text "hello world")))
|
||||
|
||||
;; Normal happy-path changes
|
||||
|
||||
(def content-changed-text
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :text] "changed"))
|
||||
|
||||
@ -34,22 +36,127 @@
|
||||
(update-in content-base [:children 0 :children 0 :children]
|
||||
#(conj % (assoc line :font-weight "700"))))
|
||||
|
||||
|
||||
(def content-changed-structure-same-attrs
|
||||
(update-in content-base [:children 0 :children 0 :children] #(conj % line)))
|
||||
|
||||
;; Special cases
|
||||
|
||||
;; Numeric value (legacy): number 14 should normalize to string "14",
|
||||
;; which equals the default value in content-base
|
||||
(def content-numeric-font-size-default
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :font-size] 14))
|
||||
|
||||
;; Numeric value (legacy): number 32 should normalize to string "32",
|
||||
;; matching content-changed-attr (which uses string "32")
|
||||
(def content-numeric-font-size-32
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :font-size] 32))
|
||||
|
||||
;; Attribute set to nil (removed)
|
||||
(def content-nil-font-size
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :font-size] nil))
|
||||
|
||||
;; Attribute set to empty string
|
||||
(def content-empty-string-font-size
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :font-size] ""))
|
||||
|
||||
;; Attribute set to empty vector
|
||||
(def content-empty-list-font-size
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :font-size] []))
|
||||
|
||||
;; Attribute set to its default value (font-size default is "14")
|
||||
(def content-default-font-size
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :font-size] "14"))
|
||||
|
||||
;; Non-text-node-attr key change (grow-type is not in text-node-attrs)
|
||||
(def content-non-text-node-attr
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :grow-type] "auto-height"))
|
||||
|
||||
;; Other text-node-attr categories
|
||||
(def content-changed-font-family
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :font-family] "Arial"))
|
||||
|
||||
(def content-changed-line-height
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :line-height] "1.5"))
|
||||
|
||||
(def content-changed-letter-spacing
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :letter-spacing] "2"))
|
||||
|
||||
(def content-changed-text-decoration
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :text-decoration] "underline"))
|
||||
|
||||
(def content-changed-text-transform
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :text-transform] "uppercase"))
|
||||
|
||||
(def content-changed-typography-ref-id
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :typography-ref-id] "new-typography-id"))
|
||||
|
||||
(def content-changed-fills
|
||||
(assoc-in content-base [:children 0 :children 0 :children 0 :fills]
|
||||
[{:fill-color "#ff0000" :fill-opacity 1}]))
|
||||
|
||||
|
||||
(t/deftest test-get-diff-type
|
||||
(let [diff-text (cttx/get-diff-type content-base content-changed-text)
|
||||
diff-attr (cttx/get-diff-type content-base content-changed-attr)
|
||||
diff-both (cttx/get-diff-type content-base content-changed-both)
|
||||
diff-structure (cttx/get-diff-type content-base content-changed-structure)
|
||||
diff-structure-same-attrs (cttx/get-diff-type content-base content-changed-structure-same-attrs)]
|
||||
diff-structure-same-attrs (cttx/get-diff-type content-base content-changed-structure-same-attrs)
|
||||
|
||||
;; Numeric normalization: number 14 → string "14" → default → nil (same as base)
|
||||
diff-numeric-default (cttx/get-diff-type content-base content-numeric-font-size-default)
|
||||
;; Numeric normalization: number 32 → string "32" (different from base's "14")
|
||||
diff-numeric-different (cttx/get-diff-type content-base content-numeric-font-size-32)
|
||||
;; Numeric 32 vs string "32": should be equal after normalization
|
||||
diff-numeric-vs-string (cttx/get-diff-type content-changed-attr content-numeric-font-size-32)
|
||||
|
||||
;; nil / empty-string / empty-list / default → all normalize to nil
|
||||
diff-nil-attr (cttx/get-diff-type content-base content-nil-font-size)
|
||||
diff-empty-string (cttx/get-diff-type content-base content-empty-string-font-size)
|
||||
diff-empty-list (cttx/get-diff-type content-base content-empty-list-font-size)
|
||||
diff-default-value (cttx/get-diff-type content-base content-default-font-size)
|
||||
|
||||
;; Non-text-node-attr key: should be ignored
|
||||
diff-non-text-node (cttx/get-diff-type content-base content-non-text-node-attr)
|
||||
|
||||
;; Other text-node-attr categories
|
||||
diff-font-family (cttx/get-diff-type content-base content-changed-font-family)
|
||||
diff-line-height (cttx/get-diff-type content-base content-changed-line-height)
|
||||
diff-letter-spacing (cttx/get-diff-type content-base content-changed-letter-spacing)
|
||||
diff-text-decoration (cttx/get-diff-type content-base content-changed-text-decoration)
|
||||
diff-text-transform (cttx/get-diff-type content-base content-changed-text-transform)
|
||||
diff-typography-ref (cttx/get-diff-type content-base content-changed-typography-ref-id)
|
||||
diff-fills (cttx/get-diff-type content-base content-changed-fills)]
|
||||
|
||||
;; Basic cases
|
||||
(t/is (= #{:text-content-text} diff-text))
|
||||
(t/is (= #{:text-content-attribute} diff-attr))
|
||||
(t/is (= #{:text-content-text :text-content-attribute} diff-both))
|
||||
(t/is (= #{:text-content-structure} diff-structure))
|
||||
(t/is (= #{:text-content-structure} diff-structure-same-attrs))))
|
||||
(t/is (= #{:text-content-structure} diff-structure-same-attrs))
|
||||
|
||||
;; Numeric normalization
|
||||
(t/is (= #{} diff-numeric-default))
|
||||
(t/is (= #{:text-content-attribute} diff-numeric-different))
|
||||
(t/is (= #{} diff-numeric-vs-string))
|
||||
|
||||
;; nil / empty / default normalization (content-base has default font-size "14",
|
||||
;; which normalizes to nil; nil also normalizes to nil → equal)
|
||||
(t/is (= #{} diff-nil-attr))
|
||||
(t/is (= #{} diff-empty-string))
|
||||
(t/is (= #{} diff-empty-list))
|
||||
(t/is (= #{} diff-default-value))
|
||||
|
||||
;; Non-text-node-attr key is ignored
|
||||
(t/is (= #{} diff-non-text-node))
|
||||
|
||||
;; Each text-node-attr category triggers attribute diff
|
||||
(t/is (= #{:text-content-attribute} diff-font-family))
|
||||
(t/is (= #{:text-content-attribute} diff-line-height))
|
||||
(t/is (= #{:text-content-attribute} diff-letter-spacing))
|
||||
(t/is (= #{:text-content-attribute} diff-text-decoration))
|
||||
(t/is (= #{:text-content-attribute} diff-text-transform))
|
||||
(t/is (= #{:text-content-attribute} diff-typography-ref))
|
||||
(t/is (= #{:text-content-attribute} diff-fills))))
|
||||
|
||||
|
||||
(t/deftest test-get-diff-attrs
|
||||
@ -57,13 +164,62 @@
|
||||
attrs-attr (cttx/get-diff-attrs content-base content-changed-attr)
|
||||
attrs-both (cttx/get-diff-attrs content-base content-changed-both)
|
||||
attrs-structure (cttx/get-diff-attrs content-base content-changed-structure)
|
||||
attrs-structure-same-attrs (cttx/get-diff-attrs content-base content-changed-structure-same-attrs)]
|
||||
attrs-structure-same-attrs (cttx/get-diff-attrs content-base content-changed-structure-same-attrs)
|
||||
|
||||
;; Numeric normalization: number 14 → string "14" → default → nil (same as base)
|
||||
attrs-numeric-default (cttx/get-diff-attrs content-base content-numeric-font-size-default)
|
||||
;; Numeric normalization: number 32 → string "32" (different from base's "14")
|
||||
attrs-numeric-different (cttx/get-diff-attrs content-base content-numeric-font-size-32)
|
||||
;; Numeric 32 vs string "32": should be equal after normalization
|
||||
attrs-numeric-vs-string (cttx/get-diff-attrs content-changed-attr content-numeric-font-size-32)
|
||||
|
||||
;; nil / empty-string / empty-list / default → all normalize to nil
|
||||
attrs-nil-attr (cttx/get-diff-attrs content-base content-nil-font-size)
|
||||
attrs-empty-string (cttx/get-diff-attrs content-base content-empty-string-font-size)
|
||||
attrs-empty-list (cttx/get-diff-attrs content-base content-empty-list-font-size)
|
||||
attrs-default-value (cttx/get-diff-attrs content-base content-default-font-size)
|
||||
|
||||
;; Non-text-node-attr key: should be ignored
|
||||
attrs-non-text-node (cttx/get-diff-attrs content-base content-non-text-node-attr)
|
||||
|
||||
;; Other text-node-attr categories
|
||||
attrs-font-family (cttx/get-diff-attrs content-base content-changed-font-family)
|
||||
attrs-line-height (cttx/get-diff-attrs content-base content-changed-line-height)
|
||||
attrs-letter-spacing (cttx/get-diff-attrs content-base content-changed-letter-spacing)
|
||||
attrs-text-decoration (cttx/get-diff-attrs content-base content-changed-text-decoration)
|
||||
attrs-text-transform (cttx/get-diff-attrs content-base content-changed-text-transform)
|
||||
attrs-typography-ref (cttx/get-diff-attrs content-base content-changed-typography-ref-id)
|
||||
attrs-fills (cttx/get-diff-attrs content-base content-changed-fills)]
|
||||
|
||||
;; Basic cases
|
||||
(t/is (= #{} attrs-text))
|
||||
(t/is (= #{:font-size} attrs-attr))
|
||||
(t/is (= #{:font-size} attrs-both))
|
||||
(t/is (= #{} attrs-structure))
|
||||
(t/is (= #{} attrs-structure-same-attrs))))
|
||||
(t/is (= #{} attrs-structure-same-attrs))
|
||||
|
||||
;; Numeric normalization
|
||||
(t/is (= #{} attrs-numeric-default))
|
||||
(t/is (= #{:font-size} attrs-numeric-different))
|
||||
(t/is (= #{} attrs-numeric-vs-string))
|
||||
|
||||
;; nil / empty / default normalization
|
||||
(t/is (= #{} attrs-nil-attr))
|
||||
(t/is (= #{} attrs-empty-string))
|
||||
(t/is (= #{} attrs-empty-list))
|
||||
(t/is (= #{} attrs-default-value))
|
||||
|
||||
;; Non-text-node-attr key is ignored
|
||||
(t/is (= #{} attrs-non-text-node))
|
||||
|
||||
;; Each text-node-attr category reports correct attr key
|
||||
(t/is (= #{:font-family} attrs-font-family))
|
||||
(t/is (= #{:line-height} attrs-line-height))
|
||||
(t/is (= #{:letter-spacing} attrs-letter-spacing))
|
||||
(t/is (= #{:text-decoration} attrs-text-decoration))
|
||||
(t/is (= #{:text-transform} attrs-text-transform))
|
||||
(t/is (= #{:typography-ref-id} attrs-typography-ref))
|
||||
(t/is (= #{:fills} attrs-fills))))
|
||||
|
||||
|
||||
(t/deftest test-equal-structure
|
||||
|
||||
@ -399,6 +399,7 @@
|
||||
(fn [_]
|
||||
;; Start the event collection pipeline
|
||||
(->> (rx/merge
|
||||
(rx/filter (ptk/type? ::force-persist) stream)
|
||||
(->> (rx/from-atom buffer)
|
||||
(rx/filter #(pos? (count %)))
|
||||
(rx/debounce 2000))
|
||||
@ -416,6 +417,7 @@
|
||||
(rx/map (constantly chunk))))))
|
||||
(rx/take-until stopper)
|
||||
(rx/subs! (fn [chunk]
|
||||
(st/emit! (ptk/data-event ::chunk-persisted {:chunk chunk}))
|
||||
(swap! buffer remove-from-buffer (count chunk)))
|
||||
(fn [cause]
|
||||
(l/error :hint "unexpected error on audit persistence" :cause cause))
|
||||
|
||||
@ -45,6 +45,7 @@
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc shortcuts*
|
||||
@ -958,17 +959,24 @@
|
||||
ev-name (if (= next-renderer :wasm)
|
||||
"enable-webgl-rendering"
|
||||
"disable-webgl-rendering")]
|
||||
|
||||
(if (cf/external-feature-flag "renderer-hard-reload" "test")
|
||||
;; Bare RPC + hard reload: skips `du/update-profile-props`, so
|
||||
;; `features/recompute-features` is not run here; bootstrap
|
||||
;; after reload resolves render-wasm/v1 from the saved profile.
|
||||
(do
|
||||
(st/emit! (ev/event {::ev/name ev-name
|
||||
::ev/origin "workspace:menu"}))
|
||||
(->> (rp/cmd! :update-profile-props {:props {:renderer next-renderer}})
|
||||
(rx/subs! (fn [_] (dom/reload-current-window true))
|
||||
(->> (rx/zip
|
||||
(rp/cmd! :update-profile-props {:props {:renderer next-renderer}})
|
||||
(rx/filter (ptk/type? ::ev/chunk-persisted) st/stream))
|
||||
(rx/timeout 2000 (rx/of :timeout))
|
||||
(rx/subs! (fn [_]
|
||||
(dom/reload-current-window true))
|
||||
(fn [_]
|
||||
(st/emit! (ntf/error (tr "errors.generic")))))))
|
||||
(st/emit! (ntf/error (tr "errors.generic"))))))
|
||||
(st/emit! (ev/event {::ev/name ev-name
|
||||
::ev/origin "workspace:menu"})
|
||||
(ptk/data-event ::ev/force-persist {})))
|
||||
|
||||
;; `update-profile-props` WatchEvent calls
|
||||
;; `features/recompute-features`.
|
||||
(st/emit! (ev/event {::ev/name ev-name
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user