diff --git a/package.json b/package.json index 37da91c..e62712c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jupyterlab-launchpad", - "version": "1.0.2", + "version": "1.0.3", "description": "A redesigned JupyterLab launcher", "keywords": [ "jupyter", diff --git a/src/dialogs.tsx b/src/dialogs.tsx index 4f882c3..402d351 100644 --- a/src/dialogs.tsx +++ b/src/dialogs.tsx @@ -4,6 +4,7 @@ import { } from '@jupyterlab/application'; import type { CommandRegistry } from '@lumino/commands'; import type { Message } from '@lumino/messaging'; +import { Signal, ISignal } from '@lumino/signaling'; import { SessionContextDialogs, ISessionContextDialogs, @@ -70,14 +71,24 @@ class CustomSessionContextDialogs extends SessionContextDialogs { const hasCheckbox = typeof autoStartDefault === 'boolean'; const settings = await this.options.settingRegistry.load(MAIN_PLUGIN_ID); + const dataChanged = new Signal(this); + sessionContext.sessionManager.runningChanged.connect(() => { + dataChanged.emit(); + }); + this.options.kernelManager.runningChanged.connect(() => { + dataChanged.emit(); + }); + const dialog = new Dialog | null>({ title: trans.__('Select Kernel'), body: new KernelSelector({ - data: { + data: () => ({ specs: sessionContext.specsManager.specs, sessions: sessionContext.sessionManager.running(), + kernels: this.options.kernelManager.running(), preference: sessionContext.kernelPreference - }, + }), + dataChanged, name: sessionContext.name, commands: this.options.commands, favoritesDatabase: this.options.database.favorites, @@ -131,6 +142,7 @@ export namespace CustomSessionContextDialogs { database: ILauncherDatabase; commands: CommandRegistry; settingRegistry: ISettingRegistry; + kernelManager: Kernel.IManager; } } @@ -154,7 +166,8 @@ export const sessionDialogsPlugin: JupyterFrontEndPlugin translator: translator, database: database, commands: app.commands, - settingRegistry: settingRegistry + settingRegistry: settingRegistry, + kernelManager: app.serviceManager.kernels }); } }; @@ -190,6 +203,7 @@ export class KernelSelector extends ReactWidget { onAfterAttach(msg: Message) { super.onAfterAttach(msg); + this.options.dataChanged.connect(this.update.bind(this)); requestAnimationFrame(() => { // Set minimum dimensions so that when user starts typing to filter // the kernels the dialog does not start jumping around. @@ -199,12 +213,18 @@ export class KernelSelector extends ReactWidget { }); } + onAfterDetach(msg: Message) { + super.onAfterDetach(msg); + this.options.dataChanged.disconnect(this.update); + } + /** * Render the launcher to virtual DOM nodes. */ protected render(): React.ReactElement | null { const items: ILauncher.IItemOptions[] = []; - const specs = this.options.data.specs!.kernelspecs!; + const data = this.options.data(); + const specs = data.specs!.kernelspecs!; // Note: this command is not executed, but it is only used to match favourite/last used metadata const command = this.options.type === 'console' @@ -236,8 +256,14 @@ export class KernelSelector extends ReactWidget { }); } const runningItems: ILauncher.IItemOptions[] = []; - for (const model of this.options.data.sessions!) { - const kernel = model.kernel; + const kernels = new Map([...data.kernels].map(k => [k.id, k])); + for (const model of data.sessions!) { + // session models may be outdated, use the more frequently + // updated instance from the kernels manager + if (!model.kernel) { + continue; + } + const kernel = kernels.get(model.kernel?.id); if (!kernel) { continue; } @@ -344,7 +370,10 @@ export namespace KernelSelector { settings: ISettingRegistry.ISettings; commands: CommandRegistry; trans: TranslationBundle; - data: SessionContext.IKernelSearch; + data: () => SessionContext.IKernelSearch & { + kernels: IterableIterator; + }; + dataChanged: ISignal; acceptDialog: () => void; name: string; // known values are "notebook" and "console" diff --git a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-linux.png b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-linux.png index a225e96..1da1c77 100644 Binary files a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-linux.png and b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-linux.png differ diff --git a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-open-quicksettings-linux.png b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-open-quicksettings-linux.png index 6fedadd..4424f62 100644 Binary files a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-open-quicksettings-linux.png and b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-open-quicksettings-linux.png differ diff --git a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-search-in-individual-linux.png b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-search-in-individual-linux.png index 35d8639..a3cf6f5 100644 Binary files a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-search-in-individual-linux.png and b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-search-in-individual-linux.png differ diff --git a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-with-starred-linux.png b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-with-starred-linux.png index 6aa2e10..5cd3c3a 100644 Binary files a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-with-starred-linux.png and b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-with-starred-linux.png differ