fix(y-indexeddb): alert user when write operation unfinished (#2085)

This commit is contained in:
Himself65
2023-04-22 17:32:57 -05:00
committed by GitHub
parent 74e21311dc
commit 2ad1b770d0
2 changed files with 69 additions and 21 deletions

View File

@@ -240,6 +240,31 @@ describe('indexeddb provider', () => {
expect(yDoc.getMap().get('foo')).toBe('bar'); expect(yDoc.getMap().get('foo')).toBe('bar');
} }
}); });
test('beforeunload', async () => {
const oldAddEventListener = window.addEventListener;
window.addEventListener = vi.fn((event: string, fn, options) => {
expect(event).toBe('beforeunload');
return oldAddEventListener(event, fn, options);
});
const oldRemoveEventListener = window.removeEventListener;
window.removeEventListener = vi.fn((event: string, fn, options) => {
expect(event).toBe('beforeunload');
return oldRemoveEventListener(event, fn, options);
});
const doc = new Doc();
const provider = createIndexedDBProvider('1', doc);
const map = doc.getMap('map');
map.set('1', 1);
provider.connect();
await provider.whenSynced;
expect(window.addEventListener).toBeCalledTimes(1);
expect(window.removeEventListener).toBeCalledTimes(1);
window.addEventListener = oldAddEventListener;
window.removeEventListener = oldRemoveEventListener;
});
}); });
describe('milestone', () => { describe('milestone', () => {

View File

@@ -21,6 +21,25 @@ const snapshotOrigin = Symbol('snapshot-origin');
let mergeCount = 500; let mergeCount = 500;
/**
* @internal
*/
const saveAlert = (event: BeforeUnloadEvent) => {
event.preventDefault();
return (event.returnValue =
'Data is not saved. Are you sure you want to leave?');
};
export const writeOperation = async (op: Promise<unknown>) => {
window.addEventListener('beforeunload', saveAlert, {
capture: true,
});
await op;
window.removeEventListener('beforeunload', saveAlert, {
capture: true,
});
};
export function setMergeCount(count: number) { export function setMergeCount(count: number) {
mergeCount = count; mergeCount = count;
} }
@@ -169,9 +188,9 @@ export const createIndexedDBProvider = (
}, },
], ],
}; };
await store.put(data); await writeOperation(store.put(data));
} else { } else {
await store.put(data); await writeOperation(store.put(data));
} }
} }
@@ -205,15 +224,17 @@ export const createIndexedDBProvider = (
return; return;
} }
if (!data) { if (!data) {
await db.put('workspace', { await writeOperation(
id, db.put('workspace', {
updates: [ id,
{ updates: [
timestamp: Date.now(), {
update: encodeStateAsUpdate(doc), timestamp: Date.now(),
}, update: encodeStateAsUpdate(doc),
], },
}); ],
})
);
} else { } else {
const updates = data.updates.map(({ update }) => update); const updates = data.updates.map(({ update }) => update);
const fakeDoc = new Doc(); const fakeDoc = new Doc();
@@ -226,16 +247,18 @@ export const createIndexedDBProvider = (
encodeStateAsUpdate(doc), encodeStateAsUpdate(doc),
encodeStateAsUpdate(fakeDoc) encodeStateAsUpdate(fakeDoc)
); );
await store.put({ await writeOperation(
...data, store.put({
updates: [ ...data,
...data.updates, updates: [
{ ...data.updates,
timestamp: Date.now(), {
update: newUpdate, timestamp: Date.now(),
}, update: newUpdate,
], },
}); ],
})
);
doc.transact(() => { doc.transact(() => {
updates.forEach(update => { updates.forEach(update => {
applyUpdate(doc, update); applyUpdate(doc, update);