Skip to content

Commit

Permalink
Merge pull request #217 from jtpio/jupyterlab-extension
Browse files Browse the repository at this point in the history
WIP: JupyterLab extension
  • Loading branch information
SylvainCorlay authored Jun 12, 2019
2 parents 79089e3 + ad8cfe1 commit b85e1e3
Show file tree
Hide file tree
Showing 6 changed files with 348 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ share/jupyter/voila/templates/default/static/*voila.js
share/jupyter/voila/templates/default/static/*[woff|woff2|eot|svg]

js/lib/

packages/jupyterlab-voila/lib/
73 changes: 73 additions & 0 deletions packages/jupyterlab-voila/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"name": "jupyterlab-voila",
"version": "0.1.0",
"description": "A JupyterLab extension for Voila",
"keywords": [
"jupyter",
"jupyterlab",
"jupyterlab-extension"
],
"homepage": "https://github.com/QuantStack/voila",
"bugs": {
"url": "https://github.com/QuantStack/voila/issues"
},
"license": "BSD-3-Clause",
"author": "Maarten Breddels, Sylvain Corlay",
"files": [
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
"style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
],
"main": "lib/index.js",
"types": "lib/index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/QuantStack/voila.git"
},
"scripts": {
"build": "tsc",
"prettier": "prettier --write '**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}'",
"clean": "rimraf lib",
"watch": "tsc -w",
"prepare": "npm run clean && npm run build"
},
"dependencies": {
"@jupyterlab/application": "^0.19.0",
"@jupyterlab/apputils": "^0.19.0",
"@jupyterlab/docregistry": "^0.19.0",
"@jupyterlab/fileeditor": "^0.19.0",
"@jupyterlab/mainmenu": "^0.8.1",
"@jupyterlab/notebook": "^0.19.0"
},
"peerDependencies": {
"@jupyterlab/application": "^0.19.0",
"@jupyterlab/apputils": "^0.19.0",
"@jupyterlab/docregistry": "^0.19.0",
"@jupyterlab/fileeditor": "^0.19.0",
"@jupyterlab/mainmenu": "^0.8.1",
"@jupyterlab/notebook": "^0.19.0"
},
"devDependencies": {
"husky": "^2.3.0",
"lint-staged": "^7.3.0",
"prettier": "^1.13.7",
"rimraf": "^2.6.1",
"tslint": "^5.10.0",
"tslint-config-prettier": "^1.13.0",
"tslint-plugin-prettier": "^1.3.0",
"typescript": "~2.9.2"
},
"lint-staged": {
"**/*{.ts,.tsx,.css,.json,.md}": [
"prettier --write",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"jupyterlab": {
"extension": true
}
}
168 changes: 168 additions & 0 deletions packages/jupyterlab-voila/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { JupyterLab, JupyterLabPlugin } from "@jupyterlab/application";

import {
INotebookTracker,
NotebookPanel,
INotebookModel
} from "@jupyterlab/notebook";

import { ReadonlyJSONObject } from "@phosphor/coreutils";

import { ICommandPalette, MainAreaWidget, IFrame } from "@jupyterlab/apputils";

import { IMainMenu } from "@jupyterlab/mainmenu";

import { PageConfig, PathExt } from "@jupyterlab/coreutils";

import { ToolbarButton } from "@jupyterlab/apputils";

import { DocumentRegistry } from "@jupyterlab/docregistry";

import { IDisposable } from "@phosphor/disposable";

import "../style/index.css";

export namespace CommandIDs {
export const voilaRender = "notebook:render-with-voila";

export const voilaOpen = "notebook:open-with-voila";
}

const VOILA_ICON_CLASS = "jp-MaterialIcon jp-VoilaIcon";

class VoilaRenderButton
implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel> {
constructor(app: JupyterLab) {
this.app = app;
}

readonly app: JupyterLab;

createNew(
panel: NotebookPanel,
context: DocumentRegistry.IContext<INotebookModel>
): IDisposable {
let renderVoila = () => {
this.app.commands.execute("notebook:render-with-voila");
};

let button = new ToolbarButton({
className: "voilaRender",
iconClassName: VOILA_ICON_CLASS,
onClick: renderVoila,
tooltip: "Render with Voila"
});

panel.toolbar.insertItem(9, "voilaRender", button);

return button;
}
}

/**
* Initialization data for the jupyterlab-voila extension.
*/
const extension: JupyterLabPlugin<void> = {
id: "jupyterlab-voila",
autoStart: true,
requires: [INotebookTracker],
optional: [ICommandPalette, IMainMenu],
activate: (
app: JupyterLab,
notebooks: INotebookTracker,
palette: ICommandPalette,
menu: IMainMenu | null
) => {
function getCurrent(args: ReadonlyJSONObject): NotebookPanel | null {
const widget = notebooks.currentWidget;
const activate = args["activate"] !== false;

if (activate && widget) {
app.shell.activateById(widget.id);
}

return widget;
}

function isEnabled(): boolean {
return (
notebooks.currentWidget !== null &&
notebooks.currentWidget === app.shell.currentWidget
);
}

let counter = 0;

function voilaIFrame(url: string, text: string): MainAreaWidget {
let content = new IFrame();

content.url = url;
content.title.label = text;
content.title.icon = VOILA_ICON_CLASS;
content.id = `voila-${++counter}`;
let widget = new MainAreaWidget({ content });
return widget;
}

function getVoilaUrl(path: string): string {
const baseUrl = PageConfig.getBaseUrl();
return `${baseUrl}voila/render/${path}`;
}

app.commands.addCommand(CommandIDs.voilaRender, {
label: "Render Notebook with Voila",
execute: async args => {
const current = getCurrent(args);
if (!current) {
return;
}
const voilaPath = current.context.path;
const voilaUrl = getVoilaUrl(voilaPath);
const name = PathExt.basename(voilaPath);
let widget = voilaIFrame(voilaUrl, name);
app.shell.addToMainArea(widget, { mode: "split-right" });
return widget;
},
isEnabled
});

app.commands.addCommand(CommandIDs.voilaOpen, {
label: "Open with Voila in New Browser Tab",
execute: async args => {
const current = getCurrent(args);
if (!current) {
return;
}
const voilaUrl = getVoilaUrl(current.context.path);
window.open(voilaUrl);
},
isEnabled
});

if (palette) {
const category = "Notebook Operations";
[CommandIDs.voilaRender, CommandIDs.voilaOpen].forEach(command => {
palette.addItem({ command, category });
});
}

if (menu) {
menu.viewMenu.addGroup(
[
{
command: CommandIDs.voilaRender
},
{
command: CommandIDs.voilaOpen
}
],
1000
);
}

let voilaButton = new VoilaRenderButton(app);
app.docRegistry.addWidgetExtension("Notebook", voilaButton);
}
};

export default extension;
3 changes: 3 additions & 0 deletions packages/jupyterlab-voila/style/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.jp-VoilaIcon {
background-image: url("./voila.svg");
}
85 changes: 85 additions & 0 deletions packages/jupyterlab-voila/style/voila.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions packages/jupyterlab-voila/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"declaration": true,
"lib": ["es2015", "dom"],
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noUnusedLocals": true,
"outDir": "./lib",
"target": "es2015",
"strict": true,
"strictNullChecks": false,
"types": [],
"skipLibCheck": true
},
"include": ["src/*"]
}

0 comments on commit b85e1e3

Please sign in to comment.