diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index fb6245c31c..6ed0feec97 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1651,3 +1651,6 @@ (dm/export dwpg/duplicate-page) (dm/export dwpg/rename-page) (dm/export dwpg/delete-page) + +;; Shapes +(dm/export dwsh/delete-shapes) diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index 32a0bdf944..fb5cd5b5fe 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -9,12 +9,16 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.exceptions :as ex] + [app.common.files.helpers :as cfh] [app.common.files.repair :as cfr] [app.common.files.validate :as cfv] [app.common.json :as json] [app.common.logging :as l] [app.common.pprint :as pp] [app.common.transit :as t] + [app.common.types.component :as ctk] + [app.common.types.components-list :as ctkl] + [app.common.types.container :as ctn] [app.common.types.file :as ctf] [app.common.uuid :as uuid] [app.main.data.changes :as dwc] @@ -28,6 +32,7 @@ [app.main.data.workspace.path.shortcuts] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shortcuts] + [app.main.data.workspace.undo :as dwu] [app.main.errors :as errors] [app.main.repo :as rp] [app.main.store :as st] @@ -528,3 +533,112 @@ [o] (app.common.pprint/pprint o {:level 100 :length 100})) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; PRUNE UNRELATED ITEMS +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn- get-related-ids + "Given a `context` map (:pindex, :fdata) and a `[page-id id]` pair, returns + the set of `[page-id id]` pairs directly related to it, NOT recursively: + - its children (including itself) + - its ancestors + - the main instance `[page-id id]` of its component, if it's inside a + component copy of a component defined in the current file (libraries + are ignored) + + Ids are only unique within a page, so every id is always tracked together + with the page it belongs to." + [{:keys [pindex fdata]} [page-id id]] + (let [page-objects (-> (get pindex page-id) :objects) + shape (get page-objects id)] + (if (nil? shape) + #{} + (let [related (-> #{} + (into (map (partial vector page-id) (cfh/get-parent-ids page-objects id))) + (into (map (partial vector page-id) (cfh/get-children-ids-with-self page-objects id)))) + head (when (ctk/in-component-copy? shape) + (ctn/get-head-shape page-objects shape)) + component (when (and (some? head) (= (:component-file head) (:id fdata))) + (ctkl/get-component fdata (:component-id head)))] + (cond-> related + (some? component) + (conj [(:main-instance-page component) (:main-instance-id component)])))))) + +(defn ^:export prune-unrelated-items + "This function is DESTRUCTIVE. It deletes from the current file all the pages and layers unrelated to the selection. + It is used to isolate bugs" + [] + (let [state @st/state + current-pid (:current-page-id state) + selected (get-selected state) + + fdata (dsh/lookup-file-data state) + pindex (:pages-index fdata) + + context {:pindex pindex + :fdata fdata} + + related + (loop [related (into #{} (map (partial vector current-pid)) selected)] + (let [expanded (->> related + (reduce (fn [acc pair] (into acc (get-related-ids context pair))) + related) + (remove (fn [[_ id]] (= id uuid/zero))) + set)] + (if (= expanded related) + related + (recur expanded)))) + + related-by-page + (reduce (fn [acc [page-id id]] (update acc page-id (fnil conj #{}) id)) + {} + related) + + unrelated-pages + (->> (:pages fdata) + (remove (fn [page-id] (seq (get related-by-page page-id)))) + vec) + + unrelated-items-by-page + (->> (:pages fdata) + (remove (set unrelated-pages)) + (map (fn [page-id] + (let [page-related (get related-by-page page-id #{}) + ids (->> (get pindex page-id) + :objects + keys + (remove #{uuid/zero}) + (remove page-related) + set)] + [page-id ids]))) + (filter (fn [[_ ids]] (seq ids))) + vec) + + items-to-delete + (reduce + (map (comp count second) unrelated-items-by-page))] + + (js/console.log (str "Pages to delete: " (count unrelated-pages) + ", items to delete: " items-to-delete)) + (.table js/console + (->> unrelated-items-by-page + (mapcat (fn [[page-id ids]] + (let [objects (-> (get pindex page-id) :objects)] + (map (fn [id] + {:page-id (str page-id) + :id (str id) + :name (:name (get objects id))}) + ids)))) + (clj->js))) + (when (and (or (seq unrelated-pages) (pos? items-to-delete)) + (js/confirm (str "Delete " (count unrelated-pages) " unrelated page(s) and " + items-to-delete " unrelated item(s)?"))) + (let [undo-id (js/Symbol)] + (apply st/emit! + (concat + [(dwu/start-undo-transaction undo-id)] + (map dw/delete-page unrelated-pages) + (map (fn [[page-id ids]] + (dw/delete-shapes page-id ids)) + unrelated-items-by-page) + [(dwu/commit-undo-transaction undo-id)])))) + nil)) \ No newline at end of file