datalayer / jupyter-ui

⚛️ React.js components 💯% compatible with 🪐 Jupyter - Storybook on https://jupyter-ui-storybook.datalayer.tech
https://jupyter-ui.datalayer.tech
Other
333 stars 46 forks source link

Additional use-cases for current library #320

Open jaydeanmartin opened 2 weeks ago

jaydeanmartin commented 2 weeks ago

I would like to use this library as a GUI to a non-standard Jupyter kernel

Problem

I have been working through the code to better understand what how it works . There are so many layers between what you see and interact with and the communications with the Jupyter server. There are a couple of modifications or use cases I would like to see (and/or help implement):

  1. Suppress displaying the input part of the cell - or at least make it readonly (which I think would be easier). I want to execute a magic command to generate some graphics (or other actions for the kernel such as "save")
  2. parse the output text of a cell
  3. Add a new language to the CodeMirror editor.

Proposed Solution

I currently do not have a proposed solution. It may be more of an education thing for me rather than an actual change in implementation.

Additional context

The kernel I am trying to use is SysML v2 (https://github.com/Systems-Modeling/SysML-v2-Release). I have that code running in 2 other Docker containers and I am using a node.js-based container for the frontend development. -->

echarles commented 2 weeks ago

Suppress displaying the input part of the cell - or at least make it readonly (which I think would be easier). I want to execute a magic command to generate some graphics (or other actions for the kernel such as "save")

There is the Output component exactly for that.

parse the output text of a cell

This example allows you to intercept and access the output in a structured way

https://github.com/datalayer/jupyter-ui/blob/main/packages/react/src/examples/KernelExecutor.tsx

Is that something that helps your case?

Add a new language to the CodeMirror editor.

Can you expand? For which component: notebook, cell ? based on a prop (quite easy to implement) or based on the kernel (more difficult) ?

jaydeanmartin commented 2 weeks ago

The code editor modifications would be for a cell. An example of these modifications for a JupyterLab cell can be found here: https://github.com/Systems-Modeling/SysML-v2-Pilot-Implementation/blob/master/org.omg.sysml.jupyter.jupyterlab/src/main/mode.ts

I may not be completely understanding how the Cells are rendered using Jupyter-UI. If the cells are rendered in a normal notebook, the javasccript for the cell logic/rendering comes from Jupyter (Lab/Hub/server). When using this Jupyter-UI library, I have assumed that it replaces all(?) of the rendering/logic on the frontend and communicates to the backend kernel(s) using a combination of the REST API and websockets.

The SysML library I have referenced already places the sysml language specific editor modifications in the JupyterLab extension, but I thought that since these are not used(?) they would have to be added to the replacement rendering code(mirror) implementation. I may be completely wrong here and am making things much more difficult, but I don't think so.

jaydeanmartin commented 1 week ago

@echarles thank you again for your help and suggestions.

In the following I make a number of statements that are meant to be questions about my current understanding.

I am trying very hard to understand the many different strategies that exist to work with Jupyter. It appears the original approach was adapting the Lumino components provided by Jupyter to work with React. This required the use of "adapters" to handle communications between react and lumino (?)

The latest suggestion to use the Output component appears to move away from adapters model and provides a direct React-based solution to communicate with Jupyter (kernel?). It does use the design pattern of a "store" to manage the state of the communications (?) I like this since it will (does?) provide more control over the user experience. While I can explore the source for the latest version (0.18.9), I can only use the version 0.16.0 due to some odd issue with a library explicitly requiring @primer/primitive 8.24.0 even though my package.json explicitly requests 9.1.2. The end result is much is the new functionality or the stores is not available to me. There is also some naming changes that occurred. Many imports have been made 'plural' (e.g. useCellStore -> useCellsStore).

At this point I am not sure if I should be trying to find a way to get the latest version to install or developing with what does work and adding functionality from the library source code into my code - a bad option but should work in the short-term.

echarles commented 1 week ago

@jaydeanmartin All the jupyter-react component developed in this repo adopt the same approach, which as you describe, relies on adapter to lumino, with a zustand state. This is applicable for the noteobok, cell or output (which is like a cell without the input).

Could you confirm the issues you are facing are linked to node 20? (does it work with eg node 18)?

jaydeanmartin commented 1 week ago

@echarles I am trying to build a container with node.js 18. I need to use hardened containers for this application so my choices are a little limited. The latest 18 is 18.20 so that is out. The error says it needs to be <18.19.0. If I pull an image with 18.18 tag, It still throws an error saying I currently have 18.19. If I pull 18.17.1 (the next version down) it says I have 18.17.1 which does not satisfy the VERY narrow version window. I am not quite sure how I can test at this point. I can try to use a non-hardened container for testing purposes at least.

The error from @primer/primitives@8.2.4 seems to be coming from a requirement in @datalayer/primer-addons, but I am not sure

jaydeanmartin commented 1 week ago

@echarles I am using node:18.18.1-slim container and got it to build with the latest jupyter-react@0.18.9

I did need to add @jupyterlite/pyodide-kernel-extension This results in still getting an error: Error: ENOENT: no such file or directory, open '/app/node_modules/@jupyter-widgets/controls7/node_modules/@jupyter-widgets/base/lib/index.js'

I have tried adding @jupyter-widgets/controls and @jupyter-widgets/base, but this does not resolve the error.

addendum

I rebuilt the container w/o adding the jupyter-widgets and it seems to compile fine now (so still adding jupyterlite/pyodide-kernel-extension)

jaydeanmartin commented 1 week ago

I have been digging deep into the Output.tsx example and the Output component. I am a little confused with the 3 variations in the example. The first is the Output with output and no editor. I think there is no need to reference a kernel so you just force it to render a constant result and suppress the editor with showEditor={false}

In the second case with show editor and output, you use the default kernel and things are pretty normal.

In the third case, the editor with empty (without?) output, I do not understand why you create a new kernel object to evaluate the code? Also, from looking at the Output component code it seems that if you set the prop lumino={false} it should suppress the output, but it doesn't seem to work that way.

I am probably not understanding some fundamental things and hope that someone (@echarles) can shed some light on this.

fcollonval commented 1 week ago

Hi @jaydeanmartin

In the third case, the editor with empty (without?) output

Indeed this case as no output.

I do not understand why you create a new kernel object to evaluate the code?

This is to ensure separation of context between the components. By default, the component will use the defaultKernel. Hence if you have multiple Output on the same page, all inputs will be executed in the same kernel; and therefore sharing state. This may or may not what you want depending on your use case.

Also, from looking at the Output component code it seems that if you set the prop lumino={false} it should suppress the output, but it doesn't seem to work that way.

If you look at the code impacted by lumino:

https://github.com/datalayer/jupyter-ui/blob/550b3ad187356d4480454a306d14c655e1d480a0/packages/react/src/components/output/Output.tsx#L219-L226

You can see that it will display outputs. The difference is the component used to display them. If lumino==true, the component is identical to the one used in JupyterLab. Otherwise, it is a pure react component - that does not cover all cases.


I would like to raise to your attention that this library is based on JupyterLab v4+ when the SysML code you mentionned is based on v3.

Notoriously a big change in v4 is the upgrade from CodeMirror v5 to v6. That will make the SysML code to add a new language obsolete. You can look at that snippet to figure out how to wrap a legacy mode into a compatible object for CodeMirror v6:

https://github.com/jupyterlab/jupyterlab/blob/ff101050c627ecebdbac1c73638debf58d0f8961/packages/codemirror/src/language.ts#L569-L578

jaydeanmartin commented 1 week ago

I am sorry for not completely understanding your responses, but I am trying to process them. The following comments are meant as a discussion to help my understanding and not as a critique in any way.

I do see in the SysML jupyterextension installation process it is specifying jupyterlab-3.* - specifically it is using version 3.6.8. Thank you for noticing this fact. Are the known ramifications for using v3 instead of v4 in general for this library? Are there more issues than the version of CodeMirror being used that may be important. I want to understand if I should also be working to get the sysml kernel working with v4 before I go too far on the frontend side.

When I try to use the pattern in the Output example to display the editor and not display the results - I still get the results being displayed. When I compare the props being sent to the Output component - I do not see any difference between the editor with results and the editor without results. Can someone indicate what is suppressing the display of the results in the editor without results case?