🐛 Fix crash when dismissing the restore version modal (#9969)

This commit is contained in:
Belén Albeza 2026-06-02 11:33:06 +02:00 committed by GitHub
parent 17fb1c49f8
commit 7fdd2ceb5c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 225 additions and 8 deletions

View File

@ -0,0 +1,143 @@
{
"~:features": {
"~#set": [
"fdata/path-data",
"plugins/runtime",
"design-tokens/v1",
"variants/v1",
"layout/grid",
"styles/v2",
"fdata/objects-map",
"tokens/numeric-input",
"render-wasm/v1",
"components/v2",
"fdata/shape-data-type"
]
},
"~:team-id": "~u99e49e93-362f-80ef-8007-3450ea52c9a4",
"~:permissions": {
"~:type": "~:membership",
"~:is-owner": true,
"~:is-admin": true,
"~:can-edit": true,
"~:can-read": true,
"~:is-logged": true
},
"~:has-media-trimmed": false,
"~:comment-thread-seqn": 0,
"~:name": "New File 11",
"~:revn": 5,
"~:modified-at": "~m1780390315939",
"~:vern": 838776213,
"~:id": "~uf3a9df94-b15a-80eb-8008-1d22a57a9f94",
"~:is-shared": false,
"~:migrations": {
"~#ordered-set": [
"legacy-2",
"legacy-3",
"legacy-5",
"legacy-6",
"legacy-7",
"legacy-8",
"legacy-9",
"legacy-10",
"legacy-11",
"legacy-12",
"legacy-13",
"legacy-14",
"legacy-16",
"legacy-17",
"legacy-18",
"legacy-19",
"legacy-25",
"legacy-26",
"legacy-27",
"legacy-28",
"legacy-29",
"legacy-31",
"legacy-32",
"legacy-33",
"legacy-34",
"legacy-36",
"legacy-37",
"legacy-38",
"legacy-39",
"legacy-40",
"legacy-41",
"legacy-42",
"legacy-43",
"legacy-44",
"legacy-45",
"legacy-46",
"legacy-47",
"legacy-48",
"legacy-49",
"legacy-50",
"legacy-51",
"legacy-52",
"legacy-53",
"legacy-54",
"legacy-55",
"legacy-56",
"legacy-57",
"legacy-59",
"legacy-62",
"legacy-65",
"legacy-66",
"legacy-67",
"0001-remove-tokens-from-groups",
"0002-normalize-bool-content-v2",
"0002-clean-shape-interactions",
"0003-fix-root-shape",
"0003-convert-path-content-v2",
"0005-deprecate-image-type",
"0006-fix-old-texts-fills",
"0008-fix-library-colors-v4",
"0009-clean-library-colors",
"0009-add-partial-text-touched-flags",
"0010-fix-swap-slots-pointing-non-existent-shapes",
"0011-fix-invalid-text-touched-flags",
"0012-fix-position-data",
"0013-fix-component-path",
"0013-clear-invalid-strokes-and-fills",
"0014-fix-tokens-lib-duplicate-ids",
"0014-clear-components-nil-objects",
"0015-fix-text-attrs-blank-strings",
"0015-clean-shadow-color",
"0016-copy-fills-from-position-data-to-text-node",
"0017-fix-layout-flex-dir",
"0018-remove-unneeded-objects-from-components",
"0019-fix-missing-swap-slots",
"0020-sync-component-id-with-near-main",
"0021-fix-shape-svg-attrs",
"0022-normalize-component-root-and-resync"
]
},
"~:version": 67,
"~:project-id": "~ucd8f7672-e5d1-810f-8007-87e124eda82a",
"~:created-at": "~m1780389392874",
"~:backend": "legacy-db",
"~:data": {
"~:pages": [
"~uf3a9df94-b15a-80eb-8008-1d22a57a9f95"
],
"~:pages-index": {
"~uf3a9df94-b15a-80eb-8008-1d22a57a9f95": {
"~:objects": {
"~#penpot/objects-map/v2": {
"~u00000000-0000-0000-0000-000000000000": "[\"~#shape\",[\"^ \",\"~:y\",0,\"~:hide-fill-on-export\",false,\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:name\",\"Root Frame\",\"~:width\",0.01,\"~:type\",\"~:frame\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",0.0,\"~:y\",0.0]],[\"^:\",[\"^ \",\"~:x\",0.01,\"~:y\",0.0]],[\"^:\",[\"^ \",\"~:x\",0.01,\"~:y\",0.01]],[\"^:\",[\"^ \",\"~:x\",0.0,\"~:y\",0.01]]],\"~:r2\",0,\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^3\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",0,\"~:proportion\",1.0,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",0,\"~:y\",0,\"^6\",0.01,\"~:height\",0.01,\"~:x1\",0,\"~:y1\",0,\"~:x2\",0.01,\"~:y2\",0.01]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#FFFFFF\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^H\",0.01,\"~:flip-y\",null,\"~:shapes\",[\"~uf78d0909-e64a-8018-8008-1d22cc6ebe3d\",\"~u9da48676-d394-80d9-8008-1d26279cf232\"]]]",
"~uf78d0909-e64a-8018-8008-1d22cc6ebe3d": "[\"~#shape\",[\"^ \",\"~:y\",220,\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:grow-type\",\"~:fixed\",\"~:hide-in-viewer\",false,\"~:name\",\"Rectangle\",\"~:width\",188,\"~:type\",\"~:rect\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",774,\"~:y\",220]],[\"^<\",[\"^ \",\"~:x\",962,\"~:y\",220]],[\"^<\",[\"^ \",\"~:x\",962,\"~:y\",332]],[\"^<\",[\"^ \",\"~:x\",774,\"~:y\",332]]],\"~:r2\",0,\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^2\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:r3\",0,\"~:r1\",0,\"~:id\",\"~uf78d0909-e64a-8018-8008-1d22cc6ebe3d\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",774,\"~:proportion\",1,\"~:r4\",0,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",774,\"~:y\",220,\"^8\",188,\"~:height\",112,\"~:x1\",774,\"~:y1\",220,\"~:x2\",962,\"~:y2\",332]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^J\",112,\"~:flip-y\",null]]",
"~u9da48676-d394-80d9-8008-1d26279cf232": "[\"~#shape\",[\"^ \",\"~:y\",-170,\"~:transform\",[\"~#matrix\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:rotation\",0,\"~:grow-type\",\"~:fixed\",\"~:hide-in-viewer\",false,\"~:name\",\"Ellipse\",\"~:width\",110,\"~:type\",\"~:circle\",\"~:points\",[[\"~#point\",[\"^ \",\"~:x\",664,\"~:y\",-170]],[\"^<\",[\"^ \",\"~:x\",774,\"~:y\",-170]],[\"^<\",[\"^ \",\"~:x\",774,\"~:y\",-99]],[\"^<\",[\"^ \",\"~:x\",664,\"~:y\",-99]]],\"~:proportion-lock\",false,\"~:transform-inverse\",[\"^2\",[\"^ \",\"~:a\",1.0,\"~:b\",0.0,\"~:c\",0.0,\"~:d\",1.0,\"~:e\",0.0,\"~:f\",0.0]],\"~:id\",\"~u9da48676-d394-80d9-8008-1d26279cf232\",\"~:parent-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:frame-id\",\"~u00000000-0000-0000-0000-000000000000\",\"~:strokes\",[],\"~:x\",664,\"~:proportion\",1,\"~:selrect\",[\"~#rect\",[\"^ \",\"~:x\",664,\"~:y\",-170,\"^8\",110,\"~:height\",71,\"~:x1\",664,\"~:y1\",-170,\"~:x2\",774,\"~:y2\",-99]],\"~:fills\",[[\"^ \",\"~:fill-color\",\"#B1B2B5\",\"~:fill-opacity\",1]],\"~:flip-x\",null,\"^F\",71,\"~:flip-y\",null]]"
}
},
"~:id": "~uf3a9df94-b15a-80eb-8008-1d22a57a9f95",
"~:name": "Page 1"
}
},
"~:id": "~uf3a9df94-b15a-80eb-8008-1d22a57a9f94",
"~:options": {
"~:components-v2": true,
"~:base-font-size": "16px"
}
}
}

View File

@ -0,0 +1,34 @@
[
{
"~:revn": 3,
"~:modified-at": "~m1780390308760",
"~:deleted-at": "~m1780476708760",
"~:created-by": "system",
"~:label": "snapshot-2026-06-02-08-51-48-760883637",
"~:id": "~uf3a9df94-b15a-80eb-8008-1d2623e61ed3",
"~:profile-id": "~u99e49e93-362f-80ef-8007-3450ea5204aa",
"~:version": 67,
"~:created-at": "~m1780390308760"
},
{
"~:revn": 0,
"~:modified-at": "~m1780389436291",
"~:deleted-at": "~m1780475836238",
"~:created-by": "system",
"~:label": "internal/snapshot/0",
"~:id": "~uf3a9df94-b15a-80eb-8008-1d22cfe0f1d4",
"~:profile-id": "~u99e49e93-362f-80ef-8007-3450ea5204aa",
"~:version": 67,
"~:created-at": "~m1780389436291"
},
{
"~:id": "~uf3a9df94-b15a-80eb-8008-1d22d3c4857a",
"~:label": "Inicial",
"~:revn": 1,
"~:version": 67,
"~:created-at": "~m1780389440274",
"~:modified-at": "~m1780389440274",
"~:created-by": "user",
"~:profile-id": "~u99e49e93-362f-80ef-8007-3450ea5204aa"
}
]

View File

@ -0,0 +1,9 @@
[
{
"~:id": "~u99e49e93-362f-80ef-8007-3450ea5204aa",
"~:email": "leia@example.com",
"~:name": "Leia Organa",
"~:fullname": "Leia Organa",
"~:is-active": true
}
]

View File

@ -147,3 +147,23 @@ test("BUG 13385 - Fix viewport not updating when restoring version", async ({ pa
// assert that the circle shape exists
await expect(workspacePage.layers.getByText("Ellipse")).toBeVisible();
});
test("BUG 14289 - Fix WASM crash when restoring version directly without preview", async ({ page }) => {
const workspacePage = new WasmWorkspacePage(page);
await workspacePage.setupEmptyFile();
await workspacePage.mockGetFile("versions/get-file-14289.json");
await workspacePage.mockRPC("get-profiles-for-file-comments?file-id=*", "versions/get-profiles-for-file-comments-14289.json");
await workspacePage.mockRPC("get-file-snapshots?file-id=*", "versions/get-file-snapshots-14289.json");
await workspacePage.goToWorkspace();
await workspacePage.rightSidebar.getByRole("button", { name: "History" }).click();
await workspacePage.rightSidebar.getByRole("button", { name: "Open version menu" }).click();
await workspacePage.rightSidebar.getByRole("button", { name: "Restore" }).click();
const dismissButton = workspacePage.page.getByRole("button", { name: /Dismiss/i });
await dismissButton.click();
await expect(dismissButton).toBeHidden();
await expect(workspacePage.viewport).toBeVisible();
});

View File

@ -176,24 +176,35 @@
;; RESTORE VERSION EVENTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn exit-preview
"Exit from preview mode and reload the live file data"
(defn- exit-preview-cleanup
"Restore the backed-up live file data and clear the preview flags."
[]
(ptk/reify ::exit-preview
(ptk/reify ::exit-preview-cleanup
ptk/UpdateEvent
(update [_ state]
(let [backup (dm/get-in state [:workspace-versions :backup])]
(-> state
(update :workspace-versions dissoc :backup)
(update :workspace-global dissoc :read-only? :preview-id)
(update :files assoc (:id backup) backup))))
(update :files assoc (:id backup) backup))))))
(defn exit-preview
"Exit from preview mode and reload the live file data.
No-op when there is no preview to exit (no backup stored), so it is
safe to call from the restore dialog dismiss action even when the
restore was triggered directly without entering preview first."
[]
(ptk/reify ::exit-preview
ptk/WatchEvent
(watch [_ state _]
(let [file-id (:current-file-id state)
page-id (:current-page-id state)]
(rx/of (dwpg/initialize-page file-id page-id))))))
;; Ensure we are actually in preview mode. Otherwise there
;; is no backup to restore and wasm crashes
(when (dm/get-in state [:workspace-versions :backup])
(let [file-id (:current-file-id state)
page-id (:current-page-id state)]
(rx/of (exit-preview-cleanup)
(dwpg/initialize-page file-id page-id)))))))
(defn- restore-version
[id]