Integrate objects-map and introduce file feature flags

This commit is contained in:
Andrey Antukh 2022-10-06 18:47:16 +02:00 committed by Andrés Moya
parent 69f084e1df
commit 951b3eb4fe
21 changed files with 406 additions and 264 deletions

View file

@ -0,0 +1,10 @@
;; 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) KALEIDOS INC
(ns app.common.files.features)
(def ^:dynamic *current* #{})
(def ^:dynamic *wrap-objects-fn* identity)

View file

@ -347,27 +347,12 @@
;; -- Components
(defmethod process-change :add-component
[data {:keys [id name path main-instance-id main-instance-page shapes]}]
(ctkl/add-component data
id
name
path
main-instance-id
main-instance-page
shapes))
[data params]
(ctkl/add-component data params))
(defmethod process-change :mod-component
[data {:keys [id name path objects]}]
(update-in data [:components id]
#(cond-> %
(some? name)
(assoc :name name)
(some? path)
(assoc :path path)
(some? objects)
(assoc :objects objects))))
[data params]
(ctkl/mod-component data params))
(defmethod process-change :del-component
[data {:keys [id skip-undelete?]}]

View file

@ -8,6 +8,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.features :as ffeat]
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
@ -50,10 +51,12 @@
(defn with-objects
[changes objects]
(let [file-data (-> (ctf/make-file-data (uuid/next) uuid/zero true)
(assoc-in [:pages-index uuid/zero :objects] objects))]
(vary-meta changes assoc ::file-data file-data
::applied-changes-count 0)))
(let [fdata (binding [ffeat/*current* #{"components/v2"}]
(ctf/make-file-data (uuid/next) uuid/zero))
fdata (assoc-in fdata [:pages-index uuid/zero :objects] objects)]
(vary-meta changes assoc
::file-data fdata
::applied-changes-count 0)))
(defn with-library-data
[changes data]
@ -268,7 +271,7 @@
:page-id (::page-id (meta changes))
:parent-id (:parent-id shape)
:shapes [(:id shape)]
:index idx})))]
:index idx})))]
(-> changes
(update :redo-changes conj set-parent-change)
@ -592,7 +595,7 @@
:main-instance-page main-instance-page
:shapes new-shapes})
(into (map mk-change) updated-shapes))))
(update :undo-changes
(update :undo-changes
(fn [undo-changes]
(-> undo-changes
(d/preconj {:type :del-component

View file

@ -9,7 +9,7 @@
(defn instance-root?
[shape]
(some? (:component-id shape)))
(defn instance-of?
[shape file-id component-id]
(and (some? (:component-id shape))

View file

@ -2,30 +2,52 @@
;; 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
;; Copyright (c) KELEIDOS INC
(ns app.common.types.components-list
(:require
[app.common.data :as d]))
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.features :as feat]))
(defn components-seq
[file-data]
(vals (:components file-data)))
(defn add-component
[file-data id name path main-instance-id main-instance-page shapes]
(let [components-v2 (get-in file-data [:options :components-v2])]
[file-data {:keys [id name path main-instance-id main-instance-page shapes]}]
(let [components-v2 (dm/get-in file-data [:options :components-v2])
wrap-object-fn feat/*wrap-objects-fn*]
(cond-> file-data
:always
(assoc-in [:components id]
{:id id
:name name
:path path
:objects (d/index-by :id shapes)})
:objects (->> shapes
(d/index-by :id)
(wrap-object-fn))})
components-v2
(update-in [:components id] assoc :main-instance-id main-instance-id
:main-instance-page main-instance-page))))
(update-in [:components id] assoc
:main-instance-id main-instance-id
:main-instance-page main-instance-page))))
(defn mod-component
[file-data {:keys [id name path objects]}]
(let [wrap-objects-fn feat/*wrap-objects-fn*]
(update-in file-data [:components id]
(fn [component]
(let [objects (some-> objects wrap-objects-fn)]
(cond-> component
(some? name)
(assoc :name name)
(some? path)
(assoc :path path)
(some? objects)
(assoc :objects objects)))))))
(defn get-component
[file-data component-id]

View file

@ -6,6 +6,7 @@
(ns app.common.types.container
(:require
[app.common.data.macros :as dm]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.common.spec :as us]
@ -41,8 +42,8 @@
(us/assert uuid? id)
(-> (if (= type :page)
(get-in file [:pages-index id])
(get-in file [:components id]))
(dm/get-in file [:pages-index id])
(dm/get-in file [:components id]))
(assoc :type type)))
(defn get-shape

View file

@ -7,6 +7,8 @@
(ns app.common.types.file
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.features :as ffeat]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.common.pages.common :refer [file-version]]
@ -65,16 +67,16 @@
:pages-index {}})
(defn make-file-data
([file-id components-v2]
(make-file-data file-id (uuid/next) components-v2))
([file-id]
(make-file-data file-id (uuid/next)))
([file-id page-id components-v2]
([file-id page-id]
(let [page (ctp/make-empty-page page-id "Page-1")]
(cond-> (-> empty-file-data
(assoc :id file-id)
(ctpl/add-page page))
components-v2
(contains? ffeat/*current* "components/v2")
(assoc-in [:options :components-v2] true)))))
;; Helpers
@ -108,7 +110,7 @@
([libraries component-id]
(some #(ctkl/get-component (:data %) component-id) (vals libraries)))
([libraries library-id component-id]
(ctkl/get-component (get-in libraries [library-id :data]) component-id)))
(ctkl/get-component (dm/get-in libraries [library-id :data]) component-id)))
(defn delete-component
"Delete a component and store it to be able to be recovered later.
@ -118,7 +120,7 @@
(delete-component file-data component-id false))
([file-data component-id skip-undelete?]
(let [components-v2 (get-in file-data [:options :components-v2])
(let [components-v2 (dm/get-in file-data [:options :components-v2])
add-to-deleted-components
(fn [file-data]
@ -144,12 +146,12 @@
(defn get-deleted-component
"Retrieve a component that has been deleted but still is in the safe store."
[file-data component-id]
(get-in file-data [:deleted-components component-id]))
(dm/get-in file-data [:deleted-components component-id]))
(defn restore-component
"Recover a deleted component and put it again in place."
[file-data component-id]
(let [component (-> (get-in file-data [:deleted-components component-id])
(let [component (-> (dm/get-in file-data [:deleted-components component-id])
(dissoc :main-instance-x :main-instance-y))]
(cond-> file-data
(some? component)
@ -242,7 +244,7 @@
[file-data]
(let [components (ctkl/components-seq file-data)]
(if (or (empty? components)
(get-in file-data [:options :components-v2]))
(dm/get-in file-data [:options :components-v2]))
(assoc-in file-data [:options :components-v2] true)
(let [grid-gap 50
@ -342,12 +344,12 @@
copy-component
(fn [file-data]
(ctkl/add-component file-data
(:id component)
(:name component)
(:path component)
(:id main-instance-shape)
page-id
(vals (:objects component))))
{:id (:id component)
:name (:name component)
:path (:path component)
:main-instance-id (:id main-instance-shape)
:main-instance-page page-id
:shapes (vals (:objects component))}))
; Change all existing instances to point to the local file
remap-instances
@ -500,10 +502,10 @@
component-file (when component-file-id (get libraries component-file-id nil))
component (when component-id
(if component-file
(get-in component-file [:data :components component-id])
(dm/get-in component-file [:data :components component-id])
(get components component-id)))
component-shape (when (and component (:shape-ref shape))
(get-in component [:objects (:shape-ref shape)]))]
(dm/get-in component [:objects (:shape-ref shape)]))]
(str/format " %s--> %s%s%s"
(cond (:component-root? shape) "#"
(:component-id shape) "@"
@ -518,7 +520,7 @@
component-file-id (:component-file shape)
component-file (when component-file-id (get libraries component-file-id nil))
component (if component-file
(get-in component-file [:data :components component-id])
(dm/get-in component-file [:data :components component-id])
(get components component-id))]
(str/format " (%s%s)"
(when component-file (str/format "<%s> " (:name component-file)))

View file

@ -7,6 +7,7 @@
(ns app.common.types.page
(:require
[app.common.data :as d]
[app.common.files.features :as ffeat]
[app.common.types.page.flow :as ctpf]
[app.common.types.page.grid :as ctpg]
[app.common.types.page.guide :as ctpu]
@ -48,9 +49,11 @@
(defn make-empty-page
[id name]
(assoc empty-page-data
:id id
:name name))
(let [wrap-fn ffeat/*wrap-objects-fn*]
(-> empty-page-data
(assoc :id id)
(assoc :name name)
(update :objects wrap-fn))))
;; --- Helpers for flow

View file

@ -2,32 +2,29 @@
;; 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
;; Copyright (c) KALEIDOS INC
(ns app.common.types.pages-list
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.pages.helpers :as cph]))
(defn get-page
[file-data id]
(get-in file-data [:pages-index id]))
(dm/get-in file-data [:pages-index id]))
(defn add-page
[file-data page]
(let [index (:index page)
page (dissoc page :index)
; It's legitimate to add a page that is already there,
; for example in an idempotent changes operation.
add-if-not-exists (fn [pages id]
(cond
(d/seek #(= % id) pages) pages
(nil? index) (conj pages id)
:else (cph/insert-at-index pages index [id])))]
(-> file-data
(update :pages add-if-not-exists (:id page))
(update :pages-index assoc (:id page) page))))
[file-data {:keys [id index] :as page}]
(-> file-data
;; It's legitimate to add a page that is already there, for
;; example in an idempotent changes operation.
(update :pages (fn [pages]
(let [exists? (some (partial = id) pages)]
(cond
exists? pages
(nil? index) (conj pages id)
:else (cph/insert-at-index pages index [id])))))
(update :pages-index assoc id (dissoc page :index))))
(defn pages-seq
[file-data]
@ -42,4 +39,3 @@
(-> file-data
(update :pages (fn [pages] (filterv #(not= % page-id) pages)))
(update :pages-index dissoc page-id)))

View file

@ -6,16 +6,22 @@
(ns app.common.pages-test
(:require
[clojure.test :as t]
[clojure.pprint :refer [pprint]]
[app.common.files.features :as ffeat]
[app.common.pages :as cp]
[app.common.types.file :as ctf]
[app.common.uuid :as uuid]))
[app.common.uuid :as uuid]
[clojure.pprint :refer [pprint]]
[clojure.test :as t]))
(defn- make-file-data
[file-id page-id]
(binding [ffeat/*current* #{"components/v2"}]
(ctf/make-file-data file-id page-id)))
(t/deftest process-change-set-option
(let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1)
data (ctf/make-file-data file-id page-id true)]
data (make-file-data file-id page-id)]
(t/testing "Sets option single"
(let [chg {:type :set-option
:page-id page-id
@ -81,7 +87,7 @@
(t/deftest process-change-add-obj
(let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1)
data (ctf/make-file-data file-id page-id true)
data (make-file-data file-id page-id)
id-a (uuid/custom 2 1)
id-b (uuid/custom 2 2)
id-c (uuid/custom 2 3)]
@ -135,7 +141,7 @@
(t/deftest process-change-mod-obj
(let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1)
data (ctf/make-file-data file-id page-id true)]
data (make-file-data file-id page-id)]
(t/testing "simple mod-obj"
(let [chg {:type :mod-obj
:page-id page-id
@ -162,7 +168,7 @@
(let [file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1)
id (uuid/custom 2 1)
data (ctf/make-file-data file-id page-id true)
data (make-file-data file-id page-id)
data (-> data
(assoc-in [:pages-index page-id :objects uuid/zero :shapes] [id])
(assoc-in [:pages-index page-id :objects id]
@ -206,7 +212,7 @@
file-id (uuid/custom 2 2)
page-id (uuid/custom 1 1)
data (ctf/make-file-data file-id page-id true)
data (make-file-data file-id page-id)
data (update-in data [:pages-index page-id :objects]
#(-> %
@ -450,7 +456,7 @@
:obj {:type :rect
:name "Shape 3"}}
]
data (ctf/make-file-data file-id page-id true)
data (make-file-data file-id page-id)
data (cp/process-changes data changes)]
(t/testing "preserve order on multiple shape mov 1"
@ -557,7 +563,7 @@
:parent-id group-1-id
:shapes [shape-1-id shape-2-id]}]
data (ctf/make-file-data file-id page-id true)
data (make-file-data file-id page-id)
data (cp/process-changes data changes)]
(t/testing "case 1"

View file

@ -6,16 +6,22 @@
(ns app.common.test-helpers.files
(:require
[app.common.geom.point :as gpt]
[app.common.types.components-list :as ctkl]
[app.common.types.colors-list :as ctcl]
[app.common.types.container :as ctn]
[app.common.types.file :as ctf]
[app.common.types.pages-list :as ctpl]
[app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctst]
[app.common.types.typographies-list :as ctyl]
[app.common.uuid :as uuid]))
[app.common.files.features :as ffeat]
[app.common.geom.point :as gpt]
[app.common.types.colors-list :as ctcl]
[app.common.types.components-list :as ctkl]
[app.common.types.container :as ctn]
[app.common.types.file :as ctf]
[app.common.types.pages-list :as ctpl]
[app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctst]
[app.common.types.typographies-list :as ctyl]
[app.common.uuid :as uuid]))
(defn- make-file-data
[file-id page-id]
(binding [ffeat/*current* #{"components/v2"}]
(ctf/make-file-data file-id page-id)))
(def ^:private idmap (atom {}))
@ -33,7 +39,7 @@
([file-id page-id props]
(merge {:id file-id
:name (get props :name "File1")
:data (ctf/make-file-data file-id page-id true)}
:data (make-file-data file-id page-id)}
props)))
(defn sample-shape
@ -81,12 +87,12 @@
#(reduce (fn [page shape] (ctst/set-shape page shape))
%
updated-shapes))
(ctkl/add-component (:id component-shape)
(:name component-shape)
""
shape-id
page-id
component-shapes))))))
(ctkl/add-component {:id (:id component-shape)
:name (:name component-shape)
:path ""
:main-instance-id shape-id
:main-instance-page page-id
:shapes component-shapes}))))))
(defn sample-instance
[file label page-id library component-id]