Hi! On the backend I save backups of the document from time to time as encodeStateAsUdate(yDoc)
to have some version history.
I want to be able to rollback to a previous state.
Given two documents I wrote the following code:
public getRevertedChanges({ currentVersion, oldVersion }: { currentVersion: Doc; oldVersion: Doc }): Uint8Array {
const currentStateVector = encodeStateVector(currentVersion);
const oldStateVector = encodeStateVector(oldVersion);
const changes = encodeStateAsUpdate(currentVersion, oldStateVector);
const um = new UndoManager([...oldVersion.share.values()]);
applyUpdate(oldVersion, changes);
um.undo();
const revertedChanges = encodeStateAsUpdate(oldVersion, currentStateVector);
um.destroy();
return revertedChanges;
}
Is oldVersionDoc required to initialize root share types, like oldVersionDoc.getMap(“map1”) etc., for UndoManager to work correctly or not? Are there any problems with this approach?
dmonad
December 7, 2024, 4:43pm
2
I think this should be fine.
encodeStateAsUpdate
always includes the full delete set. Hence, I would use the update
event to generate revertedChanges
. Something like…
const updates = []
oldVersion.on('update', update => { updates.push })
um.undo()
const revertedChanges = Y.mergeUpdates(updates)
This gives you the minimal update to revert to the previous version. However, your approach is fine too.
thanks, this way the updates are really smaller
@dmonad I found a strange behavior, in some cases the initialization of root types affects the result of undo.
if I add initialization (getMap) at the beginning, console.log will output 1. And if I don’t, it outputs 2. If this looks like a bug in yjs, I can share the states of these documents so that you can reproduce the behavior. Or this is still a planned behavior and there is a required to initialize root types
public getRevertedChanges({ currentVersion, oldVersion }: { currentVersion: Doc; oldVersion: Doc }): Uint8Array {
// oldVersion.getMap("objects")
const currentStateVector = encodeStateVector(currentVersion);
const oldStateVector = encodeStateVector(oldVersion);
const changes = encodeStateAsUpdate(currentVersion, oldStateVector);
const um = new UndoManager([...oldVersion.share.values()]);
applyUpdate(oldVersion, changes);
um.undo();
console.log("size after revert", oldVersion.getMap("objects").size);
const revertedChanges = encodeStateAsUpdate(oldVersion, currentStateVector);
um.destroy();
return revertedChanges;
}