Add "advanced" events to variants

This commit is contained in:
Pablo Alba
2025-09-03 15:43:27 +02:00
parent 2f3b464715
commit 06441063f2
11 changed files with 151 additions and 36 deletions

View File

@@ -444,7 +444,10 @@
:fn (mg/resource "app/migrations/sql/0140-mod-file-change-table.sql")}
{:name "0140-add-locked-by-column-to-file-change-table"
:fn (mg/resource "app/migrations/sql/0140-add-locked-by-column-to-file-change-table.sql")}])
:fn (mg/resource "app/migrations/sql/0140-add-locked-by-column-to-file-change-table.sql")}
{:name "0141-add-idx-to-file_library_rel"
:fn (mg/resource "app/migrations/sql/0141-add-idx-to-file_library_rel.sql")}])
(defn apply-migrations!
[pool name migrations]

View File

@@ -0,0 +1,2 @@
CREATE INDEX file_library_rel__library_file_id__idx
ON file_library_rel (library_file_id);

View File

@@ -78,6 +78,7 @@
;; --- FILE PERMISSIONS
(def ^:private sql:file-permissions
"select fpr.is_owner,
fpr.is_admin,
@@ -460,8 +461,42 @@
(:has-libraries row)))
;; --- COMMAND QUERY: get-library-usage
(declare get-library-usage)
(def schema:get-library-usage
[:map {:title "get-library-usage"}
[:file-id ::sm/uuid]])
:sample
(sv/defmethod ::get-library-usage
"Gets the number of files that use the specified library."
{::doc/added "2.10.0"
::sm/params schema:get-library-usage
::sm/result ::sm/int}
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id file-id]}]
(dm/with-open [conn (db/open pool)]
(check-read-permissions! pool profile-id file-id)
(get-library-usage conn file-id)))
(def ^:private sql:get-library-usage
"SELECT COUNT(*) AS used
FROM file_library_rel AS flr
JOIN file AS fl ON (flr.library_file_id = fl.id)
WHERE flr.library_file_id = ?::uuid
AND (fl.deleted_at IS NULL OR
fl.deleted_at > now())")
(defn- get-library-usage
[conn file-id]
(let [row (db/exec-one! conn [sql:get-library-usage file-id])]
{:used-in (:used row)}))
;; --- QUERY COMMAND: get-page
(defn- prune-objects
"Given the page data and the object-id returns the page data with all
other not needed objects removed from the `:objects` data
@@ -551,6 +586,24 @@
;; --- COMMAND QUERY: get-team-shared-files
(defn- components-and-variants
"Return a set with all the variant-ids, and a list of components, but with
only one component by variant"
[components]
(let [{:keys [variant-ids components]}
(reduce (fn [{:keys [variant-ids components] :as acc} {:keys [variant-id] :as component}]
(cond
(nil? variant-id)
{:variant-ids variant-ids :components (conj components component)}
(contains? variant-ids variant-id)
acc
:else
{:variant-ids (conj variant-ids variant-id) :components (conj components component)}))
{:variant-ids #{} :components []}
components)]
{:components components
:variant-ids variant-ids}))
(def ^:private sql:team-shared-files
"select f.id,
f.revn,
@@ -584,10 +637,13 @@
:sample (into [] (take limit sorted-assets))}))]
(binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id)]
(let [load-objects (fn [component]
(ctf/load-component-objects data component))
components-sample (-> (assets-sample (ctkl/components data) 4)
(update :sample #(mapv load-objects %)))]
(let [load-objects (fn [component]
(ctf/load-component-objects data component))
comps-and-variants (components-and-variants (ctkl/components-seq data))
components (into {} (map (juxt :id identity) (:components comps-and-variants)))
components-sample (-> (assets-sample components 4)
(update :sample #(mapv load-objects %))
(assoc :variants-count (-> comps-and-variants :variant-ids count)))]
{:components components-sample
:media (assets-sample (:media data) 3)
:colors (assets-sample (:colors data) 3)
@@ -641,6 +697,7 @@
;; --- COMMAND QUERY: Files that use this File library
(def ^:private sql:library-using-files
"SELECT f.id,
f.name
@@ -713,6 +770,7 @@
;; --- COMMAND QUERY: get-file-summary
(defn- get-file-summary
[{:keys [::db/conn] :as cfg} {:keys [profile-id id project-id] :as params}]
(check-read-permissions! conn profile-id id)
@@ -730,11 +788,13 @@
(cfeat/check-file-features! (:features file)))
(binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id)]
{:name (:name file)
:components-count (count (ctkl/components-seq (:data file)))
:graphics-count (count (get-in file [:data :media] []))
:colors-count (count (get-in file [:data :colors] []))
:typography-count (count (get-in file [:data :typographies] []))})))
(let [components-and-variants (components-and-variants (ctkl/components-seq (:data file)))]
{:name (:name file)
:components-count (-> components-and-variants :components count)
:variants-count (-> components-and-variants :variant-ids count)
:graphics-count (count (get-in file [:data :media] []))
:colors-count (count (get-in file [:data :colors] []))
:typography-count (count (get-in file [:data :typographies] []))}))))
(sv/defmethod ::get-file-summary
"Retrieve a file summary by its ID. Only authenticated users."
@@ -746,6 +806,7 @@
;; --- COMMAND QUERY: get-file-info
(defn- get-file-info
[{:keys [::db/conn] :as cfg} {:keys [id] :as params}]
(db/get* conn :file

View File

@@ -438,8 +438,14 @@
ptk/WatchEvent
(watch [_ _ _]
(let [params {:id id :is-shared is-shared}]
(->> (rp/cmd! :set-file-shared params)
(rx/ignore))))))
(rx/concat
(->> (rp/cmd! :set-file-shared params)
(rx/ignore))
(when is-shared
(->> (rp/cmd! :get-file-summary {:id id})
(rx/map (fn [summary]
(when (pos? (:variants-count summary))
(ptk/event ::ev/event {::ev/name "set-file-variants-shared" ::ev/origin "dashboard"})))))))))))
(defn set-file-thumbnail
[file-id thumbnail-id]

View File

@@ -895,7 +895,10 @@
(let [parent-type (cfh/get-shape-type all-objects (:parent-id shape))
external-lib? (not= file-id (:component-file shape))
component (ctn/get-component-from-shape shape libraries)
origin "workspace:paste"]
origin "workspace:paste"
any-parent-is-variant (->> (cfh/get-parents-with-self all-objects (:parent-id shape))
(some ctc/is-variant?)
boolean)]
;; NOTE: we don't emit the create-shape event all the time for
;; avoid send a lot of events (that are not necessary); this
@@ -906,7 +909,8 @@
:is-external-library external-lib?
:type (get shape :type)
:parent-type parent-type
:is-variant (ctc/is-variant? component)})
:is-variant (ctc/is-variant? component)
:any-parent-is-variant any-parent-is-variant})
(if (cfh/has-layout? objects (:parent-id shape))
(ev/event {::ev/name "layout-add-element"
::ev/origin origin

View File

@@ -592,6 +592,9 @@
page
libraries)
component (ctn/get-component-from-shape new-shape libraries)
any-parent-is-variant (->> (cfh/get-parents-with-self objects (:parent-id new-shape))
(some ctk/is-variant?)
boolean)
undo-id (js/Symbol)]
@@ -602,7 +605,8 @@
{::ev/name "use-library-component"
::ev/origin origin
:external-library (not= file-id current-file-id)
:is-variant (ctk/is-variant? component)})
:is-variant (ctk/is-variant? component)
:any-parent-is-variant any-parent-is-variant})
(dwu/start-undo-transaction undo-id)
(dch/commit-changes changes)
(ptk/data-event :layout/update {:ids [(:id new-shape)]})
@@ -1364,10 +1368,19 @@
(update-in state [:files id] assoc :is-shared is-shared))
ptk/WatchEvent
(watch [_ _ _]
(let [params {:id id :is-shared is-shared}]
(->> (rp/cmd! :set-file-shared params)
(rx/ignore))))))
(watch [_ state _]
(let [params {:id id :is-shared is-shared}]
(rx/concat
(->> (rp/cmd! :set-file-shared params)
(rx/ignore))
(when is-shared
(let [has-variants? (->> (dsh/lookup-file-data state)
:components
vals
(some ctk/is-variant?))]
(if has-variants?
(rx/of (ptk/event ::ev/event {::ev/name "set-file-variants-shared" ::ev/origin "workspace"}))
(rx/empty)))))))))
;; --- Link and unlink Files
@@ -1395,7 +1408,10 @@
ptk/WatchEvent
(watch [_ state _]
(let [features (get state :features)]
(let [libraries (:shared-files state)
library (get libraries library-id)
features (get state :features)
variants-count (-> library :library-summary :components :variants-count)]
(rx/concat
(rx/merge
(->> (rp/cmd! :link-file-to-library {:file-id file-id :library-id library-id})
@@ -1412,7 +1428,15 @@
(rx/map (fn [thumbnails]
(fn [state]
(update state :thumbnails merge thumbnails))))))
(rx/of (ptk/reify ::attach-library-finished)))))))
(rx/of (ptk/reify ::attach-library-finished))
(when (pos? variants-count)
(->> (rp/cmd! :get-library-usage {:file-id library-id})
(rx/map (fn [library-usage]
(ptk/event ::ev/event {::ev/name "attach-library-variants"
:file-id file-id
:library-id library-id
:variants-count variants-count
:library-used-in (:used-in library-usage)}))))))))))
(defn unlink-file-from-library
[file-id library-id]

View File

@@ -486,7 +486,11 @@
parent-type (cfh/get-shape-type objects (:parent-id shape))
external-lib? (not= file-id (:component-file shape))
component (ctn/get-component-from-shape shape libraries)
origin "workspace:duplicate-shapes"]
origin "workspace:duplicate-shapes"
any-parent-is-variant (->> (cfh/get-parents-with-self objects (:parent-id shape))
(some ctk/is-variant?)
boolean)]
;; NOTE: we don't emit the create-shape event all the time for
;; avoid send a lot of events (that are not necessary); this
@@ -497,7 +501,8 @@
:is-external-library external-lib?
:type (get shape :type)
:parent-type parent-type
:is-variant (ctk/is-variant? component)})
:is-variant (ctk/is-variant? component)
:any-parent-is-variant any-parent-is-variant})
(if (cfh/has-layout? objects (:parent-id shape))
(ev/event {::ev/name "layout-add-element"
::ev/origin origin

View File

@@ -8,6 +8,7 @@
(:require
[app.common.data :as d]
[app.common.files.tokens :as cft]
[app.common.types.component :as ctk]
[app.common.types.shape.layout :as ctsl]
[app.common.types.shape.radius :as ctsr]
[app.common.types.shape.token :as ctst]
@@ -481,14 +482,14 @@
objects (dsh/lookup-page-objects state)
selected-shapes (select-keys objects shape-ids)
shape-ids (or (->> selected-shapes
(filter (fn [[_ shape]]
(or
(and (ctsl/any-layout-immediate-child? objects shape)
(some ctt/spacing-margin-keys attributes))
(ctt/any-appliable-attr? attributes (:type shape)))))
(keys))
[])
shapes (->> selected-shapes
(filter (fn [[_ shape]]
(or
(and (ctsl/any-layout-immediate-child? objects shape)
(some ctt/spacing-margin-keys attributes))
(ctt/any-appliable-attr? attributes (:type shape))))))
shape-ids (d/nilv (keys shapes) [])
any-variant? (->> shapes (some ctk/is-variant?) boolean)
resolved-value (get-in resolved-tokens [(cft/token-identifier token) :resolved-value])
tokenized-attributes (cft/attributes-map attributes token)
@@ -497,7 +498,8 @@
(rx/of
(st/emit! (ev/event {::ev/name "apply-tokens"
:type type
:applyed-to attributes}))
:applyed-to attributes
:applied-to-variant any-variant?}))
(dwu/start-undo-transaction undo-id)
(dwsh/update-shapes shape-ids (fn [shape]
(cond-> shape

View File

@@ -577,7 +577,9 @@
any-variant? (some ctk/is-variant? shapes)
do-add-component (mf/use-fn #(st/emit! (dwl/add-component)))
do-add-multiple-components (mf/use-fn #(st/emit! (dwl/add-multiple-components)))
do-combine-as-variants (mf/use-fn #(st/emit! (dwv/combine-as-variants)))
do-combine-as-variants (mf/use-fn #(st/emit!
(ptk/event ::ev/event {::ev/name "combine-as-variants" :trigger "context-menu-component"})
(dwv/combine-as-variants)))
do-add-variant (mf/use-fn
(mf/deps shapes)
#(st/emit!

View File

@@ -505,7 +505,9 @@
ids (into #{} (map :main-instance-id comps))
page-id (->> comps first :main-instance-page)]
(st/emit! (dwv/combine-as-variants ids {:page-id page-id})))))
(st/emit!
(ptk/event ::ev/event {::ev/name "combine-as-variants" :trigger "context-menu-assets-group"})
(dwv/combine-as-variants ids {:page-id page-id})))))
on-drag-start
@@ -554,7 +556,9 @@
(let [page-id (->> selected-and-current-full first :main-instance-page)
ids (into #{} (map :main-instance-id selected-full))]
(st/emit! (dwv/combine-as-variants ids {:page-id page-id})))))]
(st/emit!
(ptk/event ::ev/event {::ev/name "combine-as-variants" :trigger "context-menu-assets"})
(dwv/combine-as-variants ids {:page-id page-id})))))]
[:& cmm/asset-section {:file-id file-id
:title (tr "workspace.assets.components")

View File

@@ -909,7 +909,9 @@
on-combine-as-variants
(mf/use-fn
#(st/emit! (dwv/combine-as-variants)))
#(st/emit!
(ptk/event ::ev/event {::ev/name "combine-as-variants" :trigger "button-design-tab"})
(dwv/combine-as-variants)))
;; NOTE: function needed for force rerender from the bottom
;; components. This is because `component-annotation`