@jupyterlab/apputils-extension
Advanced tools
Comparing version 1.0.0-alpha.6 to 1.0.0-alpha.7
517
lib/index.js
@@ -1,2 +0,1 @@ | ||
"use strict"; | ||
/*----------------------------------------------------------------------------- | ||
@@ -6,33 +5,12 @@ | Copyright (c) Jupyter Development Team. | ||
|----------------------------------------------------------------------------*/ | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const application_1 = require("@jupyterlab/application"); | ||
const apputils_1 = require("@jupyterlab/apputils"); | ||
const coreutils_1 = require("@jupyterlab/coreutils"); | ||
const mainmenu_1 = require("@jupyterlab/mainmenu"); | ||
const coreutils_2 = require("@phosphor/coreutils"); | ||
const disposable_1 = require("@phosphor/disposable"); | ||
const widgets_1 = require("@phosphor/widgets"); | ||
const palette_1 = require("./palette"); | ||
const redirect_1 = require("./redirect"); | ||
require("../style/index.css"); | ||
import { ILayoutRestorer, IRouter, JupyterFrontEnd } from '@jupyterlab/application'; | ||
import { Dialog, ICommandPalette, ISplashScreen, IThemeManager, IWindowResolver, ThemeManager, WindowResolver, Printing } from '@jupyterlab/apputils'; | ||
import { Debouncer, ISettingRegistry, IStateDB, SettingRegistry, StateDB, Throttler, URLExt } from '@jupyterlab/coreutils'; | ||
import { IMainMenu } from '@jupyterlab/mainmenu'; | ||
import { PromiseDelegate } from '@phosphor/coreutils'; | ||
import { DisposableDelegate } from '@phosphor/disposable'; | ||
import { Menu } from '@phosphor/widgets'; | ||
import { Palette } from './palette'; | ||
import '../style/index.css'; | ||
/** | ||
* The interval in milliseconds that calls to save a workspace are debounced | ||
* to allow for multiple quickly executed state changes to result in a single | ||
* workspace save operation. | ||
*/ | ||
const WORKSPACE_SAVE_DEBOUNCE_INTERVAL = 750; | ||
/** | ||
* The query string parameter indicating that a workspace name should be | ||
* automatically generated if the current request collides with an open session. | ||
*/ | ||
const WORKSPACE_RESOLVE = 'resolve-workspace'; | ||
/** | ||
* The interval in milliseconds before recover options appear during splash. | ||
@@ -48,6 +26,5 @@ */ | ||
CommandIDs.loadState = 'apputils:load-statedb'; | ||
CommandIDs.recoverState = 'apputils:recover-statedb'; | ||
CommandIDs.print = 'apputils:print'; | ||
CommandIDs.reset = 'apputils:reset'; | ||
CommandIDs.resetOnLoad = 'apputils:reset-on-load'; | ||
CommandIDs.saveState = 'apputils:save-statedb'; | ||
})(CommandIDs || (CommandIDs = {})); | ||
@@ -58,5 +35,5 @@ /** | ||
const palette = { | ||
activate: palette_1.Palette.activate, | ||
activate: Palette.activate, | ||
id: '@jupyterlab/apputils-extension:palette', | ||
provides: apputils_1.ICommandPalette, | ||
provides: ICommandPalette, | ||
autoStart: true | ||
@@ -74,5 +51,5 @@ }; | ||
const paletteRestorer = { | ||
activate: palette_1.Palette.restore, | ||
activate: Palette.restore, | ||
id: '@jupyterlab/apputils-extension:palette-restorer', | ||
requires: [application_1.ILayoutRestorer], | ||
requires: [ILayoutRestorer], | ||
autoStart: true | ||
@@ -85,9 +62,9 @@ }; | ||
id: '@jupyterlab/apputils-extension:settings', | ||
activate: (app) => __awaiter(this, void 0, void 0, function* () { | ||
activate: async (app) => { | ||
const connector = app.serviceManager.settings; | ||
const plugins = (yield connector.list()).values; | ||
return new coreutils_1.SettingRegistry({ connector, plugins }); | ||
}), | ||
const plugins = (await connector.list()).values; | ||
return new SettingRegistry({ connector, plugins }); | ||
}, | ||
autoStart: true, | ||
provides: coreutils_1.ISettingRegistry | ||
provides: ISettingRegistry | ||
}; | ||
@@ -99,10 +76,10 @@ /** | ||
id: '@jupyterlab/apputils-extension:themes', | ||
requires: [coreutils_1.ISettingRegistry, application_1.JupyterFrontEnd.IPaths], | ||
optional: [apputils_1.ISplashScreen], | ||
requires: [ISettingRegistry, JupyterFrontEnd.IPaths], | ||
optional: [ISplashScreen], | ||
activate: (app, settings, paths, splash) => { | ||
const host = app.shell; | ||
const commands = app.commands; | ||
const url = coreutils_1.URLExt.join(paths.urls.base, paths.urls.themes); | ||
const url = URLExt.join(paths.urls.base, paths.urls.themes); | ||
const key = themes.id; | ||
const manager = new apputils_1.ThemeManager({ key, host, settings, splash, url }); | ||
const manager = new ThemeManager({ key, host, settings, splash, url }); | ||
// Keep a synchronously set reference to the current theme, | ||
@@ -140,3 +117,3 @@ // since the asynchronous setting of the theme in `changeTheme` | ||
autoStart: true, | ||
provides: apputils_1.IThemeManager | ||
provides: IThemeManager | ||
}; | ||
@@ -153,4 +130,4 @@ /** | ||
id: '@jupyterlab/apputils-extension:themes-palette-menu', | ||
requires: [apputils_1.IThemeManager], | ||
optional: [apputils_1.ICommandPalette, mainmenu_1.IMainMenu], | ||
requires: [IThemeManager], | ||
optional: [ICommandPalette, IMainMenu], | ||
activate: (app, manager, palette, mainMenu) => { | ||
@@ -160,3 +137,3 @@ const commands = app.commands; | ||
if (mainMenu) { | ||
const themeMenu = new widgets_1.Menu({ commands }); | ||
const themeMenu = new Menu({ commands }); | ||
themeMenu.title.label = 'JupyterLab Theme'; | ||
@@ -197,13 +174,17 @@ void app.restored.then(() => { | ||
autoStart: true, | ||
provides: apputils_1.IWindowResolver, | ||
requires: [application_1.JupyterFrontEnd.IPaths, application_1.IRouter], | ||
activate: (_, paths, router) => __awaiter(this, void 0, void 0, function* () { | ||
provides: IWindowResolver, | ||
requires: [JupyterFrontEnd.IPaths, IRouter], | ||
activate: async (_, paths, router) => { | ||
const { hash, path, search } = router.current; | ||
const query = coreutils_1.URLExt.queryStringToObject(search || ''); | ||
const solver = new apputils_1.WindowResolver(); | ||
const query = URLExt.queryStringToObject(search || ''); | ||
const solver = new WindowResolver(); | ||
const match = path.match(new RegExp(`^${paths.urls.workspaces}([^?\/]+)`)); | ||
const workspace = (match && decodeURIComponent(match[1])) || ''; | ||
const candidate = Private.candidate(paths, workspace); | ||
const rest = workspace | ||
? path.replace(new RegExp(`^${paths.urls.workspaces}${workspace}`), '') | ||
: path.replace(new RegExp(`^${paths.urls.page}`), ''); | ||
try { | ||
yield solver.resolve(candidate); | ||
await solver.resolve(candidate); | ||
return solver; | ||
} | ||
@@ -215,29 +196,14 @@ catch (error) { | ||
return new Promise(() => { | ||
// If the user has requested workspace resolution create a new one. | ||
if (WORKSPACE_RESOLVE in query) { | ||
const { base, workspaces } = paths.urls; | ||
const pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; | ||
const random = pool[Math.floor(Math.random() * pool.length)]; | ||
const path = coreutils_1.URLExt.join(base, workspaces, `auto-${random}`); | ||
// Clone the originally requested workspace after redirecting. | ||
query['clone'] = workspace; | ||
// Change the URL and trigger a hard reload to re-route. | ||
const url = path + coreutils_1.URLExt.objectToQueryString(query) + (hash || ''); | ||
router.navigate(url, { hard: true, silent: true }); | ||
return; | ||
} | ||
// Launch a dialog to ask the user for a new workspace name. | ||
console.warn('Window resolution failed:', error); | ||
return Private.redirect(router, paths, workspace); | ||
const { base, workspaces } = paths.urls; | ||
const pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; | ||
const random = pool[Math.floor(Math.random() * pool.length)]; | ||
const path = URLExt.join(base, workspaces, `auto-${random}`) + rest; | ||
// Clone the originally requested workspace after redirecting. | ||
query['clone'] = workspace; | ||
// Change the URL and trigger a hard reload to re-route. | ||
const url = path + URLExt.objectToQueryString(query) + (hash || ''); | ||
router.navigate(url, { hard: true, silent: true }); | ||
}); | ||
} | ||
// If the user has requested workspace resolution remove the query param. | ||
if (WORKSPACE_RESOLVE in query) { | ||
delete query[WORKSPACE_RESOLVE]; | ||
// Silently scrub the URL. | ||
const url = path + coreutils_1.URLExt.objectToQueryString(query) + (hash || ''); | ||
router.navigate(url, { silent: true }); | ||
} | ||
return solver; | ||
}) | ||
} | ||
}; | ||
@@ -250,8 +216,81 @@ /** | ||
autoStart: true, | ||
provides: apputils_1.ISplashScreen, | ||
provides: ISplashScreen, | ||
activate: app => { | ||
const { commands, restored } = app; | ||
// Create splash element and populate it. | ||
const splash = document.createElement('div'); | ||
const galaxy = document.createElement('div'); | ||
const logo = document.createElement('div'); | ||
splash.id = 'jupyterlab-splash'; | ||
galaxy.id = 'galaxy'; | ||
logo.id = 'main-logo'; | ||
galaxy.appendChild(logo); | ||
['1', '2', '3'].forEach(id => { | ||
const moon = document.createElement('div'); | ||
const planet = document.createElement('div'); | ||
moon.id = `moon${id}`; | ||
moon.className = 'moon orbit'; | ||
planet.id = `planet${id}`; | ||
planet.className = 'planet'; | ||
moon.appendChild(planet); | ||
galaxy.appendChild(moon); | ||
}); | ||
splash.appendChild(galaxy); | ||
// Create debounced recovery dialog function. | ||
let dialog; | ||
const recovery = new Throttler(async () => { | ||
if (dialog) { | ||
return; | ||
} | ||
dialog = new Dialog({ | ||
title: 'Loading...', | ||
body: `The loading screen is taking a long time. | ||
Would you like to clear the workspace or keep waiting?`, | ||
buttons: [ | ||
Dialog.cancelButton({ label: 'Keep Waiting' }), | ||
Dialog.warnButton({ label: 'Clear Workspace' }) | ||
] | ||
}); | ||
try { | ||
const result = await dialog.launch(); | ||
dialog.dispose(); | ||
dialog = null; | ||
if (result.button.accept && commands.hasCommand(CommandIDs.reset)) { | ||
return commands.execute(CommandIDs.reset); | ||
} | ||
// Re-invoke the recovery timer in the next frame. | ||
requestAnimationFrame(() => { | ||
// Because recovery can be stopped, handle invocation rejection. | ||
void recovery.invoke().catch(_ => undefined); | ||
}); | ||
} | ||
catch (error) { | ||
/* no-op */ | ||
} | ||
}, SPLASH_RECOVER_TIMEOUT); | ||
// Return ISplashScreen. | ||
let splashCount = 0; | ||
return { | ||
show: (light = true) => { | ||
const { commands, restored } = app; | ||
return Private.showSplash(restored, commands, CommandIDs.reset, light); | ||
splash.classList.remove('splash-fade'); | ||
splash.classList.toggle('light', light); | ||
splash.classList.toggle('dark', !light); | ||
splashCount++; | ||
document.body.appendChild(splash); | ||
// Because recovery can be stopped, handle invocation rejection. | ||
void recovery.invoke().catch(_ => undefined); | ||
return new DisposableDelegate(async () => { | ||
await restored; | ||
if (--splashCount === 0) { | ||
void recovery.stop(); | ||
if (dialog) { | ||
dialog.dispose(); | ||
dialog = null; | ||
} | ||
splash.classList.add('splash-fade'); | ||
window.setTimeout(() => { | ||
document.body.removeChild(splash); | ||
}, 200); | ||
} | ||
}); | ||
} | ||
@@ -261,2 +300,22 @@ }; | ||
}; | ||
const print = { | ||
id: '@jupyterlab/apputils-extension:print', | ||
autoStart: true, | ||
activate: (app) => { | ||
app.commands.addCommand(CommandIDs.print, { | ||
label: 'Print...', | ||
isEnabled: () => { | ||
const widget = app.shell.currentWidget; | ||
return Printing.getPrintFunction(widget) !== null; | ||
}, | ||
execute: async () => { | ||
const widget = app.shell.currentWidget; | ||
const printFunction = Printing.getPrintFunction(widget); | ||
if (printFunction) { | ||
await printFunction(); | ||
} | ||
} | ||
}); | ||
} | ||
}; | ||
/** | ||
@@ -268,7 +327,6 @@ * The default state database for storing application state. | ||
autoStart: true, | ||
provides: coreutils_1.IStateDB, | ||
requires: [application_1.JupyterFrontEnd.IPaths, application_1.IRouter, apputils_1.IWindowResolver], | ||
optional: [apputils_1.ISplashScreen], | ||
provides: IStateDB, | ||
requires: [JupyterFrontEnd.IPaths, IRouter, IWindowResolver], | ||
optional: [ISplashScreen], | ||
activate: (app, paths, router, resolver, splash) => { | ||
let debouncer; | ||
let resolved = false; | ||
@@ -278,71 +336,12 @@ const { commands, serviceManager } = app; | ||
const workspace = resolver.name; | ||
const transform = new coreutils_2.PromiseDelegate(); | ||
const db = new coreutils_1.StateDB({ | ||
namespace: app.namespace, | ||
transform: transform.promise, | ||
windowName: workspace | ||
const transform = new PromiseDelegate(); | ||
const db = new StateDB({ transform: transform.promise }); | ||
const save = new Debouncer(async () => { | ||
const id = workspace; | ||
const metadata = { id }; | ||
const data = await db.toJSON(); | ||
await workspaces.save(id, { data, metadata }); | ||
}); | ||
commands.addCommand(CommandIDs.recoverState, { | ||
execute: ({ global }) => __awaiter(this, void 0, void 0, function* () { | ||
const immediate = true; | ||
const silent = true; | ||
// Clear the state silently so that the state changed signal listener | ||
// will not be triggered as it causes a save state. | ||
yield db.clear(silent); | ||
// If the user explictly chooses to recover state, all of local storage | ||
// should be cleared. | ||
if (global) { | ||
try { | ||
window.localStorage.clear(); | ||
console.log('Cleared local storage'); | ||
} | ||
catch (error) { | ||
console.warn('Clearing local storage failed.', error); | ||
// To give the user time to see the console warning before redirect, | ||
// do not set the `immediate` flag. | ||
return commands.execute(CommandIDs.saveState); | ||
} | ||
} | ||
return commands.execute(CommandIDs.saveState, { immediate }); | ||
}) | ||
}); | ||
// Conflate all outstanding requests to the save state command that happen | ||
// within the `WORKSPACE_SAVE_DEBOUNCE_INTERVAL` into a single promise. | ||
let conflated = null; | ||
commands.addCommand(CommandIDs.saveState, { | ||
label: () => `Save Workspace (${workspace})`, | ||
execute: ({ immediate }) => { | ||
const timeout = immediate ? 0 : WORKSPACE_SAVE_DEBOUNCE_INTERVAL; | ||
const id = workspace; | ||
const metadata = { id }; | ||
// Only instantiate a new conflated promise if one is not outstanding. | ||
if (!conflated) { | ||
conflated = new coreutils_2.PromiseDelegate(); | ||
} | ||
if (debouncer) { | ||
window.clearTimeout(debouncer); | ||
} | ||
debouncer = window.setTimeout(() => __awaiter(this, void 0, void 0, function* () { | ||
// Prevent a race condition between the timeout and saving. | ||
if (!conflated) { | ||
return; | ||
} | ||
const data = yield db.toJSON(); | ||
try { | ||
yield workspaces.save(id, { data, metadata }); | ||
conflated.resolve(undefined); | ||
} | ||
catch (error) { | ||
conflated.reject(error); | ||
} | ||
conflated = null; | ||
}), timeout); | ||
return conflated.promise; | ||
} | ||
}); | ||
const listener = (sender, change) => { | ||
return commands.execute(CommandIDs.saveState); | ||
}; | ||
commands.addCommand(CommandIDs.loadState, { | ||
execute: (args) => __awaiter(this, void 0, void 0, function* () { | ||
execute: async (args) => { | ||
// Since the command can be executed an arbitrary number of times, make | ||
@@ -355,11 +354,11 @@ // sure it is safe to call multiple times. | ||
const { urls } = paths; | ||
const query = coreutils_1.URLExt.queryStringToObject(search || ''); | ||
const query = URLExt.queryStringToObject(search || ''); | ||
const clone = typeof query['clone'] === 'string' | ||
? query['clone'] === '' | ||
? urls.defaultWorkspace | ||
: coreutils_1.URLExt.join(urls.base, urls.workspaces, query['clone']) | ||
: URLExt.join(urls.base, urls.workspaces, query['clone']) | ||
: null; | ||
const source = clone || workspace; | ||
try { | ||
const saved = yield workspaces.fetch(source); | ||
const saved = await workspaces.fetch(source); | ||
// If this command is called after a reset, the state database | ||
@@ -382,13 +381,8 @@ // will already be resolved. | ||
// Any time the local state database changes, save the workspace. | ||
if (workspace) { | ||
db.changed.connect(listener, db); | ||
} | ||
const immediate = true; | ||
db.changed.connect(() => void save.invoke(), db); | ||
if (source === clone) { | ||
// Maintain the query string parameters but remove `clone`. | ||
delete query['clone']; | ||
const url = path + coreutils_1.URLExt.objectToQueryString(query) + hash; | ||
const cloned = commands | ||
.execute(CommandIDs.saveState, { immediate }) | ||
.then(() => router.stop); | ||
const url = path + URLExt.objectToQueryString(query) + hash; | ||
const cloned = save.invoke().then(() => router.stop); | ||
// After the state has been cloned, navigate to the URL. | ||
@@ -401,17 +395,12 @@ void cloned.then(() => { | ||
// After the state database has finished loading, save it. | ||
return commands.execute(CommandIDs.saveState, { immediate }); | ||
}) | ||
await save.invoke(); | ||
} | ||
}); | ||
commands.addCommand(CommandIDs.reset, { | ||
label: 'Reset Application State', | ||
execute: () => __awaiter(this, void 0, void 0, function* () { | ||
const global = true; | ||
try { | ||
yield commands.execute(CommandIDs.recoverState, { global }); | ||
} | ||
catch (error) { | ||
/* Ignore failures and redirect. */ | ||
} | ||
execute: async () => { | ||
await db.clear(); | ||
await save.invoke(); | ||
router.reload(); | ||
}) | ||
} | ||
}); | ||
@@ -421,3 +410,3 @@ commands.addCommand(CommandIDs.resetOnLoad, { | ||
const { hash, path, search } = args; | ||
const query = coreutils_1.URLExt.queryStringToObject(search || ''); | ||
const query = URLExt.queryStringToObject(search || ''); | ||
const reset = 'reset' in query; | ||
@@ -431,3 +420,3 @@ const clone = 'clone' in query; | ||
? splash.show() | ||
: new disposable_1.DisposableDelegate(() => undefined); | ||
: new DisposableDelegate(() => undefined); | ||
// If the state database has already been resolved, resetting is | ||
@@ -445,6 +434,4 @@ // impossible without reloading. | ||
const hard = true; | ||
const url = path + coreutils_1.URLExt.objectToQueryString(query) + hash; | ||
const cleared = commands | ||
.execute(CommandIDs.recoverState) | ||
.then(() => router.stop); // Stop routing before new route navigation. | ||
const url = path + URLExt.objectToQueryString(query) + hash; | ||
const cleared = db.clear().then(() => router.stop); | ||
// After the state has been reset, navigate to the URL. | ||
@@ -475,9 +462,2 @@ if (clone) { | ||
}); | ||
// Clean up state database when the window unloads. | ||
window.addEventListener('beforeunload', () => { | ||
const silent = true; | ||
db.clear(silent).catch(() => { | ||
/* no-op */ | ||
}); | ||
}); | ||
return db; | ||
@@ -497,5 +477,6 @@ } | ||
themes, | ||
themesPaletteMenu | ||
themesPaletteMenu, | ||
]; | ||
exports.default = plugins; | ||
export default plugins; | ||
/** | ||
@@ -515,156 +496,6 @@ * The namespace for module private data. | ||
return workspace | ||
? coreutils_1.URLExt.join(paths.urls.base, paths.urls.workspaces, workspace) | ||
? URLExt.join(paths.urls.base, paths.urls.workspaces, workspace) | ||
: paths.urls.defaultWorkspace; | ||
} | ||
Private.candidate = candidate; | ||
/** | ||
* Create a splash element. | ||
*/ | ||
function createSplash() { | ||
const splash = document.createElement('div'); | ||
const galaxy = document.createElement('div'); | ||
const logo = document.createElement('div'); | ||
splash.id = 'jupyterlab-splash'; | ||
galaxy.id = 'galaxy'; | ||
logo.id = 'main-logo'; | ||
galaxy.appendChild(logo); | ||
['1', '2', '3'].forEach(id => { | ||
const moon = document.createElement('div'); | ||
const planet = document.createElement('div'); | ||
moon.id = `moon${id}`; | ||
moon.className = 'moon orbit'; | ||
planet.id = `planet${id}`; | ||
planet.className = 'planet'; | ||
moon.appendChild(planet); | ||
galaxy.appendChild(moon); | ||
}); | ||
splash.appendChild(galaxy); | ||
return splash; | ||
} | ||
/** | ||
* A debouncer for recovery attempts. | ||
*/ | ||
let debouncer = 0; | ||
/** | ||
* The recovery dialog. | ||
*/ | ||
let dialog; | ||
/** | ||
* Allows the user to clear state if splash screen takes too long. | ||
*/ | ||
function recover(fn) { | ||
if (dialog) { | ||
return; | ||
} | ||
dialog = new apputils_1.Dialog({ | ||
title: 'Loading...', | ||
body: `The loading screen is taking a long time. | ||
Would you like to clear the workspace or keep waiting?`, | ||
buttons: [ | ||
apputils_1.Dialog.cancelButton({ label: 'Keep Waiting' }), | ||
apputils_1.Dialog.warnButton({ label: 'Clear Workspace' }) | ||
] | ||
}); | ||
dialog | ||
.launch() | ||
.then(result => { | ||
if (result.button.accept) { | ||
return fn(); | ||
} | ||
dialog.dispose(); | ||
dialog = null; | ||
debouncer = window.setTimeout(() => { | ||
recover(fn); | ||
}, SPLASH_RECOVER_TIMEOUT); | ||
}) | ||
.catch(() => { | ||
/* no-op */ | ||
}); | ||
} | ||
/** | ||
* Allows the user to clear state if splash screen takes too long. | ||
*/ | ||
function redirect(router, paths, workspace, warn = false) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const form = redirect_1.createRedirectForm(warn); | ||
const dialog = new apputils_1.Dialog({ | ||
title: 'Please use a different workspace.', | ||
body: form, | ||
focusNodeSelector: 'input', | ||
buttons: [apputils_1.Dialog.okButton({ label: 'Switch Workspace' })] | ||
}); | ||
const result = yield dialog.launch(); | ||
dialog.dispose(); | ||
if (!result.value) { | ||
return redirect(router, paths, workspace, true); | ||
} | ||
// Navigate to a new workspace URL and abandon this session altogether. | ||
const page = paths.urls.page; | ||
const workspaces = paths.urls.workspaces; | ||
const prefix = (workspace ? workspaces : page).length + workspace.length; | ||
const rest = router.current.request.substring(prefix); | ||
const url = coreutils_1.URLExt.join(workspaces, result.value, rest); | ||
router.navigate(url, { hard: true, silent: true }); | ||
// This promise will never resolve because the application navigates | ||
// away to a new location. It only exists to satisfy the return type | ||
// of the `redirect` function. | ||
return new Promise(() => undefined); | ||
}); | ||
} | ||
Private.redirect = redirect; | ||
/** | ||
* The splash element. | ||
*/ | ||
const splash = createSplash(); | ||
/** | ||
* The splash screen counter. | ||
*/ | ||
let splashCount = 0; | ||
/** | ||
* Show the splash element. | ||
* | ||
* @param ready - A promise that must be resolved before splash disappears. | ||
* | ||
* @param commands - The application's command registry. | ||
* | ||
* @param recovery - A command that recovers from a hanging splash. | ||
* | ||
* @param light - A flag indicating whether the theme is light or dark. | ||
*/ | ||
function showSplash(ready, commands, recovery, light) { | ||
splash.classList.remove('splash-fade'); | ||
splash.classList.toggle('light', light); | ||
splash.classList.toggle('dark', !light); | ||
splashCount++; | ||
if (debouncer) { | ||
window.clearTimeout(debouncer); | ||
} | ||
debouncer = window.setTimeout(() => { | ||
if (commands.hasCommand(recovery)) { | ||
recover(() => { | ||
return commands.execute(recovery); | ||
}); | ||
} | ||
}, SPLASH_RECOVER_TIMEOUT); | ||
document.body.appendChild(splash); | ||
return new disposable_1.DisposableDelegate(() => { | ||
void ready.then(() => { | ||
if (--splashCount === 0) { | ||
if (debouncer) { | ||
window.clearTimeout(debouncer); | ||
debouncer = 0; | ||
} | ||
if (dialog) { | ||
dialog.dispose(); | ||
dialog = null; | ||
} | ||
splash.classList.add('splash-fade'); | ||
window.setTimeout(() => { | ||
document.body.removeChild(splash); | ||
}, 500); | ||
} | ||
}); | ||
}); | ||
} | ||
Private.showSplash = showSplash; | ||
})(Private || (Private = {})); |
@@ -1,2 +0,1 @@ | ||
"use strict"; | ||
/*----------------------------------------------------------------------------- | ||
@@ -6,7 +5,6 @@ | Copyright (c) Jupyter Development Team. | ||
|----------------------------------------------------------------------------*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const algorithm_1 = require("@phosphor/algorithm"); | ||
const commands_1 = require("@phosphor/commands"); | ||
const disposable_1 = require("@phosphor/disposable"); | ||
const widgets_1 = require("@phosphor/widgets"); | ||
import { find } from '@phosphor/algorithm'; | ||
import { CommandRegistry } from '@phosphor/commands'; | ||
import { DisposableDelegate } from '@phosphor/disposable'; | ||
import { CommandPalette } from '@phosphor/widgets'; | ||
/** | ||
@@ -23,3 +21,3 @@ * The command IDs used by the apputils extension. | ||
*/ | ||
class Palette { | ||
export class Palette { | ||
/** | ||
@@ -58,3 +56,3 @@ * Create a palette instance. | ||
let item = this._palette.addItem(options); | ||
return new disposable_1.DisposableDelegate(() => { | ||
return new DisposableDelegate(() => { | ||
this._palette.removeItem(item); | ||
@@ -64,3 +62,2 @@ }); | ||
} | ||
exports.Palette = Palette; | ||
/** | ||
@@ -78,5 +75,5 @@ * A namespace for `Palette` statics. | ||
const updatePaletteTitle = () => { | ||
const binding = algorithm_1.find(app.commands.keyBindings, b => b.command === CommandIDs.activate); | ||
const binding = find(app.commands.keyBindings, b => b.command === CommandIDs.activate); | ||
if (binding) { | ||
const ks = commands_1.CommandRegistry.formatKeystroke(binding.keys.join(' ')); | ||
const ks = CommandRegistry.formatKeystroke(binding.keys.join(' ')); | ||
palette.title.caption = `Commands (${ks})`; | ||
@@ -114,3 +111,3 @@ } | ||
Palette.restore = restore; | ||
})(Palette = exports.Palette || (exports.Palette = {})); | ||
})(Palette || (Palette = {})); | ||
/** | ||
@@ -130,3 +127,3 @@ * The namespace for module private data. | ||
if (!palette) { | ||
palette = new widgets_1.CommandPalette({ commands: app.commands }); | ||
palette = new CommandPalette({ commands: app.commands }); | ||
palette.id = 'command-palette'; | ||
@@ -133,0 +130,0 @@ palette.title.label = 'Commands'; |
{ | ||
"name": "@jupyterlab/apputils-extension", | ||
"version": "1.0.0-alpha.6", | ||
"version": "1.0.0-alpha.7", | ||
"description": "JupyterLab - Application Utilities Extension", | ||
@@ -9,2 +9,6 @@ "homepage": "https://github.com/jupyterlab/jupyterlab", | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/jupyterlab/jupyterlab.git" | ||
}, | ||
"license": "BSD-3-Clause", | ||
@@ -25,6 +29,2 @@ "author": "Project Jupyter", | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/jupyterlab/jupyterlab.git" | ||
}, | ||
"scripts": { | ||
@@ -38,6 +38,6 @@ "build": "tsc -b", | ||
"dependencies": { | ||
"@jupyterlab/application": "^1.0.0-alpha.6", | ||
"@jupyterlab/apputils": "^1.0.0-alpha.6", | ||
"@jupyterlab/coreutils": "^3.0.0-alpha.6", | ||
"@jupyterlab/mainmenu": "^1.0.0-alpha.6", | ||
"@jupyterlab/application": "^1.0.0-alpha.7", | ||
"@jupyterlab/apputils": "^1.0.0-alpha.7", | ||
"@jupyterlab/coreutils": "^3.0.0-alpha.7", | ||
"@jupyterlab/mainmenu": "^1.0.0-alpha.7", | ||
"@phosphor/algorithm": "^1.1.2", | ||
@@ -48,3 +48,3 @@ "@phosphor/commands": "^1.6.1", | ||
"@phosphor/widgets": "^1.6.0", | ||
"es6-promise": "~4.1.1" | ||
"es6-promise": "~4.2.6" | ||
}, | ||
@@ -63,3 +63,3 @@ "devDependencies": { | ||
}, | ||
"gitHead": "25152cd7c0a2d2d3d020dcd59451c236e9ecc6ab" | ||
"gitHead": "f8e210a027f6545b426caf4ab64c75a1e1619a44" | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
35019
14
866
+ Addedes6-promise@4.2.8(transitive)
- Removedes6-promise@4.1.1(transitive)
Updatedes6-promise@~4.2.6