diff --git a/src/index.ts b/src/index.ts index 95774b6..27c4d7f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,6 +9,7 @@ import { ICommandPalette, MainAreaWidget } from '@jupyterlab/apputils'; import { FileBrowserModel, IDefaultFileBrowser } from '@jupyterlab/filebrowser'; import { ILauncher, LauncherModel } from '@jupyterlab/launcher'; import { ISettingRegistry } from '@jupyterlab/settingregistry'; +import { IStateDB } from '@jupyterlab/statedb'; import { ITranslator } from '@jupyterlab/translation'; import { addIcon, launcherIcon } from '@jupyterlab/ui-components'; import { find } from '@lumino/algorithm'; @@ -33,7 +34,7 @@ const plugin: JupyterFrontEndPlugin = { description: 'A redesigned JupyterLab launcher', provides: ILauncher, autoStart: true, - requires: [ITranslator], + requires: [ITranslator, IStateDB], optional: [ILabShell, ICommandPalette, IDefaultFileBrowser, ISettingRegistry], activate }; @@ -46,6 +47,7 @@ export default plugin; function activate( app: JupyterFrontEnd, translator: ITranslator, + stateDB: IStateDB, labShell: ILabShell | null, palette: ICommandPalette | null, defaultBrowser: IDefaultFileBrowser | null, @@ -74,7 +76,10 @@ function activate( }); } - const lastUsedDatabase = new LastUsedDatabase(); + const lastUsedDatabase = new LastUsedDatabase({ + stateDB, + fetchInterval: 10000 + }); const favoritesDatabase = new FavoritesDatabase(); commands.addCommand(CommandIDs.create, { diff --git a/src/last_used.ts b/src/last_used.ts index a13cecf..b9aadd0 100644 --- a/src/last_used.ts +++ b/src/last_used.ts @@ -1,24 +1,52 @@ import { ILauncher } from '@jupyterlab/launcher'; +import { IStateDB } from '@jupyterlab/statedb'; export interface ILastUsedDatabase { get(item: ILauncher.IItemOptions): Date | null; - recordAsUsedNow(item: ILauncher.IItemOptions): void; + recordAsUsedNow(item: ILauncher.IItemOptions): Promise; } +type DatabaseLayout = Record; + export class LastUsedDatabase implements ILastUsedDatabase { - constructor() { - // TODO: use settings registry, or state db, or server to persist this info - this._db = new Map(); + constructor(options: { stateDB: IStateDB; fetchInterval: number }) { + this._stateDB = options.stateDB; + this._updateDB(); + window.setInterval(this._updateDB, options.fetchInterval); } get(item: ILauncher.IItemOptions) { - const date = this._db.get(this._itemKey(item)); + if (!this._db) { + return null; + } + const date = this._db[this._itemKey(item)]; return date ? new Date(date) : null; } - recordAsUsedNow(item: ILauncher.IItemOptions) { - this._db.set(this._itemKey(item), new Date().toUTCString()); + async recordAsUsedNow(item: ILauncher.IItemOptions) { + const db = await this._fetch(); + this._db = db; + db[this._itemKey(item)] = new Date().toUTCString(); + await this._stateDB.save(this._stateDBKey, db); + } + private _updateDB = () => { + this._fetch() + .then(db => { + this._db = db; + }) + .catch(console.warn); + }; + private async _fetch(): Promise { + const db = (await this._stateDB.fetch(this._stateDBKey)) as + | DatabaseLayout + | undefined; + if (typeof db === 'undefined') { + return {}; + } + return db; } private _itemKey(item: ILauncher.IItemOptions): string { return item.command + '_' + JSON.stringify(item.args); } - private _db: Map; + private _db: DatabaseLayout | null = null; + private _stateDB: IStateDB; + private _stateDBKey = 'new-launcher:last-used'; } diff --git a/src/launcher.tsx b/src/launcher.tsx index 57ce5c6..d047656 100644 --- a/src/launcher.tsx +++ b/src/launcher.tsx @@ -418,7 +418,7 @@ class Item implements IItem { async execute() { const { item, commands, lastUsedDatabase } = this._options; await commands.execute(item.command, this.args); - lastUsedDatabase.recordAsUsedNow(item); + await lastUsedDatabase.recordAsUsedNow(item); this.lastUsed = lastUsedDatabase.get(item); this._refreshLastUsed.emit(); }