(core) Storing last position for doc and user

Summary: Last position should be stored for document and user.

Test Plan: Updated tests

Reviewers: georgegevoian

Reviewed By: georgegevoian

Differential Revision: https://phab.getgrist.com/D3143
pull/115/head
Jarosław Sadziński 3 years ago
parent c6aa9b65d4
commit fc50079e03

@ -18,8 +18,8 @@ export class CursorMonitor extends Disposable {
// abstraction to work with local storage // abstraction to work with local storage
private _store: StorageWrapper; private _store: StorageWrapper;
// document id that this monitor is attached // key for storing position in the memory (docId + userId)
private _docId: string; private _key: string;
// flag that tells if the position was already restored // flag that tells if the position was already restored
// we track document's view change event, so we only want // we track document's view change event, so we only want
// to react to that event once // to react to that event once
@ -31,7 +31,10 @@ export class CursorMonitor extends Disposable {
super(); super();
this._store = new StorageWrapper(store); this._store = new StorageWrapper(store);
this._docId = doc.docId();
// Use document id and user id as a key for storage.
const userId = doc.app.topAppModel.appObs.get()?.currentUser?.id ?? null;
this._key = doc.docId() + userId;
/** /**
* When document loads last cursor position should be restored from local storage. * When document loads last cursor position should be restored from local storage.
@ -77,12 +80,12 @@ export class CursorMonitor extends Disposable {
} }
private _storePosition(pos: ViewCursorPos) { private _storePosition(pos: ViewCursorPos) {
this._store.update(this._docId, pos); this._store.update(this._key, pos);
} }
private _restoreLastPosition(view: IDocPage) { private _restoreLastPosition(view: IDocPage) {
const lastPosition = this._store.read(this._docId); const lastPosition = this._store.read(this._key);
this._store.clear(this._docId); this._store.clear(this._key);
if (lastPosition && lastPosition.position.viewId == view) { if (lastPosition && lastPosition.position.viewId == view) {
return lastPosition.position; return lastPosition.position;
} }

@ -22,7 +22,10 @@ export class EditorMonitor extends Disposable {
super(); super();
// create store // create store
this._store = new EditMemoryStorage(doc.docId(), store); const userId = doc.app.topAppModel.appObs.get()?.currentUser?.id ?? null;
// use document id and user id as a key for storage
const key = doc.docId() + userId;
this._store = new EditMemoryStorage(key, store);
// listen to document events to handle view load event // listen to document events to handle view load event
this._listenToReload(doc); this._listenToReload(doc);
@ -58,8 +61,8 @@ export class EditorMonitor extends Disposable {
// will be invoked only once // will be invoked only once
let executed = false; let executed = false;
// don't restore on readonly mode // don't restore on readonly mode or when there is custom nav
if (doc.isReadonly.get()) { return; } if (doc.isReadonly.get() || doc.hasCustomNav.get()) { return; }
// on view shown // on view shown
this._currentViewListener.autoDispose(doc.currentView.addListener(async view => { this._currentViewListener.autoDispose(doc.currentView.addListener(async view => {
@ -114,7 +117,7 @@ class EditMemoryStorage {
private _entry: LastEditData | null = null; private _entry: LastEditData | null = null;
private _timestamp = 0; private _timestamp = 0;
constructor(private _docId: string, private _storage = getStorage()) { constructor(private _key: string, private _storage = getStorage()) {
} }
public updateValue(pos: CellPosition, value: EditorState): void { public updateValue(pos: CellPosition, value: EditorState): void {
@ -136,13 +139,13 @@ class EditMemoryStorage {
return this._timestamp; return this._timestamp;
} }
protected _key() { protected _storageKey() {
return `grist-last-edit-${this._docId}`; return `grist-last-edit-${this._key}`;
} }
protected load() { protected load() {
const storage = this._storage; const storage = this._storage;
const data = storage.getItem(this._key()); const data = storage.getItem(this._storageKey());
this._entry = null; this._entry = null;
this._timestamp = 0; this._timestamp = 0;
@ -166,14 +169,14 @@ class EditMemoryStorage {
// if entry was removed - clear the storage // if entry was removed - clear the storage
if (!this._entry) { if (!this._entry) {
storage.removeItem(this._key()); storage.removeItem(this._storageKey());
return; return;
} }
try { try {
this._timestamp = Date.now(); this._timestamp = Date.now();
const data = { timestamp: this._timestamp, entry: this._entry }; const data = { timestamp: this._timestamp, entry: this._entry };
storage.setItem(this._key(), JSON.stringify(data)); storage.setItem(this._storageKey(), JSON.stringify(data));
} catch (ex) { } catch (ex) {
console.error("Can't save current edited cell state. Error message: " + ex?.message); console.error("Can't save current edited cell state. Error message: " + ex?.message);
} }

@ -1838,6 +1838,20 @@ export async function getEnabledOptions(): Promise<SortOption[]> {
return options; return options;
} }
/**
* Runs action in a separate tab, closing the tab after.
* In case of an error tab is not closed, consider using cleanupExtraWindows
* on whole test suit if needed.
*/
export async function onNewTab(action: () => Promise<void>) {
await driver.executeScript("return window.open('about:blank', '_blank')");
const tabs = await driver.getAllWindowHandles();
await driver.switchTo().window(tabs[tabs.length - 1]);
await action();
await driver.close();
await driver.switchTo().window(tabs[tabs.length - 2]);
}
} // end of namespace gristUtils } // end of namespace gristUtils
stackWrapOwnMethods(gristUtils); stackWrapOwnMethods(gristUtils);

Loading…
Cancel
Save