mirror of
https://github.com/penpot/penpot.git
synced 2025-08-06 08:08:29 +02:00
🎉 Allow duplicate/copy-paste/cut-paste variants
This commit is contained in:
parent
076d64df8f
commit
f04229d8cb
6 changed files with 191 additions and 103 deletions
|
@ -352,7 +352,8 @@
|
||||||
[:map {:title "RestoreComponentChange"}
|
[:map {:title "RestoreComponentChange"}
|
||||||
[:type [:= :restore-component]]
|
[:type [:= :restore-component]]
|
||||||
[:id ::sm/uuid]
|
[:id ::sm/uuid]
|
||||||
[:page-id ::sm/uuid]]]
|
[:page-id ::sm/uuid]
|
||||||
|
[:parent-id {:optional true} [:maybe ::sm/uuid]]]]
|
||||||
|
|
||||||
[:purge-component
|
[:purge-component
|
||||||
[:map {:title "PurgeComponentChange"}
|
[:map {:title "PurgeComponentChange"}
|
||||||
|
@ -963,8 +964,8 @@
|
||||||
(ctf/delete-component data id skip-undelete? main-instance))
|
(ctf/delete-component data id skip-undelete? main-instance))
|
||||||
|
|
||||||
(defmethod process-change :restore-component
|
(defmethod process-change :restore-component
|
||||||
[data {:keys [id page-id]}]
|
[data {:keys [id page-id parent-id]}]
|
||||||
(ctf/restore-component data id page-id))
|
(ctf/restore-component data id page-id parent-id))
|
||||||
|
|
||||||
(defmethod process-change :purge-component
|
(defmethod process-change :purge-component
|
||||||
[data {:keys [id]}]
|
[data {:keys [id]}]
|
||||||
|
|
|
@ -1041,12 +1041,13 @@
|
||||||
:page-id page-id})))
|
:page-id page-id})))
|
||||||
|
|
||||||
(defn restore-component
|
(defn restore-component
|
||||||
[changes id page-id main-instance]
|
[changes id page-id main-instance parent-id]
|
||||||
(assert-library! changes)
|
(assert-library! changes)
|
||||||
(-> changes
|
(-> changes
|
||||||
(update :redo-changes conj {:type :restore-component
|
(update :redo-changes conj {:type :restore-component
|
||||||
:id id
|
:id id
|
||||||
:page-id page-id})
|
:page-id page-id
|
||||||
|
:parent-id parent-id})
|
||||||
(update :undo-changes conj {:type :del-component
|
(update :undo-changes conj {:type :del-component
|
||||||
:id id
|
:id id
|
||||||
:main-instance main-instance})))
|
:main-instance main-instance})))
|
||||||
|
|
|
@ -68,7 +68,8 @@
|
||||||
:variant-bad-name
|
:variant-bad-name
|
||||||
:variant-bad-variant-name
|
:variant-bad-variant-name
|
||||||
:variant-component-bad-name
|
:variant-component-bad-name
|
||||||
:variant-no-properties})
|
:variant-no-properties
|
||||||
|
:variant-component-bad-id})
|
||||||
|
|
||||||
(def ^:private schema:error
|
(def ^:private schema:error
|
||||||
[:map {:title "ValidationError"}
|
[:map {:title "ValidationError"}
|
||||||
|
@ -469,6 +470,10 @@
|
||||||
(when-not (= (:name parent) (cfh/merge-path-item (:path component) (:name component)))
|
(when-not (= (:name parent) (cfh/merge-path-item (:path component) (:name component)))
|
||||||
(report-error :variant-component-bad-name
|
(report-error :variant-component-bad-name
|
||||||
(str/ffmt "Component % has an invalid name" (:id shape))
|
(str/ffmt "Component % has an invalid name" (:id shape))
|
||||||
|
shape file page))
|
||||||
|
(when-not (= (:variant-id component) (:variant-id shape))
|
||||||
|
(report-error :variant-component-bad-id
|
||||||
|
(str/ffmt "Variant % has adifferent variant-id than its component" (:id shape))
|
||||||
shape file page))))
|
shape file page))))
|
||||||
|
|
||||||
(defn- check-shape
|
(defn- check-shape
|
||||||
|
|
|
@ -103,84 +103,76 @@
|
||||||
(defn- duplicate-component
|
(defn- duplicate-component
|
||||||
"Clone the root shape of the component and all children. Generate new
|
"Clone the root shape of the component and all children. Generate new
|
||||||
ids from all of them."
|
ids from all of them."
|
||||||
[component new-component-id library-data force-id]
|
[component new-component-id library-data force-id delta variant-id]
|
||||||
(let [components-v2 (dm/get-in library-data [:options :components-v2])]
|
(let [main-instance-page (ctf/get-component-page library-data component)
|
||||||
(if components-v2
|
main-instance-shape (ctf/get-component-root library-data component)
|
||||||
(let [main-instance-page (ctf/get-component-page library-data component)
|
delta (or delta (gpt/point (+ (:width main-instance-shape) 50) 0))
|
||||||
main-instance-shape (ctf/get-component-root library-data component)
|
|
||||||
delta (gpt/point (+ (:width main-instance-shape) 50) 0)
|
|
||||||
|
|
||||||
ids-map (volatile! {})
|
ids-map (volatile! {})
|
||||||
inverted-ids-map (volatile! {})
|
inverted-ids-map (volatile! {})
|
||||||
nested-main-heads (volatile! #{})
|
nested-main-heads (volatile! #{})
|
||||||
|
|
||||||
update-original-shape
|
update-original-shape
|
||||||
(fn [original-shape new-shape]
|
(fn [original-shape new-shape]
|
||||||
; Save some ids for later
|
; Save some ids for later
|
||||||
(vswap! ids-map assoc (:id original-shape) (:id new-shape))
|
(vswap! ids-map assoc (:id original-shape) (:id new-shape))
|
||||||
(vswap! inverted-ids-map assoc (:id new-shape) (:id original-shape))
|
(vswap! inverted-ids-map assoc (:id new-shape) (:id original-shape))
|
||||||
(when (and (ctk/main-instance? original-shape)
|
(when (and (ctk/main-instance? original-shape)
|
||||||
(not= (:component-id original-shape) (:id component)))
|
(not= (:component-id original-shape) (:id component)))
|
||||||
(vswap! nested-main-heads conj (:id original-shape)))
|
(vswap! nested-main-heads conj (:id original-shape)))
|
||||||
original-shape)
|
original-shape)
|
||||||
|
|
||||||
update-new-shape
|
update-new-shape
|
||||||
(fn [new-shape _]
|
(fn [new-shape _]
|
||||||
(cond-> new-shape
|
(cond-> new-shape
|
||||||
; Link the new main to the new component
|
; Link the new main to the new component
|
||||||
(= (:component-id new-shape) (:id component))
|
(= (:component-id new-shape) (:id component))
|
||||||
(assoc :component-id new-component-id)
|
(assoc :component-id new-component-id)
|
||||||
|
|
||||||
:always
|
(some? variant-id)
|
||||||
(gsh/move delta)))
|
(assoc :variant-id variant-id)
|
||||||
|
|
||||||
[new-instance-shape new-instance-shapes _]
|
:always
|
||||||
(ctst/clone-shape main-instance-shape
|
(gsh/move delta)))
|
||||||
(:parent-id main-instance-shape)
|
|
||||||
(:objects main-instance-page)
|
|
||||||
:update-new-shape update-new-shape
|
|
||||||
:update-original-shape update-original-shape
|
|
||||||
:force-id force-id)
|
|
||||||
|
|
||||||
remap-frame
|
[new-instance-shape new-instance-shapes _]
|
||||||
(fn [shape]
|
(ctst/clone-shape main-instance-shape
|
||||||
|
(:parent-id main-instance-shape)
|
||||||
|
(:objects main-instance-page)
|
||||||
|
:update-new-shape update-new-shape
|
||||||
|
:update-original-shape update-original-shape
|
||||||
|
:force-id force-id)
|
||||||
|
|
||||||
|
remap-frame
|
||||||
|
(fn [shape]
|
||||||
; Remap all frame-ids internal to the component to the new shapes
|
; Remap all frame-ids internal to the component to the new shapes
|
||||||
(update shape :frame-id
|
(update shape :frame-id
|
||||||
#(get @ids-map % (:frame-id shape))))
|
#(get @ids-map % (:frame-id shape))))
|
||||||
|
|
||||||
convert-nested-main
|
convert-nested-main
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
; If there is some nested main instance, convert it into a copy of
|
; If there is some nested main instance, convert it into a copy of
|
||||||
; main nested in the original component.
|
; main nested in the original component.
|
||||||
(let [origin-shape-id (get @inverted-ids-map (:id shape))
|
(let [origin-shape-id (get @inverted-ids-map (:id shape))
|
||||||
objects (:objects main-instance-page)
|
objects (:objects main-instance-page)
|
||||||
parent-ids (cfh/get-parent-ids-seq-with-self objects origin-shape-id)]
|
parent-ids (cfh/get-parent-ids-seq-with-self objects origin-shape-id)]
|
||||||
(cond-> shape
|
(cond-> shape
|
||||||
(@nested-main-heads origin-shape-id)
|
(@nested-main-heads origin-shape-id)
|
||||||
(dissoc :main-instance)
|
(dissoc :main-instance)
|
||||||
|
|
||||||
(some @nested-main-heads parent-ids)
|
(some @nested-main-heads parent-ids)
|
||||||
(assoc :shape-ref origin-shape-id))))
|
(assoc :shape-ref origin-shape-id))))
|
||||||
|
|
||||||
xf-shape (comp (map remap-frame)
|
xf-shape (comp (map remap-frame)
|
||||||
(map convert-nested-main))
|
(map convert-nested-main))
|
||||||
|
|
||||||
new-instance-shapes (into [] xf-shape new-instance-shapes)]
|
new-instance-shapes (into [] xf-shape new-instance-shapes)]
|
||||||
|
|
||||||
[nil nil new-instance-shape new-instance-shapes])
|
[nil nil new-instance-shape new-instance-shapes]))
|
||||||
|
|
||||||
(let [component-root (d/seek #(nil? (:parent-id %)) (vals (:objects component)))
|
|
||||||
|
|
||||||
[new-component-shape new-component-shapes _]
|
|
||||||
(ctst/clone-shape component-root
|
|
||||||
nil
|
|
||||||
(get component :objects))]
|
|
||||||
|
|
||||||
[new-component-shape new-component-shapes nil nil]))))
|
|
||||||
|
|
||||||
(defn generate-duplicate-component
|
(defn generate-duplicate-component
|
||||||
"Create a new component copied from the one with the given id."
|
"Create a new component copied from the one with the given id."
|
||||||
[changes library component-id new-component-id components-v2 & {:keys [new-shape-id apply-changes-local-library?]}]
|
[changes library component-id new-component-id components-v2 & {:keys [new-shape-id apply-changes-local-library? delta new-variant-id]}]
|
||||||
(let [component (ctkl/get-component (:data library) component-id)
|
(let [component (ctkl/get-component (:data library) component-id)
|
||||||
new-name (:name component)
|
new-name (:name component)
|
||||||
|
|
||||||
|
@ -192,7 +184,7 @@
|
||||||
|
|
||||||
[new-component-shape new-component-shapes ; <- null in components-v2
|
[new-component-shape new-component-shapes ; <- null in components-v2
|
||||||
new-main-instance-shape new-main-instance-shapes]
|
new-main-instance-shape new-main-instance-shapes]
|
||||||
(duplicate-component component new-component-id (:data library) new-shape-id)]
|
(duplicate-component component new-component-id (:data library) new-shape-id delta new-variant-id)]
|
||||||
|
|
||||||
[new-main-instance-shape
|
[new-main-instance-shape
|
||||||
(-> changes
|
(-> changes
|
||||||
|
@ -209,7 +201,7 @@
|
||||||
(:id new-main-instance-shape)
|
(:id new-main-instance-shape)
|
||||||
(:id main-instance-page)
|
(:id main-instance-page)
|
||||||
(:annotation component)
|
(:annotation component)
|
||||||
(:variant-id component)
|
(or new-variant-id (:variant-id component))
|
||||||
(:variant-properties component)
|
(:variant-properties component)
|
||||||
{:apply-changes-local-library? apply-changes-local-library?})
|
{:apply-changes-local-library? apply-changes-local-library?})
|
||||||
;; Update grid layout if the new main instance is inside
|
;; Update grid layout if the new main instance is inside
|
||||||
|
@ -376,6 +368,7 @@
|
||||||
inside-component? (some? (ctn/get-instance-root (:objects page) parent))
|
inside-component? (some? (ctn/get-instance-root (:objects page) parent))
|
||||||
shapes (cfh/get-children-with-self (:objects component) (:main-instance-id component))
|
shapes (cfh/get-children-with-self (:objects component) (:main-instance-id component))
|
||||||
shapes (map #(gsh/move % delta) shapes)
|
shapes (map #(gsh/move % delta) shapes)
|
||||||
|
is-variant? (ctk/is-variant? component)
|
||||||
|
|
||||||
first-shape (cond-> (first shapes)
|
first-shape (cond-> (first shapes)
|
||||||
(not (nil? parent-id))
|
(not (nil? parent-id))
|
||||||
|
@ -389,7 +382,9 @@
|
||||||
inside-component?
|
inside-component?
|
||||||
(dissoc :component-root)
|
(dissoc :component-root)
|
||||||
(not inside-component?)
|
(not inside-component?)
|
||||||
(assoc :component-root true))
|
(assoc :component-root true)
|
||||||
|
(and is-variant? (some? parent-id))
|
||||||
|
(assoc :variant-id parent-id))
|
||||||
|
|
||||||
changes (-> changes
|
changes (-> changes
|
||||||
(pcb/with-page page)
|
(pcb/with-page page)
|
||||||
|
@ -400,7 +395,7 @@
|
||||||
changes (reduce #(pcb/add-object %1 %2 {:ignore-touched true})
|
changes (reduce #(pcb/add-object %1 %2 {:ignore-touched true})
|
||||||
changes
|
changes
|
||||||
(rest shapes))]
|
(rest shapes))]
|
||||||
{:changes (pcb/restore-component changes component-id (:id page) main-inst)
|
{:changes (pcb/restore-component changes component-id (:id page) main-inst parent-id)
|
||||||
:shape (first shapes)})))
|
:shape (first shapes)})))
|
||||||
|
|
||||||
;; ---- General library synchronization functions ----
|
;; ---- General library synchronization functions ----
|
||||||
|
@ -2160,52 +2155,89 @@
|
||||||
(pcb/with-page changes page)
|
(pcb/with-page changes page)
|
||||||
frames)))
|
frames)))
|
||||||
|
|
||||||
(defn generate-duplicate-component-change
|
(defn- duplicate-variant
|
||||||
[changes objects page component-root parent-id frame-id delta libraries library-data]
|
[changes library component base-pos parent-id]
|
||||||
(let [component-id (:component-id component-root)
|
(let [component-page (ctpl/get-page (:data library) (:main-instance-page component))
|
||||||
file-id (:component-file component-root)
|
component-shape (dm/get-in component-page [:objects (:main-instance-id component)])
|
||||||
main-component (ctf/get-component libraries file-id component-id)
|
orig-pos (gpt/point (:x component-shape) (:y component-shape))
|
||||||
moved-component (gsh/move component-root delta)
|
delta (gpt/subtract base-pos orig-pos)
|
||||||
pos (gpt/point (:x moved-component) (:y moved-component))
|
new-component-id (uuid/next)
|
||||||
origin-frame (get-in page [:objects frame-id])
|
[shape changes] (generate-duplicate-component changes
|
||||||
delta (cond-> delta
|
library
|
||||||
(some? origin-frame)
|
(:component-id component-shape)
|
||||||
(gpt/subtract (-> origin-frame :selrect gpt/point)))
|
new-component-id
|
||||||
|
true
|
||||||
|
{:apply-changes-local-library? true
|
||||||
|
:delta delta
|
||||||
|
:new-variant-id parent-id})]
|
||||||
|
[shape
|
||||||
|
(-> changes
|
||||||
|
(pcb/change-parent parent-id [shape]))]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn generate-duplicate-component-change
|
||||||
|
[changes objects page main parent-id frame-id delta libraries library-data ids-map]
|
||||||
|
(let [main-id (:id main)
|
||||||
|
component-id (:component-id main)
|
||||||
|
file-id (:component-file main)
|
||||||
|
component (ctf/get-component libraries file-id component-id)
|
||||||
|
pos (as-> (gsh/move main delta) $
|
||||||
|
(gpt/point (:x $) (:y $)))
|
||||||
|
|
||||||
|
;; When we duplicate a variant alone, we will instanciate it
|
||||||
|
;; When we duplicate a variant along with its variant-container, we will duplicate it
|
||||||
|
in-variant-container? (contains? ids-map (:variant-id main))
|
||||||
|
|
||||||
instantiate-component
|
|
||||||
#(generate-instantiate-component changes
|
|
||||||
objects
|
|
||||||
file-id
|
|
||||||
(:component-id component-root)
|
|
||||||
pos
|
|
||||||
page
|
|
||||||
libraries
|
|
||||||
(:id component-root)
|
|
||||||
parent-id
|
|
||||||
frame-id
|
|
||||||
{})
|
|
||||||
|
|
||||||
restore-component
|
restore-component
|
||||||
#(let [restore (prepare-restore-component changes library-data (:component-id component-root) page delta (:id component-root) parent-id frame-id)]
|
#(let [origin-frame (get-in page [:objects frame-id])
|
||||||
[(:shape restore) (:changes restore)])
|
delta (cond-> delta
|
||||||
|
(some? origin-frame)
|
||||||
|
(gpt/subtract (-> origin-frame :selrect gpt/point)))
|
||||||
|
{:keys [shape changes]} (prepare-restore-component changes
|
||||||
|
library-data
|
||||||
|
component-id
|
||||||
|
page
|
||||||
|
delta
|
||||||
|
main-id
|
||||||
|
parent-id
|
||||||
|
frame-id)]
|
||||||
|
[shape changes])
|
||||||
|
|
||||||
[_shape changes]
|
[_shape changes]
|
||||||
(if (nil? main-component)
|
(if (nil? component)
|
||||||
(restore-component)
|
(restore-component)
|
||||||
(instantiate-component))]
|
(if (and (ctk/is-variant? main) in-variant-container?)
|
||||||
|
(duplicate-variant changes
|
||||||
|
(get libraries file-id)
|
||||||
|
component
|
||||||
|
pos
|
||||||
|
parent-id)
|
||||||
|
|
||||||
|
(generate-instantiate-component changes
|
||||||
|
objects
|
||||||
|
file-id
|
||||||
|
component-id
|
||||||
|
pos
|
||||||
|
page
|
||||||
|
libraries
|
||||||
|
main-id
|
||||||
|
parent-id
|
||||||
|
frame-id
|
||||||
|
{})))]
|
||||||
changes))
|
changes))
|
||||||
|
|
||||||
(defn generate-duplicate-shape-change
|
(defn generate-duplicate-shape-change
|
||||||
([changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data file-id]
|
([changes objects page unames update-unames! ids ids-map obj delta level-delta libraries library-data file-id]
|
||||||
(generate-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data file-id (:frame-id obj) (:parent-id obj) false false true))
|
(generate-duplicate-shape-change changes objects page unames update-unames! ids ids-map obj delta level-delta libraries library-data file-id (:frame-id obj) (:parent-id obj) false false true))
|
||||||
|
|
||||||
([changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data file-id frame-id parent-id duplicating-component? child? remove-swap-slot?]
|
([changes objects page unames update-unames! ids ids-map obj delta level-delta libraries library-data file-id frame-id parent-id duplicating-component? child? remove-swap-slot?]
|
||||||
(cond
|
(cond
|
||||||
(nil? obj)
|
(nil? obj)
|
||||||
changes
|
changes
|
||||||
|
|
||||||
(ctf/is-main-of-known-component? obj libraries)
|
(ctf/is-main-of-known-component? obj libraries)
|
||||||
(generate-duplicate-component-change changes objects page obj parent-id frame-id delta libraries library-data)
|
(generate-duplicate-component-change changes objects page obj parent-id frame-id delta libraries library-data ids-map)
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(let [frame? (cfh/frame-shape? obj)
|
(let [frame? (cfh/frame-shape? obj)
|
||||||
|
@ -2307,6 +2339,7 @@
|
||||||
page
|
page
|
||||||
unames
|
unames
|
||||||
update-unames!
|
update-unames!
|
||||||
|
ids
|
||||||
ids-map
|
ids-map
|
||||||
child
|
child
|
||||||
delta
|
delta
|
||||||
|
@ -2349,6 +2382,7 @@
|
||||||
page
|
page
|
||||||
unames
|
unames
|
||||||
update-unames!
|
update-unames!
|
||||||
|
ids
|
||||||
ids-map
|
ids-map
|
||||||
%2
|
%2
|
||||||
delta
|
delta
|
||||||
|
|
|
@ -433,14 +433,19 @@
|
||||||
|
|
||||||
(defn restore-component
|
(defn restore-component
|
||||||
"Recover a deleted component and all its shapes and put all this again in place."
|
"Recover a deleted component and all its shapes and put all this again in place."
|
||||||
[file-data component-id page-id]
|
[file-data component-id page-id parent-id]
|
||||||
(let [components-v2 (dm/get-in file-data [:options :components-v2])
|
(let [components-v2 (dm/get-in file-data [:options :components-v2])
|
||||||
update-page? (and components-v2 (not (nil? page-id)))]
|
update-page? (and components-v2 (not (nil? page-id)))
|
||||||
|
component (ctkl/get-component file-data component-id true)
|
||||||
|
update-variant? (and (some? parent-id)
|
||||||
|
(ctk/is-variant? component))]
|
||||||
(-> file-data
|
(-> file-data
|
||||||
(ctkl/update-component component-id #(dissoc % :objects))
|
(ctkl/update-component component-id #(dissoc % :objects))
|
||||||
(ctkl/mark-component-undeleted component-id)
|
(ctkl/mark-component-undeleted component-id)
|
||||||
(cond-> update-page?
|
(cond-> update-page?
|
||||||
(ctkl/update-component component-id #(assoc % :main-instance-page page-id))))))
|
(ctkl/update-component component-id #(assoc % :main-instance-page page-id)))
|
||||||
|
(cond-> update-variant?
|
||||||
|
(ctkl/update-component component-id #(assoc % :variant-id parent-id))))))
|
||||||
|
|
||||||
(defn purge-component
|
(defn purge-component
|
||||||
"Remove permanently a component."
|
"Remove permanently a component."
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
(ns common-tests.logic.variants-test
|
(ns common-tests.logic.variants-test
|
||||||
(:require
|
(:require
|
||||||
[app.common.files.changes-builder :as pcb]
|
[app.common.files.changes-builder :as pcb]
|
||||||
|
[app.common.geom.point :as gpt]
|
||||||
|
[app.common.logic.libraries :as cll]
|
||||||
[app.common.logic.variant-properties :as clvp]
|
[app.common.logic.variant-properties :as clvp]
|
||||||
[app.common.test-helpers.components :as thc]
|
[app.common.test-helpers.components :as thc]
|
||||||
[app.common.test-helpers.files :as thf]
|
[app.common.test-helpers.files :as thf]
|
||||||
|
@ -192,3 +194,43 @@
|
||||||
;; ==== Check
|
;; ==== Check
|
||||||
(t/is (= (-> comp01' :variant-properties first :value) "NewValue1"))
|
(t/is (= (-> comp01' :variant-properties first :value) "NewValue1"))
|
||||||
(t/is (= (-> comp02' :variant-properties first :value) "NewValue2"))))
|
(t/is (= (-> comp02' :variant-properties first :value) "NewValue2"))))
|
||||||
|
|
||||||
|
|
||||||
|
(t/deftest test-duplicate-variant-container
|
||||||
|
(let [;; ==== Setup
|
||||||
|
file (-> (thf/sample-file :file1)
|
||||||
|
(thv/add-variant :v01 :c01 :m01 :c02 :m02))
|
||||||
|
data (:data file)
|
||||||
|
page (thf/current-page file)
|
||||||
|
objects (:objects page)
|
||||||
|
|
||||||
|
variant-container (ths/get-shape file :v01)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;; ==== Action
|
||||||
|
changes (-> (pcb/empty-changes nil)
|
||||||
|
(pcb/with-page-id (:id page))
|
||||||
|
(pcb/with-library-data (:data file))
|
||||||
|
(pcb/with-objects (:objects page))
|
||||||
|
(cll/generate-duplicate-changes objects ;; objects
|
||||||
|
page ;; page
|
||||||
|
#{(:id variant-container)} ;; ids
|
||||||
|
(gpt/point 0 0) ;; delta
|
||||||
|
{(:id file) file} ;; libraries
|
||||||
|
(:data file) ;; library-data
|
||||||
|
(:id file))) ;; file-id
|
||||||
|
|
||||||
|
;; ==== Get
|
||||||
|
file' (thf/apply-changes file changes)
|
||||||
|
data' (:data file')
|
||||||
|
page' (thf/current-page file')
|
||||||
|
objects' (:objects page')]
|
||||||
|
|
||||||
|
;; ==== Check
|
||||||
|
(thf/validate-file! file')
|
||||||
|
(t/is (= (count (:components data)) 2))
|
||||||
|
(t/is (= (count (:components data')) 4))
|
||||||
|
(t/is (= (count objects) 4))
|
||||||
|
(t/is (= (count objects') 7))))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue