🐛 Keep Inspect from crashing on a shape whose parent is missing

In a damaged file a shape may point to a parent that does not exist.
The Inspect tab computes the position relative to the parent, so
inspecting such a shape replaced the workspace with the internal error
page. Inspect leaves the position out and logs a warning instead.
This commit is contained in:
alonso.torres 2026-11-04 10:00:51 +01:00
parent ca72f98238
commit 24aa480aff
2 changed files with 28 additions and 1 deletions

View File

@ -12,6 +12,7 @@
[app.common.files.helpers :as cfh]
[app.common.geom.matrix :as gmt]
[app.common.geom.shapes :as gsh]
[app.common.logging :as log]
[app.common.types.shape.layout :as ctl]
[app.main.ui.formats :as fmt]
[app.util.code-gen.common :as cgc]
@ -24,12 +25,24 @@
:gradient fill-color-gradient
:image fill-image})
(defn- missing-parent?
"True when the parent of `shape` is not in `objects`, which happens in a
damaged file; the position, relative to the parent, cannot be computed."
[objects shape]
(let [missing? (not (contains? objects (:parent-id shape)))]
(when missing?
(log/wrn :hint "shape parent not found"
:shape-id (dm/str (:id shape))
:parent-id (dm/str (:parent-id shape))))
missing?))
(defn get-shape-position
[shape objects coord]
(when (and (not (cfh/root-frame? shape))
(or (not (ctl/any-layout-immediate-child? objects shape))
(ctl/position-absolute? shape)))
(ctl/position-absolute? shape))
(not (missing-parent? objects shape)))
(let [parent (get objects (:parent-id shape))

View File

@ -112,3 +112,17 @@
(let [markup (render-panel panel shapes)]
(t/is (str/includes? markup "Border width"))
(t/is (str/includes? markup "3px")))))))
;; Scenario: the selected shape points to a parent missing from the page, as
;; in a damaged file or while a rejected save is on screen. Proves: the
;; geometry panels and the code view show the size and leave out the
;; position, which needs the parent, instead of crashing the workspace.
(t/deftest geometry-without-a-parent-leaves-out-the-position
(let [orphan (assoc (shape :rect per-side-stroke) :parent-id (uuid/next) :frame-id (uuid/next))]
(doseq [panel [geometry/geometry-panel* styles-geometry/geometry-panel*]]
(let [markup (render-panel panel [orphan])]
(t/is (str/includes? markup "120px"))
(t/is (not (str/includes? markup "Left")))))
(let [code (css/get-shape-properties-css {(:id orphan) orphan} orphan css/shape-css-properties)]
(t/is (str/includes? code "width: 120px;"))
(t/is (not (str/includes? code "left:"))))))