| Age | Commit message (Collapse) | Author | Files | Lines |
|
Reported from use: a note created with only a title then saved left a db.json
entry with no file beside it, and reopening it said the file was missing.
Cause: FileView.setText("") on a path that view has not loaded creates no
file at all and reports no error. The index write (always non-empty JSON)
was fine, so only the body was lost, which is why it looked like a missing
file rather than a failed save. Bodies are now written by a Process running
cat > <file> with the text on stdin: verified against empty and non-empty
payloads, consecutive writes on one Process, and a store with no db.json at
all. The exit code is the real outcome, so a refused write reports it.
Second report in the same flow: the editor stays editable after the first
click, so typing more and then pressing Commit & push dropped the edit, the
push carrying only what the first click wrote. The second click now writes
the current title and body before it commits and pushes.
|
|
A review of the branch found four ways the page could report success for
work that never happened, all reachable in ordinary use.
Writes: setText is asynchronous unless blockWrites, and its
saved()/saveFailed() do not fire for every write (a second setText to the
same path loses the signal, which stranded the callback), so a save was
reported before it landed and a failed db.json or body write was never
seen. Both views now block and carry the outcome, so writeDb and writeBody
know the result when they return; a failed create therefore leaves no index
entry. The create path also loads the body before the index, so a failed
body write cannot leave an entry with no text.
Commits: the sync chain swallowed every commit failure with '|| true', so a
failing pre-commit hook or a signing failure pushed an unchanged HEAD and
reported success. It now stages, commits only when something is staged, and
lets 'set -e' fail the chain, with stderr folded in for the whole chain
rather than just the push.
Duplicate notes: the 'awaiting commit' state lived only in a 3 second
timer, so a slower second click re-entered create() and appended a second
note. It is now a page property that outlives the timer, and the button
follows it.
Preview: the shared Switch writes checked itself, dropping the binding, so
the switch stopped following page.preview; resynced on change, the way
StatusRow.qml does.
Also validates a note's file name as digits before read, write or rm, and
clears the index error once the index reads again.
|
|
The editor, and the write and git path behind it. Save is two clicks and
each does one thing: the first writes the note and only then arms the
button as 'Commit & push?', so a quick second click cannot commit a note
the first has not written yet.
The write path refuses when db.json cannot be read as the index. That is
not hypothetical: git pull --rebase --autostash resolves a remote db.json
change against a local uncommitted one, the stash pop conflicts, git still
exits 0, and the file is left full of merge markers. Reading that as 'no
notes' and writing it back deleted every title in a probe; Notes.valid now
distinguishes it from an empty store and the write reports instead. parse
stays tolerant for display. Stamping lastpull also only follows a pull
that worked, and only when git is on at all.
Db reads that a write is based on go through reload() plus waitForJob():
blockLoading does not make reload() blocking, contrary to the note in
AGENTS.md, and reading text() straight after reload() returns the old
contents. A body is written with a plain setText, which needs no prior
load; only reading text() before a load would.
|
|
The module resolves notes.sh's own paths by sourcing its rc, so a changed
BASEDIR moves the page with it, and notes.sh's git test is the same one the
page uses. A Module is a plain QtObject with no default property, so the
config Process and the db.json FileView are typed properties, the shape
UpdatesModule uses for its own Process.
db.json is watched rather than read on open: the tile's count has to move
when a note is added from either side, the CLI included, which is the same
call mail makes for its unread count.
The list reads db.json.notes rather than walking notes/, because that is
where the titles are; entries sort newest first on the file timestamp and
a title search filters them.
|