🎉 Improve sync algorithm when swapped copies

This commit is contained in:
Andrés Moya
2024-02-29 14:06:39 +01:00
parent 0d1af260a4
commit 07939d11dc
5 changed files with 227 additions and 59 deletions

View File

@@ -361,7 +361,8 @@
(defn set-touched-group
[touched group]
(conj (or touched #{}) group))
(when group
(conj (or touched #{}) group)))
(defn touched-group?
[shape group]

View File

@@ -4,7 +4,11 @@
;;
;; Copyright (c) KALEIDOS INC
(ns app.common.types.component)
(ns app.common.types.component
(:require
[app.common.data :as d]
[app.common.uuid :as uuid]
[cuerdas.core :as str]))
;; Attributes that may be synced in components, and the group they belong to.
;; When one attribute is modified in a shape inside a component, the corresponding
@@ -170,6 +174,29 @@
(and (= shape-id (:main-instance-id component))
(= page-id (:main-instance-page component))))
(defn build-swap-slot-group
"Convert a swap-slot into a :touched group"
[swap-slot]
(when swap-slot
(keyword (str "swap-slot-" swap-slot))))
(defn get-swap-slot
"If the shape has a :touched group in the form :swap-slot-<uuid>, get the id."
[shape]
(let [group (->> (:touched shape)
(map name)
(d/seek #(str/starts-with? % "swap-slot-")))]
(when group
(uuid/uuid (subs group 10)))))
(defn match-swap-slot?
[shape-inst shape-main]
(let [slot-inst (get-swap-slot shape-inst)
slot-main (get-swap-slot shape-main)]
(when (some? slot-inst)
(or (= slot-inst slot-main)
(= slot-inst (:id shape-main))))))
(defn get-component-root
[component]
(if (true? (:main-instance-id component))

View File

@@ -177,12 +177,36 @@
shape-id)))
(dm/get-in component [:objects shape-id]))))
(defn get-component-shape-context
"Retrieve one shape in the component by id. Return the shape and its
context (the file and the container)."
[file component shape-id]
(let [components-v2 (dm/get-in file [:data :options :components-v2])]
(if (and components-v2 (not (:deleted component)))
(let [component-page (get-component-page (:data file) component)]
(when component-page
(let [child (cfh/get-child (:objects component-page)
(:main-instance-id component)
shape-id)]
(when child
[child file (ctn/make-container component-page :page)]))))
[(dm/get-in component [:objects shape-id])
file
(ctn/make-container component :component)])))
(defn get-ref-shape
"Retrieve the shape in the component that is referenced by the instance shape."
[file-data component shape]
(when (:shape-ref shape)
(get-component-shape file-data component (:shape-ref shape))))
(defn get-ref-shape-context
"Retrieve the shape in the component that is referenced by the instance shape.
Return the shape and its context (the file and the container)."
[file component shape]
(when (:shape-ref shape)
(get-component-shape-context file component (:shape-ref shape))))
(defn get-shape-in-copy
"Given a shape in the main component and the root of the copy component returns the equivalent
shape inside the root copy that matches the main-shape"
@@ -196,11 +220,33 @@
[file page libraries shape & {:keys [include-deleted?] :or {include-deleted? false}}]
(let [find-ref-shape-in-head
(fn [head-shape]
(let [head-file (find-component-file file libraries (:component-file head-shape))
head-component (when (some? head-file)
(ctkl/get-component (:data head-file) (:component-id head-shape) include-deleted?))]
(when (some? head-component)
(get-ref-shape (:data head-file) head-component shape))))]
(let [component-file (find-component-file file libraries (:component-file head-shape))
component (when (some? component-file)
(ctkl/get-component (:data component-file) (:component-id head-shape) include-deleted?))]
(when (some? component)
(get-ref-shape (:data component-file) component shape))))]
(some find-ref-shape-in-head (ctn/get-parent-heads (:objects page) shape))))
(defn find-ref-shape-context
"Locate the nearest component in the local file or libraries, and retrieve the shape
referenced by the instance shape. Return the shape and its context (the file and
the container)."
; TODO: It should be nice to avoid this duplicity without adding overhead in the simple case.
; Perhaps adding the context as metadata of the shape?
[file page libraries shape & {:keys [include-deleted?] :or {include-deleted? false}}]
(let [find-ref-shape-in-head
(fn [head-shape]
;; (js/console.log "head-shape" (clj->js head-shape))
;; (js/console.log " component-file" (str (:component-file head-shape)))
;; (js/console.log " component-id" (str (:component-id head-shape)))
(let [component-file (find-component-file file libraries (:component-file head-shape))
component (when (some? component-file)
(ctkl/get-component (:data component-file) (:component-id head-shape) include-deleted?))]
;; (js/console.log "component-file" (clj->js component-file))
;; (js/console.log "component" (clj->js component))
(when (some? component)
(get-ref-shape-context component-file component shape))))]
(some find-ref-shape-in-head (ctn/get-parent-heads (:objects page) shape))))
@@ -210,12 +256,14 @@
[file page libraries shape & {:keys [include-deleted?] :or {include-deleted? false}}]
(let [find-ref-component-in-head
(fn [head-shape]
(let [head-file (find-component-file file libraries (:component-file head-shape))
head-component (when (some? head-file)
(ctkl/get-component (:data head-file) (:component-id head-shape) include-deleted?))]
(when (some? head-component)
(when (get-ref-shape (:data head-file) head-component shape)
head-component))))]
(let [component-file (find-component-file file libraries (:component-file head-shape))
component (when (some? component-file)
(ctkl/get-component (:data component-file)
(:component-id head-shape)
include-deleted?))]
(when (some? component)
(when (get-ref-shape (:data component-file) component shape)
component))))]
(some find-ref-component-in-head (ctn/get-parent-copy-heads (:objects page) shape))))
@@ -251,6 +299,35 @@
(let [ref-component (find-ref-component file page libraries shape :include-deleted? true)]
(true? (= (:id component) (:id ref-component)))))
(defn find-swap-slot
[shape page file libraries]
(dm/assert! "expected shape is head" (ctk/instance-head? shape))
;; (js/console.log "find-swap-slot" (clj->js shape))
(if-let [swap-slot (ctk/get-swap-slot shape)]
;; (do (js/console.log "uno" (str swap-slot)) swap-slot)
swap-slot
(let [[ref-shape ref-file ref-container] (find-ref-shape-context file
page
libraries
shape
:include-deleted? true)]
;; (js/console.log "ref-shape" (clj->js ref-shape))
(when ref-shape
;; (js/console.log "ref-shape" (clj->js ref-shape))
(if-let [swap-slot (ctk/get-swap-slot ref-shape)]
;; (do (js/console.log "dos" (str swap-slot)) swap-slot)
swap-slot
(if (ctk/main-instance? ref-shape)
(:id shape)
(find-swap-slot ref-shape ref-container ref-file libraries)))))))
(defn match-swap-slot?
[shape-inst shape-main page-inst page-main file libraries]
(let [slot-inst (find-swap-slot shape-inst page-inst file libraries)
slot-main (find-swap-slot shape-main page-main file libraries)]
(or (= slot-inst slot-main)
(= slot-inst (:id shape-main)))))
(defn get-component-shapes
"Retrieve all shapes of the component"
[file-data component]