Skip to content

Commit

Permalink
Working solution with ipywidgets 7
Browse files Browse the repository at this point in the history
  • Loading branch information
martinRenou committed Oct 16, 2024
1 parent f38e2b9 commit af2c153
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 64 deletions.
3 changes: 0 additions & 3 deletions packages/voila/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ async function main() {
})
);

console.log('labextensions data', extensionData, extensions);

extensions.forEach((p) => {
if (p.status === 'rejected') {
// There was an error loading the component
Expand Down Expand Up @@ -141,7 +139,6 @@ async function main() {
});
app.registerPluginModules(mods);
await app.start();
console.log('__webpack_share_scopes__.default', __webpack_share_scopes__.default);
window.jupyterapp = app;
}

Expand Down
2 changes: 0 additions & 2 deletions packages/voila/src/plugins/outputs/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,11 @@ export const renderOutputsPlugin: JupyterFrontEndPlugin<void> = {
const model = JSON.parse(cellOutput.innerHTML);

const mimeType = rendermime.preferredMimeType(model.data, 'any');
console.log('mimetype', mimeType, rendermime);

if (!mimeType) {
return null;
}
const output = rendermime.createRenderer(mimeType);
console.log('rendering model', model);
output.renderModel(model).catch((error) => {
// Manually append error message to output
const pre = document.createElement('pre');
Expand Down
120 changes: 61 additions & 59 deletions packages/widgets_manager7/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,32 @@ import {
JupyterFrontEndPlugin
} from '@jupyterlab/application';
import { PageConfig } from '@jupyterlab/coreutils';
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
import { IRenderMime, IRenderMimeRegistry } from '@jupyterlab/rendermime';
import { KernelAPI, ServerConnection } from '@jupyterlab/services';
import { KernelConnection } from '@jupyterlab/services/lib/kernel/default';

import { VoilaWidgetManager } from './manager';

const WIDGET_MIMETYPE = 'application/vnd.jupyter.widget-view+json';

class VoilaWidgetRenderer extends WidgetRenderer {

constructor(options: IRenderMime.IRendererOptions, manager: VoilaWidgetManager) {
super(options, manager);

this.voilaManager = manager;
}

async renderModel(model: IRenderMime.IMimeModel): Promise<void> {
await this.voilaManager.loadedModelsFromKernel;

return super.renderModel(model);
}

private voilaManager: VoilaWidgetManager;

};

/**
* The Voila widgets manager plugin.
*/
Expand Down Expand Up @@ -99,16 +117,55 @@ const widgetManager: JupyterFrontEndPlugin<IJupyterWidgetRegistry> = {
);
(app as any).widgetManager = manager;

console.log('manager promise!', manager);
rendermime.removeMimeType(WIDGET_MIMETYPE);
rendermime.addFactory(
{
safe: false,
mimeTypes: [WIDGET_MIMETYPE],
createRenderer: (options) => new WidgetRenderer(options, manager)
createRenderer: (options) => new VoilaWidgetRenderer(options, manager)
},
-10
);

manager.register({
name: '@jupyter-widgets/controls',
version: JUPYTER_CONTROLS_VERSION,
exports: () => {
return new Promise((resolve, reject) => {
(require as any).ensure(
['@jupyter-widgets/controls'],
(require: NodeRequire) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
resolve(require('@jupyter-widgets/controls'));
},
(err: any) => {
reject(err);
},
'@jupyter-widgets/controls'
);
});
}
});

manager.register({
name: '@jupyter-widgets/base',
version: JUPYTER_WIDGETS_VERSION,
exports: {
WidgetModel: WidgetModel as any,
WidgetView: WidgetView as any,
DOMWidgetView: DOMWidgetView as any,
DOMWidgetModel: DOMWidgetModel as any,
LayoutModel: LayoutModel as any,
LayoutView: LayoutView as any,
StyleModel: StyleModel as any,
StyleView: StyleView as any
}
});

app.started.then(async() => {
await manager._loadFromKernel();
});

window.addEventListener('beforeunload', (e) => {
const data = new FormData();
// it seems if we attach this to early, it will not be called
Expand All @@ -132,59 +189,4 @@ const widgetManager: JupyterFrontEndPlugin<IJupyterWidgetRegistry> = {
}
};

/**
* The base widgets.
*/
const baseWidgets7Plugin: JupyterFrontEndPlugin<void> = {
id: `@jupyter-widgets/jupyterlab-manager:base-${JUPYTER_WIDGETS_VERSION}`,
requires: [IJupyterWidgetRegistry],
autoStart: true,
activate: (app: JupyterFrontEnd, registry: IJupyterWidgetRegistry): void => {
registry.registerWidget({
name: '@jupyter-widgets/base',
version: JUPYTER_WIDGETS_VERSION,
exports: {
WidgetModel: WidgetModel as any,
WidgetView: WidgetView as any,
DOMWidgetView: DOMWidgetView as any,
DOMWidgetModel: DOMWidgetModel as any,
LayoutModel: LayoutModel as any,
LayoutView: LayoutView as any,
StyleModel: StyleModel as any,
StyleView: StyleView as any
}
});
}
};

/**
* The control widgets.
*/
const controlWidgets7Plugin: JupyterFrontEndPlugin<void> = {
id: `@jupyter-widgets/jupyterlab-manager:controls-${JUPYTER_CONTROLS_VERSION}`,
requires: [IJupyterWidgetRegistry],
autoStart: true,
activate: (app: JupyterFrontEnd, registry: IJupyterWidgetRegistry): void => {
registry.registerWidget({
name: '@jupyter-widgets/controls',
version: JUPYTER_CONTROLS_VERSION,
exports: () => {
return new Promise((resolve, reject) => {
(require as any).ensure(
['@jupyter-widgets/controls'],
(require: NodeRequire) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
resolve(require('@jupyter-widgets/controls'));
},
(err: any) => {
reject(err);
},
'@jupyter-widgets/controls'
);
});
}
});
}
};

export default [widgetManager, baseWidgets7Plugin, controlWidgets7Plugin];
export default [widgetManager];
31 changes: 31 additions & 0 deletions packages/widgets_manager7/src/manager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { PromiseDelegate } from '@lumino/coreutils';
import { WidgetModel } from '@jupyter-widgets/base';
import { WidgetManager } from '@jupyter-widgets/jupyterlab-manager';
import { ISignal, Signal } from '@lumino/signaling';
import { INotebookModel } from '@jupyterlab/notebook';
import { Widget } from '@lumino/widgets';
import { MessageLoop } from '@lumino/messaging';


export class VoilaWidgetManager extends WidgetManager {
register_model(model_id: string, modelPromise: Promise<WidgetModel>): void {
Expand All @@ -22,10 +26,37 @@ export class VoilaWidgetManager extends WidgetManager {
this._registeredModels.delete(modelId);
}

async _loadFromKernel(): Promise<void> {
await super._loadFromKernel();

this._loadedFromKernel.resolve();
}

get loadedModelsFromKernel(): Promise<void> {
return this._loadedFromKernel.promise;
}

async display_view(msg: any, view: any, options: any): Promise<Widget> {
if (options.el) {
Widget.attach(view.pWidget, options.el);
}
if (view.el) {
view.el.setAttribute('data-voila-jupyter-widget', '');
view.el.addEventListener('jupyterWidgetResize', (e: Event) => {
MessageLoop.postMessage(
view.pWidget,
Widget.ResizeMessage.UnknownSize
);
});
}
return view.pWidget;
}

restoreWidgets(notebook: INotebookModel): Promise<void> {
return Promise.resolve();
}

private _loadedFromKernel: PromiseDelegate<void> = new PromiseDelegate();
private _modelRegistered = new Signal<VoilaWidgetManager, string>(this);
private _registeredModels = new Set<string>();
}

0 comments on commit af2c153

Please sign in to comment.