mirror of
https://github.com/penpot/penpot.git
synced 2025-08-07 14:38:33 +02:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
f15caf54dd
6 changed files with 213 additions and 168 deletions
|
@ -9,12 +9,14 @@
|
||||||
(:refer-clojure :exclude [parse-uuid])
|
(:refer-clojure :exclude [parse-uuid])
|
||||||
#_:clj-kondo/ignore
|
#_:clj-kondo/ignore
|
||||||
(:require
|
(:require
|
||||||
|
[app.binfile.common :as bfc]
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.exceptions :as ex]
|
[app.common.exceptions :as ex]
|
||||||
[app.common.features :as cfeat]
|
[app.common.features :as cfeat]
|
||||||
[app.common.files.changes :as cpc]
|
[app.common.files.changes :as cpc]
|
||||||
[app.common.files.migrations :as pmg]
|
[app.common.files.migrations :as fmg]
|
||||||
[app.common.files.repair :as repair]
|
[app.common.files.repair :as repair]
|
||||||
|
[app.common.files.validate :as cfv]
|
||||||
[app.common.files.validate :as validate]
|
[app.common.files.validate :as validate]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.pprint :refer [pprint]]
|
[app.common.pprint :refer [pprint]]
|
||||||
|
@ -38,7 +40,8 @@
|
||||||
[expound.alpha :as expound]
|
[expound.alpha :as expound]
|
||||||
[promesa.core :as p]
|
[promesa.core :as p]
|
||||||
[promesa.exec :as px]
|
[promesa.exec :as px]
|
||||||
[promesa.exec.csp :as sp]))
|
[promesa.exec.semaphore :as ps]
|
||||||
|
[promesa.util :as pu]))
|
||||||
|
|
||||||
(def ^:dynamic *system* nil)
|
(def ^:dynamic *system* nil)
|
||||||
|
|
||||||
|
@ -62,15 +65,21 @@
|
||||||
{:data data}
|
{:data data}
|
||||||
{:id id}))))
|
{:id id}))))
|
||||||
|
|
||||||
(defn get-file
|
(defn- get-file*
|
||||||
"Get the migrated data of one file."
|
"Get the migrated data of one file."
|
||||||
[id & {:keys [migrate?] :or {migrate? true}}]
|
[system id]
|
||||||
(db/run! main/system
|
(db/run! system
|
||||||
(fn [system]
|
(fn [system]
|
||||||
(binding [pmap/*load-fn* (partial feat.fdata/load-pointer system id)]
|
(binding [pmap/*load-fn* (partial feat.fdata/load-pointer system id)]
|
||||||
(-> (files/get-file system id :migrate? migrate?)
|
(-> (files/get-file system id :migrate? false)
|
||||||
(update :data feat.fdata/process-pointers deref)
|
(update :data feat.fdata/process-pointers deref)
|
||||||
(update :data feat.fdata/process-objects (partial into {})))))))
|
(update :data feat.fdata/process-objects (partial into {}))
|
||||||
|
(fmg/migrate-file))))))
|
||||||
|
|
||||||
|
(defn get-file
|
||||||
|
"Get the migrated data of one file."
|
||||||
|
[id]
|
||||||
|
(get-file* main/system id))
|
||||||
|
|
||||||
(defn validate
|
(defn validate
|
||||||
"Validate structure, referencial integrity and semantic coherence of
|
"Validate structure, referencial integrity and semantic coherence of
|
||||||
|
@ -78,92 +87,89 @@
|
||||||
[id]
|
[id]
|
||||||
(db/tx-run! main/system
|
(db/tx-run! main/system
|
||||||
(fn [{:keys [::db/conn] :as system}]
|
(fn [{:keys [::db/conn] :as system}]
|
||||||
(binding [pmap/*load-fn* (partial feat.fdata/load-pointer system id)]
|
|
||||||
(let [id (if (string? id) (parse-uuid id) id)
|
(let [id (if (string? id) (parse-uuid id) id)
|
||||||
file (files/get-file system id)
|
file (get-file* system id)
|
||||||
libs (->> (files/get-file-libraries conn id)
|
libs (->> (files/get-file-libraries conn id)
|
||||||
(into [file] (map (fn [{:keys [id]}]
|
(into [file] (map (fn [{:keys [id]}]
|
||||||
(binding [pmap/*load-fn* (partial feat.fdata/load-pointer system id)]
|
(get-file* system id))))
|
||||||
(-> (files/get-file system id :migrate? false)
|
|
||||||
(update :data feat.fdata/process-pointers deref)
|
|
||||||
(pmg/migrate-file))))))
|
|
||||||
(d/index-by :id))]
|
(d/index-by :id))]
|
||||||
(validate/validate-file file libs))))))
|
(validate/validate-file file libs)))))
|
||||||
|
|
||||||
(defn repair!
|
(defn repair!
|
||||||
"Repair the list of errors detected by validation."
|
"Repair the list of errors detected by validation."
|
||||||
[id]
|
[id]
|
||||||
(db/tx-run! main/system
|
(db/tx-run! main/system
|
||||||
(fn [{:keys [::db/conn] :as system}]
|
(fn [{:keys [::db/conn] :as system}]
|
||||||
(binding [pmap/*tracked* (pmap/create-tracked)
|
|
||||||
pmap/*load-fn* (partial feat.fdata/load-pointer system id)]
|
|
||||||
(let [id (if (string? id) (parse-uuid id) id)
|
(let [id (if (string? id) (parse-uuid id) id)
|
||||||
file (files/get-file system id)
|
file (get-file* system id)
|
||||||
libs (->> (files/get-file-libraries conn id)
|
libs (->> (files/get-file-libraries conn id)
|
||||||
(into [file] (map (fn [{:keys [id]}]
|
(into [file] (map (fn [{:keys [id]}]
|
||||||
(binding [pmap/*load-fn* (partial feat.fdata/load-pointer system id)]
|
(get-file* system id))))
|
||||||
(-> (files/get-file system id :migrate? false)
|
|
||||||
(update :data feat.fdata/process-pointers deref)
|
|
||||||
(pmg/migrate-file))))))
|
|
||||||
(d/index-by :id))
|
(d/index-by :id))
|
||||||
errors (validate/validate-file file libs)
|
errors (validate/validate-file file libs)
|
||||||
changes (repair/repair-file file libs errors)
|
changes (repair/repair-file file libs errors)
|
||||||
|
|
||||||
file (-> file
|
file (-> file
|
||||||
(update :revn inc)
|
(update :revn inc)
|
||||||
(update :data cpc/process-changes changes)
|
(update :data cpc/process-changes changes))
|
||||||
(update :data blob/encode))]
|
|
||||||
|
|
||||||
(when (contains? (:features file) "fdata/pointer-map")
|
file (if (contains? (:features file) "fdata/objects-map")
|
||||||
(feat.fdata/persist-pointers! system id))
|
(feat.fdata/enable-objects-map file)
|
||||||
|
file)
|
||||||
|
|
||||||
|
file (if (contains? (:features file) "fdata/pointer-map")
|
||||||
|
(binding [pmap/*tracked* (pmap/create-tracked)]
|
||||||
|
(let [file (feat.fdata/enable-pointer-map file)]
|
||||||
|
(feat.fdata/persist-pointers! system id)
|
||||||
|
file))
|
||||||
|
file)]
|
||||||
|
|
||||||
(db/update! conn :file
|
(db/update! conn :file
|
||||||
{:revn (:revn file)
|
{:revn (:revn file)
|
||||||
:data (:data file)
|
:data (blob/encode (:data file))
|
||||||
:data-backend nil
|
:data-backend nil
|
||||||
:modified-at (dt/now)
|
:modified-at (dt/now)
|
||||||
:has-media-trimmed false}
|
:has-media-trimmed false}
|
||||||
{:id (:id file)})
|
{:id (:id file)})
|
||||||
:repaired)))))
|
|
||||||
|
:repaired))))
|
||||||
|
|
||||||
|
|
||||||
(defn update-file!
|
(defn update-file!
|
||||||
"Apply a function to the data of one file. Optionally save the changes or not.
|
"Apply a function to the data of one file. Optionally save the changes or not.
|
||||||
The function receives the decoded and migrated file data."
|
The function receives the decoded and migrated file data."
|
||||||
[& {:keys [update-fn id rollback? migrate? inc-revn?]
|
[& {:keys [update-fn id rollback? inc-revn?]
|
||||||
:or {rollback? true migrate? true inc-revn? true}}]
|
:or {rollback? true inc-revn? true}}]
|
||||||
(letfn [(process-file [{:keys [::db/conn] :as system} {:keys [features] :as file}]
|
(letfn [(process-file [{:keys [::db/conn] :as system} file-id]
|
||||||
(binding [pmap/*tracked* (pmap/create-tracked)
|
(let [file (get-file* system file-id)
|
||||||
pmap/*load-fn* (partial feat.fdata/load-pointer system id)
|
file (cond-> (update-fn file)
|
||||||
cfeat/*wrap-with-pointer-map-fn*
|
|
||||||
(if (contains? features "fdata/pointer-map") pmap/wrap identity)
|
|
||||||
cfeat/*wrap-with-objects-map-fn*
|
|
||||||
(if (contains? features "fdata/objectd-map") omap/wrap identity)]
|
|
||||||
|
|
||||||
(let [file (cond-> (update-fn file)
|
|
||||||
inc-revn? (update :revn inc))
|
inc-revn? (update :revn inc))
|
||||||
features (db/create-array conn "text" (:features file))
|
|
||||||
data (blob/encode (:data file))]
|
_ (cfv/validate-file-schema! file)
|
||||||
|
|
||||||
|
file (if (contains? (:features file) "fdata/objects-map")
|
||||||
|
(feat.fdata/enable-objects-map file)
|
||||||
|
file)
|
||||||
|
|
||||||
|
file (if (contains? (:features file) "fdata/pointer-map")
|
||||||
|
(binding [pmap/*tracked* (pmap/create-tracked)]
|
||||||
|
(let [file (feat.fdata/enable-pointer-map file)]
|
||||||
|
(feat.fdata/persist-pointers! system id)
|
||||||
|
file))
|
||||||
|
file)]
|
||||||
|
|
||||||
(db/update! conn :file
|
(db/update! conn :file
|
||||||
{:data data
|
{:data (blob/encode (:data file))
|
||||||
:revn (:revn file)
|
:features (db/create-array conn "text" (:features file))
|
||||||
:features features}
|
:revn (:revn file)}
|
||||||
{:id id}))
|
{:id (:id file)})
|
||||||
|
|
||||||
(when (contains? (:features file) "fdata/pointer-map")
|
|
||||||
(feat.fdata/persist-pointers! system id))
|
|
||||||
|
|
||||||
(dissoc file :data)))]
|
(dissoc file :data)))]
|
||||||
|
|
||||||
(db/tx-run! (or *system* main/system)
|
(db/tx-run! (or *system* (assoc main/system ::db/rollback rollback?))
|
||||||
(fn [system]
|
(fn [system]
|
||||||
(binding [*system* system]
|
(binding [*system* system]
|
||||||
(try
|
(process-file system id))))))
|
||||||
(->> (files/get-file system id :migrate? migrate?)
|
|
||||||
(process-file system))
|
|
||||||
(finally
|
|
||||||
(when rollback?
|
|
||||||
(db/rollback! system)))))))))
|
|
||||||
|
|
||||||
|
|
||||||
(def ^:private sql:get-file-ids
|
(def ^:private sql:get-file-ids
|
||||||
|
@ -190,16 +196,11 @@
|
||||||
(strace/print-stack-trace cause))
|
(strace/print-stack-trace cause))
|
||||||
|
|
||||||
(process-file [{:keys [::db/conn] :as system} file-id]
|
(process-file [{:keys [::db/conn] :as system} file-id]
|
||||||
(let [file (binding [pmap/*load-fn* (partial feat.fdata/load-pointer system file-id)]
|
(let [file (get-file* system file-id)
|
||||||
(-> (files/get-file system file-id)
|
|
||||||
(update :data feat.fdata/process-pointers deref)))
|
|
||||||
|
|
||||||
libs (when with-libraries?
|
libs (when with-libraries?
|
||||||
(->> (files/get-file-libraries conn file-id)
|
(->> (files/get-file-libraries conn file-id)
|
||||||
(into [file] (map (fn [{:keys [id]}]
|
(into [file] (map (fn [{:keys [id]}]
|
||||||
(binding [pmap/*load-fn* (partial feat.fdata/load-pointer system id)]
|
(get-file* system id))))
|
||||||
(-> (files/get-file system id)
|
|
||||||
(update :data feat.fdata/process-pointers deref))))))
|
|
||||||
(d/index-by :id)))]
|
(d/index-by :id)))]
|
||||||
(try
|
(try
|
||||||
(if with-libraries?
|
(if with-libraries?
|
||||||
|
@ -208,7 +209,7 @@
|
||||||
(catch Throwable cause
|
(catch Throwable cause
|
||||||
((or on-error on-error*) cause file)))))]
|
((or on-error on-error*) cause file)))))]
|
||||||
|
|
||||||
(db/tx-run! main/system
|
(db/tx-run! (assoc main/system ::db/rollback true)
|
||||||
(fn [{:keys [::db/conn] :as system}]
|
(fn [{:keys [::db/conn] :as system}]
|
||||||
(try
|
(try
|
||||||
(binding [*system* system]
|
(binding [*system* system]
|
||||||
|
@ -217,83 +218,125 @@
|
||||||
(get-candidates conn)))
|
(get-candidates conn)))
|
||||||
(finally
|
(finally
|
||||||
(when (fn? on-end)
|
(when (fn? on-end)
|
||||||
(ex/ignoring (on-end)))
|
(ex/ignoring (on-end)))))))))
|
||||||
(db/rollback! system)))))))
|
|
||||||
|
(defn repair-file-media
|
||||||
|
[{:keys [id data] :as file}]
|
||||||
|
(let [conn (db/get-connection *system*)
|
||||||
|
used (bfc/collect-used-media data)
|
||||||
|
ids (db/create-array conn "uuid" used)
|
||||||
|
sql (str "SELECT * FROM file_media_object WHERE id = ANY(?)")
|
||||||
|
rows (db/exec! conn [sql ids])
|
||||||
|
index (reduce (fn [index media]
|
||||||
|
(if (not= (:file-id media) id)
|
||||||
|
(let [media-id (uuid/next)]
|
||||||
|
(l/wrn :hint "found not referenced media"
|
||||||
|
:file-id (str id)
|
||||||
|
:media-id (str (:id media)))
|
||||||
|
|
||||||
|
(db/insert! *system* :file-media-object
|
||||||
|
(-> media
|
||||||
|
(assoc :file-id id)
|
||||||
|
(assoc :id media-id)))
|
||||||
|
(assoc index (:id media) media-id))
|
||||||
|
index))
|
||||||
|
{}
|
||||||
|
rows)]
|
||||||
|
|
||||||
|
(when (seq index)
|
||||||
|
(binding [bfc/*state* (atom {:index index})]
|
||||||
|
(update file :data (fn [fdata]
|
||||||
|
(-> fdata
|
||||||
|
(update :pages-index #'bfc/relink-shapes)
|
||||||
|
(update :components #'bfc/relink-shapes)
|
||||||
|
(update :media #'bfc/relink-media)
|
||||||
|
(d/without-nils))))))))
|
||||||
|
|
||||||
(defn process-files!
|
(defn process-files!
|
||||||
"Apply a function to all files in the database, reading them in
|
"Apply a function to all files in the database"
|
||||||
batches."
|
|
||||||
[& {:keys [max-items
|
[& {:keys [max-items
|
||||||
workers
|
max-jobs
|
||||||
start-at
|
start-at
|
||||||
on-file
|
on-file
|
||||||
on-error
|
|
||||||
on-end
|
|
||||||
on-init
|
|
||||||
rollback?]
|
rollback?]
|
||||||
:or {workers 1
|
:or {max-jobs 1
|
||||||
rollback? true}}]
|
rollback? true}}]
|
||||||
(letfn [(get-candidates [conn]
|
|
||||||
(cond->> (db/cursor conn [sql:get-file-ids (or start-at (dt/now))])
|
|
||||||
(some? max-items)
|
|
||||||
(take max-items)))
|
|
||||||
|
|
||||||
(on-error* [cause file]
|
(l/dbg :hint "process:start"
|
||||||
(println! "unexpected exception happened on processing file: " (:id file))
|
:rollback rollback?
|
||||||
(strace/print-stack-trace cause))
|
:max-jobs max-jobs
|
||||||
|
:max-items max-items)
|
||||||
|
|
||||||
(process-file [system file-id]
|
(let [tpoint (dt/tpoint)
|
||||||
|
factory (px/thread-factory :virtual false :prefix "penpot/file-process/")
|
||||||
|
executor (px/cached-executor :factory factory)
|
||||||
|
sjobs (ps/create :permits max-jobs)
|
||||||
|
|
||||||
|
process-file
|
||||||
|
(fn [file-id tpoint]
|
||||||
(try
|
(try
|
||||||
(let [{:keys [features] :as file} (files/get-file system file-id)]
|
(l/trc :hint "process:file:start" :file-id (str file-id))
|
||||||
(binding [pmap/*tracked* (pmap/create-tracked)
|
(db/tx-run! (assoc main/system ::db/rollback rollback?)
|
||||||
pmap/*load-fn* (partial feat.fdata/load-pointer system file-id)
|
(fn [{:keys [::db/conn] :as system}]
|
||||||
cfeat/*wrap-with-pointer-map-fn*
|
(let [file' (get-file* system file-id)
|
||||||
(if (contains? features "fdata/pointer-map") pmap/wrap identity)
|
file (binding [*system* system]
|
||||||
cfeat/*wrap-with-objects-map-fn*
|
(on-file file'))]
|
||||||
(if (contains? features "fdata/objectd-map") omap/wrap identity)]
|
|
||||||
|
|
||||||
(on-file file)
|
(when (and (some? file)
|
||||||
|
(not (identical? file file')))
|
||||||
|
|
||||||
(when (contains? features "fdata/pointer-map")
|
(cfv/validate-file-schema! file)
|
||||||
(feat.fdata/persist-pointers! system file-id))))
|
|
||||||
|
(let [file (if (contains? (:features file) "fdata/objects-map")
|
||||||
|
(feat.fdata/enable-objects-map file)
|
||||||
|
file)
|
||||||
|
|
||||||
|
file (if (contains? (:features file) "fdata/pointer-map")
|
||||||
|
(binding [pmap/*tracked* (pmap/create-tracked)]
|
||||||
|
(let [file (feat.fdata/enable-pointer-map file)]
|
||||||
|
(feat.fdata/persist-pointers! system file-id)
|
||||||
|
file))
|
||||||
|
file)]
|
||||||
|
|
||||||
|
(db/update! conn :file
|
||||||
|
{:data (blob/encode (:data file))
|
||||||
|
:features (db/create-array conn "text" (:features file))
|
||||||
|
:revn (:revn file)}
|
||||||
|
{:id file-id}))))))
|
||||||
|
(catch Throwable cause
|
||||||
|
(l/wrn :hint "unexpected error on processing file (skiping)"
|
||||||
|
:file-id (str file-id)
|
||||||
|
:cause cause))
|
||||||
|
(finally
|
||||||
|
(ps/release! sjobs)
|
||||||
|
(let [elapsed (dt/format-duration (tpoint))]
|
||||||
|
(l/trc :hint "process:file:end"
|
||||||
|
:file-id (str file-id)
|
||||||
|
:elapsed elapsed)))))]
|
||||||
|
|
||||||
|
|
||||||
|
(try
|
||||||
|
(db/tx-run! main/system
|
||||||
|
(fn [{:keys [::db/conn] :as system}]
|
||||||
|
(db/exec! conn ["SET statement_timeout = 0"])
|
||||||
|
(db/exec! conn ["SET idle_in_transaction_session_timeout = 0"])
|
||||||
|
|
||||||
|
(run! (fn [file-id]
|
||||||
|
(ps/acquire! sjobs)
|
||||||
|
(px/run! executor (partial process-file file-id (dt/tpoint))))
|
||||||
|
(->> (db/cursor conn [sql:get-file-ids (or start-at (dt/now))])
|
||||||
|
(take max-items)
|
||||||
|
(map :id)))
|
||||||
|
|
||||||
|
;; Close and await tasks
|
||||||
|
(pu/close! executor)))
|
||||||
|
|
||||||
(catch Throwable cause
|
(catch Throwable cause
|
||||||
((or on-error on-error*) cause file-id))))
|
(l/dbg :hint "process:error" :cause cause))
|
||||||
|
|
||||||
(run-worker [in index]
|
(finally
|
||||||
(db/tx-run! main/system
|
(let [elapsed (dt/format-duration (tpoint))]
|
||||||
(fn [system]
|
(l/dbg :hint "process:end"
|
||||||
(binding [*system* system]
|
:rollback rollback?
|
||||||
(loop [i 0]
|
:elapsed elapsed))))))
|
||||||
(when-let [file-id (sp/take! in)]
|
|
||||||
(println! "=> worker: index:" index "| loop:" i "| file:" (str file-id) "|" (px/get-name))
|
|
||||||
(process-file system file-id)
|
|
||||||
(recur (inc i)))))
|
|
||||||
|
|
||||||
(when rollback?
|
|
||||||
(db/rollback! system)))))
|
|
||||||
|
|
||||||
(run-producer [input]
|
|
||||||
(db/tx-run! main/system
|
|
||||||
(fn [{:keys [::db/conn]}]
|
|
||||||
(doseq [file-id (get-candidates conn)]
|
|
||||||
(println! "=> producer:" file-id "|" (px/get-name))
|
|
||||||
(sp/put! input file-id))
|
|
||||||
(sp/close! input))))]
|
|
||||||
|
|
||||||
(when (fn? on-init) (on-init))
|
|
||||||
|
|
||||||
(let [input (sp/chan :buf 25)
|
|
||||||
producer (px/thread
|
|
||||||
{:name "penpot/srepl/producer"}
|
|
||||||
(run-producer input))
|
|
||||||
threads (->> (range workers)
|
|
||||||
(map (fn [index]
|
|
||||||
(px/thread
|
|
||||||
{:name (str "penpot/srepl/worker/" index)}
|
|
||||||
(run-worker input index))))
|
|
||||||
(cons producer)
|
|
||||||
(doall))]
|
|
||||||
|
|
||||||
(run! p/await! threads)
|
|
||||||
(when (fn? on-end) (on-end)))))
|
|
||||||
|
|
|
@ -205,6 +205,7 @@
|
||||||
[:map {:title "DelComponentChange"}
|
[:map {:title "DelComponentChange"}
|
||||||
[:type [:= :del-component]]
|
[:type [:= :del-component]]
|
||||||
[:id ::sm/uuid]
|
[:id ::sm/uuid]
|
||||||
|
[:main-instance {:optional true} :any]
|
||||||
[:skip-undelete? {:optional true} :boolean]]]
|
[:skip-undelete? {:optional true} :boolean]]]
|
||||||
|
|
||||||
[:restore-component
|
[:restore-component
|
||||||
|
@ -642,8 +643,8 @@
|
||||||
(ctkl/mod-component data params))
|
(ctkl/mod-component data params))
|
||||||
|
|
||||||
(defmethod process-change :del-component
|
(defmethod process-change :del-component
|
||||||
[data {:keys [id skip-undelete?]}]
|
[data {:keys [id skip-undelete? main-instance]}]
|
||||||
(ctf/delete-component data id skip-undelete?))
|
(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]}]
|
||||||
|
|
|
@ -752,17 +752,15 @@
|
||||||
:page-id page-id})))
|
:page-id page-id})))
|
||||||
|
|
||||||
(defn restore-component
|
(defn restore-component
|
||||||
([changes id]
|
[changes id page-id main-instance]
|
||||||
(restore-component changes id nil))
|
|
||||||
([changes id page-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})
|
||||||
(update :undo-changes conj {:type :del-component
|
(update :undo-changes conj {:type :del-component
|
||||||
:id id}))))
|
:id id
|
||||||
|
:main-instance main-instance})))
|
||||||
(defn ignore-remote
|
(defn ignore-remote
|
||||||
[changes]
|
[changes]
|
||||||
(letfn [(add-ignore-remote
|
(letfn [(add-ignore-remote
|
||||||
|
|
|
@ -258,15 +258,17 @@
|
||||||
(defn delete-component
|
(defn delete-component
|
||||||
"Mark a component as deleted and store the main instance shapes iside it, to
|
"Mark a component as deleted and store the main instance shapes iside it, to
|
||||||
be able to be recovered later."
|
be able to be recovered later."
|
||||||
([file-data component-id]
|
[file-data component-id skip-undelete? main-instance]
|
||||||
(delete-component file-data component-id false))
|
|
||||||
|
|
||||||
([file-data component-id skip-undelete?]
|
|
||||||
(let [components-v2 (dm/get-in file-data [:options :components-v2])]
|
(let [components-v2 (dm/get-in file-data [:options :components-v2])]
|
||||||
(if (or (not components-v2) skip-undelete?)
|
(if (or (not components-v2) skip-undelete?)
|
||||||
(ctkl/delete-component file-data component-id)
|
(ctkl/delete-component file-data component-id)
|
||||||
|
(let [set-main-instance ;; If there is a saved main-instance, restore it. This happens on the restore-component action
|
||||||
|
#(if main-instance
|
||||||
|
(assoc-in % [:objects (:main-instance-id %)] main-instance)
|
||||||
|
%)]
|
||||||
(-> file-data
|
(-> file-data
|
||||||
(ctkl/update-component component-id (partial load-component-objects file-data))
|
(ctkl/update-component component-id (partial load-component-objects file-data))
|
||||||
|
(ctkl/update-component component-id set-main-instance)
|
||||||
(ctkl/mark-component-deleted component-id))))))
|
(ctkl/mark-component-deleted component-id))))))
|
||||||
|
|
||||||
(defn restore-component
|
(defn restore-component
|
||||||
|
|
|
@ -254,6 +254,7 @@
|
||||||
([changes library-data component-id it page delta old-id parent-id frame-id]
|
([changes library-data component-id it page delta old-id parent-id frame-id]
|
||||||
(let [component (ctkl/get-deleted-component library-data component-id)
|
(let [component (ctkl/get-deleted-component library-data component-id)
|
||||||
parent (get-in page [:objects parent-id])
|
parent (get-in page [:objects parent-id])
|
||||||
|
main-inst (get-in component [:objects (:main-instance-id component)])
|
||||||
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))
|
||||||
|
@ -281,7 +282,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))
|
{:changes (pcb/restore-component changes component-id (:id page) main-inst)
|
||||||
:shape (first shapes)})))
|
:shape (first shapes)})))
|
||||||
|
|
||||||
;; ---- General library synchronization functions ----
|
;; ---- General library synchronization functions ----
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
w+10 (+ 10 width)]
|
w+10 (+ 10 width)]
|
||||||
(case style
|
(case style
|
||||||
:mixed (str/concat "" w+5 "," w+5 "," w+1 "," w+5)
|
:mixed (str/concat "" w+5 "," w+5 "," w+1 "," w+5)
|
||||||
:dotted (str/concat "" (- (* width 2)) "," w+5)
|
:dotted (str/concat "0," w+5)
|
||||||
:dashed (str/concat "" w+10 "," w+10)
|
:dashed (str/concat "" w+10 "," w+10)
|
||||||
"")))
|
"")))
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue