diff --git a/packages/react/package.json b/packages/react/package.json index 1600be64..e22b5bff 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -155,6 +155,8 @@ "@jupyterlab/builder": "4.0.3", "@jupyterlab/geojson-extension": "3.4.0", "@jupyterlab/launcher": "4.0.3", + "@jupyterlab/running": "4.0.3", + "@jupyterlab/running-extension": "4.0.3", "@jupyterlab/testutils": "4.0.3", "@jupyterlab/vega3-extension": "3.3.0", "@types/codemirror": "5.60.4", diff --git a/packages/react/src/components/jupyterlab/JupyterLabApp.tsx b/packages/react/src/components/jupyterlab/JupyterLabApp.tsx index d995498b..ae506bf2 100644 --- a/packages/react/src/components/jupyterlab/JupyterLabApp.tsx +++ b/packages/react/src/components/jupyterlab/JupyterLabApp.tsx @@ -11,7 +11,8 @@ import JupyterLabAppCss from "./JupyterLabAppCss"; let _adapter: JupyterLabAppAdapter | undefined = undefined; // The webpack public path needs to be set before loading the CSS assets. -(global as any).__webpack_public_path__ = PageConfig.getOption('fullStaticUrl') + '/'; +(globalThis as any).__webpack_public_path__ = PageConfig.getOption('fullStaticUrl') + '/'; +(window as any).__webpack_public_path__ = PageConfig.getOption('fullStaticUrl') + '/'; export type JupyterLabAppProps = { devMode: boolean; diff --git a/packages/react/src/components/output/OutputIPyWidgets.tsx b/packages/react/src/components/output/OutputIPyWidgets.tsx index e808b325..12db8c64 100644 --- a/packages/react/src/components/output/OutputIPyWidgets.tsx +++ b/packages/react/src/components/output/OutputIPyWidgets.tsx @@ -1,4 +1,4 @@ -import IPyWidgetsAttached from '../../jupyter/lumino/IPyWidgetsAttached'; +import IPyWidgetsAttached from '../../jupyter/ipywidgets/IPyWidgetsAttached'; import './OutputIPyWidgets.css'; diff --git a/packages/react/src/examples/JupyterLabHeadlessApp.tsx b/packages/react/src/examples/JupyterLabHeadlessApp.tsx index 17a78537..8bdaeeda 100644 --- a/packages/react/src/examples/JupyterLabHeadlessApp.tsx +++ b/packages/react/src/examples/JupyterLabHeadlessApp.tsx @@ -1,11 +1,11 @@ import { useState } from 'react'; import { createRoot } from 'react-dom/client'; import { Box, Text, ToggleSwitch, ThemeProvider, useTheme } from "@primer/react"; -import { BoxPanel } from '@lumino/widgets'; +import { BoxPanel, Widget } from '@lumino/widgets'; +import { ThemeManager } from '@jupyterlab/apputils'; import { NotebookPanel } from '@jupyterlab/notebook'; +import { RunningSessions } from '@jupyterlab/running'; // import { NotebookTracker } from '@jupyterlab/notebook'; -import { ThemeManager } from '@jupyterlab/apputils'; -import { Widget } from '@lumino/widgets'; import Jupyter from '../jupyter/Jupyter'; import Lumino from '../jupyter/lumino/Lumino'; import { JupyterLabTheme } from '../jupyter/lab/JupyterLabTheme'; @@ -14,6 +14,7 @@ import JupyterLabAppAdapter from "../components/jupyterlab/JupyterLabAppAdapter" import * as darkThemeExtension from '@jupyterlab/theme-dark-extension'; import * as lightThemeExtension from '@jupyterlab/theme-light-extension'; +import * as runningExtension from '@jupyterlab/running-extension'; import * as ipywidgetsExtension from '@jupyter-widgets/jupyterlab-manager'; import * as plotlyExtension from 'jupyterlab-plotly/lib/jupyterlab-plugin'; import * as mimePlotlyExtension from 'jupyterlab-plotly/lib/plotly-renderer'; @@ -28,7 +29,8 @@ const PATHS = [ const PATH_INDEX = 1; const JupyterLabHeadlessAppExample = () => { - const [boxPanel, setBoxPanel] = useState(); + const [notebookBoxPanel, setNotebookBoxPanel] = useState(); + const [runningSessions, setRunningSessions] = useState(); const [theme, setTheme] = useState('light'); const [jupyterLabAdapter, setJupyterlabAdapter] = useState(); const { setColorMode } = useTheme(); @@ -63,7 +65,10 @@ const JupyterLabHeadlessAppExample = () => { boxPanel.addClass('dla-Jupyter-Notebook'); boxPanel.spacing = 0; boxPanel.addWidget(notebookPanel); - setBoxPanel(boxPanel); + setNotebookBoxPanel(boxPanel); + const runningSessionManagers = jupyterLabAdapter.service('@jupyterlab/running-extension:plugin'); + const runningSessions = new RunningSessions(runningSessionManagers); + setRunningSessions(runningSessions); } const onPlugin = (themeManager: ThemeManager) => { // const notebookTracker = jupyterlabAdapter.service("@jupyterlab/notebook-extension:tracker") as NotebookTracker; @@ -94,7 +99,12 @@ const JupyterLabHeadlessAppExample = () => { - { boxPanel && + { runningSessions && + + {runningSessions} + + } + { notebookBoxPanel &&
{ }, }} > - {boxPanel} + {notebookBoxPanel}
} @@ -114,6 +124,7 @@ const JupyterLabHeadlessAppExample = () => { extensions={[ lightThemeExtension, darkThemeExtension, + runningExtension, ipywidgetsExtension, plotlyExtension, ]} diff --git a/packages/react/src/examples/Lumino.tsx b/packages/react/src/examples/Lumino.tsx new file mode 100755 index 00000000..084b2262 --- /dev/null +++ b/packages/react/src/examples/Lumino.tsx @@ -0,0 +1,23 @@ +import { useMemo } from 'react'; +import { createRoot } from 'react-dom/client'; +import LuminoBox from './../jupyter/lumino/LuminoBox'; +import LuminoWidget from './lumino/LuminoWidget'; + +export const LuminoExample = () => { + const luminoWidget = useMemo(() => new LuminoWidget(), []); + return ( + + {luminoWidget.panel} + + ) +} + +const div = document.createElement('div'); +document.body.appendChild(div); +const root = createRoot(div) + +root.render( + <> + + +); diff --git a/packages/react/src/examples/NotebookKernelChange.tsx b/packages/react/src/examples/NotebookKernelChange.tsx index 829d9071..04bee905 100755 --- a/packages/react/src/examples/NotebookKernelChange.tsx +++ b/packages/react/src/examples/NotebookKernelChange.tsx @@ -10,7 +10,7 @@ import CellSidebar from '../components/notebook/cell/sidebar/CellSidebar'; const NOTEBOOK_UID = 'notebook-kernel-id'; -const NEW_KERNEL_NAME = "python-slow" +const NEW_KERNEL_NAME = "python-bis" const NotebookKernelChange = () => { const { kernelManager, serverSettings } = useJupyter(); @@ -26,7 +26,7 @@ const NotebookKernelChange = () => { }); kernel.ready.then(() => { dispatch(notebookActions.changeKernel({ uid: NOTEBOOK_UID, kernel })); - alert('The kernel is changed.') + alert('The kernel is changed (was python3, now is python-bis). Bummer, all your variables are lost!') }); } } diff --git a/packages/react/src/examples/lumino/LuminoWidget.css b/packages/react/src/examples/lumino/LuminoWidget.css new file mode 100644 index 00000000..81ad6f82 --- /dev/null +++ b/packages/react/src/examples/lumino/LuminoWidget.css @@ -0,0 +1,34 @@ +.content { + min-width: 50px; + min-height: 50px; + display: block; + padding: 8px; + border: 1px solid #C0C0C0; + border-top: none; + box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2); +} + +.content > div { + border: 1px solid #505050; + overflow: auto; +} + +.content input { + margin: 8px; +} + +.red > div { + background: #E74C3C; +} + +.yellow > div { + background: #F1C40F; +} + +.green > div { + background: #27AE60; +} + +.blue > div { + background: #3498DB; +} diff --git a/packages/react/src/examples/lumino/LuminoWidget.ts b/packages/react/src/examples/lumino/LuminoWidget.ts new file mode 100755 index 00000000..67f27ea4 --- /dev/null +++ b/packages/react/src/examples/lumino/LuminoWidget.ts @@ -0,0 +1,90 @@ +import { Message } from '@lumino/messaging'; +import { DockPanel, BoxPanel, Widget } from '@lumino/widgets'; + +import '@lumino/default-theme/style/index.css'; + +import './LuminoWidget.css' + +class LuminoWidget extends Widget { + + constructor(name: string) { + super({ node: LuminoWidget.createNode() }); + this.setFlag(Widget.Flag.DisallowLayout); + this.addClass('content'); + this.addClass(name.toLowerCase()); + this.title.label = name; + this.title.closable = true; + this.title.caption = `Long description for: ${name}`; + } + + static createNode(): HTMLElement { + let node = document.createElement('div'); + let content = document.createElement('div'); + let input = document.createElement('input'); + input.placeholder = 'Placeholder...'; + content.appendChild(input); + node.appendChild(content); + return node; + } + + get inputNode(): HTMLInputElement { + return this.node.getElementsByTagName('input')[0] as HTMLInputElement; + } + + protected onActivateRequest(msg: Message): void { + if (this.isAttached) { + this.inputNode.focus(); + } + } + +} + +class SimpleAdapter { + private simplePanel: BoxPanel; + + constructor() { + const colors = [ + 'Red', + 'Yellow', + 'Green', + 'Blue' + ]; + + this.simplePanel = new BoxPanel(); + this.simplePanel.id = 'simple-panel'; + // this.simplePanel.direction = 'top-to-bottom'; + this.simplePanel.spacing = 0; + + // Dock Panel + const r1 = new LuminoWidget('Red'); + const b1 = new LuminoWidget('Blue'); + const g1 = new LuminoWidget('Green'); + const y1 = new LuminoWidget('Yellow'); + const r2 = new LuminoWidget('Red'); + const b2 = new LuminoWidget('Blue'); + + const dockPanel = new DockPanel(); + dockPanel.addWidget(r1); + dockPanel.addWidget(b1, { mode: 'split-right', ref: r1 }); + dockPanel.addWidget(y1, { mode: 'split-bottom', ref: b1 }); + dockPanel.addWidget(g1, { mode: 'split-left', ref: y1 }); + dockPanel.addWidget(r2, { ref: b1 }); + dockPanel.addWidget(b2, { mode: 'split-right', ref: y1 }); + dockPanel.id = 'simple-dock-panel'; + + this.simplePanel.addWidget(dockPanel); + + for (let i = 0; i < 20; i++) { + const c = new LuminoWidget(colors[Math.floor(Math.random() * 4)]); + this.simplePanel.addWidget(c); + } + + } + + get panel(): BoxPanel { + return this.simplePanel; + } + +} + +export default SimpleAdapter; diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 91225575..028aff20 100755 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -47,6 +47,8 @@ export * from './components/notebook/cell/sidebar/CellSidebar'; export * from './components/notebook/cell/sidebar/CellSidebarRun'; // IPyWidgets. +export * from './jupyter/ipywidgets/IPyWidgetsAttached'; +export * from './jupyter/ipywidgets/IPyWidgetsViewManager'; export * from './jupyter/ipywidgets/IPyWidgetsViewManager'; // Commands. @@ -60,13 +62,13 @@ export * from './components/console/ConsoleState'; // Dialog. export * from './components/dialog/Dialog'; -// FileBrowser. +// File Browser. export * from './components/filebrowser/FileBrowser'; -// FileManager. +// File Manager. export * from './components/filemanager/FileManagerState'; -// FileManager (JupyterLab variant). +// File Manager (JupyterLab variant). export * from './components/filemanager/FileManagerJupyterLab'; // Outputs. diff --git a/packages/react/src/jupyter/lumino/IPyWidgetsAttached.tsx b/packages/react/src/jupyter/ipywidgets/IPyWidgetsAttached.tsx similarity index 90% rename from packages/react/src/jupyter/lumino/IPyWidgetsAttached.tsx rename to packages/react/src/jupyter/ipywidgets/IPyWidgetsAttached.tsx index 2c2e8edd..5902c748 100644 --- a/packages/react/src/jupyter/lumino/IPyWidgetsAttached.tsx +++ b/packages/react/src/jupyter/ipywidgets/IPyWidgetsAttached.tsx @@ -1,4 +1,4 @@ -import IPyWidgetsViewManager from '../ipywidgets/IPyWidgetsViewManager'; +import IPyWidgetsViewManager from './IPyWidgetsViewManager'; type Props = { view: any, diff --git a/packages/react/src/jupyter/lumino/Lumino.tsx b/packages/react/src/jupyter/lumino/Lumino.tsx index 28f135de..993aaadf 100644 --- a/packages/react/src/jupyter/lumino/Lumino.tsx +++ b/packages/react/src/jupyter/lumino/Lumino.tsx @@ -4,12 +4,13 @@ import { Widget } from '@lumino/widgets'; type LuminoProps = { id?: string; + height?: string | number; children: Widget; } export const Lumino = (props: LuminoProps) => { const ref = useRef(null); - const { children, id } = props; + const { children, id, height } = props; useEffect(() => { if (ref && ref.current) { try { @@ -31,11 +32,12 @@ export const Lumino = (props: LuminoProps) => { } } }, [ref, children]); - return
+ return
} Lumino.defaultProps = { id: "lumino-id", + height: "100%", } export default Lumino; diff --git a/packages/react/webpack.config.js b/packages/react/webpack.config.js index 0ffac0ad..3e4dae51 100644 --- a/packages/react/webpack.config.js +++ b/packages/react/webpack.config.js @@ -14,6 +14,7 @@ const ENTRY = // "./src/app/App"; // "./src/examples/JupyterLabApp"; "./src/examples/JupyterLabHeadlessApp"; +// "./src/examples/Lumino"; // "./src/examples/Matplotlib"; // "./src/examples/Notebook"; // "./src/examples/NotebookKernelChange";