Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,6 @@
"@jupyter-notebook/notebook-extension": true,
"@jupyter-notebook/terminal-extension": true,
"@jupyterlab/application-extension": [
"@jupyterlab/application-extension:commands",
Copy link
Collaborator Author

@brichet brichet Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This extension is not enabled anymore, except for the tree view, because it already uses the Ctrl + B shortcut.
AFAIK the commands in this extension may not be necessary for the Notebook view (not sure it is necessary at all, most of them requires a LabShell to work).

"@jupyterlab/application-extension:context-menu",
"@jupyterlab/application-extension:faviconbusy",
"@jupyterlab/application-extension:router",
Expand Down Expand Up @@ -313,6 +312,9 @@
"@jupyterlab/video-extension": true
},
"/tree": {
"@jupyterlab/application-extension": [
"@jupyterlab/application-extension:commands"
],
"@jupyterlab/cell-toolbar-extension": true,
"@jupyterlab/extensionmanager-extension": true,
"@jupyterlab/filebrowser-extension": [
Expand Down
11 changes: 9 additions & 2 deletions packages/console-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,15 @@
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/apputils": "~4.7.0-alpha.0",
"@jupyterlab/console": "~4.6.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@lumino/algorithm": "^2.0.4"
"@jupyterlab/notebook": "~4.6.0-alpha.0",
"@jupyterlab/translation": "~4.6.0-alpha.0",
"@jupyterlab/ui-components": "~4.6.0-alpha.0",
"@lumino/algorithm": "^2.0.4",
"@lumino/coreutils": "^2.2.2",
"@lumino/widgets": "^2.7.2"
},
"devDependencies": {
"rimraf": "^3.0.2",
Expand All @@ -52,7 +58,8 @@
"access": "public"
},
"jupyterlab": {
"extension": true
"extension": true,
"schemaDir": "schema"
},
"styleModule": "style/index.js"
}
38 changes: 38 additions & 0 deletions packages/console-extension/schema/scratch-pad.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"title": "Jupyter Notebook Scratchpad Console",
"description": "Jupyter Notebook Scratchpad Console",
"jupyter.lab.menus": {
"main": [
{
"id": "jp-mainmenu-file",
"items": [
{
"type": "submenu",
"submenu": {
"id": "jp-mainmenu-file-new",
"items": [
{
"command": "scratch-pad-console:open",
"rank": 2,
"args": {
"isMenu": true
}
}
]
}
}
]
}
]
},
"jupyter.lab.shortcuts": [
{
"command": "scratch-pad-console:open",
"keys": ["Accel B"],
"selector": "body"
}
],
"properties": {},
"additionalProperties": false,
"type": "object"
}
178 changes: 174 additions & 4 deletions packages/console-extension/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,40 @@ import {
JupyterFrontEndPlugin,
} from '@jupyterlab/application';

import { ICommandPalette } from '@jupyterlab/apputils';

import { IConsoleTracker } from '@jupyterlab/console';

import { PageConfig, URLExt } from '@jupyterlab/coreutils';

import { INotebookTracker } from '@jupyterlab/notebook';

import { ITranslator, nullTranslator } from '@jupyterlab/translation';

import { consoleIcon } from '@jupyterlab/ui-components';

import {
INotebookPathOpener,
INotebookShell,
defaultNotebookPathOpener,
} from '@jupyter-notebook/application';

import { find } from '@lumino/algorithm';

import { ReadonlyJSONObject } from '@lumino/coreutils';

import { Widget } from '@lumino/widgets';

const COMMANDS_TO_PATCH = [
'console:clear',
'console:run-unforced',
'console:run-forced',
'console:linebreak',
'console:interrupt-kernel',
'console:restart-kernel',
'console:change-kernel',
];

/**
* A plugin to open consoles in a new tab
*/
Expand Down Expand Up @@ -53,23 +76,58 @@ const opener: JupyterFrontEndPlugin<void> = {
};

