Skip to content

Commit 9d2e0b2

Browse files
committed
Basic support for widgets in lab code consoles
1 parent 98e6c86 commit 9d2e0b2

File tree

4 files changed

+411
-13
lines changed

4 files changed

+411
-13
lines changed

jupyterlab_widgets/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"@jupyter-widgets/controls": "^4.0.0-alpha.2",
5454
"@jupyter-widgets/output": "^5.0.0-alpha.2",
5555
"@jupyterlab/application": "^3.0.0",
56+
"@jupyterlab/console": "^3.0.0",
5657
"@jupyterlab/docregistry": "^3.0.0",
5758
"@jupyterlab/logconsole": "^3.0.0",
5859
"@jupyterlab/mainmenu": "^3.0.0",

jupyterlab_widgets/src/plugin.ts

Lines changed: 103 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
// Distributed under the terms of the Modified BSD License.
33

44
import { ISettingRegistry } from '@jupyterlab/settingregistry';
5+
56
import * as nbformat from '@jupyterlab/nbformat';
67

8+
import { IConsoleTracker, CodeConsole } from '@jupyterlab/console';
9+
710
import { DocumentRegistry } from '@jupyterlab/docregistry';
811

912
import {
@@ -34,7 +37,11 @@ import { AttachedProperty } from '@lumino/properties';
3437

3538
import { WidgetRenderer } from './renderer';
3639

37-
import { WidgetManager, WIDGET_VIEW_MIMETYPE } from './manager';
40+
import {
41+
WidgetManager,
42+
WIDGET_VIEW_MIMETYPE,
43+
KernelWidgetManager
44+
} from './manager';
3845

3946
import { OutputModel, OutputView, OUTPUT_WIDGET_VERSION } from './output';
4047

@@ -58,7 +65,7 @@ const SETTINGS: WidgetManager.Settings = { saveState: false };
5865
/**
5966
* Iterate through all widget renderers in a notebook.
6067
*/
61-
function* widgetRenderers(
68+
function* notebookWidgetRenderers(
6269
nb: Notebook
6370
): Generator<WidgetRenderer, void, unknown> {
6471
for (const cell of nb.widgets) {
@@ -74,6 +81,25 @@ function* widgetRenderers(
7481
}
7582
}
7683

84+
/**
85+
* Iterate through all widget renderers in a console.
86+
*/
87+
function* consoleWidgetRenderers(
88+
console: CodeConsole
89+
): Generator<WidgetRenderer, void, unknown> {
90+
for (const cell of toArray(console.cells)) {
91+
if (cell.model.type === 'code') {
92+
for (const codecell of (cell as CodeCell).outputArea.widgets) {
93+
for (const output of toArray(codecell.children())) {
94+
if (output instanceof WidgetRenderer) {
95+
yield output;
96+
}
97+
}
98+
}
99+
}
100+
}
101+
}
102+
77103
/**
78104
* Iterate through all matching linked output views
79105
*/
@@ -140,13 +166,58 @@ export function registerWidgetManager(
140166
});
141167
}
142168

169+
export function registerConsoleWidgetManager(
170+
console: CodeConsole,
171+
rendermime: IRenderMimeRegistry,
172+
renderers: IterableIterator<WidgetRenderer>
173+
): DisposableDelegate {
174+
let wManager = Private.widgetManagerProperty.get(console);
175+
if (!wManager) {
176+
wManager = new KernelWidgetManager(
177+
console.sessionContext.session?.kernel!,
178+
rendermime
179+
);
180+
WIDGET_REGISTRY.forEach(data => wManager!.register(data));
181+
Private.widgetManagerProperty.set(console, wManager);
182+
}
183+
184+
for (const r of renderers) {
185+
r.manager = wManager;
186+
}
187+
188+
// Replace the placeholder widget renderer with one bound to this widget
189+
// manager.
190+
rendermime.removeMimeType(WIDGET_VIEW_MIMETYPE);
191+
rendermime.addFactory(
192+
{
193+
safe: false,
194+
mimeTypes: [WIDGET_VIEW_MIMETYPE],
195+
createRenderer: options => new WidgetRenderer(options, wManager)
196+
},
197+
0
198+
);
199+
200+
return new DisposableDelegate(() => {
201+
if (rendermime) {
202+
rendermime.removeMimeType(WIDGET_VIEW_MIMETYPE);
203+
}
204+
wManager!.dispose();
205+
});
206+
}
207+
143208
/**
144209
* The widget manager provider.
145210
*/
146211
const plugin: JupyterFrontEndPlugin<base.IJupyterWidgetRegistry> = {
147212
id: '@jupyter-widgets/jupyterlab-manager:plugin',
148213
requires: [IRenderMimeRegistry],
149-
optional: [INotebookTracker, ISettingRegistry, IMainMenu, ILoggerRegistry],
214+
optional: [
215+
INotebookTracker,
216+
IConsoleTracker,
217+
ISettingRegistry,
218+
IMainMenu,
219+
ILoggerRegistry
220+
],
150221
provides: base.IJupyterWidgetRegistry,
151222
activate: activateWidgetExtension,
152223
autoStart: true
@@ -165,6 +236,7 @@ function activateWidgetExtension(
165236
app: JupyterFrontEnd,
166237
rendermime: IRenderMimeRegistry,
167238
tracker: INotebookTracker | null,
239+
consoleTracker: IConsoleTracker | null,
168240
settingRegistry: ISettingRegistry | null,
169241
menu: IMainMenu | null,
170242
loggerRegistry: ILoggerRegistry | null
@@ -179,7 +251,10 @@ function activateWidgetExtension(
179251
const wManager = Private.widgetManagerProperty.get(nb.context);
180252
if (wManager) {
181253
wManager.onUnhandledIOPubMessage.connect(
182-
(sender: WidgetManager, msg: KernelMessage.IIOPubMessage) => {
254+
(
255+
sender: WidgetManager | KernelWidgetManager,
256+
msg: KernelMessage.IIOPubMessage
257+
) => {
183258
const logger = loggerRegistry.getLogger(nb.context.path);
184259
let level: LogLevel = 'warning';
185260
if (
@@ -226,7 +301,7 @@ function activateWidgetExtension(
226301
panel.context,
227302
panel.content.rendermime,
228303
chain(
229-
widgetRenderers(panel.content),
304+
notebookWidgetRenderers(panel.content),
230305
outputViews(app, panel.context.path)
231306
)
232307
);
@@ -238,7 +313,7 @@ function activateWidgetExtension(
238313
panel.context,
239314
panel.content.rendermime,
240315
chain(
241-
widgetRenderers(panel.content),
316+
notebookWidgetRenderers(panel.content),
242317
outputViews(app, panel.context.path)
243318
)
244319
);
@@ -247,6 +322,24 @@ function activateWidgetExtension(
247322
});
248323
}
249324

325+
if (consoleTracker !== null) {
326+
consoleTracker.forEach(async panel => {
327+
await panel.sessionContext.ready;
328+
registerConsoleWidgetManager(
329+
panel.console,
330+
panel.console.rendermime,
331+
chain(consoleWidgetRenderers(panel.console))
332+
);
333+
});
334+
consoleTracker.widgetAdded.connect(async (sender, panel) => {
335+
await panel.sessionContext.ready;
336+
registerConsoleWidgetManager(
337+
panel.console,
338+
panel.console.rendermime,
339+
chain(consoleWidgetRenderers(panel.console))
340+
);
341+
});
342+
}
250343
if (settingRegistry !== null) {
251344
// Add a command for automatically saving (jupyter-)widget state.
252345
commands.addCommand('@jupyter-widgets/jupyterlab-manager:saveWidgetState', {
@@ -321,10 +414,11 @@ namespace Private {
321414
* A private attached property for a widget manager.
322415
*/
323416
export const widgetManagerProperty = new AttachedProperty<
324-
DocumentRegistry.Context,
325-
WidgetManager | undefined
417+
DocumentRegistry.Context | CodeConsole,
418+
WidgetManager | KernelWidgetManager | undefined
326419
>({
327420
name: 'widgetManager',
328-
create: (owner: DocumentRegistry.Context): undefined => undefined
421+
create: (owner: DocumentRegistry.Context | CodeConsole): undefined =>
422+
undefined
329423
});
330424
}

jupyterlab_widgets/src/renderer.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@ import { Panel, Widget as LuminoWidget } from '@lumino/widgets';
99

1010
import { IRenderMime } from '@jupyterlab/rendermime-interfaces';
1111

12-
import { WidgetManager } from './manager';
12+
import { LabWidgetManager } from './manager';
1313
import { DOMWidgetModel } from '@jupyter-widgets/base';
1414

1515
/**
1616
* A renderer for widgets.
1717
*/
1818
export class WidgetRenderer extends Panel
1919
implements IRenderMime.IRenderer, IDisposable {
20-
constructor(options: IRenderMime.IRendererOptions, manager?: WidgetManager) {
20+
constructor(
21+
options: IRenderMime.IRendererOptions,
22+
manager?: LabWidgetManager
23+
) {
2124
super();
2225
this.mimeType = options.mimeType;
2326
if (manager) {
@@ -28,7 +31,7 @@ export class WidgetRenderer extends Panel
2831
/**
2932
* The widget manager.
3033
*/
31-
set manager(value: WidgetManager) {
34+
set manager(value: LabWidgetManager) {
3235
value.restored.connect(this._rerender, this);
3336
this._manager.resolve(value);
3437
}
@@ -125,6 +128,6 @@ export class WidgetRenderer extends Panel
125128
* The mimetype being rendered.
126129
*/
127130
readonly mimeType: string;
128-
private _manager = new PromiseDelegate<WidgetManager>();
131+
private _manager = new PromiseDelegate<LabWidgetManager>();
129132
private _rerenderMimeModel: IRenderMime.IMimeModel | null = null;
130133
}

0 commit comments

Comments
 (0)