From 3e8c665b7f6fed40360a2b68d9949aed7812ec8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Tue, 28 May 2024 13:55:38 +0200 Subject: [PATCH] :wrench: Add optional validation to check missing swap slots --- common/src/app/common/files/repair.cljc | 15 ++++++++ common/src/app/common/files/validate.cljc | 46 ++++++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/common/src/app/common/files/repair.cljc b/common/src/app/common/files/repair.cljc index 4c42d9225..98e1642a9 100644 --- a/common/src/app/common/files/repair.cljc +++ b/common/src/app/common/files/repair.cljc @@ -460,6 +460,21 @@ (pcb/with-library-data file-data) (pcb/update-component (:id shape) repair-component)))) +(defmethod repair-error :missing-slot + [_ {:keys [shape page-id args] :as error} file-data _] + (let [repair-shape + (fn [shape] + ;; Set the desired swap slot + (let [slot (:swap-slot args)] + (when (some? slot) + (log/debug :hint (str " -> set swap-slot to " slot)) + (update shape :touched cfh/set-touched-group (ctk/build-swap-slot-group slot)))))] + + (log/dbg :hint "repairing shape :missing-slot" :id (:id shape) :name (:name shape) :page-id page-id) + (-> (pcb/empty-changes nil page-id) + (pcb/with-file-data file-data) + (pcb/update-shapes [(:id shape)] repair-shape)))) + (defmethod repair-error :default [_ error file _] (log/error :hint "Unknown error code, don't know how to repair" :code (:code error)) diff --git a/common/src/app/common/files/validate.cljc b/common/src/app/common/files/validate.cljc index 17c0f130c..7959c5f31 100644 --- a/common/src/app/common/files/validate.cljc +++ b/common/src/app/common/files/validate.cljc @@ -6,6 +6,7 @@ (ns app.common.files.validate (:require + [app.common.data :as d] [app.common.data.macros :as dm] [app.common.exceptions :as ex] [app.common.files.helpers :as cfh] @@ -50,7 +51,8 @@ :not-head-copy-not-allowed :not-component-not-allowed :component-nil-objects-not-allowed - :instance-head-not-frame}) + :instance-head-not-frame + :missing-slot}) (def ^:private schema:error @@ -454,6 +456,8 @@ ;; PUBLIC API: VALIDATION FUNCTIONS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(declare check-swap-slots) + (defn validate-file "Validate full referential integrity and semantic coherence on file data. @@ -464,6 +468,8 @@ (doseq [page (filter :id (ctpl/pages-seq data))] (check-shape uuid/zero file page libraries) + (when (str/includes? (:name file) "check-swap-slot") + (check-swap-slots uuid/zero file page libraries)) (->> (get-orphan-shapes page) (run! #(check-shape % file page libraries)))) @@ -517,3 +523,41 @@ :hint "error on validating file referential integrity" :file-id (:id file) :details errors))) + + +(declare compare-slots) + +;; Optional check to look for missing swap slots. +;; Search for copies that do not point the shape-ref to the near component but don't have swap slot +;; (looking for position relative to the parent, in the copy and the main). +;; +;; This check cannot be generally enabled, because files that have been migrated from components v1 +;; may have copies with shapes that do not match by position, but have not been swapped. So we enable +;; it for specific files only. To activate the check, you need to add the string "check-swap-slot" to +;; the name of the file. +(defn- check-swap-slots + [shape-id file page libraries] + (let [shape (ctst/get-shape page shape-id)] + (if (and (ctk/instance-root? shape) (ctk/in-component-copy? shape)) + (let [ref-shape (ctf/find-ref-shape file page libraries shape :include-deleted? true :with-context? true) + container (:container (meta ref-shape))] + (when (some? ref-shape) + (compare-slots shape ref-shape file page container))) + (doall (for [child-id (:shapes shape)] + (check-swap-slots child-id file page libraries)))))) + +(defn- compare-slots + [shape-copy shape-main file container-copy container-main] + (if (and (not= (:shape-ref shape-copy) (:id shape-main)) + (nil? (ctk/get-swap-slot shape-copy))) + (report-error :missing-slot + "Shape has been swapped, should have swap slot" + shape-copy file container-copy + :swap-slot (or (ctk/get-swap-slot shape-main) (:id shape-main))) + (when (nil? (ctk/get-swap-slot shape-copy)) + (let [children-id-pairs (d/zip-all (:shapes shape-copy) (:shapes shape-main))] + (doall (for [[child-copy-id child-main-id] children-id-pairs] + (let [child-copy (ctst/get-shape container-copy child-copy-id) + child-main (ctst/get-shape container-main child-main-id)] + (when (and (some? child-copy) (some? child-main)) + (compare-slots child-copy child-main file container-copy container-main)))))))))