mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 22:10:34 +00:00
A save whose changes failed validation was rejected as a whole: autosave stopped, the edits made after it piled up unsent, and a reload lost them all, the valid ones included. The frontend now sends each commit of a save as its own group with its commit id (:changes-with-metadata). When applying and validating all of them at once fails, the backend searches by bisection for the first commit that fails, keeps the commits before it and answers with :rejected (that commit and every later one). Only the kept changes are stored, snapshotted and broadcast, so other users never see the rejected ones. Flat :changes and groups without ids stay all-or-nothing; database and network errors still fail the whole request. A rejection without an error type is reported as an internal error. The frontend rolls the file back to what the server holds: it undoes every pending commit of that file, applies again the remote changes that arrived meanwhile, and redoes the kept commits. Undoing only the rejected commits would write stale values over a peer's later change to the same attribute. The rejected and later commits leave the queue, the buffer and the undo history, and a warning that hides after ten seconds tells the user. The pure bookkeeping lives in app.main.data.persistence.commits. The pending notice of a commit the rollback dropped no longer leaves the save status at pending, which made "Pin this version" hang and fail. Debug tools drive these cases by hand: debug.commitInvalidChange() makes a save fail validation, holdSaves() delays the answers, failNextSave() and failNextRollback() fail them on purpose (backend flag debug-save-faults), and persistenceState() shows the queue.