mirror of
https://github.com/penpot/penpot.git
synced 2025-01-24 15:39:50 -05:00
🐛 Add filter to remove groups without content in all files
This commit is contained in:
parent
b50ffa087d
commit
42072f2584
7 changed files with 170 additions and 31 deletions
94
backend/tests/app/tests/test_common_pages_migrations.clj
Normal file
94
backend/tests/app/tests/test_common_pages_migrations.clj
Normal file
|
@ -0,0 +1,94 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) UXBOX Labs SL
|
||||
|
||||
(ns app.tests.test-common-pages-migrations
|
||||
(:require
|
||||
[clojure.test :as t]
|
||||
[clojure.pprint :refer [pprint]]
|
||||
[promesa.core :as p]
|
||||
[mockery.core :refer [with-mock]]
|
||||
[app.common.data :as d]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages.migrations :as cpm]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.tests.helpers :as th]))
|
||||
|
||||
(t/deftest test-migration-8-1
|
||||
(let [page-id (uuid/custom 0 0)
|
||||
objects [{:type :rect :id (uuid/custom 1 0)}
|
||||
{:type :group
|
||||
:id (uuid/custom 1 1)
|
||||
:selrect {}
|
||||
:shapes [(uuid/custom 1 2) (uuid/custom 1 0)]}
|
||||
{:type :group
|
||||
:id (uuid/custom 1 2)
|
||||
:selrect {}
|
||||
:shapes [(uuid/custom 1 3)]}
|
||||
{:type :group
|
||||
:id (uuid/custom 1 3)
|
||||
:selrect {}
|
||||
:shapes [(uuid/custom 1 4)]}
|
||||
{:type :group
|
||||
:id (uuid/custom 1 4)
|
||||
:selrect {}
|
||||
:shapes [(uuid/custom 1 5)]}
|
||||
{:type :path :id (uuid/custom 1 5)}]
|
||||
|
||||
data {:pages-index {page-id {:objects (d/index-by :id objects)}}
|
||||
:components {}
|
||||
:version 7}
|
||||
|
||||
res (cpm/migrate-data data)]
|
||||
|
||||
(pprint data)
|
||||
(pprint res)
|
||||
|
||||
(t/is (= (dissoc data :version)
|
||||
(dissoc res :version)))))
|
||||
|
||||
(t/deftest test-migration-8-2
|
||||
(let [page-id (uuid/custom 0 0)
|
||||
objects [{:type :rect :id (uuid/custom 1 0)}
|
||||
{:type :group
|
||||
:id (uuid/custom 1 1)
|
||||
:selrect {}
|
||||
:shapes [(uuid/custom 1 2) (uuid/custom 1 0)]}
|
||||
{:type :group
|
||||
:id (uuid/custom 1 2)
|
||||
:selrect {}
|
||||
:shapes [(uuid/custom 1 3)]}
|
||||
{:type :group
|
||||
:id (uuid/custom 1 3)
|
||||
:selrect {}
|
||||
:shapes [(uuid/custom 1 4)]}
|
||||
{:type :group
|
||||
:id (uuid/custom 1 4)
|
||||
:selrect {}
|
||||
:shapes []}
|
||||
{:type :path :id (uuid/custom 1 5)}]
|
||||
|
||||
data {:pages-index {page-id {:objects (d/index-by :id objects)}}
|
||||
:components {}
|
||||
:version 7}
|
||||
|
||||
expct (-> data
|
||||
(update-in [:pages-index page-id :objects] dissoc
|
||||
(uuid/custom 1 2)
|
||||
(uuid/custom 1 3)
|
||||
(uuid/custom 1 4))
|
||||
(update-in [:pages-index page-id :objects (uuid/custom 1 1) :shapes]
|
||||
(fn [shapes]
|
||||
(let [id (uuid/custom 1 2)]
|
||||
(into [] (remove #(= id %)) shapes)))))
|
||||
|
||||
res (cpm/migrate-data data)]
|
||||
|
||||
(pprint res)
|
||||
(pprint expct)
|
||||
|
||||
(t/is (= (dissoc expct :version)
|
||||
(dissoc res :version)))
|
||||
))
|
|
@ -8,7 +8,7 @@
|
|||
(:require
|
||||
[app.common.uuid :as uuid]))
|
||||
|
||||
(def file-version 7)
|
||||
(def file-version 8)
|
||||
(def default-color "#b1b2b5") ;; $color-gray-20
|
||||
(def root uuid/zero)
|
||||
|
||||
|
|
|
@ -179,3 +179,46 @@
|
|||
|
||||
(update data :pages-index #(d/mapm update-page %))))
|
||||
|
||||
|
||||
;; Remove groups without any shape, both in pages and components
|
||||
|
||||
(defmethod migrate 8
|
||||
[data]
|
||||
(letfn [(clean-parents [obj deleted?]
|
||||
(d/update-when obj :shapes
|
||||
(fn [shapes]
|
||||
(into [] (remove deleted?) shapes))))
|
||||
|
||||
(obj-is-empty? [obj]
|
||||
(and (= (:type obj) :group)
|
||||
(or (empty? (:shapes obj))
|
||||
(nil? (:selrect obj)))))
|
||||
|
||||
(clean-objects [objects]
|
||||
(loop [entries (seq objects)
|
||||
deleted #{}
|
||||
result objects]
|
||||
(let [[id obj :as entry] (first entries)]
|
||||
(if entry
|
||||
(if (obj-is-empty? obj)
|
||||
(recur (rest entries)
|
||||
(conj deleted id)
|
||||
(dissoc result id))
|
||||
(recur (rest entries)
|
||||
deleted
|
||||
result))
|
||||
[(count deleted)
|
||||
(d/mapm #(clean-parents %2 deleted) result)]))))
|
||||
|
||||
(clean-container [_ container]
|
||||
(loop [n 0
|
||||
objects (:objects container)]
|
||||
(let [[deleted objects] (clean-objects objects)]
|
||||
(if (and (pos? deleted) (< n 1000))
|
||||
(recur (inc n) objects)
|
||||
(assoc container :objects objects)))))]
|
||||
|
||||
(-> data
|
||||
(update :pages-index #(d/mapm clean-container %))
|
||||
(d/update-when :components #(d/mapm clean-container %)))))
|
||||
|
||||
|
|
|
@ -62,6 +62,10 @@
|
|||
{:target :node-test
|
||||
:output-to "target/tests.js"
|
||||
:ns-regexp "^app.test-"
|
||||
:autorun true}}}
|
||||
:autorun true
|
||||
|
||||
:compiler-options
|
||||
{:output-feature-set :es8
|
||||
:output-wrapper false
|
||||
:warnings {:fn-deprecated false}}}}}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
(:require
|
||||
[app.util.transit :as t]
|
||||
[app.util.timers :as tm]
|
||||
[app.util.globals :as g]
|
||||
[app.common.exceptions :as ex]))
|
||||
|
||||
(defn- ^boolean is-worker?
|
||||
|
@ -36,17 +37,18 @@
|
|||
|
||||
(defn- load
|
||||
[storage]
|
||||
(let [len (.-length ^js storage)]
|
||||
(reduce (fn [res index]
|
||||
(let [key (.key ^js storage index)
|
||||
val (.getItem ^js storage key)]
|
||||
(try
|
||||
(assoc res (t/decode key) (t/decode val))
|
||||
(catch :default e
|
||||
res))))
|
||||
{}
|
||||
(range len))))
|
||||
(when storage
|
||||
(let [len (.-length ^js storage)]
|
||||
(reduce (fn [res index]
|
||||
(let [key (.key ^js storage index)
|
||||
val (.getItem ^js storage key)]
|
||||
(try
|
||||
(assoc res (t/decode key) (t/decode val))
|
||||
(catch :default e
|
||||
res))))
|
||||
{}
|
||||
(range len)))))
|
||||
|
||||
|
||||
(defonce storage (atom (load js/localStorage)))
|
||||
(defonce storage (atom (load (unchecked-get g/global "localStorage"))))
|
||||
(add-watch storage :persistence #(persist js/localStorage %3 %4))
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
(ns app.test-components-sync
|
||||
(:require [cljs.test :as t :include-macros true]
|
||||
[cljs.pprint :refer [pprint]]
|
||||
[clojure.stacktrace :as stk]
|
||||
[beicon.core :as rx]
|
||||
[linked.core :as lks]
|
||||
[app.test-helpers.events :as the]
|
||||
[app.test-helpers.pages :as thp]
|
||||
[app.test-helpers.libraries :as thl]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.data :as d]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.libraries-helpers :as dwlh]))
|
||||
(:require
|
||||
[cljs.test :as t :include-macros true]
|
||||
[cljs.pprint :refer [pprint]]
|
||||
[beicon.core :as rx]
|
||||
[linked.core :as lks]
|
||||
[app.test-helpers.events :as the]
|
||||
[app.test-helpers.pages :as thp]
|
||||
[app.test-helpers.libraries :as thl]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.data :as d]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.main.data.workspace.changes :as dwc]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.libraries-helpers :as dwlh]))
|
||||
|
||||
(t/use-fixtures :each
|
||||
{:before thp/reset-idmap!})
|
||||
|
|
|
@ -50,10 +50,6 @@
|
|||
(dwl/add-recent-color color))
|
||||
(rx/map
|
||||
(fn [new-state]
|
||||
(t/is (= (get-in new-state [:workspace-file
|
||||
:data
|
||||
:recent-colors])
|
||||
[color]))
|
||||
(t/is (= (get-in new-state [:workspace-data
|
||||
:recent-colors])
|
||||
[color]))))
|
||||
|
|
Loading…
Add table
Reference in a new issue