Jupyterlab - Extension: Referencing the notebook that spawned a Widget

Hi Guys!

I want to program an JL extension for my Bachelor´s Thesis and started to dig into the topic over the last week and found the topic to be quite hard to systematically address. Some of the important samples for me in the extension-samples also can be built and installed but dont show a panel (kernel-messaging & kernel-output). So I am a bit on shaky footing in my trial and error learning.

To my specific questions I currently have:
I use a button I found on ajbozarth´s talk:

export class ButtonExtension implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel> {

  createNew(panel: NotebookPanel, context: DocumentRegistry.IContext<INotebookModel>): IDisposable {
    // Create the toolbar button
    let mybutton = new ToolbarButton({
        label: 'Start Parameter Set&Track',
        onClick: async () => {
            const content = new MyWidget();
            const widget = new MainAreaWidget({ content });
            widget.id = 'Paramater Set&Track';
            widget.title.label = 'Paramater Set&Track';
            widget.title.closable = true;

            // added by me
            context.addSibling(widget);
        }
    });

    // Add the toolbar button to the notebook toolbar
    panel.toolbar.insertItem(10, 'mybutton', mybutton);

    // The ToolbarButton class implements `IDisposable`, so the
    // button *is* the extension for the purposes of this method.
    return mybutton;
  }
}

And in my activate-function I add it to the toolbar of a notebook with:

const plugin: JupyterFrontEndPlugin<void> = {
  id: 'ParameterTracker:plugin',
  autoStart: true,
  requires: [],
  activate: activate
};

function activate(app: JupyterFrontEnd) : void {
  app.docRegistry.addWidgetExtension('Notebook', new ButtonExtension());
}

This works as intended but now I am a bit stuck:

  • When I press the toolbar button, I want the new Panel to show up(as it does now) and I want to be able to access the cells/kernel from the notebook that spawned the Panel. How do I get a handle on those things? My idea was to implement it in the notebook toolbar, so the panel “knows where it came from” and leaves no ambiguity for the user.
  • I use the “context.addSibling()” to bring up the new Panel due to not knowing any better. Is this acceptable?
  • How can I avoid that more than one Panel gets spawned from the same notebook?

Ultimately, the idea is to provide an UI that allows us to interact (set code & execute code) with the one panel´s kernel that spawned the UI-Panel.

Sorry for the long post, but I am a bit hardstuck and appreciate any help.

Best Regards from Austria :slight_smile:
Martin

Just in case someone comes here with search - a possible solution I found for opening one Widget at max per notebook is using a stored value. I used metadata, but I am not sure this is the best way:

export class ButtonExtension implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel> {
  createNew(panel: NotebookPanel, context: DocumentRegistry.IContext<INotebookModel>): IDisposable {
    // Create the toolbar button
    let mybutton = new ToolbarButton({
        label: 'Start Parameter Set&Track',
        onClick: async () => {
            const content = new MyWidget();
            const widget = new MainAreaWidget({ content });
            
            widget.id = 'Paramater Set&Track';
            widget.title.label = 'Paramater Set&Track';
            widget.title.closable = true;

            // One NotebookPanel can only spawn one ParameterTracker at max
            const flag = "trackerSpawned";
            widget.disposed.connect(()=>{
              context.model.metadata.set(flag, false)
            })
            if (!context.model.metadata.get(flag)){
              context.addSibling(widget);
              context.model.metadata.set(flag, true);
            }
        }
    });

    // Add the toolbar button to the notebook toolbar
    panel.toolbar.insertItem(10, 'mybutton', mybutton);

    // The ToolbarButton class implements `IDisposable`, so the
    // button *is* the extension for the purposes of this method.
    return mybutton;
  }
}

Also - why didnt I see this :smiley: - you can access the respective notebookcells easily with the “panel”. E.g. use your kernel with “panel.sessionContext.session?.kernel?.requestExecute(“1+2”)”.