-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement persistence of starred items
- Loading branch information
1 parent
4282865
commit 574fd9e
Showing
5 changed files
with
87 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { IStateDB } from '@jupyterlab/statedb'; | ||
import { ReadonlyPartialJSONValue, PromiseDelegate } from '@lumino/coreutils'; | ||
import { ILauncher } from '@jupyterlab/launcher'; | ||
|
||
abstract class Database<V extends ReadonlyPartialJSONValue, K> { | ||
ready: Promise<void>; | ||
constructor(options: { stateDB: IStateDB; fetchInterval: number }) { | ||
this._stateDB = options.stateDB; | ||
const ready = new PromiseDelegate<void>(); | ||
this.ready = ready.promise; | ||
this._updateDB().then(() => ready.resolve()); | ||
window.setInterval(this._updateDB, options.fetchInterval); | ||
} | ||
protected _get(item: K) { | ||
if (!this._db) { | ||
console.error('Database is not ready!'); | ||
return null; | ||
} | ||
return this._db[this._itemKey(item)]; | ||
} | ||
protected async _set(item: K, value: V) { | ||
const db = await this._fetch(); | ||
this._db = db; | ||
db[this._itemKey(item)] = value; | ||
await this._stateDB.save(this._stateDBKey, db); | ||
} | ||
private _updateDB = async () => { | ||
const db = await this._fetch(); | ||
this._db = db; | ||
}; | ||
private async _fetch(): Promise<Record<string, V>> { | ||
let db = (await this._stateDB.fetch(this._stateDBKey)) as | ||
| Record<string, V> | ||
| undefined; | ||
if (typeof db === 'undefined') { | ||
// retry once: sometimes state DB does not load up on first try | ||
db = (await this._stateDB.fetch(this._stateDBKey)) as | ||
| Record<string, V> | ||
| undefined; | ||
} | ||
if (typeof db === 'undefined') { | ||
return {}; | ||
} | ||
return db; | ||
} | ||
protected abstract _itemKey(item: K): string; | ||
protected abstract _stateDBKey: string; | ||
private _db: Record<string, V> | null = null; | ||
private _stateDB: IStateDB; | ||
} | ||
|
||
export abstract class ItemDatabase< | ||
V extends ReadonlyPartialJSONValue | ||
> extends Database<V, ILauncher.IItemOptions> { | ||
protected _itemKey(item: ILauncher.IItemOptions): string { | ||
return item.command + '_' + JSON.stringify(item.args); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,22 @@ | ||
import { ILauncher } from '@jupyterlab/launcher'; | ||
import { ItemDatabase } from './database'; | ||
|
||
export interface IFavoritesDatabase { | ||
get(item: ILauncher.IItemOptions): boolean | null; | ||
set(item: ILauncher.IItemOptions, isFavourite: boolean): void; | ||
set(item: ILauncher.IItemOptions, isFavourite: boolean): Promise<void>; | ||
} | ||
|
||
export class FavoritesDatabase implements IFavoritesDatabase { | ||
constructor() { | ||
// TODO: use settings registry, or state db, or server to persist this info | ||
this._db = new Map(); | ||
} | ||
export class FavoritesDatabase | ||
extends ItemDatabase<boolean> | ||
implements IFavoritesDatabase | ||
{ | ||
protected _stateDBKey = 'new-launcher:favorites'; | ||
|
||
get(item: ILauncher.IItemOptions) { | ||
return this._db.get(this._itemKey(item)) ?? null; | ||
return super._get(item) ?? null; | ||
} | ||
set(item: ILauncher.IItemOptions, isFavourite: boolean) { | ||
this._db.set(this._itemKey(item), isFavourite); | ||
} | ||
private _itemKey(item: ILauncher.IItemOptions): string { | ||
return item.command + '_' + JSON.stringify(item.args); | ||
|
||
async set(item: ILauncher.IItemOptions, isFavourite: boolean) { | ||
this._set(item, isFavourite); | ||
} | ||
private _db: Map<string, boolean>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,23 @@ | ||
import { ILauncher } from '@jupyterlab/launcher'; | ||
import { IStateDB } from '@jupyterlab/statedb'; | ||
import { ItemDatabase } from './database'; | ||
|
||
export interface ILastUsedDatabase { | ||
get(item: ILauncher.IItemOptions): Date | null; | ||
recordAsUsedNow(item: ILauncher.IItemOptions): Promise<void>; | ||
} | ||
|
||
type DatabaseLayout = Record<string, string>; | ||
export class LastUsedDatabase | ||
extends ItemDatabase<string> | ||
implements ILastUsedDatabase | ||
{ | ||
protected _stateDBKey = 'new-launcher:last-used'; | ||
|
||
export class LastUsedDatabase implements ILastUsedDatabase { | ||
constructor(options: { stateDB: IStateDB; fetchInterval: number }) { | ||
this._stateDB = options.stateDB; | ||
this._updateDB(); | ||
window.setInterval(this._updateDB, options.fetchInterval); | ||
} | ||
get(item: ILauncher.IItemOptions) { | ||
if (!this._db) { | ||
return null; | ||
} | ||
const date = this._db[this._itemKey(item)]; | ||
const date = super._get(item); | ||
return date ? new Date(date) : null; | ||
} | ||
|
||
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<DatabaseLayout> { | ||
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); | ||
this._set(item, new Date().toUTCString()); | ||
} | ||
private _db: DatabaseLayout | null = null; | ||
private _stateDB: IStateDB; | ||
private _stateDBKey = 'new-launcher:last-used'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters