0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Creating a simple JupyterLab plugin having BookMark menu

0
Last updated at Posted at 2018-04-19

abstract

in this document, we are going to discuss how to create a simple jupyterlab plugin having a custom menu 'BookMark'.

image.png

Let's start

let's start with a simple plugin project created from extension-cookiecutter-ts

if you are a newbie to cookiecutter, this post would be a help.

Basic Skelecton

this is a basic skelecton of a jupyterlab plugin.
image.png

import part

import {IMainMenu} from '@jupyterlab/mainmenu'

import {IFrame, ICommandPalette} from '@jupyterlab/apputils'

import {Menu} from '@phosphor/widgets'

to use @jupyterlab/mainmenu package, you might need to describe the package name in package.json file.

image.png

if you use pycharm, alt+enter will do that for you.

image.png

not installed? don't be worry. jlpm install comannd will make you have the package under node_modules directory.

extension part

/**
 * Initialization data for the jupyterlab_myext extension.
 */
const extension: JupyterLabPlugin<void> = {
  id: 'jupyterlab_myext',
  autoStart: true,
  requires: [IMainMenu, ICommandPalette],
  activate: activate_custom_menu
};

image.png

in webstorm, do Ctrl+click the requires and you can navigate to the definition.

image.png

bookmark data part

export const BookMarks = [
    {
        name: 'gmo',
        url: 'https://www.gmo.jp/en/',
        description: 'Creating a simple JupyterLab plugin adding BookMark menu',
        target: 'widget'
    }
];

this is a hard-coded bookmark data. of course, you can change it to load from file, url(ajax) or to be delivered by javascript from index.html, which is rendered by jupyterlab_launcher/handlers.py

activation definition part

export function activate_custom_menu(app: JupyterLab, mainMenu: IMainMenu, palette:
    ICommandPalette): Promise<void>{
    // todo
    return Promise.resolve(void 0);
}

by the declaration requires: [IMainMenu, ICommandPalette] at extension definition,
those parameters are dynamically delivered when calling activate_custom_menu

image.png

if you want to provide a service other widgets can refer, use provides property.

for details, refer
jupyterlab_myext\node_modules@phosphor\application\lib\index.d.ts

Register Commands

phosphorjs uses command|event / listener model like VSCode does.

image.png

I believe you can understand what this typescript does.

    function appendNewCommand(item: any) {
        let iframe: IFrame = null;
        let command = `BookMark-${item.name}:show`;
        app.commands.addCommand(command, {

            label: item.name,
            execute: () => {
                if (item.target == '_blank') {
                    let win = window.open(item.url, '_blank');
                    win.focus();
                } else if (item.target == 'widget') {
                    if (!iframe) {
                        iframe = new IFrame();
                        iframe.url = item.url;
                        iframe.id = item.name;
                        iframe.title.label = item.name;
                        iframe.title.closable = true;
                        iframe.node.style.overflowY = 'auto';
                    }

                    if (iframe == null || !iframe.isAttached) {
                        app.shell.addToMainArea(iframe);
                        app.shell.activateById(iframe.id);
                    } else {
                        app.shell.activateById(iframe.id);
                    }
                }
            }
        });
    }

    BookMarks.forEach(item => appendNewCommand(item));

IFrame came from @jupyterlab/apputils

import {IFrame, ICommandPalette} from '@jupyterlab/apputils'

UI rednering

and make menu show actually.
we usually describe rendering part on Private namespace like below.
image.png

build

image.png

image.png
what? no Set? then, make target and lib use ES6 on tsconfig.json
image.png
image.png
Okay.

jupyter labextension list
jupyter lab build

image.png
image.png

run

jupyter lab

image.png

image.png

the whole code

import {
  JupyterLab, JupyterLabPlugin
} from '@jupyterlab/application';

import {IMainMenu} from '@jupyterlab/mainmenu'

import {IFrame, ICommandPalette} from '@jupyterlab/apputils'

import {Menu} from '@phosphor/widgets'

import '../style/index.css';


/**
 * Initialization data for the jupyterlab_myext extension.
 */
const extension: JupyterLabPlugin<void> = {
  id: 'jupyterlab_myext',
  autoStart: true,
  requires: [IMainMenu, ICommandPalette],
  activate: activate_custom_menu
};


export default extension;

export const BookMarks = [
    {
        name: 'gmo',
        url: 'https://www.gmo.jp/en/',
        description: 'Creating a simple JupyterLab plugin adding BookMark menu',
        target: 'widget'
    }
];

export function activate_custom_menu(app: JupyterLab, mainMenu: IMainMenu, palette:
    ICommandPalette): Promise<void>{

    // create new commands and add them to app.commands

    function appendNewCommand(item: any) {
        let iframe: IFrame = null;
        let command = `BookMark-${item.name}:show`;
        app.commands.addCommand(command, {

            label: item.name,
            execute: () => {
                if (item.target == '_blank') {
                    let win = window.open(item.url, '_blank');
                    win.focus();
                } else if (item.target == 'widget') {
                    if (!iframe) {
                        iframe = new IFrame();
                        iframe.url = item.url;
                        iframe.id = item.name;
                        iframe.title.label = item.name;
                        iframe.title.closable = true;
                        iframe.node.style.overflowY = 'auto';
                    }

                    if (iframe == null || !iframe.isAttached) {
                        app.shell.addToMainArea(iframe);
                        app.shell.activateById(iframe.id);
                    } else {
                        app.shell.activateById(iframe.id);
                    }
                }
            }
        });
    }

    BookMarks.forEach(item => appendNewCommand(item));

    // add to mainMenu
    let menu = Private.createMenu(app);
    mainMenu.addMenu(menu, {rank: 80});
    return Promise.resolve(void 0);
}

/**
 * A namespace for help plugin private functions.
 */

namespace Private {

    /**
     * Creates a menu for the help plugin.
     */
    export function createMenu(app: JupyterLab): Menu {

        const {commands} = app;
        let menu:Menu = new Menu({commands});
        menu.title.label = 'BookMark';
        BookMarks.forEach(item => menu.addItem({command: `BookMark-${item.name}:show`}));

        return menu;
    }
}

ref

jupyterlabのexternal extensionを作ってみた。
https://qiita.com/crowdy/items/167a65cee4a857184ac7

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?