Skip to content

ZenNotes v2.47.0

Latest

Choose a tag to compare

@github-actions github-actions released this 09 Sep 16:12
· 3 commits to main since this release

ZenNotes 2.47.0: switching drawings no longer overwrites one with the other, wikilinks at files are files, tasks stay visible during Cloud conflicts, and matching files stop waiting for review

A data-loss fix for Excalidraw drawings from #755, the Connections panel and gd treating a wikilink at an image or PDF as a missing note from #757, and two fixes from Unyanda's September 8 report: a note waiting for a Cloud decision no longer takes its tasks out of your day, and copying the same complete file to both devices no longer leaves it stuck in review. Unfinished merge drafts stay protected, including across desktop windows. Release PR: #752.

🐛 Fixes

  • A wikilink at a file in the vault is a file, not a missing note (#757, reported by Unyanda). The Connections panel listed an embedded image such as ![[assets/diagram.png]] under Links From Here as an unresolved wikilink and offered to create assets/diagram.png.md for it. The panel only asked the note index whether a target resolved, and an image is not a note. It now checks the vault's files with the same rules that render the embed (relative to the note, relative to the vault root, then a unique file name), lists a match as a file row that opens the file in its own tab, and offers to create a note only for a wikilink that reaches nothing. The same step now runs in every place a wikilink is followed: gd in the editor, a click on a rendered wikilink, and Cmd/Ctrl-click, none of which should propose file.png.md either. PDFs keep their existing gd behaviour of pinning into the reference pane.

    How to test locally: launch the isolated desktop as described below, put a PNG in assets/, and write ![[assets/diagram.png]] and [[assets/diagram.png]] in a note. Press Mod+2. Before: a CREATE row for assets/diagram.png suggesting /assets/diagram.png.md. After: a FILE row named diagram.png; j onto it and Enter opens the image in a tab. Put the cursor inside [[assets/diagram.png]] and press gd in normal mode. Before: a "Create note for" prompt. After: the image tab opens.

  • Switching between drawings no longer overwrites the one you open (#755, reported by gverger). Opening a second Excalidraw drawing could replace its file with the scene of the drawing you just left, and switching back and forth left both files holding the same scene. The drawing editor kept one "latest scene" and wrote it, after its short save delay, to whichever drawing was showing when the delay ran out. On a local vault the next drawing loads within a millisecond, so React folded "clear the canvas" and "show the next drawing" into one update and the previous canvas was never torn down. Excalidraw only reads the scene it is given once, at mount, so that surviving canvas kept reporting the old drawing under the new file's name. Each drawing now saves through its own session, bound to the path it was read from, the canvas is remounted per path, and a canvas being torn down can no longer arm a write against the drawing that replaced it. The viewport memory that restores your pan and zoom per drawing follows the same binding, so a switch no longer copies the previous drawing's viewport onto the next one.

    How to test locally: build and launch the isolated desktop as described below. In the sidebar, create a drawing named First and draw a circle, then create Second and draw a rectangle. Click First, then Second, then First, pausing about a second on each. Before: within a second of a switch, the drawing you opened shows and saves the previous drawing's shape, and reopening either file confirms the loss. After: each drawing keeps its own shape through any number of switches, and the files on disk still hold one circle and one rectangle. The same holds when you switch immediately after drawing, before the save delay has run.

  • A conflicted note keeps its tasks in view. List, Calendar, Kanban and the calendar panel continue showing the tasks from your local note, with a small Conflict pending label. Previously those tasks were deliberately withheld until the note was resolved, so deferring a sync decision also hid work from your task views. They now remain visible and refresh when you edit the local note. Resolving the conflict updates them only as the resulting note changes.

    How to test locally: launch the isolated desktop as described below. Put a dated task in a note, sync it, then edit the same line differently on two linked test devices. Press Sync now, leave the conflict unresolved, and open Tasks in List, Calendar and Kanban. Before: the note's tasks disappear. After: they remain with Conflict pending. Resolve the note and confirm the tasks match the chosen content and the label clears.

  • Identical files stop waiting for a decision. On the next sync, ZenNotes checks the current local file against the latest tracked Cloud version. When the same file at the same path has identical content and no separate draft to preserve, the conflict clears, the review closes if nothing else is waiting, and later edits sync normally. It does not rewrite either copy or choose one device over the other. Real differences, path/rename/deletion conflicts and unfinished combined-note drafts still need review.

    How to test locally: create a conflict and leave Review now open. Copy the complete Cloud version into the local file, then sync. Before: identical versions still block the file. After: the review closes and the next edit uploads. Repeat after typing a distinct combined-note draft: the review and saved draft must remain. Open the same vault in a second desktop window and sync there; the draft stays intact, and only one window can edit that conflict at a time.

🧰 For contributors

  • The drawing fix is commit 29c5287 on v2.47.0 (#755 closed 2026-09-09). Verified in the built desktop app over CDP: with seeded drawings, switching alone corrupted a file in 4 of 6 runs before the fix and 0 of 6 after; with the reporter's flow driven by real mouse drags (draw, switch inside the save delay, draw, switch, then rapid switches), 3 of 3 runs corrupted before and 0 of 3 after. The unit tests in ExcalidrawView.test.ts model the batched read and the late canvas report; both fail on the previous view. The app's bridge object is frozen in the renderer, so the harness watched the files on disk and hooked the renderer's timers instead of spying on writeNote.
  • The wikilink-file fix is commit bee2284 on v2.47.0 (#757 closed 2026-09-09). Verified in the built desktop app over CDP against the previous build: the Connections row for assets/diagram.png went from a CREATE row suggesting /assets/diagram.png.md to a FILE row, j then Enter on it opened the asset tab, and gd inside [[assets/diagram.png]] went from the create prompt to the image tab. Unit tests cover the outgoing-link classifier (connections-outgoing.test.ts) and the follow-link path. Harness note: a real CDP mouse click on a panel row fires no handler, before and after the fix, so the check drives rows through the keyboard.
  • Build with npm run build --workspace @zennotes/desktop. Create a scratch root with mktemp -d /tmp/zennotes-247.XXXXXX, then launch ZEN_PERF=1 ZENNOTES_USER_DATA_PATH=<scratch>/userdata ZENNOTES_CONFIG_DIR=<scratch>/config ZENNOTES_CLOUD_BASE_URL=http://127.0.0.1:43183 apps/desktop/node_modules/.bin/electron apps/desktop/out/main/index.js --remote-debugging-port=9326. Use a scratch vault and local test account only. The existing node tooling/scripts/cloud-conflict-demo-fixture.mjs supplies the local Cloud server.
  • Draft saves are flushed before sync takes the vault lock. Same-vault desktop windows acknowledge preparation and share the result; failed saves or a window opening/closing mid-preparation pause that run safely. Retry after the window loads.
  • Verified in the built desktop UI against the local fixture: task visibility, live and persisted conflict convergence, subsequent upload, draft retention, restart and two-window review ownership.
  • Release gates run fresh at the cut: apps/desktop build:prod (typecheck, tests, build, packaged CLI isolation), Go vet and tests, the app-core suite (1,980 tests), the signed packaged app launched in an isolated profile and reached a CDP page target in about 3 seconds, and the website suite (691 tests) with the release page entry in place.
  • The high-severity audit findings for js-yaml and svgo were cleared on main by #753 and merged into this branch before the cut. One moderate finding (hono) remains and predates this release.

Local-first and keyboard-first, as always.