Skip to content

Commit

Permalink
Activate the deferred plugins after shell restore (jupyterlab#14610)
Browse files Browse the repository at this point in the history
* Activate the deferred plugins after shell restore

* Update packages/application/src/lab.ts

Co-authored-by: Frédéric Collonval <fcollonval@users.noreply.github.com>

* Update packages/application/src/lab.ts

Co-authored-by: Frédéric Collonval <fcollonval@users.noreply.github.com>

* fix lint

* Remove try/catch when activating deferred extensions

* Add a promise to the application for deferred plugins activation, and add tests on plugin activation

* lint

---------

Co-authored-by: Frédéric Collonval <fcollonval@users.noreply.github.com>
  • Loading branch information
brichet and fcollonval authored Aug 16, 2023
1 parent 6638a23 commit 0ec915d
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 7 deletions.
40 changes: 36 additions & 4 deletions packages/application/src/lab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { PageConfig } from '@jupyterlab/coreutils';
import { Base64ModelFactory } from '@jupyterlab/docregistry';
import { IRenderMime } from '@jupyterlab/rendermime-interfaces';
import { ServiceManager } from '@jupyterlab/services';
import { Token } from '@lumino/coreutils';
import { PromiseDelegate, Token } from '@lumino/coreutils';
import { JupyterFrontEnd, JupyterFrontEndPlugin } from './frontend';
import { createRendermimePlugins } from './mimerenderers';
import { ILabShell, LabShell } from './shell';
Expand All @@ -30,9 +30,6 @@ export class JupyterLab extends JupyterFrontEnd<ILabShell> {
}
})
});
this.restored = this.shell.restored
.then(() => undefined)
.catch(() => undefined);

// Create an IInfo dictionary from the options to override the defaults.
const info = Object.keys(JupyterLab.defaultInfo).reduce((acc, val) => {
Expand All @@ -45,6 +42,34 @@ export class JupyterLab extends JupyterFrontEnd<ILabShell> {
// Populate application info.
this._info = { ...JupyterLab.defaultInfo, ...info };

this.restored = this.shell.restored
.then(async () => {
const activated: Promise<void | void[]>[] = [];
const deferred = this.activateDeferredPlugins().catch(error => {
console.error('Error when activating deferred plugins\n:', error);
});
activated.push(deferred);
if (this._info.deferred) {
const customizedDeferred = Promise.all(
this._info.deferred.matches.map(pluginID =>
this.activatePlugin(pluginID)
)
).catch(error => {
console.error(
'Error when activating customized list of deferred plugins:\n',
error
);
});
activated.push(customizedDeferred);
}
Promise.all(activated)
.then(() => {
this._allPluginsActivated.resolve();
})
.catch(() => undefined);
})
.catch(() => undefined);

// Populate application paths override the defaults if necessary.
const defaultURLs = JupyterLab.defaultPaths.urls;
const defaultDirs = JupyterLab.defaultPaths.directories;
Expand Down Expand Up @@ -134,6 +159,12 @@ export class JupyterLab extends JupyterFrontEnd<ILabShell> {
return this._paths;
}

/**
* Promise that resolves when all the plugins are activated, including the deferred.
*/
get allPluginsActivated(): Promise<void> {
return this._allPluginsActivated.promise;
}
/**
* Register plugins from a plugin module.
*
Expand Down Expand Up @@ -170,6 +201,7 @@ export class JupyterLab extends JupyterFrontEnd<ILabShell> {

private _info: JupyterLab.IInfo = JupyterLab.defaultInfo;
private _paths: JupyterFrontEnd.IPaths;
private _allPluginsActivated = new PromiseDelegate<void>();
}

/**
Expand Down
84 changes: 84 additions & 0 deletions packages/application/test/lab.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import {
JupyterFrontEndPlugin,
JupyterLab,
LayoutRestorer
} from '@jupyterlab/application';
import { StateDB } from '@jupyterlab/statedb';
import { CommandRegistry } from '@lumino/commands';
import { DockPanel } from '@lumino/widgets';

describe('plugins', () => {
let lab: JupyterLab;
let plugin: JupyterFrontEndPlugin<void> = {
id: '@jupyterlab/test-extension:plugin',
autoStart: true,
activate: async () => {
await new Promise(f => setTimeout(f, 5000));
}
};

beforeEach(() => {
lab = new JupyterLab({});
});

it('autoStart plugin should be activated when application restore', async () => {
lab.registerPlugin(plugin);
await lab.start();
const restorer = new LayoutRestorer({
connector: new StateDB(),
first: Promise.resolve<void>(void 0),
registry: new CommandRegistry()
});
const mode: DockPanel.Mode = 'multiple-document';
void lab.shell.restoreLayout(mode, restorer);
await lab.restored;
expect(
lab.isPluginActivated('@jupyterlab/test-extension:plugin')
).toBeTruthy();
});

it('autoStart=false plugin should never be activated', async () => {
plugin.autoStart = false;
lab.registerPlugin(plugin);
await lab.start();
const restorer = new LayoutRestorer({
connector: new StateDB(),
first: Promise.resolve<void>(void 0),
registry: new CommandRegistry()
});
const mode: DockPanel.Mode = 'multiple-document';
void lab.shell.restoreLayout(mode, restorer);
await lab.restored;
expect(
lab.isPluginActivated('@jupyterlab/test-extension:plugin')
).toBeFalsy();
await lab.allPluginsActivated;
expect(
lab.isPluginActivated('@jupyterlab/test-extension:plugin')
).toBeFalsy();
});

it('deferred plugin should not be activated right after application restore', async () => {
plugin.autoStart = 'defer';
lab.registerPlugin(plugin);
await lab.start();
const restorer = new LayoutRestorer({
connector: new StateDB(),
first: Promise.resolve<void>(void 0),
registry: new CommandRegistry()
});
const mode: DockPanel.Mode = 'multiple-document';
void lab.shell.restoreLayout(mode, restorer);
await lab.restored;
expect(
lab.isPluginActivated('@jupyterlab/test-extension:plugin')
).toBeFalsy();
await lab.allPluginsActivated;
expect(
lab.isPluginActivated('@jupyterlab/test-extension:plugin')
).toBeTruthy();
});
});
6 changes: 3 additions & 3 deletions packages/apputils-extension/src/settingconnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class SettingConnector extends DataConnector<
async list(
query: 'active' | 'all' | 'ids' = 'all'
): Promise<{ ids: string[]; values?: ISettingRegistry.IPlugin[] }> {
const { isDeferred, isDisabled } = PageConfig.Extension;
const { isDisabled } = PageConfig.Extension;
const { ids, values } = await this._connector.list(
query === 'ids' ? 'ids' : undefined
);
Expand All @@ -59,8 +59,8 @@ export class SettingConnector extends DataConnector<
}

return {
ids: ids.filter(id => !isDeferred(id) && !isDisabled(id)),
values: values.filter(({ id }) => !isDeferred(id) && !isDisabled(id))
ids: ids.filter(id => !isDisabled(id)),
values: values.filter(({ id }) => !isDisabled(id))
};
}

Expand Down

0 comments on commit 0ec915d

Please sign in to comment.