/**
* Open consoles in a new tab.
* Open consoles in a new tab or in the side panel (scratch-pad like).
*/
const redirect: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/console-extension:redirect',
requires: [IConsoleTracker],
optional: [INotebookPathOpener],
optional: [INotebookPathOpener, INotebookShell, INotebookTracker],
autoStart: true,
description: 'Open consoles in a new tab',
activate: (
app: JupyterFrontEnd,
tracker: IConsoleTracker,
notebookPathOpener: INotebookPathOpener | null
notebookPathOpener: INotebookPathOpener | null,
notebookShell: INotebookShell | null,
notebookTracker: INotebookTracker | null
) => {
const baseUrl = PageConfig.getBaseUrl();
const opener = notebookPathOpener ?? defaultNotebookPathOpener;

tracker.widgetAdded.connect(async (send, console) => {
// Check if we should open the console in side panel:
// - this is a notebook view
// - the notebook and the console share the same kernel
// Otherwise, the console opens in a new tab.
if (notebookShell && notebookTracker) {
const notebook = notebookTracker.currentWidget;

// Wait for the notebook and console to be ready.
await Promise.all([
notebook?.sessionContext.ready,
console.sessionContext.ready,
]);
const notebookKernelId = notebook?.sessionContext.session?.kernel?.id;
const consoleKernelId = console.sessionContext.session?.kernel?.id;

if (notebookKernelId === consoleKernelId) {
notebookShell.add(console, 'right');
notebookShell.expandRight(console.id);

// Some commands needs to be patched to be enabled.
// TODO: fix it upstream in jupyterlab.
app.commands
.listCommands()
.filter((id) => COMMANDS_TO_PATCH.includes(id))
.forEach((id) => {
(app.commands as any)._commands.get(id).isEnabled = () =>
tracker.currentWidget !== null &&
tracker.currentWidget.node.contains(document.activeElement);
});
Comment on lines +119 to +126
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allow the console commands to run in the side panel

This patch updates the isEnabled function for the commands, to allow running the commands in the side panel.
It should be fixed with jupyterlab/jupyterlab#18238.

return;
}
}

const { sessionContext } = console;
await sessionContext.ready;
const widget = find(
Expand All @@ -92,9 +150,121 @@ const redirect: JupyterFrontEndPlugin<void> = {
},
};

/**
* Open consoles in the side panel.
*/
const scratchPadConsole: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/console-extension:scratch-pad',
requires: [INotebookTracker],
optional: [INotebookShell, ICommandPalette, ITranslator],
autoStart: true,
description: 'Open consoles in a new tab',
activate: (
app: JupyterFrontEnd,
tracker: INotebookTracker,
notebookShell: INotebookShell | null,
palette: ICommandPalette | null,
translator: ITranslator | null
) => {
const { commands } = app;
const manager = app.serviceManager;

const trans = (translator ?? nullTranslator).load('notebook');

const command = 'scratch-pad-console:open';
commands.addCommand(command, {
label: (args) =>
args['isPalette']
? trans.__('Open a scratch-pad console')
: trans.__('Scratch-pad console'),
isVisible: () => !!tracker.currentWidget,
icon: (args) => (args['isPalette'] ? undefined : consoleIcon),
execute: async (args) => {
if (!notebookShell) {
return;
}
const consoleId = scratchPadConsole.id;
const sidebar = notebookShell.rightHandler;

// Close the console if it is already opened (shortcut only).
if (sidebar.isVisible && sidebar.currentWidget?.id === consoleId) {
if (!args.isPalette && !args.isMenu) {
notebookShell.collapseRight();
notebookShell.currentWidget?.activate();
}
return;
}

let panel: Widget | undefined = sidebar.widgets.find(
(w) => w.id === consoleId
);

// Create the widget if it is not already in the right area.
if (!panel) {
const notebook = tracker.currentWidget;
if (!notebook) {
return;
}
const notebookSessionContext = notebook.sessionContext;

await Promise.all([notebookSessionContext.ready, manager.ready]);

const id = notebookSessionContext.session?.kernel?.id;
const kernelPref = notebookSessionContext.kernelPreference;

panel = await commands.execute('console:create', {
kernelPreference: { ...kernelPref, id } as ReadonlyJSONObject,
});

if (!panel) {
console.log('An error occurred during console widget creation');
return;
}

panel.title.caption = trans.__('Console');
panel.id = consoleId;
} else {
notebookShell.expandRight(consoleId);
}
},
describedBy: {
args: {
type: 'object',
properties: {
isPalette: {
type: 'boolean',
description: trans.__(
trans.__('Whether the command is executed from the palette')
),
},
isMenu: {
type: 'boolean',
description: trans.__(
trans.__('Whether the command is executed from the menu')
),
},
},
},
},
});

if (palette) {
palette.addItem({
category: 'Notebook Console',
command,
args: { isPalette: true },
});
}
},
};

/**
* Export the plugins as default.
*/
const plugins: JupyterFrontEndPlugin<any>[] = [opener, redirect];
const plugins: JupyterFrontEndPlugin<any>[] = [
opener,
redirect,
scratchPadConsole,
];

export default plugins;
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2383,9 +2383,15 @@ __metadata:
dependencies:
"@jupyter-notebook/application": ^7.6.0-alpha.0
"@jupyterlab/application": ~4.6.0-alpha.0
"@jupyterlab/apputils": ~4.7.0-alpha.0
"@jupyterlab/console": ~4.6.0-alpha.0
"@jupyterlab/coreutils": ~6.6.0-alpha.0
"@jupyterlab/notebook": ~4.6.0-alpha.0
"@jupyterlab/translation": ~4.6.0-alpha.0
"@jupyterlab/ui-components": ~4.6.0-alpha.0
"@lumino/algorithm": ^2.0.4
"@lumino/coreutils": ^2.2.2
"@lumino/widgets": ^2.7.2
rimraf: ^3.0.2
typescript: ~5.5.4
languageName: unknown
Expand Down
Loading