jupyterlab / jupyterlab

JupyterLab computational environment.
https://jupyterlab.readthedocs.io/
Other
14.16k stars 3.38k forks source link

Trigger mimerender extension from another extension #7982

Open aliasmrchips opened 4 years ago

aliasmrchips commented 4 years ago

I made a mimerender extension and I am able to trigger the extension by opening a file from the file browser. I can also trigger the extension in the output cell of a notebook by using IPython.display({my_mimetype: data}, raw=True). I would like to do "the same thing" but using javascript (i.e., from within another extension). So, I would make the data object locally and then call something, trigger an event, generate a message or send a signal that would do the equivalent of IPython.display.

In other words, let's say I have two extensions; foo and bar. The "foo" extension will render objects of type "foo" and the "bar" extension will render objects of type "bar".

example.foo.json

{
    "key": "value",
    "index": 0
}

example.bar.json

{
    "index": 0
}

Note that the "bar" mimetype is actually a subset of the "foo" mimetype. So, I can open .foo.json and .bar.json files and they will be rendered (in separate tabs) by their respective extensions. So far, so good.

However, since all the data required to render a "bar" type document is included in a "foo" type document, I would like to include that capability in the "foo" extension. So, the sequence of events would be: 1) Open the "foo" document with the "foo" extension. 2) Do something within the "foo" extension (click on a link or a button or something) that will result in 3) the "bar" extension rendering the "bar" portion of the original "foo" document (again in a separate jlab tab).

I am not sure what the correct mechanism to do this is. My inclination is to have the "foo" extension generate a message or emit a signal (similar to what the filebrowser must be doing), but have been so far unsuccessful.

jasongrout commented 4 years ago

For reference: this question started in a conversation on Gitter [1, 2].

jasongrout commented 4 years ago

1) Open the "foo" document with the "foo" extension. 2) Do something within the "foo" extension (click on a link or a button or something) that will result in 3) the "bar" extension rendering the "bar" portion of the original "foo" document (again in a separate jlab tab).

So in the end, you want two tabs, one with the foo rendering, and one with the bar rendering? Or do you want the bar rendering inside the foo tab?

aliasmrchips commented 4 years ago

Separate tabs. As if, I had opened two files with the file browser.

jasongrout commented 4 years ago

So it sounds like the suggestions on gitter are appropriate:

Look at how the rendermime registry is used in JupyterLab: https://github.com/jupyterlab/jupyterlab/blob/8dc587729e5f2b2fa6087e854f0f988c0232802e/packages/tooltip/src/widget.ts#L71-L80 https://github.com/jupyterlab/jupyterlab/blob/7fb018558f9c812e3e2a3355fb6ab7c1a30486d8/packages/inspector/src/handler.ts#L152-L160 https://github.com/jupyterlab/jupyterlab/blob/d322d6b1f2d7abb32a2ab1c1a457beaa006ec8c1/packages/outputarea/src/widget.ts#L391 Take one of those as an example for:

  1. Create a bundle of data
  2. Ask the registry for a renderer for that mimetype
  3. Create a new MainAreaWidget with that renderer as the content
  4. Add that MainAreaWidget to the dock panel.
aliasmrchips commented 4 years ago

Ok, I think I get it now. For steps 3) and 4), I assume I would do something like in the tutorial?https://github.com/jupyterlab/jupyterlab/blob/master/docs/source/developer/extension_tutorial.rst

Is there an "app" instance I can access from within a mimerender extension?

jasongrout commented 4 years ago

You are going to have to make a normal extension for this.

aliasmrchips commented 4 years ago

What handles this (creating a new MainAreaWidget) normally? For example, when you open a file in the file browser? The FileBrowser extension or something else?

jasongrout commented 4 years ago

Whoever wants to create a widget. See the astronomy picture of the day tutorial in the docs, for example.

aliasmrchips commented 4 years ago

Ok, two more questions:

  1. Is there an example of making a mimerender extension from a normal extension?
  2. Is there an example of lumino signals/messaging?
saulshanabrook commented 4 years ago

@aliasmrchips

Is there an example of making a mimerender extension from a normal extension?

Here is an example of adding a rendermime widget but that won't add the file handling part.

Is there an example of lumino signals/messaging?

Tons!

Here is one I just made up

import { Signal, ISignal } from '@lumino/signaling';

type SENDER = string;
type VALUE = number;
const s = new Signal<SENDER, VALUE>("sender");

const si: ISignal<SENDER, VALUE> = s;
// I can't emit on the ISignal only on the concrete
// this lets us protect emission and only provide the ability to connect

function slot(sender: SENDER, args: VALUE) {
  console.assert(sender === "sender")
  console.assert(args === 123)
}
// Connect a function to be called on each emmission
si.connect(slot);

// Emit some value. all connected "slots" (callbacks) will be called
s.emit(123)

// disconnect your slot when you are done.
si.disconnect(slot)
aliasmrchips commented 4 years ago

Trying the signaling example, I get this error:

Screen Shot 2020-03-04 at 11 05 31 AM

I have split the code between two extensions with the "emit" in one and the "slot" connect in the other. Any ideas?