diff --git a/.github/workflows/check-release.yml b/.github/workflows/check-release.yml index 5fe3600ae..a89cbf35a 100644 --- a/.github/workflows/check-release.yml +++ b/.github/workflows/check-release.yml @@ -31,7 +31,7 @@ jobs: version_spec: next - name: Upload Distributions - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: voila-releaser-dist-${{ github.run_number }} path: .jupyter_releaser_checkout/dist diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a686d40ea..3b29ee5d1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -74,7 +74,7 @@ jobs: strategy: fail-fast: false matrix: - os: [macos] + os: [macos-12] python_version: ['3.8', '3.9', '3.10', '3.11'] steps: diff --git a/.github/workflows/packaging.yml b/.github/workflows/packaging.yml index 8a615e083..45565758a 100644 --- a/.github/workflows/packaging.yml +++ b/.github/workflows/packaging.yml @@ -50,36 +50,36 @@ jobs: sha256sum * | tee SHA256SUMS - name: Upload distributions - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: dist ${{ github.run_number }} path: ./dist install: - runs-on: ${{ matrix.os }}-latest + runs-on: ${{ matrix.os }} needs: [build] strategy: fail-fast: false matrix: - os: [ubuntu, macos, windows] + os: [ubuntu-latest, macos-12, windows-latest] python: ['3.8', '3.10'] include: - python: '3.8' dist: 'voila*.tar.gz' - python: '3.10' dist: 'voila*.whl' - - os: windows + - os: windows-latest py_cmd: python - - os: macos + - os: macos-12 py_cmd: python3 - - os: ubuntu + - os: ubuntu-latest py_cmd: python steps: - name: Install Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: dist ${{ github.run_number }} path: ./dist diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 20355df06..aa27f2344 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -12,7 +12,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - jupyter-server-version: ["1.24.0", "2.14.2"] + jupyter-server-version: ['1.24.0', '2.14.2'] + progressive_rendering: [false, true] + exclude: + - jupyter-server-version: '1.24.0' + progressive_rendering: true fail-fast: false steps: @@ -35,7 +39,7 @@ jobs: - name: Launch Voila run: | # Mount a volume to overwrite the server configuration - jlpm start 2>&1 > /tmp/voila_server.log & + jlpm start --progressive_rendering=${{ matrix.progressive_rendering }} 2>&1 > /tmp/voila_server.log & working-directory: ui-tests - name: Install browser @@ -49,30 +53,46 @@ jobs: timeout: 360000 - name: Test + env: + PROGRESSIVE_RENDERING: ${{ matrix.progressive_rendering }} run: jlpm run test working-directory: ui-tests + - name: Set test report name for progressive rendering + if: always() && matrix.progressive_rendering == true + run: | + echo "TEST_REPORT_NAME=progressive-voila-test-report-${{ matrix.jupyter-server-version }}" >> $GITHUB_ENV + echo "TEST_ASSETS_NAME=progressive-voila-test-assets-${{ matrix.jupyter-server-version }}" >> $GITHUB_ENV + echo "TEST_BENCHMARK_NAME=progressive-voila-test-benchmark-${{ matrix.jupyter-server-version }}" >> $GITHUB_ENV + + - name: Set test report name for non-progressive rendering + if: always() && matrix.progressive_rendering == false + run: | + echo "TEST_REPORT_NAME=voila-test-report-${{ matrix.jupyter-server-version }}" >> $GITHUB_ENV + echo "TEST_ASSETS_NAME=voila-test-assets-${{ matrix.jupyter-server-version }}" >> $GITHUB_ENV + echo "TEST_BENCHMARK_NAME=voila-test-benchmark-${{ matrix.jupyter-server-version }}" >> $GITHUB_ENV + - name: Upload Playwright Test assets if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: voila-test-assets + name: ${{ env.TEST_ASSETS_NAME }} path: | ui-tests/test-results - name: Upload Playwright Benchmark report if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: voila-benchmark-report + name: ${{ env.TEST_BENCHMARK_NAME }} path: | ui-tests/benchmark-results - name: Upload Playwright Test report if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: voila-test-report + name: ${{ env.TEST_REPORT_NAME }} path: | ui-tests/playwright-report diff --git a/.github/workflows/update_galata_references.yaml b/.github/workflows/update_galata_references.yaml index 76171b165..4c73b9855 100644 --- a/.github/workflows/update_galata_references.yaml +++ b/.github/workflows/update_galata_references.yaml @@ -15,29 +15,70 @@ defaults: jobs: update-reference-screenshots: name: Update Galata References - if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, 'update galata references') }} + if: > + ( + github.event.comment.author_association == 'OWNER' || + github.event.comment.author_association == 'COLLABORATOR' || + github.event.comment.author_association == 'MEMBER' + ) && github.event.issue.pull_request && contains(github.event.comment.body, 'please update snapshots') runs-on: ubuntu-latest strategy: matrix: - python-version: [3.8] - node-version: [16.x] + python-version: [3.10] + node-version: [18.x] steps: - - name: Base Setup - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + - name: React to the triggering comment + run: | + gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions --raw-field 'content=+1' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} - - name: Configure git to use https - run: git config --global hub.protocol https + - name: Get PR Info + id: pr + env: + PR_NUMBER: ${{ github.event.issue.number }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + COMMENT_AT: ${{ github.event.comment.created_at }} + run: | + pr="$(gh api /repos/${GH_REPO}/pulls/${PR_NUMBER})" + head_sha="$(echo "$pr" | jq -r .head.sha)" + pushed_at="$(echo "$pr" | jq -r .pushed_at)" + + if [[ $(date -d "$pushed_at" +%s) -gt $(date -d "$COMMENT_AT" +%s) ]]; then + echo "Updating is not allowed because the PR was pushed to (at $pushed_at) after the triggering comment was issued (at $COMMENT_AT)" + exit 1 + fi + + echo "head_sha=$head_sha" >> $GITHUB_OUTPUT - name: Checkout the branch from the PR that triggered the job - run: hub pr checkout ${{ github.event.issue.number }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh pr checkout ${{ github.event.issue.number }} + + - name: Validate the fetched branch HEAD revision + env: + EXPECTED_SHA: ${{ steps.pr.outputs.head_sha }} + run: | + actual_sha="$(git rev-parse HEAD)" + + if [[ "$actual_sha" != "$EXPECTED_SHA" ]]; then + echo "The HEAD of the checked out branch ($actual_sha) differs from the HEAD commit available at the time when trigger comment was submitted ($EXPECTED_SHA)" + exit 1 + fi + + - name: Base Setup + uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 + + - name: Configure git to use https + run: git config --global hub.protocol https - name: Install dependencies run: | diff --git a/docs/customize.md b/docs/customize.md index fe3fd59fc..d5bb143ce 100644 --- a/docs/customize.md +++ b/docs/customize.md @@ -665,3 +665,33 @@ By default, Voilà will attempt to resolve a kernel spec to the best fit, based ```py c.VoilaConfiguration.attempt_fix_notebook = False ``` + +## Changing dashboard rendering technique + +There are two dashboard rendering techniques in Voilà: + +- **Blocking rendering** (default): In this method, Voilà completes the execution of the entire notebook before displaying the dashboard. It is ideal for lightweight notebooks, as a loading spinner is shown until execution finishes.. +- **Progressive rendering** (introduced in Voilà 0.6): With this method, the dashboard appears immediately, with placeholders filling the cell outputs. These outputs are updated as each cell is executed by the kernel. + +To start Voilà with progressive rendering mode using CLI: + +```bash +voila ... --progressive_rendering=True +``` + +or using `voila.json` file + +```python +# voila.json +{ + ... + "VoilaConfiguration": { + "progressive_rendering": true, + ... + } +} +``` + +:::{warning} +Progressive rendering mode is incompatible with the preheated kernels functionality. +::: diff --git a/packages/voila/src/app.ts b/packages/voila/src/app.ts index f06399f2e..3db7d0851 100644 --- a/packages/voila/src/app.ts +++ b/packages/voila/src/app.ts @@ -10,7 +10,7 @@ import { PageConfig } from '@jupyterlab/coreutils'; import { IRenderMime } from '@jupyterlab/rendermime'; -import { KernelWidgetManager } from '@jupyter-widgets/jupyterlab-manager'; +import { VoilaWidgetManager } from './plugins/widget'; import { IShell, VoilaShell } from './shell'; @@ -121,23 +121,23 @@ export class VoilaApp extends JupyterFrontEnd { /** * A promise that resolves when the Voila Widget Manager is created */ - get widgetManagerPromise(): PromiseDelegate { + get widgetManagerPromise(): PromiseDelegate { return this._widgetManagerPromise; } - set widgetManager(manager: KernelWidgetManager | null) { + set widgetManager(manager: VoilaWidgetManager | null) { this._widgetManager = manager; if (this._widgetManager) { this._widgetManagerPromise.resolve(this._widgetManager); } } - get widgetManager(): KernelWidgetManager | null { + get widgetManager(): VoilaWidgetManager | null { return this._widgetManager; } - protected _widgetManager: KernelWidgetManager | null = null; - protected _widgetManagerPromise = new PromiseDelegate(); + protected _widgetManager: VoilaWidgetManager | null = null; + protected _widgetManagerPromise = new PromiseDelegate(); } /** diff --git a/packages/voila/src/plugins/widget/index.ts b/packages/voila/src/plugins/widget/index.ts index 23e090e5c..2819a5a51 100644 --- a/packages/voila/src/plugins/widget/index.ts +++ b/packages/voila/src/plugins/widget/index.ts @@ -1,166 +1,13 @@ -/*************************************************************************** - * Copyright (c) 2018, Voilà contributors * - * Copyright (c) 2018, QuantStack * - * * - * Distributed under the terms of the BSD 3-Clause License. * - * * - * The full license is in the file LICENSE, distributed with this software. * - ****************************************************************************/ - -import { - JupyterFrontEnd, - JupyterFrontEndPlugin -} from '@jupyterlab/application'; - -import { PageConfig } from '@jupyterlab/coreutils'; - -import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; - -import { KernelAPI, ServerConnection } from '@jupyterlab/services'; - -import { KernelConnection } from '@jupyterlab/services/lib/kernel/default'; - +import { VoilaWidgetManager } from './manager'; import { - WidgetRenderer, - KernelWidgetManager -} from '@jupyter-widgets/jupyterlab-manager'; - -import { - IJupyterWidgetRegistry, - IWidgetRegistryData -} from '@jupyter-widgets/base'; - -import { VoilaApp } from '../../app'; - -import { Widget } from '@lumino/widgets'; -import { RenderedCells } from './renderedcells'; - -const WIDGET_MIMETYPE = 'application/vnd.jupyter.widget-view+json'; - -/** - * The Voila widgets manager plugin. - */ -export const widgetManager: JupyterFrontEndPlugin = { - id: '@voila-dashboards/voila:widget-manager', - autoStart: true, - requires: [IRenderMimeRegistry], - provides: IJupyterWidgetRegistry, - activate: async ( - app: JupyterFrontEnd, - rendermime: IRenderMimeRegistry - ): Promise => { - if (!(app instanceof VoilaApp)) { - throw Error( - 'The Voila Widget Manager plugin must be activated in a VoilaApp' - ); - } - const baseUrl = PageConfig.getBaseUrl(); - const kernelId = PageConfig.getOption('kernelId'); - const serverSettings = ServerConnection.makeSettings({ baseUrl }); - - const model = await KernelAPI.getKernelModel(kernelId, serverSettings); - if (!model) { - return { - registerWidget(data: IWidgetRegistryData): void { - throw Error(`The model for kernel id ${kernelId} does not exist`); - } - }; - } - const kernel = new KernelConnection({ model, serverSettings }); - const manager = new KernelWidgetManager(kernel, rendermime); - app.widgetManager = manager; - - rendermime.removeMimeType(WIDGET_MIMETYPE); - rendermime.addFactory( - { - safe: false, - mimeTypes: [WIDGET_MIMETYPE], - createRenderer: (options) => new WidgetRenderer(options, manager) - }, - -10 - ); - window.addEventListener('beforeunload', (e) => { - const data = new FormData(); - // it seems if we attach this to early, it will not be called - const matches = document.cookie.match('\\b_xsrf=([^;]*)\\b'); - const xsrfToken = (matches && matches[1]) || ''; - data.append('_xsrf', xsrfToken); - window.navigator.sendBeacon( - `${baseUrl}voila/api/shutdown/${kernel.id}`, - data - ); - kernel.dispose(); - }); - - return { - registerWidget: async (data: IWidgetRegistryData) => { - const manager = await app.widgetManagerPromise.promise; - - manager.register(data); - } - }; - } -}; - -/** - * The plugin that renders outputs. - */ -export const renderOutputsPlugin: JupyterFrontEndPlugin = { - id: '@voila-dashboards/voila:render-outputs', - autoStart: true, - requires: [IRenderMimeRegistry, IJupyterWidgetRegistry], - activate: async ( - app: JupyterFrontEnd, - rendermime: IRenderMimeRegistry - ): Promise => { - // TODO: Typeset a fake element to get MathJax loaded, remove this hack once - // MathJax 2 is removed. - await rendermime.latexTypesetter?.typeset(document.createElement('div')); - - // Render latex in markdown cells - const mdOutput = document.body.querySelectorAll('div.jp-MarkdownOutput'); - mdOutput.forEach((md) => { - rendermime.latexTypesetter?.typeset(md as HTMLElement); - }); - // Render code cell - const cellOutputs = document.body.querySelectorAll( - 'script[type="application/vnd.voila.cell-output+json"]' - ); - cellOutputs.forEach(async (cellOutput) => { - const model = JSON.parse(cellOutput.innerHTML); - - const mimeType = rendermime.preferredMimeType(model.data, 'any'); - - if (!mimeType) { - return null; - } - const output = rendermime.createRenderer(mimeType); - output.renderModel(model).catch((error) => { - // Manually append error message to output - const pre = document.createElement('pre'); - pre.textContent = `Javascript Error: ${error.message}`; - output.node.appendChild(pre); - - // Remove mime-type-specific CSS classes - pre.className = 'lm-Widget jp-RenderedText'; - pre.setAttribute('data-mime-type', 'application/vnd.jupyter.stderr'); - }); - - output.addClass('jp-OutputArea-output'); - - if (cellOutput.parentElement) { - const container = cellOutput.parentElement; - - container.removeChild(cellOutput); - - // Attach output - Widget.attach(output, container); - } - }); - const node = document.getElementById('rendered_cells'); - if (node) { - const cells = new RenderedCells({ node }); - app.shell.add(cells, 'main'); - } - } + widgetManager, + renderOutputsPlugin, + renderOutputsProgressivelyPlugin +} from './plugins'; + +export { + VoilaWidgetManager, + widgetManager, + renderOutputsPlugin, + renderOutputsProgressivelyPlugin }; diff --git a/packages/voila/src/plugins/widget/manager.ts b/packages/voila/src/plugins/widget/manager.ts new file mode 100644 index 000000000..32132ca7c --- /dev/null +++ b/packages/voila/src/plugins/widget/manager.ts @@ -0,0 +1,22 @@ +import { WidgetModel } from '@jupyter-widgets/base'; +import { KernelWidgetManager } from '@jupyter-widgets/jupyterlab-manager'; +import { ISignal, Signal } from '@lumino/signaling'; + +export class VoilaWidgetManager extends KernelWidgetManager { + register_model(model_id: string, modelPromise: Promise): void { + super.register_model(model_id, modelPromise); + this._registeredModels.add(model_id); + this._modelRegistered.emit(model_id); + } + get registeredModels(): ReadonlySet { + return this._registeredModels; + } + get modelRegistered(): ISignal { + return this._modelRegistered; + } + removeRegisteredModel(modelId: string) { + this._registeredModels.delete(modelId); + } + private _modelRegistered = new Signal(this); + private _registeredModels = new Set(); +} diff --git a/packages/voila/src/plugins/widget/plugins.ts b/packages/voila/src/plugins/widget/plugins.ts new file mode 100644 index 000000000..1aa7312c6 --- /dev/null +++ b/packages/voila/src/plugins/widget/plugins.ts @@ -0,0 +1,240 @@ +/*************************************************************************** + * Copyright (c) 2018, Voilà contributors * + * Copyright (c) 2018, QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ +import { + IJupyterWidgetRegistry, + IWidgetRegistryData +} from '@jupyter-widgets/base'; +import { WidgetRenderer } from '@jupyter-widgets/jupyterlab-manager'; +import { + JupyterFrontEnd, + JupyterFrontEndPlugin +} from '@jupyterlab/application'; +import { PageConfig } from '@jupyterlab/coreutils'; +import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; +import { KernelAPI, ServerConnection } from '@jupyterlab/services'; +import { KernelConnection } from '@jupyterlab/services/lib/kernel/default'; +import { Widget } from '@lumino/widgets'; + +import { VoilaApp } from '../../app'; +import { VoilaWidgetManager } from './manager'; +import { RenderedCells } from './renderedcells'; +import { + createSkeleton, + getExecutionURL, + handleExecutionResult, + IExecutionMessage, + IReceivedWidgetModel +} from './tools'; + +const WIDGET_MIMETYPE = 'application/vnd.jupyter.widget-view+json'; + +/** + * The Voila widgets manager plugin. + */ +export const widgetManager: JupyterFrontEndPlugin = { + id: '@voila-dashboards/voila:widget-manager', + autoStart: true, + requires: [IRenderMimeRegistry], + provides: IJupyterWidgetRegistry, + activate: async ( + app: JupyterFrontEnd, + rendermime: IRenderMimeRegistry + ): Promise => { + if (!(app instanceof VoilaApp)) { + throw Error( + 'The Voila Widget Manager plugin must be activated in a VoilaApp' + ); + } + const baseUrl = PageConfig.getBaseUrl(); + const kernelId = PageConfig.getOption('kernelId'); + const serverSettings = ServerConnection.makeSettings({ baseUrl }); + + const model = await KernelAPI.getKernelModel(kernelId, serverSettings); + if (!model) { + return { + registerWidget(data: IWidgetRegistryData): void { + throw Error(`The model for kernel id ${kernelId} does not exist`); + } + }; + } + const kernel = new KernelConnection({ model, serverSettings }); + const manager = new VoilaWidgetManager(kernel, rendermime); + app.widgetManager = manager; + + rendermime.removeMimeType(WIDGET_MIMETYPE); + rendermime.addFactory( + { + safe: false, + mimeTypes: [WIDGET_MIMETYPE], + createRenderer: (options) => new WidgetRenderer(options, manager) + }, + -10 + ); + window.addEventListener('beforeunload', (e) => { + const data = new FormData(); + // it seems if we attach this to early, it will not be called + const matches = document.cookie.match('\\b_xsrf=([^;]*)\\b'); + const xsrfToken = (matches && matches[1]) || ''; + data.append('_xsrf', xsrfToken); + window.navigator.sendBeacon( + `${baseUrl}voila/api/shutdown/${kernel.id}`, + data + ); + kernel.dispose(); + }); + + return { + registerWidget: async (data: IWidgetRegistryData) => { + const manager = await app.widgetManagerPromise.promise; + + manager.register(data); + } + }; + } +}; + +/** + * The plugin that renders outputs. + */ +export const renderOutputsPlugin: JupyterFrontEndPlugin = { + id: '@voila-dashboards/voila:render-outputs', + autoStart: true, + requires: [IRenderMimeRegistry, IJupyterWidgetRegistry], + activate: async ( + app: JupyterFrontEnd, + rendermime: IRenderMimeRegistry + ): Promise => { + // TODO: Typeset a fake element to get MathJax loaded, remove this hack once + // MathJax 2 is removed. + await rendermime.latexTypesetter?.typeset(document.createElement('div')); + + // Render latex in markdown cells + const mdOutput = document.body.querySelectorAll('div.jp-MarkdownOutput'); + mdOutput.forEach((md) => { + rendermime.latexTypesetter?.typeset(md as HTMLElement); + }); + // Render code cell + const cellOutputs = document.body.querySelectorAll( + 'script[type="application/vnd.voila.cell-output+json"]' + ); + cellOutputs.forEach(async (cellOutput) => { + const model = JSON.parse(cellOutput.innerHTML); + + const mimeType = rendermime.preferredMimeType(model.data, 'any'); + + if (!mimeType) { + return null; + } + const output = rendermime.createRenderer(mimeType); + output.renderModel(model).catch((error) => { + // Manually append error message to output + const pre = document.createElement('pre'); + pre.textContent = `Javascript Error: ${error.message}`; + output.node.appendChild(pre); + + // Remove mime-type-specific CSS classes + pre.className = 'lm-Widget jp-RenderedText'; + pre.setAttribute('data-mime-type', 'application/vnd.jupyter.stderr'); + }); + + output.addClass('jp-OutputArea-output'); + + if (cellOutput.parentElement) { + const container = cellOutput.parentElement; + + container.removeChild(cellOutput); + + // Attach output + Widget.attach(output, container); + } + }); + + const node = document.getElementById('rendered_cells'); + if (node) { + const cells = new RenderedCells({ node }); + app.shell.add(cells, 'main'); + } + } +}; + +/** + * The plugin that renders outputs. + */ +export const renderOutputsProgressivelyPlugin: JupyterFrontEndPlugin = { + id: '@voila-dashboards/voila:render-outputs-progressively', + autoStart: true, + requires: [IRenderMimeRegistry, IJupyterWidgetRegistry], + activate: async ( + app: JupyterFrontEnd, + rendermime: IRenderMimeRegistry + ): Promise => { + const progressiveRendering = + PageConfig.getOption('progressiveRendering') === 'true'; + if (!progressiveRendering) { + return; + } + + createSkeleton(); + + const widgetManager = await (app as VoilaApp).widgetManagerPromise.promise; + + if (!widgetManager) { + return; + } + + const kernelId = widgetManager.kernel.id; + + const receivedWidgetModel: IReceivedWidgetModel = {}; + const modelRegisteredHandler = (_: VoilaWidgetManager, modelId: string) => { + if (receivedWidgetModel[modelId]) { + const { outputModel, executionModel } = receivedWidgetModel[modelId]; + outputModel.add(executionModel); + widgetManager.removeRegisteredModel(modelId); + } + }; + widgetManager.modelRegistered.connect(modelRegisteredHandler); + const wsUrl = getExecutionURL(kernelId); + const ws = new WebSocket(wsUrl); + ws.onmessage = async (msg) => { + const { action, payload }: IExecutionMessage = JSON.parse(msg.data); + switch (action) { + case 'execution_result': { + const result = handleExecutionResult({ + payload, + rendermime, + widgetManager + }); + if (result) { + Object.entries(result).forEach(([key, val]) => { + receivedWidgetModel[key] = val; + }); + } + const { cell_index, total_cell } = payload; + if (cell_index + 1 === total_cell) { + // Executed all cells + ws.close(); + } + + break; + } + case 'execution_error': { + console.error(`Execution error: ${payload.error}`); + break; + } + default: + break; + } + }; + ws.onopen = () => { + ws.send( + JSON.stringify({ action: 'execute', payload: { kernel_id: kernelId } }) + ); + }; + } +}; diff --git a/packages/voila/src/plugins/widget/tools.ts b/packages/voila/src/plugins/widget/tools.ts new file mode 100644 index 000000000..5e1bf41a8 --- /dev/null +++ b/packages/voila/src/plugins/widget/tools.ts @@ -0,0 +1,160 @@ +import { IOutput } from '@jupyterlab/nbformat'; +import { OutputAreaModel, SimplifiedOutputArea } from '@jupyterlab/outputarea'; +import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; +import { Widget } from '@lumino/widgets'; +import { VoilaWidgetManager } from './manager'; +import { PageConfig, URLExt } from '@jupyterlab/coreutils'; + +/** + * Interface representing the structure of an execution result message. + */ +export interface IExecutionResultMessage { + action: 'execution_result'; + payload: { + output_cell: { outputs: IOutput[] }; + cell_index: number; + total_cell: number; + }; +} + +/** + * Interface representing the structure of an execution error message. + */ +export interface IExecutionErrorMessage { + action: 'execution_error'; + payload: { + error: string; + }; +} + +/** + * Interface representing a received widget model + * containing output and execution models. + */ +export interface IReceivedWidgetModel { + [modelId: string]: { + outputModel: OutputAreaModel; + executionModel: IOutput; + }; +} +export type IExecutionMessage = + | IExecutionResultMessage + | IExecutionErrorMessage; + +export function getExecutionURL(kernelId?: string): string { + const wsUrl = PageConfig.getWsUrl(); + return URLExt.join(wsUrl, 'voila/execution', kernelId ?? ''); +} + +/** + * Handles the execution result by rendering the output area and managing widget models. + * + * @param payload - The payload from the execution result message, + * including the output cell and cell index. + * @param rendermime - A render mime registry to render the output. + * @param widgetManager - The Voila widget manager to manage Jupyter widgets. + * @returns An object containing a model ID and its corresponding output and + * execution models if the model is not ready to be rendered, undefined otherwise. + */ +export function handleExecutionResult({ + payload, + rendermime, + widgetManager +}: { + payload: IExecutionResultMessage['payload']; + rendermime: IRenderMimeRegistry; + widgetManager: VoilaWidgetManager; +}): IReceivedWidgetModel | undefined { + const { cell_index, output_cell } = payload; + const element = document.querySelector(`[cell-index="${cell_index + 1}"]`); + if (element) { + const skeleton = element + .getElementsByClassName('voila-skeleton-container') + .item(0); + if (skeleton) { + element.removeChild(skeleton); + } + const model = createOutputArea({ rendermime, parent: element }); + if (!output_cell.outputs) { + return; + } + if (output_cell.outputs.length > 0) { + element.lastElementChild?.classList.remove( + 'jp-mod-noOutputs', + 'jp-mod-noInput' + ); + } + const key = 'application/vnd.jupyter.widget-view+json'; + for (const outputData of output_cell.outputs) { + const modelId = (outputData?.data as any)?.[key]?.model_id; + if (modelId) { + if (widgetManager.registeredModels.has(modelId)) { + model.add(outputData); + } else { + return { + [modelId]: { + outputModel: model, + executionModel: outputData + } + }; + } + } else { + model.add(outputData); + } + } + } +} + +/** + * Creates an output area model and attaches the output area to a specified parent element. + * + * @param rendermime - The render mime registry. + * @param parent - The parent HTML element where the output area will be appended. + * @returns The created OutputAreaModel. + */ +export function createOutputArea({ + rendermime, + parent +}: { + rendermime: IRenderMimeRegistry; + parent: Element; +}): OutputAreaModel { + const model = new OutputAreaModel({ trusted: true }); + const area = new SimplifiedOutputArea({ + model, + rendermime + }); + + const wrapper = document.createElement('div'); + wrapper.classList.add('jp-Cell-outputWrapper'); + const collapser = document.createElement('div'); + collapser.classList.add( + 'jp-Collapser', + 'jp-OutputCollapser', + 'jp-Cell-outputCollapser' + ); + wrapper.appendChild(collapser); + parent.lastElementChild?.appendChild(wrapper); + area.node.classList.add('jp-Cell-outputArea'); + + area.node.style.display = 'flex'; + area.node.style.flexDirection = 'column'; + + Widget.attach(area, wrapper); + return model; +} + +export function createSkeleton(): void { + const innerHtml = `
+
+
+
+
`; + const elements = document.querySelectorAll('[cell-index]'); + elements.forEach((it) => { + const element = document.createElement('div'); + element.className = 'voila-skeleton-container'; + element.innerHTML = innerHtml; + it.appendChild(element); + }); +} diff --git a/packages/voila/src/voilaplugins.ts b/packages/voila/src/voilaplugins.ts index 7e52e7113..dfcb67526 100644 --- a/packages/voila/src/voilaplugins.ts +++ b/packages/voila/src/voilaplugins.ts @@ -12,6 +12,7 @@ import { pathsPlugin } from './plugins/path'; import { translatorPlugin } from './plugins/translator'; import { renderOutputsPlugin, widgetManager } from './plugins/widget'; import { themePlugin, themesManagerPlugin } from './plugins/themes'; +import { renderOutputsProgressivelyPlugin } from './plugins/widget/index'; /** * Export the plugins as default. @@ -21,6 +22,7 @@ const plugins: JupyterFrontEndPlugin[] = [ translatorPlugin, widgetManager, renderOutputsPlugin, + renderOutputsProgressivelyPlugin, themesManagerPlugin, themePlugin ]; @@ -32,6 +34,7 @@ export { translatorPlugin, widgetManager, renderOutputsPlugin, + renderOutputsProgressivelyPlugin, themesManagerPlugin, themePlugin }; diff --git a/share/jupyter/voila/templates/base/spinner.macro.html.j2 b/share/jupyter/voila/templates/base/spinner.macro.html.j2 index 627c8ee14..a3ebb98ba 100644 --- a/share/jupyter/voila/templates/base/spinner.macro.html.j2 +++ b/share/jupyter/voila/templates/base/spinner.macro.html.j2 @@ -34,6 +34,63 @@ .voila-spinner-color2{ fill:#f8e14b; } + + .voila-skeleton-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + } + + .voila-skeleton-post { + width: 220px; + height: 80px; + } + .voila-skeleton-post .voila-skeleton-avatar { + float: left; + width: 52px; + height: 52px; + background-color: var(--jp-layout-color1); + border-radius: 25%; + margin: 8px; + background-image: linear-gradient(90deg, var(--jp-layout-color2) 0px, var(--jp-layout-color3) 40px, var(--jp-layout-color2) 80px); + background-size: 600px; + animation: shine-avatar 1.6s infinite linear; + } + .voila-skeleton-post .voila-skeleton-line { + float: left; + width: 140px; + height: 16px; + margin-top: 12px; + border-radius: 7px; + background-image: linear-gradient(90deg, var(--jp-layout-color2) 0px, var(--jp-layout-color3) 40px, var(--jp-layout-color2) 80px); + background-size: 600px; + animation: shine-lines 1.6s infinite linear; + } + .voila-skeleton-post .voila-skeleton-avatar + .voila-skeleton-line { + margin-top: 11px; + width: 100px; + } + .voila-skeleton-post .voila-skeleton-line ~ .voila-skeleton-line { + background-color: var(--jp-layout-color2); + } + + @keyframes shine-lines { + 0% { + background-position: -100px; + } + 40%, 100% { + background-position: 140px; + } + } + @keyframes shine-avatar { + 0% { + background-position: -32px; + } + 40%, 100% { + background-position: 208px; + } + } {% endmacro %} diff --git a/share/jupyter/voila/templates/base/voila_setup.macro.html.j2 b/share/jupyter/voila/templates/base/voila_setup.macro.html.j2 index 8da579fab..cc6afbdb1 100644 --- a/share/jupyter/voila/templates/base/voila_setup.macro.html.j2 +++ b/share/jupyter/voila/templates/base/voila_setup.macro.html.j2 @@ -19,7 +19,11 @@ spinner.style.display="flex"; } var el = document.getElementById("loading_text"); - innterText = text ?? `Executing ${cell_index} of ${cell_count}` + let defaultText = `Executing ${cell_index} of ${cell_count}` + if("{{ progressive_rendering | default("False", true) }}" === "True"){ + defaultText = `Reading ${cell_index} of ${cell_count}` + } + innterText = text ?? defaultText if(el){ el.innerHTML = innterText; } diff --git a/tests/app/conftest.py b/tests/app/conftest.py index 333d6c997..62a10738a 100644 --- a/tests/app/conftest.py +++ b/tests/app/conftest.py @@ -47,15 +47,31 @@ def preheat_mode(): return False +@pytest.fixture +def progressive_rendering_mode(): + """Fixture used to activate/deactivate progressive rendering mode. + Override this fixture in test file if you want to activate + progressive rendering mode. + """ + return False + + @pytest.fixture def preheat_config(preheat_mode): return f"--preheat_kernel={preheat_mode}" @pytest.fixture -def voila_app(voila_args, voila_config, preheat_config): +def progressive_rendering_config(progressive_rendering_mode): + return f"--progressive_rendering={progressive_rendering_mode}" + + +@pytest.fixture +def voila_app(voila_args, voila_config, preheat_config, progressive_rendering_config): voila_app = VoilaTest.instance() - voila_app.initialize([*voila_args, "--no-browser", preheat_config]) + voila_app.initialize( + [*voila_args, "--no-browser", preheat_config, progressive_rendering_config] + ) voila_config(voila_app) voila_app.start() yield voila_app diff --git a/tests/app/progressive_rendering_activation_test.py b/tests/app/progressive_rendering_activation_test.py new file mode 100644 index 000000000..7df48d211 --- /dev/null +++ b/tests/app/progressive_rendering_activation_test.py @@ -0,0 +1,37 @@ +import os +import voila.app +import pytest + + +@pytest.fixture +def progressive_rendering_mode(): + return True + + +@pytest.fixture +def preheat_mode(): + return True + + +@pytest.fixture +def voila_notebook(notebook_directory): + return os.path.join(notebook_directory, "preheat", "pre_heat.ipynb") + + +class VoilaTest(voila.app.Voila): + def listen(self): + pass + + +def test_voila(voila_args, voila_config, preheat_config, progressive_rendering_config): + with pytest.raises(Exception) as e_info: + voila_app = VoilaTest.instance() + voila_app.initialize( + [*voila_args, "--no-browser", preheat_config, progressive_rendering_config] + ) + voila_config(voila_app) + voila_app.start() + assert ( + str(e_info.value) + == "`preheat_kernel` and `progressive_rendering` are incompatible" + ) diff --git a/tests/app/progressive_rendering_test.py b/tests/app/progressive_rendering_test.py new file mode 100644 index 000000000..0208696d5 --- /dev/null +++ b/tests/app/progressive_rendering_test.py @@ -0,0 +1,39 @@ +import asyncio +import os +import time + +import pytest + + +@pytest.fixture +def progressive_rendering_mode(): + return True + + +@pytest.fixture +def voila_notebook(notebook_directory): + return os.path.join(notebook_directory, "preheat", "pre_heat.ipynb") + + +NOTEBOOK_EXECUTION_TIME = 2 +TIME_THRESHOLD = NOTEBOOK_EXECUTION_TIME + + +async def send_request(sc, url, wait=0): + await asyncio.sleep(wait) + real_time = time.time() + response = await sc.fetch(url) + real_time = time.time() - real_time + html_text = response.body.decode("utf-8") + return real_time, html_text + + +async def test_request(http_server_client, base_url): + """ + We send a request to server immediately, the returned HTML should + not contain the output. + """ + time, text = await send_request(sc=http_server_client, url=base_url) + assert '"progressiveRendering": true' in text + assert "hello world" not in text + assert time < NOTEBOOK_EXECUTION_TIME diff --git a/ui-tests/package.json b/ui-tests/package.json index 7f6aa41fc..c721d3826 100644 --- a/ui-tests/package.json +++ b/ui-tests/package.json @@ -5,15 +5,17 @@ "private": true, "scripts": { "start": "voila ../notebooks --no-browser --show_tracebacks True", + "start:progressive_rendering": "voila ../notebooks --no-browser --show_tracebacks True --progressive_rendering=true", "start:detached": "yarn run start&", "test": "npx playwright test", "test:debug": "PWDEBUG=1 playwright test", "test:report": "http-server ./playwright-report -a localhost -o", - "test:update": "npx playwright test --update-snapshots" + "test:update": "npx playwright test --update-snapshots", + "test:update:progressive_rendering": "PROGRESSIVE_RENDERING=true && npx playwright test --update-snapshots" }, "author": "Project Jupyter", "license": "BSD-3-Clause", "dependencies": { - "@jupyterlab/galata": "^5.0.0-beta.0" + "@jupyterlab/galata": "^5.2.5" } } diff --git a/ui-tests/playwright.config.js b/ui-tests/playwright.config.js index 70ad94266..59ea65364 100644 --- a/ui-tests/playwright.config.js +++ b/ui-tests/playwright.config.js @@ -18,7 +18,7 @@ module.exports = { // Try one retry as some tests are flaky retries: 1, expect: { - toMatchSnapshot: { + toHaveScreenshot: { maxDiffPixelRatio: 0.05 } } diff --git a/ui-tests/tests/voila.test.ts b/ui-tests/tests/voila.test.ts index 0a13c15a4..209b9606b 100644 --- a/ui-tests/tests/voila.test.ts +++ b/ui-tests/tests/voila.test.ts @@ -4,6 +4,7 @@ import { expect, test } from '@playwright/test'; import { addBenchmarkToTest } from './utils'; +const PROGRESSIVE_RENDERING = process.env.PROGRESSIVE_RENDERING === 'true'; test.describe('Voila performance Tests', () => { test.beforeEach(({ page }) => { page.setDefaultTimeout(120000); @@ -24,7 +25,8 @@ test.describe('Voila performance Tests', () => { browserName ); - expect(await page.screenshot()).toMatchSnapshot('voila-tree-classic.png'); + // await expect(page).toHaveScreenshot('voila-tree-classic.png'); + await expect(page).toHaveScreenshot('voila-tree-classic.png'); }); test('Render tree light theme', async ({ page, browserName }, testInfo) => { @@ -40,7 +42,7 @@ test.describe('Voila performance Tests', () => { browserName ); - expect(await page.screenshot()).toMatchSnapshot('voila-tree-light.png'); + await expect(page).toHaveScreenshot('voila-tree-light.png'); }); test('Render tree dark theme', async ({ page, browserName }, testInfo) => { @@ -56,7 +58,7 @@ test.describe('Voila performance Tests', () => { browserName ); - expect(await page.screenshot()).toMatchSnapshot('voila-tree-dark.png'); + await expect(page).toHaveScreenshot('voila-tree-dark.png'); }); test('Render tree miami theme', async ({ page, browserName }, testInfo) => { @@ -72,7 +74,7 @@ test.describe('Voila performance Tests', () => { browserName ); - expect(await page.screenshot()).toMatchSnapshot('voila-tree-miami.png'); + await expect(page).toHaveScreenshot('voila-tree-miami.png'); }); test('Render and benchmark basics.ipynb with classic template', async ({ @@ -90,9 +92,7 @@ test.describe('Voila performance Tests', () => { // wait for the final MathJax message to be hidden await page.$('text=Typesetting math: 100%'); await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); - expect(await page.screenshot()).toMatchSnapshot( - `${notebookName}-classic.png` - ); + await expect(page).toHaveScreenshot(`${notebookName}-classic.png`); }); test('Render and benchmark basics.ipynb', async ({ @@ -117,7 +117,7 @@ test.describe('Voila performance Tests', () => { // wait for the final MathJax message to be hidden await page.$('text=Typesetting math: 100%'); await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); - expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + await expect(page).toHaveScreenshot(`${notebookName}.png`); }); test('Render basics.ipynb with dark theme', async ({ @@ -135,7 +135,7 @@ test.describe('Voila performance Tests', () => { // wait for the final MathJax message to be hidden await page.$('text=Typesetting math: 100%'); await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); - expect(await page.screenshot()).toMatchSnapshot(`${notebookName}-dark.png`); + await expect(page).toHaveScreenshot(`${notebookName}-dark.png`); }); test('Render basics.ipynb with miami theme', async ({ @@ -155,30 +155,28 @@ test.describe('Voila performance Tests', () => { // wait for the final MathJax message to be hidden await page.$('text=Typesetting math: 100%'); await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); - expect(await page.screenshot()).toMatchSnapshot( - `${notebookName}-miami.png` - ); + await expect(page).toHaveScreenshot(`${notebookName}-miami.png`); }); test('Render 404 error', async ({ page }) => { await page.goto('/voila/render/unknown.ipynb'); await page.waitForSelector('.voila-error'); - expect(await page.screenshot()).toMatchSnapshot('404.png'); + await expect(page).toHaveScreenshot('404.png'); }); test('Render 404 error with classic template', async ({ page }) => { await page.goto('/voila/render/unknown.ipynb?template=classic'); await page.waitForSelector('.voila-error'); - expect(await page.screenshot()).toMatchSnapshot('404-classic.png'); + await expect(page).toHaveScreenshot('404-classic.png'); }); test('Render 404 error with dark theme', async ({ page }) => { await page.goto('/voila/render/unknown.ipynb?theme=dark'); await page.waitForSelector('.voila-error'); - expect(await page.screenshot()).toMatchSnapshot('404-dark.png'); + await expect(page).toHaveScreenshot('404-dark.png'); }); test('Render and benchmark bqplot.ipynb', async ({ @@ -191,7 +189,7 @@ test.describe('Voila performance Tests', () => { await page.waitForSelector('svg.svg-figure'); }; await addBenchmarkToTest(notebookName, testFunction, testInfo, browserName); - expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + await expect(page).toHaveScreenshot(`${notebookName}.png`); }); test('Render and benchmark dashboard.ipynb', async ({ @@ -222,7 +220,7 @@ test.describe('Voila performance Tests', () => { ); }; await addBenchmarkToTest(notebookName, testFunction, testInfo, browserName); - expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + await expect(page).toHaveScreenshot(`${notebookName}.png`); }); test('Render and benchmark interactive.ipynb', async ({ @@ -240,7 +238,7 @@ test.describe('Voila performance Tests', () => { await page.mouse.click(0, 0); }; await addBenchmarkToTest(notebookName, testFunction, testInfo, browserName); - expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + await expect(page).toHaveScreenshot(`${notebookName}.png`); }); test('Render and benchmark ipympl.ipynb', async ({ @@ -253,7 +251,7 @@ test.describe('Voila performance Tests', () => { await page.waitForSelector('div.jupyter-matplotlib-figure'); }; await addBenchmarkToTest(notebookName, testFunction, testInfo, browserName); - expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + await expect(page).toHaveScreenshot(`${notebookName}.png`); }); test('Render and benchmark mimerenderers.ipynb', async ({ @@ -268,7 +266,7 @@ test.describe('Voila performance Tests', () => { await page.waitForTimeout(2000); }; await addBenchmarkToTest(notebookName, testFunction, testInfo, browserName); - expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + await expect(page).toHaveScreenshot(`${notebookName}.png`); }); test('Render and benchmark bokeh.ipynb', async ({ @@ -281,7 +279,7 @@ test.describe('Voila performance Tests', () => { await page.waitForSelector('.bk-Canvas'); }; await addBenchmarkToTest(notebookName, testFunction, testInfo, browserName); - expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + await expect(page).toHaveScreenshot(`${notebookName}.png`); }); test('Benchmark the multiple widgets notebook', async ({ @@ -301,7 +299,7 @@ test.describe('Voila performance Tests', () => { testInfo, browserName ); - expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + await expect(page).toHaveScreenshot(`${notebookName}.png`); }); test('Render and benchmark query-strings.ipynb', async ({ @@ -311,6 +309,15 @@ test.describe('Voila performance Tests', () => { const notebookName = 'query-strings'; const testFunction = async () => { await page.goto(`/voila/render/${notebookName}.ipynb`); + if (PROGRESSIVE_RENDERING) { + await page.waitForSelector( + 'div.lm-Widget[data-mime-type="application/vnd.jupyter.stdout"]' + ); + } else { + await page.waitForSelector( + 'div.jp-OutputArea-output[data-mime-type="text/plain"]' + ); + } const userName = await page.$$( 'div.jp-RenderedText.jp-OutputArea-output > pre' ); @@ -318,13 +325,22 @@ test.describe('Voila performance Tests', () => { }; await addBenchmarkToTest(notebookName, testFunction, testInfo, browserName); await page.goto(`/voila/render/${notebookName}.ipynb?username=Riley`); + if (PROGRESSIVE_RENDERING) { + await page.waitForSelector( + 'div.lm-Widget[data-mime-type="application/vnd.jupyter.stdout"]' + ); + } else { + await page.waitForSelector( + 'div.jp-OutputArea-output[data-mime-type="text/plain"]' + ); + } const userName = await page.$$( 'div.jp-RenderedText.jp-OutputArea-output > pre' ); expect(await userName[1].innerHTML()).toContain('Hi Riley'); await page.$('text=Typesetting math: 100%'); await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); - expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + await expect(page).toHaveScreenshot(`${notebookName}.png`); }); test('Render and benchmark reveal.ipynb', async ({ @@ -337,13 +353,13 @@ test.describe('Voila performance Tests', () => { await page.waitForSelector('.slider-container'); }; await addBenchmarkToTest(notebookName, testFunction, testInfo, browserName); - expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + await expect(page).toHaveScreenshot(`${notebookName}.png`); }); test('Render yaml.ipynb', async ({ page, browserName }, testInfo) => { const notebookName = 'yaml'; await page.goto(`/voila/render/${notebookName}.ipynb`); await page.waitForSelector('span >> text=hey'); - expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + await expect(page).toHaveScreenshot(`${notebookName}.png`); }); }); diff --git a/ui-tests/tests/voila.test.ts-snapshots/404-dark-linux.png b/ui-tests/tests/voila.test.ts-snapshots/404-dark-linux.png index b81e5d451..5e5731036 100644 Binary files a/ui-tests/tests/voila.test.ts-snapshots/404-dark-linux.png and b/ui-tests/tests/voila.test.ts-snapshots/404-dark-linux.png differ diff --git a/ui-tests/tests/voila.test.ts-snapshots/404-linux.png b/ui-tests/tests/voila.test.ts-snapshots/404-linux.png index 7ac9b6054..40151eb1e 100644 Binary files a/ui-tests/tests/voila.test.ts-snapshots/404-linux.png and b/ui-tests/tests/voila.test.ts-snapshots/404-linux.png differ diff --git a/ui-tests/tests/voila.test.ts-snapshots/bokeh-linux.png b/ui-tests/tests/voila.test.ts-snapshots/bokeh-linux.png index e5fda33b9..3cdd25e63 100644 Binary files a/ui-tests/tests/voila.test.ts-snapshots/bokeh-linux.png and b/ui-tests/tests/voila.test.ts-snapshots/bokeh-linux.png differ diff --git a/ui-tests/tests/voila.test.ts-snapshots/gridspecLayout-linux.png b/ui-tests/tests/voila.test.ts-snapshots/gridspecLayout-linux.png index eb77fc2a5..d8950e4f5 100644 Binary files a/ui-tests/tests/voila.test.ts-snapshots/gridspecLayout-linux.png and b/ui-tests/tests/voila.test.ts-snapshots/gridspecLayout-linux.png differ diff --git a/ui-tests/tests/voila.test.ts-snapshots/ipympl-linux.png b/ui-tests/tests/voila.test.ts-snapshots/ipympl-linux.png index 5b93301dc..adfea8303 100644 Binary files a/ui-tests/tests/voila.test.ts-snapshots/ipympl-linux.png and b/ui-tests/tests/voila.test.ts-snapshots/ipympl-linux.png differ diff --git a/ui-tests/tests/voila.test.ts-snapshots/voila-tree-classic-linux.png b/ui-tests/tests/voila.test.ts-snapshots/voila-tree-classic-linux.png index 62320aaea..c7df7f70f 100644 Binary files a/ui-tests/tests/voila.test.ts-snapshots/voila-tree-classic-linux.png and b/ui-tests/tests/voila.test.ts-snapshots/voila-tree-classic-linux.png differ diff --git a/ui-tests/tests/voila.test.ts-snapshots/voila-tree-dark-linux.png b/ui-tests/tests/voila.test.ts-snapshots/voila-tree-dark-linux.png index 833bd75d1..158400b58 100644 Binary files a/ui-tests/tests/voila.test.ts-snapshots/voila-tree-dark-linux.png and b/ui-tests/tests/voila.test.ts-snapshots/voila-tree-dark-linux.png differ diff --git a/ui-tests/tests/voila.test.ts-snapshots/voila-tree-light-linux.png b/ui-tests/tests/voila.test.ts-snapshots/voila-tree-light-linux.png index c082fa0f2..0a95bca04 100644 Binary files a/ui-tests/tests/voila.test.ts-snapshots/voila-tree-light-linux.png and b/ui-tests/tests/voila.test.ts-snapshots/voila-tree-light-linux.png differ diff --git a/ui-tests/yarn.lock b/ui-tests/yarn.lock index 2fd663795..71841ce94 100644 --- a/ui-tests/yarn.lock +++ b/ui-tests/yarn.lock @@ -5,7 +5,7 @@ __metadata: version: 6 cacheKey: 8 -"@codemirror/autocomplete@npm:^6.0.0, @codemirror/autocomplete@npm:^6.3.2, @codemirror/autocomplete@npm:^6.5.1, @codemirror/autocomplete@npm:^6.7.1": +"@codemirror/autocomplete@npm:^6.0.0, @codemirror/autocomplete@npm:^6.3.2, @codemirror/autocomplete@npm:^6.7.1": version: 6.9.1 resolution: "@codemirror/autocomplete@npm:6.9.1" dependencies: @@ -22,15 +22,32 @@ __metadata: languageName: node linkType: hard -"@codemirror/commands@npm:^6.2.3": - version: 6.2.5 - resolution: "@codemirror/commands@npm:6.2.5" +"@codemirror/autocomplete@npm:^6.15.0": + version: 6.18.1 + resolution: "@codemirror/autocomplete@npm:6.18.1" dependencies: "@codemirror/language": ^6.0.0 - "@codemirror/state": ^6.2.0 + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.17.0 + "@lezer/common": ^1.0.0 + peerDependencies: + "@codemirror/language": ^6.0.0 + "@codemirror/state": ^6.0.0 "@codemirror/view": ^6.0.0 "@lezer/common": ^1.0.0 - checksum: 6d373bcfd4337160243e1493c8703a8e367e208811742331679a6410a3645de36ae8a5664e11790fec521137b45f34d703e9292932a98c4de10139510f3f29a3 + checksum: d488b3f76c330cc3776ef3c766347c178aa0773afd1791d2d8a7b72c4cd8a75c413bc47daba7ec29eedab954966b11ebb7c0085d12f814999ec192f060c884a9 + languageName: node + linkType: hard + +"@codemirror/commands@npm:^6.3.3": + version: 6.7.0 + resolution: "@codemirror/commands@npm:6.7.0" + dependencies: + "@codemirror/language": ^6.0.0 + "@codemirror/state": ^6.4.0 + "@codemirror/view": ^6.27.0 + "@lezer/common": ^1.1.0 + checksum: a71dccb1776bfe1456aaa2fe5ea36241bb99ada642217f4daf21b001ce439c40cdbc7fc1d6c3dcde587ab4c1a36aba3e28ff0c6e76d66abeb35fc9a3ce8fa1e3 languageName: node linkType: hard @@ -44,7 +61,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-css@npm:^6.0.0, @codemirror/lang-css@npm:^6.1.1": +"@codemirror/lang-css@npm:^6.0.0": version: 6.2.1 resolution: "@codemirror/lang-css@npm:6.2.1" dependencies: @@ -57,7 +74,20 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-html@npm:^6.0.0, @codemirror/lang-html@npm:^6.4.3": +"@codemirror/lang-css@npm:^6.2.1": + version: 6.3.0 + resolution: "@codemirror/lang-css@npm:6.3.0" + dependencies: + "@codemirror/autocomplete": ^6.0.0 + "@codemirror/language": ^6.0.0 + "@codemirror/state": ^6.0.0 + "@lezer/common": ^1.0.2 + "@lezer/css": ^1.1.7 + checksum: e98e89fa436f0a27c95323efbb6a1c43a52ca0b9253ab3c12af16f38cb93670d42f8a63cc566e2f6b0348af2cdfa1a6c03cf045af2d6cb253b27b2efdce9b2b2 + languageName: node + linkType: hard + +"@codemirror/lang-html@npm:^6.0.0": version: 6.4.6 resolution: "@codemirror/lang-html@npm:6.4.6" dependencies: @@ -74,6 +104,23 @@ __metadata: languageName: node linkType: hard +"@codemirror/lang-html@npm:^6.4.8": + version: 6.4.9 + resolution: "@codemirror/lang-html@npm:6.4.9" + dependencies: + "@codemirror/autocomplete": ^6.0.0 + "@codemirror/lang-css": ^6.0.0 + "@codemirror/lang-javascript": ^6.0.0 + "@codemirror/language": ^6.4.0 + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.17.0 + "@lezer/common": ^1.0.0 + "@lezer/css": ^1.1.0 + "@lezer/html": ^1.3.0 + checksum: ac8c3ceb0396f2e032752c5079bd950124dca708bc64e96fc147dc5fe7133e5cee0814fe951abdb953ec1d11fa540e4b30a712b5149d9a36016a197a28de45d7 + languageName: node + linkType: hard + "@codemirror/lang-java@npm:^6.0.1": version: 6.0.1 resolution: "@codemirror/lang-java@npm:6.0.1" @@ -84,7 +131,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-javascript@npm:^6.0.0, @codemirror/lang-javascript@npm:^6.1.7": +"@codemirror/lang-javascript@npm:^6.0.0": version: 6.2.1 resolution: "@codemirror/lang-javascript@npm:6.2.1" dependencies: @@ -99,6 +146,21 @@ __metadata: languageName: node linkType: hard +"@codemirror/lang-javascript@npm:^6.2.2": + version: 6.2.2 + resolution: "@codemirror/lang-javascript@npm:6.2.2" + dependencies: + "@codemirror/autocomplete": ^6.0.0 + "@codemirror/language": ^6.6.0 + "@codemirror/lint": ^6.0.0 + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.17.0 + "@lezer/common": ^1.0.0 + "@lezer/javascript": ^1.0.0 + checksum: 66379942a8347dff2bd76d10ed7cf313bca83872f8336fdd3e14accfef23e7b690cd913c9d11a3854fba2b32299da07fc3275995327642c9ee43c2a8e538c19d + languageName: node + linkType: hard + "@codemirror/lang-json@npm:^6.0.1": version: 6.0.1 resolution: "@codemirror/lang-json@npm:6.0.1" @@ -109,18 +171,18 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-markdown@npm:^6.1.1": - version: 6.2.1 - resolution: "@codemirror/lang-markdown@npm:6.2.1" +"@codemirror/lang-markdown@npm:^6.2.4": + version: 6.3.0 + resolution: "@codemirror/lang-markdown@npm:6.3.0" dependencies: "@codemirror/autocomplete": ^6.7.1 "@codemirror/lang-html": ^6.0.0 "@codemirror/language": ^6.3.0 "@codemirror/state": ^6.0.0 "@codemirror/view": ^6.0.0 - "@lezer/common": ^1.0.0 + "@lezer/common": ^1.2.1 "@lezer/markdown": ^1.0.0 - checksum: ef3bdfd01e418efc7f7fdf0baa2e8e91875b37f870fcad98f846954763c7cc71bac95736591cd6c52b39cc380261d76ae7b37ca97ef1641c4c266476748046d3 + checksum: 8f3a231a0008d6b6834e58d44eac3c383cf472083ef2a68de66f9b4209bb4de1fb14f167e6e04236dbf58444299bce74715df372b1e97c9b4f207cc65daf6285 languageName: node linkType: hard @@ -137,14 +199,16 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-python@npm:^6.1.3": - version: 6.1.3 - resolution: "@codemirror/lang-python@npm:6.1.3" +"@codemirror/lang-python@npm:^6.1.4": + version: 6.1.6 + resolution: "@codemirror/lang-python@npm:6.1.6" dependencies: "@codemirror/autocomplete": ^6.3.2 "@codemirror/language": ^6.8.0 + "@codemirror/state": ^6.0.0 + "@lezer/common": ^1.2.1 "@lezer/python": ^1.1.4 - checksum: 65a0276a4503e4e3b70dd28d1c93ef472632b6d2c4bf3ae92d305d14ee8cf60b0bbbf62d5ceb51294de9598d9e2d42eafcde26f317ee7b90d0a11dfa863c1d1a + checksum: eb1faabd332bb95d0f3e227eb19ac5a31140cf238905bbe73e061040999f5680a012f9145fb3688bc2fcbb1908c957511edc8eeb8a9aa88d27d4fa55ad451e95 languageName: node linkType: hard @@ -158,40 +222,43 @@ __metadata: languageName: node linkType: hard -"@codemirror/lang-sql@npm:^6.4.1": - version: 6.5.4 - resolution: "@codemirror/lang-sql@npm:6.5.4" +"@codemirror/lang-sql@npm:^6.6.1": + version: 6.8.0 + resolution: "@codemirror/lang-sql@npm:6.8.0" dependencies: "@codemirror/autocomplete": ^6.0.0 "@codemirror/language": ^6.0.0 "@codemirror/state": ^6.0.0 + "@lezer/common": ^1.2.0 "@lezer/highlight": ^1.0.0 "@lezer/lr": ^1.0.0 - checksum: face21b0231ac5a7981949b5bf6a99ed092d0d6f7eb83f35dcd31d56ecf07dafa19d21623e0bad36cec7a12e3149df7b45c3588aeee31eae41e9b05942c4fdd7 + checksum: 1b5a3c8129b09f24039d8c0906fc4cb8d0f706a424a1d56721057bd1e647797c2b1240bb53eed9bf2bac5806a4e0363e555a3963f04c478efa05829890c537f7 languageName: node linkType: hard -"@codemirror/lang-wast@npm:^6.0.1": - version: 6.0.1 - resolution: "@codemirror/lang-wast@npm:6.0.1" +"@codemirror/lang-wast@npm:^6.0.2": + version: 6.0.2 + resolution: "@codemirror/lang-wast@npm:6.0.2" dependencies: "@codemirror/language": ^6.0.0 + "@lezer/common": ^1.2.0 "@lezer/highlight": ^1.0.0 "@lezer/lr": ^1.0.0 - checksum: 600d98d3ea6a4e99292244ed707e39a2abd9f3abf62cfeff5c819a0cc0c7e86b8c5b91e91c1b7ea21233d9ea09c41abe61d8a40b2547bb5db74239c6df857934 + checksum: 72119d4a7d726c54167aa227c982ae9fa785c8ad97a158d8350ae95eecfbd8028a803eef939f7e6c5c6e626fcecda1dc37e9dffc6d5d6ec105f686aeda6b2c24 languageName: node linkType: hard -"@codemirror/lang-xml@npm:^6.0.2": - version: 6.0.2 - resolution: "@codemirror/lang-xml@npm:6.0.2" +"@codemirror/lang-xml@npm:^6.1.0": + version: 6.1.0 + resolution: "@codemirror/lang-xml@npm:6.1.0" dependencies: "@codemirror/autocomplete": ^6.0.0 "@codemirror/language": ^6.4.0 "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.0.0 "@lezer/common": ^1.0.0 "@lezer/xml": ^1.0.0 - checksum: e156ecafaa87e9b6ef4ab6812ccd00d8f3c6cb81f232837636b36336d80513b61936dfee6f4f6800574f236208b61e95a2abcb997cdcd7366585a6b796e0e13b + checksum: 3a1b7af07b29ad7e53b77bf584245580b613bc92256059f175f2b1d7c28c4e39b75654fe169b9a8a330a60164b53ff5254bdb5b8ee8c6e6766427ee115c4e229 languageName: node linkType: hard @@ -209,12 +276,26 @@ __metadata: languageName: node linkType: hard -"@codemirror/legacy-modes@npm:^6.3.2": - version: 6.3.3 - resolution: "@codemirror/legacy-modes@npm:6.3.3" +"@codemirror/language@npm:^6.10.1": + version: 6.10.3 + resolution: "@codemirror/language@npm:6.10.3" + dependencies: + "@codemirror/state": ^6.0.0 + "@codemirror/view": ^6.23.0 + "@lezer/common": ^1.1.0 + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + style-mod: ^4.0.0 + checksum: 53fb72299500f63706f78c888d6b5fd81043ea11ea2fa4c72c13c6d4794bb6f4ec29450208c56b4f40e839984b3dc73505262803fa61416baf588da389a7c577 + languageName: node + linkType: hard + +"@codemirror/legacy-modes@npm:^6.3.3": + version: 6.4.1 + resolution: "@codemirror/legacy-modes@npm:6.4.1" dependencies: "@codemirror/language": ^6.0.0 - checksum: 3cd32b0f011b0a193e0948e5901b625f38aa6d9a8b24344531d6e142eb6fbb3e6cb5969429102044f3d04fbe53c4deaebd9f659c05067a0b18d17766290c9e05 + checksum: 3947842c5f06db49a152bf7dd03a626806c5f2e80abfa9840927396fef08ff8bc2dfb228e7231bd8d0b7bb1a84b7ef582df8361b2bef77419e0e04bf43cc6b7d languageName: node linkType: hard @@ -229,25 +310,32 @@ __metadata: languageName: node linkType: hard -"@codemirror/search@npm:^6.3.0": - version: 6.5.4 - resolution: "@codemirror/search@npm:6.5.4" +"@codemirror/search@npm:^6.5.6": + version: 6.5.6 + resolution: "@codemirror/search@npm:6.5.6" dependencies: "@codemirror/state": ^6.0.0 "@codemirror/view": ^6.0.0 crelt: ^1.0.5 - checksum: 32a68e40486730949ee79f54b9fcc6c744559aef188d3c5bf82881f62e5fc9468fa21cf227507638160043c797eb054205802a649cf4a2350928fc161d5aac40 + checksum: 19dc88d09fc750563347001e83c6194bbb2a25c874bd919d2d81809e1f98d6330222ddbd284aa9758a09eeb41fd153ec7c2cf810b2ee51452c25963d7f5833d5 languageName: node linkType: hard -"@codemirror/state@npm:^6.0.0, @codemirror/state@npm:^6.1.4, @codemirror/state@npm:^6.2.0": +"@codemirror/state@npm:^6.0.0, @codemirror/state@npm:^6.1.4": version: 6.2.1 resolution: "@codemirror/state@npm:6.2.1" checksum: d12a321d0471b264b9d3259042bff913a8b939e8d28d408ff452004538a71ca9d5329df3f8a1d8a9183f5b42a7ef5b200737bcab1065714f5ae8e0a5ba9d59d3 languageName: node linkType: hard -"@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.9.6": +"@codemirror/state@npm:^6.4.0, @codemirror/state@npm:^6.4.1": + version: 6.4.1 + resolution: "@codemirror/state@npm:6.4.1" + checksum: b81b55574091349eed4d32fc0eadb0c9688f1f7c98b681318f59138ee0f527cb4c4a97831b70547c0640f02f3127647838ae6730782de4a3dd2cc58836125d01 + languageName: node + linkType: hard + +"@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0": version: 6.20.0 resolution: "@codemirror/view@npm:6.20.0" dependencies: @@ -258,6 +346,17 @@ __metadata: languageName: node linkType: hard +"@codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.26.0, @codemirror/view@npm:^6.27.0": + version: 6.34.1 + resolution: "@codemirror/view@npm:6.34.1" + dependencies: + "@codemirror/state": ^6.4.0 + style-mod: ^4.1.0 + w3c-keyname: ^2.2.4 + checksum: 5c7bf199f0b45a3cc192f08c2ac89e5ab972f313cb4f2c979edf6e05b27bccd60c6cb42d5dacb6813ef3a928d75476eb0a00ffdeffd7431c8e9f44bab4f6e12e + languageName: node + linkType: hard + "@fortawesome/fontawesome-free@npm:^5.12.0": version: 5.15.4 resolution: "@fortawesome/fontawesome-free@npm:5.15.4" @@ -279,9 +378,32 @@ __metadata: languageName: node linkType: hard -"@jupyter/ydoc@npm:^1.0.2": - version: 1.1.0 - resolution: "@jupyter/ydoc@npm:1.1.0" +"@jupyter/react-components@npm:^0.15.3": + version: 0.15.3 + resolution: "@jupyter/react-components@npm:0.15.3" + dependencies: + "@jupyter/web-components": ^0.15.3 + "@microsoft/fast-react-wrapper": ^0.3.22 + react: ">=17.0.0 <19.0.0" + checksum: 1a6b256314259c6465c4b6d958575710536b82234a7bf0fba3e889a07e1f19ff8ab321450be354359876f92c45dbcc9d21a840237ff4a619806d9de696f55496 + languageName: node + linkType: hard + +"@jupyter/web-components@npm:^0.15.3": + version: 0.15.3 + resolution: "@jupyter/web-components@npm:0.15.3" + dependencies: + "@microsoft/fast-colors": ^5.3.1 + "@microsoft/fast-element": ^1.12.0 + "@microsoft/fast-foundation": ^2.49.4 + "@microsoft/fast-web-utilities": ^5.4.1 + checksum: a0980af934157bfdbdb6cc169c0816c1b2e57602d524c56bdcef746a4c25dfeb8f505150d83207c8695ed89b5486cf53d35a3382584d25ef64db666e4e16e45b + languageName: node + linkType: hard + +"@jupyter/ydoc@npm:^2.0.1": + version: 2.1.2 + resolution: "@jupyter/ydoc@npm:2.1.2" dependencies: "@jupyterlab/nbformat": ^3.0.0 || ^4.0.0-alpha.21 || ^4.0.0 "@lumino/coreutils": ^1.11.0 || ^2.0.0 @@ -289,212 +411,211 @@ __metadata: "@lumino/signaling": ^1.10.0 || ^2.0.0 y-protocols: ^1.0.5 yjs: ^13.5.40 - checksum: 75530fa80ee157763d20c53251d3f28a8f19396145a7b59b003abd0ba4b040f977e259aaf61e220a2f74340902a0620f7a71f9ed09a165276e0178f4821fc821 + checksum: 4e4840120d5c93fffc62668c3867c25ef9d72f70c7cf2beefe2caaab47c4d3d08b1b2092806a9ae2a24852256584d3e2aa0b066295c2696147cd41e10f14e5b0 languageName: node linkType: hard -"@jupyterlab/application@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/application@npm:4.0.6" +"@jupyterlab/application@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/application@npm:4.2.5" dependencies: "@fortawesome/fontawesome-free": ^5.12.0 - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/docregistry": ^4.0.6 - "@jupyterlab/rendermime": ^4.0.6 - "@jupyterlab/rendermime-interfaces": ^3.8.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/statedb": ^4.0.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/docregistry": ^4.2.5 + "@jupyterlab/rendermime": ^4.2.5 + "@jupyterlab/rendermime-interfaces": ^3.10.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/statedb": ^4.2.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 "@lumino/algorithm": ^2.0.1 - "@lumino/application": ^2.2.1 - "@lumino/commands": ^2.1.3 + "@lumino/application": ^2.3.1 + "@lumino/commands": ^2.3.0 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/polling": ^2.1.2 "@lumino/properties": ^2.0.1 "@lumino/signaling": ^2.1.2 - "@lumino/widgets": ^2.3.0 - checksum: 1212b71d3717bc02543b3eee74e69be799634421bd9b291b7adf07ba27bf6f9c7db860c423c824eaced9c2524db2f6b58de2c58e7edd5de2f0d7fabbb2c94b8c + "@lumino/widgets": ^2.3.2 + checksum: c424ea191ef4da45eeae44e366e2b3cb23426cc72c0321226c83000c02b91fa7c4bc54978aa0b0e9416211cce9c17469204fc2b133cb2bec3d8896a0b2f75ce1 languageName: node linkType: hard -"@jupyterlab/apputils@npm:^4.1.6": - version: 4.1.6 - resolution: "@jupyterlab/apputils@npm:4.1.6" +"@jupyterlab/apputils@npm:^4.3.5": + version: 4.3.5 + resolution: "@jupyterlab/apputils@npm:4.3.5" dependencies: - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/observables": ^5.0.6 - "@jupyterlab/rendermime-interfaces": ^3.8.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/settingregistry": ^4.0.6 - "@jupyterlab/statedb": ^4.0.6 - "@jupyterlab/statusbar": ^4.0.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/observables": ^5.2.5 + "@jupyterlab/rendermime-interfaces": ^3.10.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/settingregistry": ^4.2.5 + "@jupyterlab/statedb": ^4.2.5 + "@jupyterlab/statusbar": ^4.2.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 "@lumino/algorithm": ^2.0.1 - "@lumino/commands": ^2.1.3 + "@lumino/commands": ^2.3.0 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/domutils": ^2.0.1 "@lumino/messaging": ^2.0.1 "@lumino/signaling": ^2.1.2 "@lumino/virtualdom": ^2.0.1 - "@lumino/widgets": ^2.3.0 + "@lumino/widgets": ^2.3.2 "@types/react": ^18.0.26 react: ^18.2.0 - sanitize-html: ~2.7.3 - checksum: 40fb43f5a6464c665f1b941d164f3366ab8ea906fed72894ccf026ebeebf0734409edb6546a151ac267cbd4f945e23474251aed644f7f0f0dbf2548b9230ae22 + sanitize-html: ~2.12.1 + checksum: a2307657bfab1aff687eccfdb7a2c378a40989beea618ad6e5a811dbd250753588ea704a11250ddef42a551c8360717c1fe4c8827c5e2c3bfff1e84fc7fdc836 languageName: node linkType: hard -"@jupyterlab/attachments@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/attachments@npm:4.0.6" +"@jupyterlab/attachments@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/attachments@npm:4.2.5" dependencies: - "@jupyterlab/nbformat": ^4.0.6 - "@jupyterlab/observables": ^5.0.6 - "@jupyterlab/rendermime": ^4.0.6 - "@jupyterlab/rendermime-interfaces": ^3.8.6 + "@jupyterlab/nbformat": ^4.2.5 + "@jupyterlab/observables": ^5.2.5 + "@jupyterlab/rendermime": ^4.2.5 + "@jupyterlab/rendermime-interfaces": ^3.10.5 "@lumino/disposable": ^2.1.2 "@lumino/signaling": ^2.1.2 - checksum: b7efd01d6a0b7f28a4ee8114723cdc33267f1c1f84763b71a04e783024a87f639e442be74eda5afecff7eea5750d094f4da8a46ee711ec1298645eb92252c7ee - languageName: node - linkType: hard - -"@jupyterlab/cells@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/cells@npm:4.0.6" - dependencies: - "@codemirror/state": ^6.2.0 - "@codemirror/view": ^6.9.6 - "@jupyter/ydoc": ^1.0.2 - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/attachments": ^4.0.6 - "@jupyterlab/codeeditor": ^4.0.6 - "@jupyterlab/codemirror": ^4.0.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/documentsearch": ^4.0.6 - "@jupyterlab/filebrowser": ^4.0.6 - "@jupyterlab/nbformat": ^4.0.6 - "@jupyterlab/observables": ^5.0.6 - "@jupyterlab/outputarea": ^4.0.6 - "@jupyterlab/rendermime": ^4.0.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/toc": ^6.0.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 + checksum: f49fc50f9889de9c7da88e004ae4dd562460da050ff373c946ec54863fcf293dacb5e15de57dbfb0b01141648989a873188a00b898cbb491bbd6c50140a0392c + languageName: node + linkType: hard + +"@jupyterlab/cells@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/cells@npm:4.2.5" + dependencies: + "@codemirror/state": ^6.4.1 + "@codemirror/view": ^6.26.0 + "@jupyter/ydoc": ^2.0.1 + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/attachments": ^4.2.5 + "@jupyterlab/codeeditor": ^4.2.5 + "@jupyterlab/codemirror": ^4.2.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/documentsearch": ^4.2.5 + "@jupyterlab/filebrowser": ^4.2.5 + "@jupyterlab/nbformat": ^4.2.5 + "@jupyterlab/observables": ^5.2.5 + "@jupyterlab/outputarea": ^4.2.5 + "@jupyterlab/rendermime": ^4.2.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/toc": ^6.2.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/domutils": ^2.0.1 - "@lumino/dragdrop": ^2.1.3 + "@lumino/dragdrop": ^2.1.4 "@lumino/messaging": ^2.0.1 "@lumino/polling": ^2.1.2 "@lumino/signaling": ^2.1.2 "@lumino/virtualdom": ^2.0.1 - "@lumino/widgets": ^2.3.0 + "@lumino/widgets": ^2.3.2 react: ^18.2.0 - checksum: b0bb039c05ee0d83f40b5ccb0efa27d90723808c50821f8b8abedc8770387916bbc46d8a886102bf353b58e434cf33849981f782f1dbb3658835cce219940f33 + checksum: 6b2f84c0036dbc8808eb6f5057d07dae00d8000fac2f91568ca3f9b6abe30e6724d1be7ce53f085f6e8a93850817316f4e9e2c0e4fb81c3b29e104908a570d3b languageName: node linkType: hard -"@jupyterlab/codeeditor@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/codeeditor@npm:4.0.6" - dependencies: - "@codemirror/state": ^6.2.0 - "@jupyter/ydoc": ^1.0.2 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/nbformat": ^4.0.6 - "@jupyterlab/observables": ^5.0.6 - "@jupyterlab/statusbar": ^4.0.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 +"@jupyterlab/codeeditor@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/codeeditor@npm:4.2.5" + dependencies: + "@codemirror/state": ^6.4.1 + "@jupyter/ydoc": ^2.0.1 + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/nbformat": ^4.2.5 + "@jupyterlab/observables": ^5.2.5 + "@jupyterlab/statusbar": ^4.2.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 - "@lumino/dragdrop": ^2.1.3 + "@lumino/dragdrop": ^2.1.4 "@lumino/messaging": ^2.0.1 "@lumino/signaling": ^2.1.2 - "@lumino/widgets": ^2.3.0 + "@lumino/widgets": ^2.3.2 react: ^18.2.0 - checksum: 831d330273280781dbdc223325d575ac373c0db17fab208f327bce4e1c2286c62f8264d1d612da1a762bc006cd81dfb0eb5108dd3bd8f8298f9be8ecac98b2ca + checksum: 0b6f3f7a1fe02d2bb0b07571e03c6be645d58e182f3e1fcc5452e79dee8eab2097e13544eb461ff2bed72337bd335c539b8cb7cfe5f7bfd840163cc26d200c58 languageName: node linkType: hard -"@jupyterlab/codemirror@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/codemirror@npm:4.0.6" +"@jupyterlab/codemirror@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/codemirror@npm:4.2.5" dependencies: - "@codemirror/autocomplete": ^6.5.1 - "@codemirror/commands": ^6.2.3 + "@codemirror/autocomplete": ^6.15.0 + "@codemirror/commands": ^6.3.3 "@codemirror/lang-cpp": ^6.0.2 - "@codemirror/lang-css": ^6.1.1 - "@codemirror/lang-html": ^6.4.3 + "@codemirror/lang-css": ^6.2.1 + "@codemirror/lang-html": ^6.4.8 "@codemirror/lang-java": ^6.0.1 - "@codemirror/lang-javascript": ^6.1.7 + "@codemirror/lang-javascript": ^6.2.2 "@codemirror/lang-json": ^6.0.1 - "@codemirror/lang-markdown": ^6.1.1 + "@codemirror/lang-markdown": ^6.2.4 "@codemirror/lang-php": ^6.0.1 - "@codemirror/lang-python": ^6.1.3 + "@codemirror/lang-python": ^6.1.4 "@codemirror/lang-rust": ^6.0.1 - "@codemirror/lang-sql": ^6.4.1 - "@codemirror/lang-wast": ^6.0.1 - "@codemirror/lang-xml": ^6.0.2 - "@codemirror/language": ^6.6.0 - "@codemirror/legacy-modes": ^6.3.2 - "@codemirror/search": ^6.3.0 - "@codemirror/state": ^6.2.0 - "@codemirror/view": ^6.9.6 - "@jupyter/ydoc": ^1.0.2 - "@jupyterlab/codeeditor": ^4.0.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/documentsearch": ^4.0.6 - "@jupyterlab/nbformat": ^4.0.6 - "@jupyterlab/translation": ^4.0.6 - "@lezer/common": ^1.0.2 - "@lezer/generator": ^1.2.2 - "@lezer/highlight": ^1.1.4 - "@lezer/markdown": ^1.0.2 + "@codemirror/lang-sql": ^6.6.1 + "@codemirror/lang-wast": ^6.0.2 + "@codemirror/lang-xml": ^6.1.0 + "@codemirror/language": ^6.10.1 + "@codemirror/legacy-modes": ^6.3.3 + "@codemirror/search": ^6.5.6 + "@codemirror/state": ^6.4.1 + "@codemirror/view": ^6.26.0 + "@jupyter/ydoc": ^2.0.1 + "@jupyterlab/codeeditor": ^4.2.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/documentsearch": ^4.2.5 + "@jupyterlab/nbformat": ^4.2.5 + "@jupyterlab/translation": ^4.2.5 + "@lezer/common": ^1.2.1 + "@lezer/generator": ^1.7.0 + "@lezer/highlight": ^1.2.0 + "@lezer/markdown": ^1.2.0 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/signaling": ^2.1.2 yjs: ^13.5.40 - checksum: fdd0c4655e8597b1beb985b84b82dcfe29b4c8d0ae7e7ff3b0aecdbc94bc2b94ec0b617b3d59d7739e271e76433b2e624672d94ec64cfa4efc628cab92418175 + checksum: 6c612c861dbc6a6acdc1887e7dd25d5029d1a40cda20735fb3f009867e27aacd0e2d05e9b01c71b3a6f9a35218d881159954e679806b118df24d90565b9c16c4 languageName: node linkType: hard -"@jupyterlab/console@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/console@npm:4.0.6" - dependencies: - "@codemirror/state": ^6.2.0 - "@codemirror/view": ^6.9.6 - "@jupyter/ydoc": ^1.0.2 - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/cells": ^4.0.6 - "@jupyterlab/codeeditor": ^4.0.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/nbformat": ^4.0.6 - "@jupyterlab/observables": ^5.0.6 - "@jupyterlab/rendermime": ^4.0.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 +"@jupyterlab/console@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/console@npm:4.2.5" + dependencies: + "@jupyter/ydoc": ^2.0.1 + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/cells": ^4.2.5 + "@jupyterlab/codeeditor": ^4.2.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/nbformat": ^4.2.5 + "@jupyterlab/observables": ^5.2.5 + "@jupyterlab/rendermime": ^4.2.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 - "@lumino/dragdrop": ^2.1.3 + "@lumino/dragdrop": ^2.1.4 "@lumino/messaging": ^2.0.1 "@lumino/signaling": ^2.1.2 - "@lumino/widgets": ^2.3.0 - checksum: 2d7213c83dc088b51976378b88c88f4cfd05d9cd14aa476cb8130ffbfedd7ac8af25a2e9a34b60bc8ec50ea973f33ed7689845d894d00c8cd095b3fec8fb5fa2 + "@lumino/widgets": ^2.3.2 + checksum: 4f716339479f240fdebd74d05e7c90ed5b3c540861cce3c7bcbb3d0680d9581db5b8bfb63a7bb62fa45c7b054b6ef948632b6e877a7c058bb1bdbae0d966efe1 languageName: node linkType: hard -"@jupyterlab/coreutils@npm:^6.0.6": - version: 6.0.6 - resolution: "@jupyterlab/coreutils@npm:6.0.6" +"@jupyterlab/coreutils@npm:^6.2.5": + version: 6.2.5 + resolution: "@jupyterlab/coreutils@npm:6.2.5" dependencies: "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 @@ -502,181 +623,187 @@ __metadata: minimist: ~1.2.0 path-browserify: ^1.0.0 url-parse: ~1.5.4 - checksum: cf3cfbc7c48cae20549f5514a949b253c2f9d67c79db107ab0a81c2b7a9c08e28f9fd264e3d944a05a8cb1bbb9676c6b4163b75c28788d1cb3a3cc523d44d802 - languageName: node - linkType: hard - -"@jupyterlab/debugger@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/debugger@npm:4.0.6" - dependencies: - "@codemirror/state": ^6.2.0 - "@codemirror/view": ^6.9.6 - "@jupyter/ydoc": ^1.0.2 - "@jupyterlab/application": ^4.0.6 - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/cells": ^4.0.6 - "@jupyterlab/codeeditor": ^4.0.6 - "@jupyterlab/codemirror": ^4.0.6 - "@jupyterlab/console": ^4.0.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/docregistry": ^4.0.6 - "@jupyterlab/fileeditor": ^4.0.6 - "@jupyterlab/notebook": ^4.0.6 - "@jupyterlab/observables": ^5.0.6 - "@jupyterlab/rendermime": ^4.0.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 + checksum: 3b6a10b117ee82a437b6535801fe012bb5af7769a850be95c8ffa666ee2d6f7c29041ba546c9cfca0ab32b65f91c661570541f4f785f48af9022d08407c0a3e5 + languageName: node + linkType: hard + +"@jupyterlab/debugger@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/debugger@npm:4.2.5" + dependencies: + "@codemirror/state": ^6.4.1 + "@codemirror/view": ^6.26.0 + "@jupyter/react-components": ^0.15.3 + "@jupyter/ydoc": ^2.0.1 + "@jupyterlab/application": ^4.2.5 + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/cells": ^4.2.5 + "@jupyterlab/codeeditor": ^4.2.5 + "@jupyterlab/codemirror": ^4.2.5 + "@jupyterlab/console": ^4.2.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/docregistry": ^4.2.5 + "@jupyterlab/fileeditor": ^4.2.5 + "@jupyterlab/notebook": ^4.2.5 + "@jupyterlab/observables": ^5.2.5 + "@jupyterlab/rendermime": ^4.2.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 "@lumino/algorithm": ^2.0.1 - "@lumino/commands": ^2.1.3 + "@lumino/commands": ^2.3.0 "@lumino/coreutils": ^2.1.2 - "@lumino/datagrid": ^2.2.0 + "@lumino/datagrid": ^2.3.1 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/polling": ^2.1.2 "@lumino/signaling": ^2.1.2 - "@lumino/widgets": ^2.3.0 + "@lumino/widgets": ^2.3.2 "@vscode/debugprotocol": ^1.51.0 react: ^18.2.0 - checksum: 7e686d218202fa8ec3511c789b77a8a6a53fe7a3b791023dd2b4a3c9a4ea943e0a59a675153c2807a29fe80f82e3ca050523eec0fa03bcb567204f408bdfdc3f + checksum: 6f5d6ae6991cea76b39d93991cd4c02308fc84a741068e176d9d72368ebf5b504f118f714c7555de13b4760f6df4b5ad9b03a8256793b2acdf98c5b30ebca362 languageName: node linkType: hard -"@jupyterlab/docmanager@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/docmanager@npm:4.0.6" - dependencies: - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/docregistry": ^4.0.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/statusbar": ^4.0.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 +"@jupyterlab/docmanager@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/docmanager@npm:4.2.5" + dependencies: + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/docregistry": ^4.2.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/statedb": ^4.2.5 + "@jupyterlab/statusbar": ^4.2.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 "@lumino/properties": ^2.0.1 "@lumino/signaling": ^2.1.2 - "@lumino/widgets": ^2.3.0 + "@lumino/widgets": ^2.3.2 react: ^18.2.0 - checksum: 25d3f694ae8664ca6c54bfcd36d8913caba9455fea68ed3df23963ce9723254c1f2c38fb6a93e267187f095392507d40cd2a4181c30173306c1c0b962e001b93 + checksum: 0fa3fcbdccab2dfc5d9075dbd7fdf9a15c912843a3ed18c83248fd867d6f4c493c40f88964a406396fc335f60dc71e99df7465f38a94e7210bbdd209ae752d0c languageName: node linkType: hard -"@jupyterlab/docregistry@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/docregistry@npm:4.0.6" - dependencies: - "@jupyter/ydoc": ^1.0.2 - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/codeeditor": ^4.0.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/observables": ^5.0.6 - "@jupyterlab/rendermime": ^4.0.6 - "@jupyterlab/rendermime-interfaces": ^3.8.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 +"@jupyterlab/docregistry@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/docregistry@npm:4.2.5" + dependencies: + "@jupyter/ydoc": ^2.0.1 + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/codeeditor": ^4.2.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/observables": ^5.2.5 + "@jupyterlab/rendermime": ^4.2.5 + "@jupyterlab/rendermime-interfaces": ^3.10.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/properties": ^2.0.1 "@lumino/signaling": ^2.1.2 - "@lumino/widgets": ^2.3.0 - checksum: 57de3751ea04037f27596ffe782392fb4840f3fba1776a64bb7b0dc5936a3cee4de115b2133147cda23a697d3da7802daaec0effae10be329d6c774f102091ee + "@lumino/widgets": ^2.3.2 + react: ^18.2.0 + checksum: 7e93987f4c6cd82058231c10c69a66aba38913c73f425a01c565a45e330e20dcb6f80489d3bd35d78b5b36a7798ed50485635fae3317b5c87d75ce30a144827e languageName: node linkType: hard -"@jupyterlab/documentsearch@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/documentsearch@npm:4.0.6" +"@jupyterlab/documentsearch@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/documentsearch@npm:4.2.5" dependencies: - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 + "@lumino/commands": ^2.3.0 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/polling": ^2.1.2 "@lumino/signaling": ^2.1.2 - "@lumino/widgets": ^2.3.0 + "@lumino/widgets": ^2.3.2 react: ^18.2.0 - checksum: e6cf3533cdae29ca2f81147b26b056718df16998f6d89274d90cffcc70eab705634a7e36d353e9dcaea38640b490315b4ae683e937755547f42b8a5623bc914a + checksum: 9f9726b4e779f04c29f5e3dea56c410152607f9c00f60eb1ece03cdcea4bf84d0ab0cfe6500496d9d8da33dbac187df5eda5eafbd840d173953de9b2173e9706 languageName: node linkType: hard -"@jupyterlab/filebrowser@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/filebrowser@npm:4.0.6" - dependencies: - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/docmanager": ^4.0.6 - "@jupyterlab/docregistry": ^4.0.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/statedb": ^4.0.6 - "@jupyterlab/statusbar": ^4.0.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 +"@jupyterlab/filebrowser@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/filebrowser@npm:4.2.5" + dependencies: + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/docmanager": ^4.2.5 + "@jupyterlab/docregistry": ^4.2.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/statedb": ^4.2.5 + "@jupyterlab/statusbar": ^4.2.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/domutils": ^2.0.1 - "@lumino/dragdrop": ^2.1.3 + "@lumino/dragdrop": ^2.1.4 "@lumino/messaging": ^2.0.1 "@lumino/polling": ^2.1.2 "@lumino/signaling": ^2.1.2 "@lumino/virtualdom": ^2.0.1 - "@lumino/widgets": ^2.3.0 + "@lumino/widgets": ^2.3.2 react: ^18.2.0 - checksum: abe7eca4072a9c3d1f7a756840d0ad209403928b958fe09dfd81fbb693cb18c91c64027157babe1e7353a556b11c070716326b16ee2eb629089399906a3467be - languageName: node - linkType: hard - -"@jupyterlab/fileeditor@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/fileeditor@npm:4.0.6" - dependencies: - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/codeeditor": ^4.0.6 - "@jupyterlab/codemirror": ^4.0.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/docregistry": ^4.0.6 - "@jupyterlab/documentsearch": ^4.0.6 - "@jupyterlab/lsp": ^4.0.6 - "@jupyterlab/statusbar": ^4.0.6 - "@jupyterlab/toc": ^6.0.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 - "@lumino/commands": ^2.1.3 + checksum: bce079263a141c76ec0a28be0d662c0a627ceaa12bcbe13be97a40f99abf37838fc87284701da1f6a7dce0be82f7322c8530f9fd9b3d1f4f253da5ddfa2e04ff + languageName: node + linkType: hard + +"@jupyterlab/fileeditor@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/fileeditor@npm:4.2.5" + dependencies: + "@jupyter/ydoc": ^2.0.1 + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/codeeditor": ^4.2.5 + "@jupyterlab/codemirror": ^4.2.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/docregistry": ^4.2.5 + "@jupyterlab/documentsearch": ^4.2.5 + "@jupyterlab/lsp": ^4.2.5 + "@jupyterlab/statusbar": ^4.2.5 + "@jupyterlab/toc": ^6.2.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 + "@lumino/commands": ^2.3.0 "@lumino/coreutils": ^2.1.2 "@lumino/messaging": ^2.0.1 - "@lumino/widgets": ^2.3.0 + "@lumino/widgets": ^2.3.2 react: ^18.2.0 regexp-match-indices: ^1.0.2 - checksum: cc70beea6dffe131574a73106e9381c80fe05b440f00f37312e4c12a0995dd22989f414916f4b450d455db20bf28d9ea3c2ef339e5ecfd45e61ce433c0bb8a0a + checksum: 6b00a11dbfecad510d5103b9d9b24e48d6fcc4daebaa6375cf2bd66cd80330e2d0da25847a5584a74b79c9107ce1e0361662ff121b670146fcb77480bbc1690b languageName: node linkType: hard -"@jupyterlab/galata@npm:^5.0.0-beta.0": - version: 5.0.6 - resolution: "@jupyterlab/galata@npm:5.0.6" +"@jupyterlab/galata@npm:^5.2.5": + version: 5.2.5 + resolution: "@jupyterlab/galata@npm:5.2.5" dependencies: - "@jupyterlab/application": ^4.0.6 - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/debugger": ^4.0.6 - "@jupyterlab/docmanager": ^4.0.6 - "@jupyterlab/nbformat": ^4.0.6 - "@jupyterlab/notebook": ^4.0.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/settingregistry": ^4.0.6 + "@jupyterlab/application": ^4.2.5 + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/debugger": ^4.2.5 + "@jupyterlab/docmanager": ^4.2.5 + "@jupyterlab/nbformat": ^4.2.5 + "@jupyterlab/notebook": ^4.2.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/settingregistry": ^4.2.5 "@lumino/coreutils": ^2.1.2 - "@playwright/test": ^1.32.2 + "@playwright/test": ^1.43.1 "@stdlib/stats": ~0.0.13 fs-extra: ^10.1.0 json5: ^2.2.3 @@ -685,32 +812,34 @@ __metadata: vega: ^5.20.0 vega-lite: ^5.6.1 vega-statistics: ^1.7.9 - checksum: a854c580923335595e091a52fbf9e575eeaa3b08fe4a3a1bdaa5ef044b18058e51a50983205068d63d51943fbf3d63f47853bfba31935dc265e3ecf7432b210f + checksum: 34cc7d0a78ef065697c62fcd32a9abce667c431027e9c23bd0ec44de10e0fbb5cca9c08005c046cd5c835776eb3baf1608df15d652e28847e71b90d05e87a572 languageName: node linkType: hard -"@jupyterlab/lsp@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/lsp@npm:4.0.6" - dependencies: - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/codeeditor": ^4.0.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/docregistry": ^4.0.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/translation": ^4.0.6 +"@jupyterlab/lsp@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/lsp@npm:4.2.5" + dependencies: + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/codeeditor": ^4.2.5 + "@jupyterlab/codemirror": ^4.2.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/docregistry": ^4.2.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/translation": ^4.2.5 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/signaling": ^2.1.2 + "@lumino/widgets": ^2.3.2 lodash.mergewith: ^4.6.1 vscode-jsonrpc: ^6.0.0 vscode-languageserver-protocol: ^3.17.0 vscode-ws-jsonrpc: ~1.0.2 - checksum: 7a20f402bd2777e5ec36efe3193357ae59a8d619516ccf34bb569afe68d32df2af2c77479216826a08fd6dc16952e1430f2465e1fd9878bf092ca8773e5e2d1e + checksum: 8dfaeb330a6b72b32f8eae6b5d4c3c0ff64203fe5fd69dbfbe15e22c46851a9fbc8c968608e4a6cd887760e194d4e4bb757135aff2df4eaee31acf248d603e9a languageName: node linkType: hard -"@jupyterlab/nbformat@npm:^3.0.0 || ^4.0.0-alpha.21 || ^4.0.0, @jupyterlab/nbformat@npm:^4.0.6": +"@jupyterlab/nbformat@npm:^3.0.0 || ^4.0.0-alpha.21 || ^4.0.0": version: 4.0.6 resolution: "@jupyterlab/nbformat@npm:4.0.6" dependencies: @@ -719,218 +848,232 @@ __metadata: languageName: node linkType: hard -"@jupyterlab/notebook@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/notebook@npm:4.0.6" - dependencies: - "@jupyter/ydoc": ^1.0.2 - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/cells": ^4.0.6 - "@jupyterlab/codeeditor": ^4.0.6 - "@jupyterlab/codemirror": ^4.0.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/docregistry": ^4.0.6 - "@jupyterlab/documentsearch": ^4.0.6 - "@jupyterlab/lsp": ^4.0.6 - "@jupyterlab/nbformat": ^4.0.6 - "@jupyterlab/observables": ^5.0.6 - "@jupyterlab/rendermime": ^4.0.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/settingregistry": ^4.0.6 - "@jupyterlab/statusbar": ^4.0.6 - "@jupyterlab/toc": ^6.0.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 +"@jupyterlab/nbformat@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/nbformat@npm:4.2.5" + dependencies: + "@lumino/coreutils": ^2.1.2 + checksum: b3ad2026969bfa59f8cfb7b1a991419f96f7e6dc8c4acf4ac166c210d7ab99631350c785e9b04350095488965d2824492c8adbff24a2e26db615457545426b3c + languageName: node + linkType: hard + +"@jupyterlab/notebook@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/notebook@npm:4.2.5" + dependencies: + "@jupyter/ydoc": ^2.0.1 + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/cells": ^4.2.5 + "@jupyterlab/codeeditor": ^4.2.5 + "@jupyterlab/codemirror": ^4.2.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/docregistry": ^4.2.5 + "@jupyterlab/documentsearch": ^4.2.5 + "@jupyterlab/lsp": ^4.2.5 + "@jupyterlab/nbformat": ^4.2.5 + "@jupyterlab/observables": ^5.2.5 + "@jupyterlab/rendermime": ^4.2.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/settingregistry": ^4.2.5 + "@jupyterlab/statusbar": ^4.2.5 + "@jupyterlab/toc": ^6.2.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 + "@lumino/disposable": ^2.1.2 "@lumino/domutils": ^2.0.1 - "@lumino/dragdrop": ^2.1.3 + "@lumino/dragdrop": ^2.1.4 "@lumino/messaging": ^2.0.1 + "@lumino/polling": ^2.1.2 "@lumino/properties": ^2.0.1 "@lumino/signaling": ^2.1.2 "@lumino/virtualdom": ^2.0.1 - "@lumino/widgets": ^2.3.0 + "@lumino/widgets": ^2.3.2 react: ^18.2.0 - checksum: 9ffb5f39b5e6d34fc2df2662c790121fda3880a271f0606bd56f3bcff416b43b1697640d43f0a30231fcf24a935e193ca9b5bf016d34675ede0e02e1185afffb + checksum: 1c91b42e890407574451903af7d48db8c216fa9e27ecc4e60ee76366572029ff73be3974085427b72eaedf67e718a7d4f93207f7b66dd3cf27a0b51172ca7727 languageName: node linkType: hard -"@jupyterlab/observables@npm:^5.0.6": - version: 5.0.6 - resolution: "@jupyterlab/observables@npm:5.0.6" +"@jupyterlab/observables@npm:^5.2.5": + version: 5.2.5 + resolution: "@jupyterlab/observables@npm:5.2.5" dependencies: "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/signaling": ^2.1.2 - checksum: 23232972e6a049b2addeae1d445bc3a10bb6c9a3dd4794225a0344aaa1ff62421ee300ef8803a19a3f068d2bba2de8b9a8dec719a7f47019fbd77c8d5dafb7a0 + checksum: 21fd2828463c08a770714692ff44aeca500f8ea8f3a743ad203a61fbf04cfa81921a47b432d8e65f4935fb45c08fce2b8858cb7e2198cc9bf0fa51f482ec37bd languageName: node linkType: hard -"@jupyterlab/outputarea@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/outputarea@npm:4.0.6" - dependencies: - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/nbformat": ^4.0.6 - "@jupyterlab/observables": ^5.0.6 - "@jupyterlab/rendermime": ^4.0.6 - "@jupyterlab/rendermime-interfaces": ^3.8.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/translation": ^4.0.6 +"@jupyterlab/outputarea@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/outputarea@npm:4.2.5" + dependencies: + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/nbformat": ^4.2.5 + "@jupyterlab/observables": ^5.2.5 + "@jupyterlab/rendermime": ^4.2.5 + "@jupyterlab/rendermime-interfaces": ^3.10.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/translation": ^4.2.5 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/properties": ^2.0.1 "@lumino/signaling": ^2.1.2 - "@lumino/widgets": ^2.3.0 - checksum: 2691fe7e4bdff895c821e970edbc19867107dbd8150aa7f32c7f3a4a7608f9ae9c7862dc5887fdca6983b9d6a947e05f23bbf5160c7c99eef93a0abf20d085a4 + "@lumino/widgets": ^2.3.2 + checksum: 0e2834244dfc12491d7207e9749c92caaa44424e5541cb227f5933a61884e6d42c67791f5c8982cbefebf6b7ce94fe595e633571d9ebc381dd130616899a4291 languageName: node linkType: hard -"@jupyterlab/rendermime-interfaces@npm:^3.8.6": - version: 3.8.6 - resolution: "@jupyterlab/rendermime-interfaces@npm:3.8.6" +"@jupyterlab/rendermime-interfaces@npm:^3.10.5": + version: 3.10.5 + resolution: "@jupyterlab/rendermime-interfaces@npm:3.10.5" dependencies: "@lumino/coreutils": ^1.11.0 || ^2.1.2 - "@lumino/widgets": ^1.37.2 || ^2.3.0 - checksum: 84ba0c3979e6ace6246e00248d1248075afb112f55be202257bb89a553b235d36ca82879c56f46f58285a5fc6d39914e93fea203c53245e0ac8d1b5ef838bb50 + "@lumino/widgets": ^1.37.2 || ^2.3.2 + checksum: acfb10315a3ed4d0b0ef664437b33f8938968c61993351fd4067b0eaf6cb6ccd4c5caf50ae050d184a34b35b88d844eee6689d00244e54a02b228c02eab544b4 languageName: node linkType: hard -"@jupyterlab/rendermime@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/rendermime@npm:4.0.6" - dependencies: - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/nbformat": ^4.0.6 - "@jupyterlab/observables": ^5.0.6 - "@jupyterlab/rendermime-interfaces": ^3.8.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/translation": ^4.0.6 +"@jupyterlab/rendermime@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/rendermime@npm:4.2.5" + dependencies: + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/nbformat": ^4.2.5 + "@jupyterlab/observables": ^5.2.5 + "@jupyterlab/rendermime-interfaces": ^3.10.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/translation": ^4.2.5 "@lumino/coreutils": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/signaling": ^2.1.2 - "@lumino/widgets": ^2.3.0 + "@lumino/widgets": ^2.3.2 lodash.escape: ^4.0.1 - checksum: 8f44601ccd6abe9985f8f713dcabf48ae38246b8b5a17a3963ebfe298dc2a03cc49d1f99c6d3bfeadbe1eb74803d0b3138c01347693a99166d7d70cb832c400b + checksum: e3e68c66306dc4bc7d4497d017e9e32cbfacfdc3ba14da6dfa6d7dbd328a3e8d5b710260365a06cd508209393e21985e7a69d0a160e239e4fdc1f0eb0874f35c languageName: node linkType: hard -"@jupyterlab/services@npm:^7.0.6": - version: 7.0.6 - resolution: "@jupyterlab/services@npm:7.0.6" +"@jupyterlab/services@npm:^7.2.5": + version: 7.2.5 + resolution: "@jupyterlab/services@npm:7.2.5" dependencies: - "@jupyter/ydoc": ^1.0.2 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/nbformat": ^4.0.6 - "@jupyterlab/settingregistry": ^4.0.6 - "@jupyterlab/statedb": ^4.0.6 + "@jupyter/ydoc": ^2.0.1 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/nbformat": ^4.2.5 + "@jupyterlab/settingregistry": ^4.2.5 + "@jupyterlab/statedb": ^4.2.5 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/polling": ^2.1.2 "@lumino/properties": ^2.0.1 "@lumino/signaling": ^2.1.2 ws: ^8.11.0 - checksum: 6e12ef309559977209e61ce3ec8ca74aa486d54f50d8f38211b684055fb2335a21c2ae6e846d2863e48524bffd7d6ac4d36dfc9f7ca610ae4b1c60752fa6c3a8 + checksum: 72d7578a86af1277b574095423fafb4176bc66373662fdc0e243a7d20e4baf8f291377b6c80300841dba6486767f16664f0e893174c2761658aedb74024e1db6 languageName: node linkType: hard -"@jupyterlab/settingregistry@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/settingregistry@npm:4.0.6" +"@jupyterlab/settingregistry@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/settingregistry@npm:4.2.5" dependencies: - "@jupyterlab/nbformat": ^4.0.6 - "@jupyterlab/statedb": ^4.0.6 - "@lumino/commands": ^2.1.3 + "@jupyterlab/nbformat": ^4.2.5 + "@jupyterlab/statedb": ^4.2.5 + "@lumino/commands": ^2.3.0 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/signaling": ^2.1.2 - "@rjsf/utils": ^5.1.0 + "@rjsf/utils": ^5.13.4 ajv: ^8.12.0 json5: ^2.2.3 peerDependencies: react: ">=16" - checksum: 70b6fc44a25e0d4ec36501c1418fe2764b9a9415f892df0901c43480b608a1621141ec8045183dfbca5aedf11ebaf1518dd76e2e96373b9ebe0efa6586ce856d + checksum: 2403e3198f2937fb9e4c12f96121e8bfc4f2a9ed47a9ad64182c88c8c19d59fcdf7443d0bf7d04527e89ac06378ceb39d6b4196c7f575c2a21fea23283ad3892 languageName: node linkType: hard -"@jupyterlab/statedb@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/statedb@npm:4.0.6" +"@jupyterlab/statedb@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/statedb@npm:4.2.5" dependencies: - "@lumino/commands": ^2.1.3 + "@lumino/commands": ^2.3.0 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/properties": ^2.0.1 "@lumino/signaling": ^2.1.2 - checksum: de507d094afcce7f7d12f9dc846788765616140b2f75ea22997f780056baaaadae0cf9683471a1d96c61d448b38860640c823302aeef0d5e5d7c9cf598074328 + checksum: 236e7628070971af167eb4fdeac96a0090b2256cfa14b6a75aee5ef23b156cd57a8b25518125fbdc58dea09490f8f473740bc4b454d8ad7c23949f64a61b757e languageName: node linkType: hard -"@jupyterlab/statusbar@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/statusbar@npm:4.0.6" +"@jupyterlab/statusbar@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/statusbar@npm:4.2.5" dependencies: - "@jupyterlab/ui-components": ^4.0.6 + "@jupyterlab/ui-components": ^4.2.5 "@lumino/algorithm": ^2.0.1 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/signaling": ^2.1.2 - "@lumino/widgets": ^2.3.0 + "@lumino/widgets": ^2.3.2 react: ^18.2.0 - checksum: c5d579b101e19670182d87de0d601fc9c73c40b5a81120e18e6cd7853ee9fd744fa31524f24b2c92cb587bb2d6aa54c08f6e257d868426a73d968e48b1101b7c + checksum: fa429b88a5bcd6889b9ac32b5f2500cb10a968cc636ca8dede17972535cc47454cb7fc96518fc8def76935f826b66b071752d0fd26afdacba579f6f3785e97b2 languageName: node linkType: hard -"@jupyterlab/toc@npm:^6.0.6": - version: 6.0.6 - resolution: "@jupyterlab/toc@npm:6.0.6" - dependencies: - "@jupyterlab/apputils": ^4.1.6 - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/docregistry": ^4.0.6 - "@jupyterlab/observables": ^5.0.6 - "@jupyterlab/rendermime": ^4.0.6 - "@jupyterlab/translation": ^4.0.6 - "@jupyterlab/ui-components": ^4.0.6 +"@jupyterlab/toc@npm:^6.2.5": + version: 6.2.5 + resolution: "@jupyterlab/toc@npm:6.2.5" + dependencies: + "@jupyterlab/apputils": ^4.3.5 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/docregistry": ^4.2.5 + "@jupyterlab/observables": ^5.2.5 + "@jupyterlab/rendermime": ^4.2.5 + "@jupyterlab/rendermime-interfaces": ^3.10.5 + "@jupyterlab/translation": ^4.2.5 + "@jupyterlab/ui-components": ^4.2.5 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 "@lumino/signaling": ^2.1.2 - "@lumino/widgets": ^2.3.0 + "@lumino/widgets": ^2.3.2 react: ^18.2.0 - checksum: d8d955a00e6678c50f73f18205dd79d77c752c3b0d33699554cdb77c3501657708c699642889975c97b58a85704c3bca40de01019ce087f188681bb843f35c3a + checksum: 49e856b710369308bdf2cc00c9025fa4c9942d221e8a97c548843113e321e78f4f0ef44115605ba01331732b2f4c2574c0e42ba7b53466c8c52a89ecbf00feb0 languageName: node linkType: hard -"@jupyterlab/translation@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/translation@npm:4.0.6" +"@jupyterlab/translation@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/translation@npm:4.2.5" dependencies: - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/rendermime-interfaces": ^3.8.6 - "@jupyterlab/services": ^7.0.6 - "@jupyterlab/statedb": ^4.0.6 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/rendermime-interfaces": ^3.10.5 + "@jupyterlab/services": ^7.2.5 + "@jupyterlab/statedb": ^4.2.5 "@lumino/coreutils": ^2.1.2 - checksum: 490243a26898bbdcc1909e8e1649be90580c6d4502417590fd1b3ca24db5aeff2323e567dbfb1d528c56df89ed2e7717753ece784134f9e409d14df92bf25682 + checksum: 8983efad2b0d54381cb94799a10eab30f284a87103f93e844bd87106e2df3c304e260b9c95540317819cc2b2520c74ad78cb724816c81e0c315fdb43d0bdaab3 languageName: node linkType: hard -"@jupyterlab/ui-components@npm:^4.0.6": - version: 4.0.6 - resolution: "@jupyterlab/ui-components@npm:4.0.6" +"@jupyterlab/ui-components@npm:^4.2.5": + version: 4.2.5 + resolution: "@jupyterlab/ui-components@npm:4.2.5" dependencies: - "@jupyterlab/coreutils": ^6.0.6 - "@jupyterlab/observables": ^5.0.6 - "@jupyterlab/rendermime-interfaces": ^3.8.6 - "@jupyterlab/translation": ^4.0.6 + "@jupyter/react-components": ^0.15.3 + "@jupyter/web-components": ^0.15.3 + "@jupyterlab/coreutils": ^6.2.5 + "@jupyterlab/observables": ^5.2.5 + "@jupyterlab/rendermime-interfaces": ^3.10.5 + "@jupyterlab/translation": ^4.2.5 "@lumino/algorithm": ^2.0.1 - "@lumino/commands": ^2.1.3 + "@lumino/commands": ^2.3.0 "@lumino/coreutils": ^2.1.2 "@lumino/disposable": ^2.1.2 "@lumino/messaging": ^2.0.1 @@ -938,15 +1081,15 @@ __metadata: "@lumino/properties": ^2.0.1 "@lumino/signaling": ^2.1.2 "@lumino/virtualdom": ^2.0.1 - "@lumino/widgets": ^2.3.0 - "@rjsf/core": ^5.1.0 - "@rjsf/utils": ^5.1.0 + "@lumino/widgets": ^2.3.2 + "@rjsf/core": ^5.13.4 + "@rjsf/utils": ^5.13.4 react: ^18.2.0 react-dom: ^18.2.0 typestyle: ^2.0.4 peerDependencies: react: ^18.2.0 - checksum: 02997c3c35c15c0eda6a0d49fe9cfd12a3c5194c026b2ae8d8e53c7af80b769ba1598e7c24283450bacae7b8fab838d18f6c614d686c98d3d43e68f1f00b2528 + checksum: 9d2b887910a3b0d41645388c5ac6183d6fd2f3af4567de9b077b2492b1a9380f98c4598a4ae6d1c3186624ed4f956bedf8ba37adb5f772c96555761384a93e1e languageName: node linkType: hard @@ -957,6 +1100,13 @@ __metadata: languageName: node linkType: hard +"@lezer/common@npm:^1.2.0, @lezer/common@npm:^1.2.1": + version: 1.2.2 + resolution: "@lezer/common@npm:1.2.2" + checksum: ebac1144893ffb6b86feb9e84cbf617493e5c8f498ceac24382e0627e787372175aad0fad007d292e0cb2a748577d87f880d34b31f22b5a57f4c651330da68c9 + languageName: node + linkType: hard + "@lezer/cpp@npm:^1.0.0": version: 1.1.1 resolution: "@lezer/cpp@npm:1.1.1" @@ -977,19 +1127,30 @@ __metadata: languageName: node linkType: hard -"@lezer/generator@npm:^1.2.2": - version: 1.5.1 - resolution: "@lezer/generator@npm:1.5.1" +"@lezer/css@npm:^1.1.7": + version: 1.1.9 + resolution: "@lezer/css@npm:1.1.9" dependencies: - "@lezer/common": ^1.0.2 + "@lezer/common": ^1.2.0 + "@lezer/highlight": ^1.0.0 + "@lezer/lr": ^1.0.0 + checksum: 25c63475061a3c9f87961a7f85c5f547f14fb7e81b0864675d2206999a874a0559d676145c74c6ccde39519dbc8aa33e216265f5366d08060507b6c9e875fe0f + languageName: node + linkType: hard + +"@lezer/generator@npm:^1.7.0": + version: 1.7.1 + resolution: "@lezer/generator@npm:1.7.1" + dependencies: + "@lezer/common": ^1.1.0 "@lezer/lr": ^1.3.0 bin: lezer-generator: src/lezer-generator.cjs - checksum: 4d8267e6d356e48ca5214a234679b2b3b1d3706cb9dffecee4495b7a16c8a02502d6a078f8afdf5d8c79f94af34f2c1b5c08556aead8376d7b23795612b651d0 + checksum: e46df5a31252fb036ea17fce820acdf47672bb5405b2a38e26a430182b9a50b8513fde37d9a43d8334cde3bb2f2106ce7a5ab1a01e244876ce3217c4db59e627 languageName: node linkType: hard -"@lezer/highlight@npm:^1.0.0, @lezer/highlight@npm:^1.1.3, @lezer/highlight@npm:^1.1.4": +"@lezer/highlight@npm:^1.0.0, @lezer/highlight@npm:^1.1.3": version: 1.1.6 resolution: "@lezer/highlight@npm:1.1.6" dependencies: @@ -998,6 +1159,15 @@ __metadata: languageName: node linkType: hard +"@lezer/highlight@npm:^1.2.0": + version: 1.2.1 + resolution: "@lezer/highlight@npm:1.2.1" + dependencies: + "@lezer/common": ^1.0.0 + checksum: a8822d7e37f79ff64669eb2df4a9f9d16580e88f2b276a646092e19a9bdccac304e92510e200e35869a8b1f6c27eba5972c508d347a277e9b722d582ab7a23d5 + languageName: node + linkType: hard + "@lezer/html@npm:^1.3.0": version: 1.3.6 resolution: "@lezer/html@npm:1.3.6" @@ -1048,7 +1218,7 @@ __metadata: languageName: node linkType: hard -"@lezer/markdown@npm:^1.0.0, @lezer/markdown@npm:^1.0.2": +"@lezer/markdown@npm:^1.0.0": version: 1.1.0 resolution: "@lezer/markdown@npm:1.1.0" dependencies: @@ -1058,6 +1228,16 @@ __metadata: languageName: node linkType: hard +"@lezer/markdown@npm:^1.2.0": + version: 1.3.1 + resolution: "@lezer/markdown@npm:1.3.1" + dependencies: + "@lezer/common": ^1.0.0 + "@lezer/highlight": ^1.0.0 + checksum: b5cbb857a90411e174e7ad23433756a81cf2ab422ef749e529211e078ed4061b4595fa8cbcca56119919c0b2735e8ecac11ff34768d64cb90e599fde2bc6c730 + languageName: node + linkType: hard + "@lezer/php@npm:^1.0.0": version: 1.0.1 resolution: "@lezer/php@npm:1.0.1" @@ -1105,14 +1285,21 @@ __metadata: languageName: node linkType: hard -"@lumino/application@npm:^2.2.1": - version: 2.2.1 - resolution: "@lumino/application@npm:2.2.1" +"@lumino/algorithm@npm:^2.0.2": + version: 2.0.2 + resolution: "@lumino/algorithm@npm:2.0.2" + checksum: 34b25684b845f1bdbf78ca45ebd99a97b67b2992440c9643aafe5fc5a99fae1ddafa9e5890b246b233dc3a12d9f66aa84afe4a2aac44cf31071348ed217740db + languageName: node + linkType: hard + +"@lumino/application@npm:^2.3.1": + version: 2.4.1 + resolution: "@lumino/application@npm:2.4.1" dependencies: - "@lumino/commands": ^2.1.3 - "@lumino/coreutils": ^2.1.2 - "@lumino/widgets": ^2.3.0 - checksum: a33e661703728440bc7d2ddb4674261f4de0d20eb8c9846646cbd6debac03b5c65e78d739a500903550fd83b8f47b47fa82ec178c97bc9967ca3ac4014075cde + "@lumino/commands": ^2.3.1 + "@lumino/coreutils": ^2.2.0 + "@lumino/widgets": ^2.5.0 + checksum: b7166d1bf4f0e3cc945d984b4057a4cd106d38df6cb4c6f1259c75484e2b976018aca55f169fa4af7dd174ce7117be1920966bef0fb7cba756f503f0df1d211e languageName: node linkType: hard @@ -1125,18 +1312,27 @@ __metadata: languageName: node linkType: hard -"@lumino/commands@npm:^2.1.3": - version: 2.1.3 - resolution: "@lumino/commands@npm:2.1.3" +"@lumino/collections@npm:^2.0.2": + version: 2.0.2 + resolution: "@lumino/collections@npm:2.0.2" dependencies: - "@lumino/algorithm": ^2.0.1 - "@lumino/coreutils": ^2.1.2 - "@lumino/disposable": ^2.1.2 - "@lumino/domutils": ^2.0.1 - "@lumino/keyboard": ^2.0.1 - "@lumino/signaling": ^2.1.2 - "@lumino/virtualdom": ^2.0.1 - checksum: e4e3ee279f2a5e8d68e4ce142c880333f5542f90c684972402356936ecb5cf5e07163800b59e7cb8c911cbdb4e5089edcc5dd2990bc8db10c87517268de1fc5d + "@lumino/algorithm": ^2.0.2 + checksum: e8bb2068a3741940e0dd396fa729c3c9d12458b41b7c2a9d171c5c034e69fb5834116a824094a8aa4182397e13abace06025ed5032a755ea85b976eae74ee9a9 + languageName: node + linkType: hard + +"@lumino/commands@npm:^2.3.0, @lumino/commands@npm:^2.3.1": + version: 2.3.1 + resolution: "@lumino/commands@npm:2.3.1" + dependencies: + "@lumino/algorithm": ^2.0.2 + "@lumino/coreutils": ^2.2.0 + "@lumino/disposable": ^2.1.3 + "@lumino/domutils": ^2.0.2 + "@lumino/keyboard": ^2.0.2 + "@lumino/signaling": ^2.1.3 + "@lumino/virtualdom": ^2.0.2 + checksum: 83bc6d66de37e58582b00f70ce66e797c9fcf84e36041c6881631ed0d281305e2a49927f5b2fe6c5c965733f3cd6fb4a233c7b7967fc050497024a941659bd65 languageName: node linkType: hard @@ -1147,20 +1343,29 @@ __metadata: languageName: node linkType: hard -"@lumino/datagrid@npm:^2.2.0": +"@lumino/coreutils@npm:^2.2.0": version: 2.2.0 - resolution: "@lumino/datagrid@npm:2.2.0" + resolution: "@lumino/coreutils@npm:2.2.0" dependencies: - "@lumino/algorithm": ^2.0.1 - "@lumino/coreutils": ^2.1.2 - "@lumino/disposable": ^2.1.2 - "@lumino/domutils": ^2.0.1 - "@lumino/dragdrop": ^2.1.3 - "@lumino/keyboard": ^2.0.1 - "@lumino/messaging": ^2.0.1 - "@lumino/signaling": ^2.1.2 - "@lumino/widgets": ^2.3.0 - checksum: dcd6e06500c05b0f30b9924a25a2cc4c1cb98b8432f488148e74e98a7fe092a1f19cadbdc9edfbede9e2030d30b84e5633e40753fbe8d6bbb120d3336d3675ff + "@lumino/algorithm": ^2.0.2 + checksum: 345fcd5d7493d745831dd944edfbd8eda06cc59a117e71023fc97ce53badd697be2bd51671f071f5ff0064f75f104575d9695f116a07517bafbedd38e5c7a785 + languageName: node + linkType: hard + +"@lumino/datagrid@npm:^2.3.1": + version: 2.4.1 + resolution: "@lumino/datagrid@npm:2.4.1" + dependencies: + "@lumino/algorithm": ^2.0.2 + "@lumino/coreutils": ^2.2.0 + "@lumino/disposable": ^2.1.3 + "@lumino/domutils": ^2.0.2 + "@lumino/dragdrop": ^2.1.5 + "@lumino/keyboard": ^2.0.2 + "@lumino/messaging": ^2.0.2 + "@lumino/signaling": ^2.1.3 + "@lumino/widgets": ^2.5.0 + checksum: e24e29b3b08a5c7f01b86b98dbb0343a34ffcedee83b2d52ea2beca021aea95392dee5005f8511a354f331244f37e49e01276ce250cc85b261a301aef82d4f55 languageName: node linkType: hard @@ -1173,6 +1378,15 @@ __metadata: languageName: node linkType: hard +"@lumino/disposable@npm:^2.1.3": + version: 2.1.3 + resolution: "@lumino/disposable@npm:2.1.3" + dependencies: + "@lumino/signaling": ^2.1.3 + checksum: b9a346fa2752b3cd1b053cb637ee173501d33082a73423429070e8acc508b034ea0babdae0549b923cbdd287ee1fc7f6159f0539c9fff7574393a214eef07c57 + languageName: node + linkType: hard + "@lumino/domutils@npm:^2.0.1": version: 2.0.1 resolution: "@lumino/domutils@npm:2.0.1" @@ -1180,20 +1394,27 @@ __metadata: languageName: node linkType: hard -"@lumino/dragdrop@npm:^2.1.3": - version: 2.1.3 - resolution: "@lumino/dragdrop@npm:2.1.3" +"@lumino/domutils@npm:^2.0.2": + version: 2.0.2 + resolution: "@lumino/domutils@npm:2.0.2" + checksum: 037b8d0b62af43887fd7edd506fa551e2af104a4b46d62e6fef256e16754dba40d351513beb5083834d468b2c7806aae0fe205fd6aac8ef24759451ee998bbd9 + languageName: node + linkType: hard + +"@lumino/dragdrop@npm:^2.1.4, @lumino/dragdrop@npm:^2.1.5": + version: 2.1.5 + resolution: "@lumino/dragdrop@npm:2.1.5" dependencies: - "@lumino/coreutils": ^2.1.2 - "@lumino/disposable": ^2.1.2 - checksum: d5f7eb4cc9f9a084cb9af10f02d6741b25d683350878ecbc324e24ba9d4b5246451a410e2ca5fff227aab1c191d1e73a2faf431f93e13111d67a4e426e126258 + "@lumino/coreutils": ^2.2.0 + "@lumino/disposable": ^2.1.3 + checksum: 48e34bea73186dcde4565fa68cd25067b7f5fe910813d28da9ab3c5392bfaa0b26aab1290635dc953d85bbb139da7ac1ffc040a5d5777d58fd087975dd4b5ef7 languageName: node linkType: hard -"@lumino/keyboard@npm:^2.0.1": - version: 2.0.1 - resolution: "@lumino/keyboard@npm:2.0.1" - checksum: cf33f13427a418efd7cc91061233321e860d5404f3d86397781028309bef86c8ad2d88276ffe335c1db0fe619bd9d1e60641c81f881696957a58703ee4652c3e +"@lumino/keyboard@npm:^2.0.2": + version: 2.0.2 + resolution: "@lumino/keyboard@npm:2.0.2" + checksum: 198e8c17825c9a831fa0770f58a71574b936acb0f0bbbe7f8feb73d89686dda7ff41fcb02d12b401f5d462b45fe0bba24f7f38befb7cefe0826576559f0bee6d languageName: node linkType: hard @@ -1207,6 +1428,16 @@ __metadata: languageName: node linkType: hard +"@lumino/messaging@npm:^2.0.2": + version: 2.0.2 + resolution: "@lumino/messaging@npm:2.0.2" + dependencies: + "@lumino/algorithm": ^2.0.2 + "@lumino/collections": ^2.0.2 + checksum: 66abd8c473026123589dc22f2ce8f85da10e0b1a05c05ed9b2011035721da5f751cc7ef63b628877f446a78a4287e26ad1450efbeaf0c2e03b1d08be9abaca4d + languageName: node + linkType: hard + "@lumino/polling@npm:^2.1.2": version: 2.1.2 resolution: "@lumino/polling@npm:2.1.2" @@ -1225,6 +1456,13 @@ __metadata: languageName: node linkType: hard +"@lumino/properties@npm:^2.0.2": + version: 2.0.2 + resolution: "@lumino/properties@npm:2.0.2" + checksum: cbe802bd49ced7e13e50b1d89b82e0f03fb44a590c704e6b9343226498b21d8abfe119b024209e79876b4fc0938dbf85e964c6c4cd5bbdd4d7ba41ce0fb69f3f + languageName: node + linkType: hard + "@lumino/signaling@npm:^1.10.0 || ^2.0.0, @lumino/signaling@npm:^2.1.2": version: 2.1.2 resolution: "@lumino/signaling@npm:2.1.2" @@ -1235,6 +1473,16 @@ __metadata: languageName: node linkType: hard +"@lumino/signaling@npm:^2.1.3": + version: 2.1.3 + resolution: "@lumino/signaling@npm:2.1.3" + dependencies: + "@lumino/algorithm": ^2.0.2 + "@lumino/coreutils": ^2.2.0 + checksum: ce59383bd75fe30df5800e0442dbc4193cc6778e2530b9be0f484d159f1d8668be5c6ee92cee9df36d5a0c3dbd9126d0479a82581dee1df889d5c9f922d3328d + languageName: node + linkType: hard + "@lumino/virtualdom@npm:^2.0.1": version: 2.0.1 resolution: "@lumino/virtualdom@npm:2.0.1" @@ -1244,22 +1492,78 @@ __metadata: languageName: node linkType: hard -"@lumino/widgets@npm:^1.37.2 || ^2.3.0, @lumino/widgets@npm:^2.3.0": - version: 2.3.0 - resolution: "@lumino/widgets@npm:2.3.0" +"@lumino/virtualdom@npm:^2.0.2": + version: 2.0.2 + resolution: "@lumino/virtualdom@npm:2.0.2" dependencies: - "@lumino/algorithm": ^2.0.1 - "@lumino/commands": ^2.1.3 - "@lumino/coreutils": ^2.1.2 - "@lumino/disposable": ^2.1.2 - "@lumino/domutils": ^2.0.1 - "@lumino/dragdrop": ^2.1.3 - "@lumino/keyboard": ^2.0.1 - "@lumino/messaging": ^2.0.1 - "@lumino/properties": ^2.0.1 - "@lumino/signaling": ^2.1.2 - "@lumino/virtualdom": ^2.0.1 - checksum: a8559bd3574b7fc16e7679e05994c515b0d3e78dada35786d161f67c639941d134e92ce31d95c2e4ac06709cdf83b0e7fb4b6414a3f7779579222a2fb525d025 + "@lumino/algorithm": ^2.0.2 + checksum: 0e1220d5b3b2441e7668f3542a6341e015bdbea0c8bd6d4be962009386c034336540732596d5dedcd54ca57fbde61c2942549129a3e1b0fccb1aa143685fcd15 + languageName: node + linkType: hard + +"@lumino/widgets@npm:^1.37.2 || ^2.3.2, @lumino/widgets@npm:^2.3.2, @lumino/widgets@npm:^2.5.0": + version: 2.5.0 + resolution: "@lumino/widgets@npm:2.5.0" + dependencies: + "@lumino/algorithm": ^2.0.2 + "@lumino/commands": ^2.3.1 + "@lumino/coreutils": ^2.2.0 + "@lumino/disposable": ^2.1.3 + "@lumino/domutils": ^2.0.2 + "@lumino/dragdrop": ^2.1.5 + "@lumino/keyboard": ^2.0.2 + "@lumino/messaging": ^2.0.2 + "@lumino/properties": ^2.0.2 + "@lumino/signaling": ^2.1.3 + "@lumino/virtualdom": ^2.0.2 + checksum: c5055e42b0b7d5d9a0c29d14c7053478cbdef057525e262ccd59c987971364d5462ed1a59d5008b889cf5ecc6810e90c681364239500b9c8ee0ae4624d60df84 + languageName: node + linkType: hard + +"@microsoft/fast-colors@npm:^5.3.1": + version: 5.3.1 + resolution: "@microsoft/fast-colors@npm:5.3.1" + checksum: ff87f402faadb4b5aeee3d27762566c11807f927cd4012b8bbc7f073ca68de0e2197f95330ff5dfd7038f4b4f0e2f51b11feb64c5d570f5c598d37850a5daf60 + languageName: node + linkType: hard + +"@microsoft/fast-element@npm:^1.12.0, @microsoft/fast-element@npm:^1.13.0": + version: 1.13.0 + resolution: "@microsoft/fast-element@npm:1.13.0" + checksum: 1cb7b4cfb7531116a3542d3f59bf1dd35106194f5764205403590250aaff744de79e35a5a1f36b4941c4eda9edc088148d4d629fb80be15fdf25f6be01770f3a + languageName: node + linkType: hard + +"@microsoft/fast-foundation@npm:^2.49.4, @microsoft/fast-foundation@npm:^2.49.6": + version: 2.49.6 + resolution: "@microsoft/fast-foundation@npm:2.49.6" + dependencies: + "@microsoft/fast-element": ^1.13.0 + "@microsoft/fast-web-utilities": ^5.4.1 + tabbable: ^5.2.0 + tslib: ^1.13.0 + checksum: 15fdf9dd0b910a72a9cff140f765d522304df11f8a78d5a97a815e2bbae25027c2b336e94f89ca31e650d6aabe17b590b7453acc0d2cb7340c219eb76350a942 + languageName: node + linkType: hard + +"@microsoft/fast-react-wrapper@npm:^0.3.22": + version: 0.3.24 + resolution: "@microsoft/fast-react-wrapper@npm:0.3.24" + dependencies: + "@microsoft/fast-element": ^1.13.0 + "@microsoft/fast-foundation": ^2.49.6 + peerDependencies: + react: ">=16.9.0" + checksum: 1d7a87509c22872bafc9b5c64f66659e52ba0cfdff484d7204125e503dafdea143f5e1bd2a643e2f3fbba6cc7567d916393369433f19dab9f0adcbe7a88b7d98 + languageName: node + linkType: hard + +"@microsoft/fast-web-utilities@npm:^5.4.1": + version: 5.4.1 + resolution: "@microsoft/fast-web-utilities@npm:5.4.1" + dependencies: + exenv-es6: ^1.1.1 + checksum: 303e87847f962944f474e3716c3eb305668243916ca9e0719e26bb9a32346144bc958d915c103776b3e552cea0f0f6233f839fad66adfdf96a8436b947288ca7 languageName: node linkType: hard @@ -1292,36 +1596,36 @@ __metadata: languageName: node linkType: hard -"@playwright/test@npm:^1.32.2": - version: 1.38.0 - resolution: "@playwright/test@npm:1.38.0" +"@playwright/test@npm:^1.43.1": + version: 1.48.0 + resolution: "@playwright/test@npm:1.48.0" dependencies: - playwright: 1.38.0 + playwright: 1.48.0 bin: playwright: cli.js - checksum: 0768b6b98f0993d9d8017e4bcca3a5c3fe1bf0270acaa89b141479c4319c16350d60e6d2511cbd655283942059fa409ce23fce30435f0936f5e2577834f356ba + checksum: 81a6260db1b2dd4a6bff7a31f6fd83a6db21109268a3516e47f24e3de64b0da1b9fa985dab5fdccc73fc9c5cca2e0c1ef2137f5cdc5c5cacdfc7d13f4a36c5fd languageName: node linkType: hard -"@rjsf/core@npm:^5.1.0": - version: 5.13.0 - resolution: "@rjsf/core@npm:5.13.0" +"@rjsf/core@npm:^5.13.4": + version: 5.21.2 + resolution: "@rjsf/core@npm:5.21.2" dependencies: lodash: ^4.17.21 lodash-es: ^4.17.21 - markdown-to-jsx: ^7.3.2 - nanoid: ^3.3.6 + markdown-to-jsx: ^7.4.1 + nanoid: ^3.3.7 prop-types: ^15.8.1 peerDependencies: - "@rjsf/utils": ^5.12.x + "@rjsf/utils": ^5.20.x react: ^16.14.0 || >=17 - checksum: d7d66d20fcdf310f4b152c22e1ac1ca8abe5f40b502711c9cabc4241b3252ec0e58345aa194529d2bdfb7a51b9f1179c9ddefc0cdc7fd9f94ad10c5e5b1032b8 + checksum: ac5c4ff0e0cf74ba8cf6d58df314f8f17de6be5b00bb0ca14f79861347bbaa59f37b8f572d80f30388c5007de1d2dedfc3ff70e419eb874331d58f0ba9eeeb42 languageName: node linkType: hard -"@rjsf/utils@npm:^5.1.0": - version: 5.13.0 - resolution: "@rjsf/utils@npm:5.13.0" +"@rjsf/utils@npm:^5.13.4": + version: 5.21.2 + resolution: "@rjsf/utils@npm:5.21.2" dependencies: json-schema-merge-allof: ^0.8.1 jsonpointer: ^5.0.1 @@ -1330,7 +1634,7 @@ __metadata: react-is: ^18.2.0 peerDependencies: react: ^16.14.0 || >=17 - checksum: 283e2b405eac2f4fdd243b2e35ade7e83a4bf7551eb5e075499e8eb5d3a3ae161e9c047bcf63d2e6fef7c6b2e7438f1a150f353b909df992e85194940c311f9b + checksum: 05460f3c95e1a407001accaf2e9b90c0731433936cfea6a129ac01b49575f56ba336f1ae46e3930f0226580d06c6300c8622d1c3a56354c3e723caf3654f02e1 languageName: node linkType: hard @@ -2225,41 +2529,41 @@ __metadata: languageName: node linkType: hard -"dom-serializer@npm:^1.0.1": - version: 1.4.1 - resolution: "dom-serializer@npm:1.4.1" +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" dependencies: - domelementtype: ^2.0.1 - domhandler: ^4.2.0 - entities: ^2.0.0 - checksum: fbb0b01f87a8a2d18e6e5a388ad0f7ec4a5c05c06d219377da1abc7bb0f674d804f4a8a94e3f71ff15f6cb7dcfc75704a54b261db672b9b3ab03da6b758b0b22 + domelementtype: ^2.3.0 + domhandler: ^5.0.2 + entities: ^4.2.0 + checksum: cd1810544fd8cdfbd51fa2c0c1128ec3a13ba92f14e61b7650b5de421b88205fd2e3f0cc6ace82f13334114addb90ed1c2f23074a51770a8e9c1273acbc7f3e6 languageName: node linkType: hard -"domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0": +"domelementtype@npm:^2.3.0": version: 2.3.0 resolution: "domelementtype@npm:2.3.0" checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 languageName: node linkType: hard -"domhandler@npm:^4.0.0, domhandler@npm:^4.2.0": - version: 4.3.1 - resolution: "domhandler@npm:4.3.1" +"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" dependencies: - domelementtype: ^2.2.0 - checksum: 4c665ceed016e1911bf7d1dadc09dc888090b64dee7851cccd2fcf5442747ec39c647bb1cb8c8919f8bbdd0f0c625a6bafeeed4b2d656bbecdbae893f43ffaaa + domelementtype: ^2.3.0 + checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c languageName: node linkType: hard -"domutils@npm:^2.5.2": - version: 2.8.0 - resolution: "domutils@npm:2.8.0" +"domutils@npm:^3.0.1": + version: 3.1.0 + resolution: "domutils@npm:3.1.0" dependencies: - dom-serializer: ^1.0.1 - domelementtype: ^2.2.0 - domhandler: ^4.2.0 - checksum: abf7434315283e9aadc2a24bac0e00eab07ae4313b40cc239f89d84d7315ebdfd2fb1b5bf750a96bc1b4403d7237c7b2ebf60459be394d625ead4ca89b934391 + dom-serializer: ^2.0.0 + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + checksum: e5757456ddd173caa411cfc02c2bb64133c65546d2c4081381a3bafc8a57411a41eed70494551aa58030be9e58574fcc489828bebd673863d39924fb4878f416 languageName: node linkType: hard @@ -2293,10 +2597,10 @@ __metadata: languageName: node linkType: hard -"entities@npm:^2.0.0": - version: 2.2.0 - resolution: "entities@npm:2.2.0" - checksum: 19010dacaf0912c895ea262b4f6128574f9ccf8d4b3b65c7e8334ad0079b3706376360e28d8843ff50a78aabcb8f08f0a32dbfacdc77e47ed77ca08b713669b3 +"entities@npm:^4.2.0, entities@npm:^4.4.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7 languageName: node linkType: hard @@ -2328,6 +2632,13 @@ __metadata: languageName: node linkType: hard +"exenv-es6@npm:^1.1.1": + version: 1.1.1 + resolution: "exenv-es6@npm:1.1.1" + checksum: 7f2aa12025e6f06c48dc286f380cf3183bb19c6017b36d91695034a3e5124a7235c4f8ff24ca2eb88ae801322f0f99605cedfcfd996a5fcbba7669320e2a448e + languageName: node + linkType: hard + "exponential-backoff@npm:^3.1.1": version: 3.1.1 resolution: "exponential-backoff@npm:3.1.1" @@ -2436,15 +2747,15 @@ __metadata: languageName: node linkType: hard -"htmlparser2@npm:^6.0.0": - version: 6.1.0 - resolution: "htmlparser2@npm:6.1.0" +"htmlparser2@npm:^8.0.0": + version: 8.0.2 + resolution: "htmlparser2@npm:8.0.2" dependencies: - domelementtype: ^2.0.1 - domhandler: ^4.0.0 - domutils: ^2.5.2 - entities: ^2.0.0 - checksum: 81a7b3d9c3bb9acb568a02fc9b1b81ffbfa55eae7f1c41ae0bf840006d1dbf54cb3aa245b2553e2c94db674840a9f0fdad7027c9a9d01a062065314039058c4e + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + domutils: ^3.0.1 + entities: ^4.4.0 + checksum: 29167a0f9282f181da8a6d0311b76820c8a59bc9e3c87009e21968264c2987d2723d6fde5a964d4b7b6cba663fca96ffb373c06d8223a85f52a6089ced942700 languageName: node linkType: hard @@ -2744,12 +3055,12 @@ __metadata: languageName: node linkType: hard -"markdown-to-jsx@npm:^7.3.2": - version: 7.3.2 - resolution: "markdown-to-jsx@npm:7.3.2" +"markdown-to-jsx@npm:^7.4.1": + version: 7.5.0 + resolution: "markdown-to-jsx@npm:7.5.0" peerDependencies: react: ">= 0.14.0" - checksum: 8885c6343b71570b0a7ec16cd85a49b853a830234790ee7430e2517ea5d8d361ff138bd52147f650790f3e7b3a28a15c755fc16f8856dd01ddf09a6161782e06 + checksum: c9c6f1bfad5f2d9b1d3476eb0313ae3dffd0a9f14011c74efdd7c664fd32ee1842ef48abb16a496046f90361af49aa80a827e9d9c0bc04824a1986fdeb4d1852 languageName: node linkType: hard @@ -2885,6 +3196,15 @@ __metadata: languageName: node linkType: hard +"nanoid@npm:^3.3.7": + version: 3.3.7 + resolution: "nanoid@npm:3.3.7" + bin: + nanoid: bin/nanoid.cjs + checksum: d36c427e530713e4ac6567d488b489a36582ef89da1d6d4e3b87eded11eb10d7042a877958c6f104929809b2ab0bafa17652b076cdf84324aa75b30b722204f2 + languageName: node + linkType: hard + "negotiator@npm:^0.6.3": version: 0.6.3 resolution: "negotiator@npm:0.6.3" @@ -3001,27 +3321,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.38.0": - version: 1.38.0 - resolution: "playwright-core@npm:1.38.0" +"playwright-core@npm:1.48.0": + version: 1.48.0 + resolution: "playwright-core@npm:1.48.0" bin: playwright-core: cli.js - checksum: 9eb43fc6c3cb392d5f35b0fd0b7291b38a8cbdc3cbb944a8261f744f30d09196dfa3b5d84aa02ffc09af87d08d31b385b007b6af20d0b6cd50a29344f3b0db8d + checksum: 8c6ecf1ca2484408e8a11bbb107cf4cb19621bbb85c5f4b29206df29ea13b4e6a008fb434df03e3411719c74e4f130a4ece05365fc1a2940e243725a10d04ad4 languageName: node linkType: hard -"playwright@npm:1.38.0": - version: 1.38.0 - resolution: "playwright@npm:1.38.0" +"playwright@npm:1.48.0": + version: 1.48.0 + resolution: "playwright@npm:1.48.0" dependencies: fsevents: 2.3.2 - playwright-core: 1.38.0 + playwright-core: 1.48.0 dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: c5356690a391d5dd41f814d4e2694b93ba9e79381ce63de752da1c6c59b1f9c69bc6be853d973d0542d73a44a6b15f7c0081a164a64cd27b6b31207710c0ab34 + checksum: e19431f432b68fc08109382a0707e18d2034554f0857925d7d9b75b2277136cef2e756bd93e4228c26ece1446761641b398b0cc0e1c799db1b466a0953fda787 languageName: node linkType: hard @@ -3118,6 +3438,15 @@ __metadata: languageName: node linkType: hard +"react@npm:>=17.0.0 <19.0.0": + version: 18.3.1 + resolution: "react@npm:18.3.1" + dependencies: + loose-envify: ^1.1.0 + checksum: a27bcfa8ff7c15a1e50244ad0d0c1cb2ad4375eeffefd266a64889beea6f6b64c4966c9b37d14ee32d6c9fcd5aa6ba183b6988167ab4d127d13e7cb5b386a376 + languageName: node + linkType: hard + "react@npm:^18.2.0": version: 18.2.0 resolution: "react@npm:18.2.0" @@ -3216,17 +3545,17 @@ __metadata: languageName: node linkType: hard -"sanitize-html@npm:~2.7.3": - version: 2.7.3 - resolution: "sanitize-html@npm:2.7.3" +"sanitize-html@npm:~2.12.1": + version: 2.12.1 + resolution: "sanitize-html@npm:2.12.1" dependencies: deepmerge: ^4.2.2 escape-string-regexp: ^4.0.0 - htmlparser2: ^6.0.0 + htmlparser2: ^8.0.0 is-plain-object: ^5.0.0 parse-srcset: ^1.0.2 postcss: ^8.3.11 - checksum: 2399d1fdbbc3a263fb413c1fe1971b3dc2b51abc6cc5cb49490624539d1c57a8fe31e2b21408c118e2a957f4e673e3169b1f9a5807654408f17b130a9d78aed7 + checksum: fb96ea7170d51b5af2607f5cfd84464c78fc6f47e339407f55783e781c6a0288a8d40bbf97ea6a8758924ba9b2d33dcc4846bb94caacacd90d7f2de10ed8541a languageName: node linkType: hard @@ -3383,6 +3712,13 @@ __metadata: languageName: node linkType: hard +"tabbable@npm:^5.2.0": + version: 5.3.3 + resolution: "tabbable@npm:5.3.3" + checksum: 1aa56e1bb617cc10616c407f4e756f0607f3e2d30f9803664d70b85db037ca27e75918ed1c71443f3dc902e21dc9f991ce4b52d63a538c9b69b3218d3babcd70 + languageName: node + linkType: hard + "tar@npm:^6.1.11, tar@npm:^6.1.2": version: 6.2.0 resolution: "tar@npm:6.2.0" @@ -3417,6 +3753,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^1.13.0": + version: 1.14.1 + resolution: "tslib@npm:1.14.1" + checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd + languageName: node + linkType: hard + "tslib@npm:~2.6.2": version: 2.6.2 resolution: "tslib@npm:2.6.2" @@ -3952,7 +4295,7 @@ __metadata: version: 0.0.0-use.local resolution: "voila-ui-tests@workspace:." dependencies: - "@jupyterlab/galata": ^5.0.0-beta.0 + "@jupyterlab/galata": ^5.2.5 languageName: unknown linkType: soft diff --git a/voila/app.py b/voila/app.py index 9476403cf..609e6d3e9 100644 --- a/voila/app.py +++ b/voila/app.py @@ -20,6 +20,10 @@ import threading import webbrowser +from .tornado.kernel_websocket_handler import VoilaKernelWebsocketHandler + +from .tornado.execution_request_handler import ExecutionRequestHandler + from .tornado.contentshandler import VoilaContentsHandler from urllib.parse import urljoin @@ -37,7 +41,6 @@ try: JUPYTER_SERVER_2 = True - from jupyter_server.services.kernels.websocket import KernelWebsocketHandler from jupyter_server.auth.authorizer import AllowAllAuthorizer, Authorizer from jupyter_server.auth.identity import PasswordIdentityProvider from jupyter_server import DEFAULT_TEMPLATE_PATH_LIST, DEFAULT_STATIC_FILES_PATH @@ -59,7 +62,6 @@ except ImportError: JUPYTER_SERVER_2 = False - from jupyter_server.services.kernels.handlers import ZMQChannelsHandler from jupyter_server.utils import url_path_join, run_sync from jupyter_server.services.config import ConfigManager @@ -188,6 +190,7 @@ class Voila(Application): "pool_size": "VoilaConfiguration.default_pool_size", "show_tracebacks": "VoilaConfiguration.show_tracebacks", "preheat_kernel": "VoilaConfiguration.preheat_kernel", + "progressive_rendering": "VoilaConfiguration.progressive_rendering", "strip_sources": "VoilaConfiguration.strip_sources", "template": "VoilaConfiguration.template", "theme": "VoilaConfiguration.theme", @@ -611,6 +614,17 @@ def init_settings(self) -> Dict: if preheat_kernel and self.prelaunch_hook: raise Exception("`preheat_kernel` and `prelaunch_hook` are incompatible") + progressive_rendering = self.voila_configuration.progressive_rendering + if preheat_kernel and progressive_rendering: + raise Exception( + "`preheat_kernel` and `progressive_rendering` are incompatible" + ) + + if not JUPYTER_SERVER_2 and progressive_rendering: + raise Exception( + "`progressive_rendering` can only be enabled with jupyter_server>=2" + ) + kernel_manager_class = voila_kernel_manager_factory( self.voila_configuration.multi_kernel_manager_class, preheat_kernel, @@ -714,7 +728,7 @@ def init_handlers(self) -> List: url_path_join( self.server_url, r"/api/kernels/%s/channels" % _kernel_id_regex ), - KernelWebsocketHandler if JUPYTER_SERVER_2 else ZMQChannelsHandler, + VoilaKernelWebsocketHandler, ), ( url_path_join(self.server_url, r"/voila/templates/(.*)"), @@ -754,6 +768,15 @@ def init_handlers(self) -> List: RequestInfoSocketHandler, ) ) + if self.voila_configuration.progressive_rendering: + handlers.append( + ( + url_path_join( + self.server_url, r"/voila/execution/%s" % _kernel_id_regex + ), + ExecutionRequestHandler, + ) + ) # Serving JupyterLab extensions handlers.append( ( @@ -865,6 +888,8 @@ def listen(self): try: self.app.listen(port, self.ip) self.port = port + if self.voila_configuration.progressive_rendering: + self.log.info("Progressive rendering is activated") self.log.info("Voilà is running at:\n%s" % self.display_url) except OSError as e: if e.errno == errno.EADDRINUSE: diff --git a/voila/configuration.py b/voila/configuration.py index e44fb338f..229aa1ec9 100644 --- a/voila/configuration.py +++ b/voila/configuration.py @@ -217,3 +217,11 @@ def _valid_file_blacklist(self, proposal): config=True, help="""Whether or not voila should attempt to fix and resolve a notebooks kernelspec metadata""", ) + + progressive_rendering = Bool( + False, + config=True, + help="""Flag to enable or disable progressive rendering option. + This option is not compatible with preheat-kernel option. + """, + ) diff --git a/voila/handler.py b/voila/handler.py index 22a541524..059e23ca8 100644 --- a/voila/handler.py +++ b/voila/handler.py @@ -19,6 +19,8 @@ from tornado.httputil import split_host_and_port from traitlets.traitlets import Bool +from voila.tornado.execution_request_handler import ExecutionRequestHandler + from .configuration import VoilaConfiguration from ._version import __version__ @@ -236,6 +238,12 @@ def time_out(): ) kernel_future = self.kernel_manager.get_kernel(kernel_id) queue = asyncio.Queue() + if self.voila_configuration.progressive_rendering: + ExecutionRequestHandler._execution_data[kernel_id] = { + "nb": gen.notebook, + "config": self.traitlet_config, + "show_tracebacks": self.voila_configuration.show_tracebacks, + } async def put_html(): async for html_snippet, _ in gen.generate_content_generator( diff --git a/voila/notebook_renderer.py b/voila/notebook_renderer.py index 2ba094e59..c1a8791d3 100644 --- a/voila/notebook_renderer.py +++ b/voila/notebook_renderer.py @@ -13,7 +13,7 @@ import traceback from functools import partial from copy import deepcopy -from typing import Generator, List, Tuple, Union +from typing import AsyncGenerator, Generator, List, Tuple, Union import nbformat import tornado.web @@ -156,7 +156,7 @@ def generate_content_generator( self, kernel_id: Union[str, None] = None, kernel_future=None, - ) -> Generator: + ) -> AsyncGenerator: inner_kernel_start = partial( self._jinja_kernel_start, kernel_id=kernel_id, kernel_future=kernel_future ) @@ -171,9 +171,16 @@ def generate_content_generator( "frontend": "voila", "main_js": "voila.js", "kernel_start": inner_kernel_start, - "cell_generator": self._jinja_cell_generator, "notebook_execute": self._jinja_notebook_execute, + "progressive_rendering": self.voila_configuration.progressive_rendering, } + if self.voila_configuration.progressive_rendering: + extra_context["cell_generator"] = ( + self._jinja_cell_generator_without_execution + ) + else: + extra_context["cell_generator"] = self._jinja_cell_generator + # render notebook in snippets, then return an iterator so we can flush # them out to the browser progressively. return self.exporter.generate_from_notebook_node( @@ -242,15 +249,30 @@ async def _jinja_kernel_start(self, nb, kernel_id, kernel_future): return kernel_id async def _jinja_notebook_execute(self, nb, kernel_id): - result = await self.executor.async_execute(cleanup_kc=False) # we modify the notebook in place, since the nb variable cannot be # reassigned it seems in jinja2 e.g. if we do {% with nb = notebook_execute(nb, kernel_id) %} # ,the base template/blocks will not see the updated variable # (it seems to be local to our block) + if self.voila_configuration.progressive_rendering: + result, _ = ClearOutputPreprocessor().preprocess( + nb, {"metadata": {"path": self.cwd}} + ) + else: + result = await self.executor.async_execute(cleanup_kc=False) + nb.cells = result.cells await self._cleanup_resources() + async def _jinja_cell_generator_without_execution(self, nb, kernel_id): + nb, _ = ClearOutputPreprocessor().preprocess( + nb, {"metadata": {"path": self.cwd}} + ) + for input_cell in nb.cells: + output = input_cell.copy() + yield output + await self._cleanup_resources() + async def _jinja_cell_generator(self, nb, kernel_id): """Generator that will execute a single notebook cell at a time""" nb, _ = ClearOutputPreprocessor().preprocess( diff --git a/voila/request_info_handler.py b/voila/request_info_handler.py index 57e8ac610..8e1596b85 100644 --- a/voila/request_info_handler.py +++ b/voila/request_info_handler.py @@ -44,7 +44,7 @@ def send_updates(cls: "RequestInfoSocketHandler", msg: Dict) -> None: notebook. This method is called in `VoilaHandler` when the request info becomes available. If this method is called before the opening of websocket connection, - `msg` is stored in `_cache0` and the message will be dispatched when + `msg` is stored in `_cache` and the message will be dispatched when a notebook with corresponding kernel id is connected. Args: @@ -59,5 +59,5 @@ def send_updates(cls: "RequestInfoSocketHandler", msg: Dict) -> None: waiter.write_message(payload) except Exception: logging.error("Error sending message", exc_info=True) - - cls._cache[kernel_id] = payload + else: + cls._cache[kernel_id] = payload diff --git a/voila/server_extension.py b/voila/server_extension.py index 6a5a99b47..37e69b446 100644 --- a/voila/server_extension.py +++ b/voila/server_extension.py @@ -16,6 +16,8 @@ from jupyterlab_server.themes_handler import ThemesHandler from jupyter_core.paths import jupyter_config_path from jupyter_server.serverapp import ServerApp + +from .tornado.execution_request_handler import ExecutionRequestHandler, JUPYTER_SERVER_2 from .tornado.contentshandler import VoilaContentsHandler from traitlets.config import ( JSONFileConfigLoader, @@ -35,6 +37,8 @@ from .tornado.treehandler import TornadoVoilaTreeHandler from .utils import get_data_dir, get_server_root_dir, pjoin +_kernel_id_regex = r"(?P\w+-\w+-\w+-\w+-\w+)" + def _jupyter_server_extension_points(): """ @@ -105,67 +109,72 @@ def _load_jupyter_server_extension(server_app: ServerApp): tree_handler_conf = {"voila_configuration": voila_configuration} themes_dir = pjoin(get_data_dir(), "themes") - web_app.add_handlers( - host_pattern, - [ - ( - url_path_join(base_url, "/voila/render/(.*)"), - TornadoVoilaHandler, - { - "config": server_app.config, - "template_paths": template_paths, - "voila_configuration": voila_configuration, - }, - ), - ( - url_path_join(base_url, "/voila"), - TornadoVoilaTreeHandler, - tree_handler_conf, - ), + handlers = [ + ( + url_path_join(base_url, "/voila/render/(.*)"), + TornadoVoilaHandler, + { + "config": server_app.config, + "template_paths": template_paths, + "voila_configuration": voila_configuration, + }, + ), + ( + url_path_join(base_url, "/voila"), + TornadoVoilaTreeHandler, + tree_handler_conf, + ), + ( + url_path_join(base_url, "/voila/tree" + path_regex), + TornadoVoilaTreeHandler, + tree_handler_conf, + ), + ( + url_path_join(base_url, "/voila/templates/(.*)"), + TemplateStaticFileHandler, + ), + ( + url_path_join(base_url, r"/voila/api/themes/(.*)"), + ThemesHandler, + { + "themes_url": "/voila/api/themes", + "path": themes_dir, + "labextensions_path": jupyter_path("labextensions"), + "no_cache_paths": ["/"], + }, + ), + ( + url_path_join(base_url, "/voila/static/(.*)"), + MultiStaticFileHandler, + {"paths": static_paths}, + ), + ( + url_path_join(base_url, r"/voila/api/shutdown/(.*)"), + VoilaShutdownKernelHandler, + ), + ( + url_path_join(base_url, r"/voila/files/(.*)"), + AllowListFileHandler, + { + "allowlist": voila_configuration.file_allowlist, + "denylist": voila_configuration.file_denylist, + "path": os.path.expanduser(get_server_root_dir(web_app.settings)), + }, + ), + ( + url_path_join(base_url, r"/voila/api/contents%s" % path_regex), + VoilaContentsHandler, + tree_handler_conf, + ), + ] + if JUPYTER_SERVER_2 and voila_configuration.progressive_rendering: + handlers.append( ( - url_path_join(base_url, "/voila/tree" + path_regex), - TornadoVoilaTreeHandler, - tree_handler_conf, - ), - ( - url_path_join(base_url, "/voila/templates/(.*)"), - TemplateStaticFileHandler, - ), - ( - url_path_join(base_url, r"/voila/api/themes/(.*)"), - ThemesHandler, - { - "themes_url": "/voila/api/themes", - "path": themes_dir, - "labextensions_path": jupyter_path("labextensions"), - "no_cache_paths": ["/"], - }, - ), - ( - url_path_join(base_url, "/voila/static/(.*)"), - MultiStaticFileHandler, - {"paths": static_paths}, - ), - ( - url_path_join(base_url, r"/voila/api/shutdown/(.*)"), - VoilaShutdownKernelHandler, - ), - ( - url_path_join(base_url, r"/voila/files/(.*)"), - AllowListFileHandler, - { - "allowlist": voila_configuration.file_allowlist, - "denylist": voila_configuration.file_denylist, - "path": os.path.expanduser(get_server_root_dir(web_app.settings)), - }, - ), - ( - url_path_join(base_url, r"/voila/api/contents%s" % path_regex), - VoilaContentsHandler, - tree_handler_conf, - ), - ], - ) + url_path_join(base_url, r"/voila/execution/%s" % _kernel_id_regex), + ExecutionRequestHandler, + ) + ) + web_app.add_handlers(host_pattern, handlers) # Serving lab extensions # TODO: reuse existing lab server endpoint? diff --git a/voila/tornado/execution_request_handler.py b/voila/tornado/execution_request_handler.py new file mode 100644 index 000000000..61d85bca9 --- /dev/null +++ b/voila/tornado/execution_request_handler.py @@ -0,0 +1,144 @@ +import asyncio +import json +from typing import Awaitable, Union +from jupyter_server.base.handlers import JupyterHandler +from tornado.websocket import WebSocketHandler +from tornado.web import HTTPError + +try: + JUPYTER_SERVER_2 = True + from jupyter_server.base.websocket import WebSocketMixin +except ImportError: + JUPYTER_SERVER_2 = False +from jupyter_core.utils import ensure_async +from nbclient.exceptions import CellExecutionError +from voila.execute import VoilaExecutor, strip_code_cell_warnings +import nbformat +import traceback +import sys + +if JUPYTER_SERVER_2: + + class ExecutionRequestHandler(WebSocketMixin, WebSocketHandler, JupyterHandler): + _execution_data = {} + + def initialize(self, **kwargs): + super().initialize() + + async def open(self, kernel_id: str) -> None: + """Create a new websocket connection, this connection is + identified by the kernel id. + + Args: + kernel_id (str): Kernel id used by the notebook when it opens + the websocket connection. + """ + identity_provider = self.settings.get("identity_provider") + user = await ensure_async(identity_provider.get_user(self)) + if user is None: + raise HTTPError(403, "Unauthenticated") + super().open() + + self._kernel_id = kernel_id + self.write_message({"action": "initialized", "payload": {}}) + + async def on_message( + self, message_str: Union[str, bytes] + ) -> Union[Awaitable[None], None]: + message = json.loads(message_str) + action = message.get("action", None) + payload = message.get("payload", {}) + if action == "execute": + request_kernel_id = payload.get("kernel_id") + if request_kernel_id != self._kernel_id: + await self.write_message( + { + "action": "execution_error", + "payload": {"error": "Kernel ID does not match"}, + } + ) + return + kernel_future = self.kernel_manager.get_kernel(self._kernel_id) + km = await ensure_async(kernel_future) + execution_data = self._execution_data.pop(self._kernel_id, None) + if execution_data is None: + await self.write_message( + { + "action": "execution_error", + "payload": {"error": "Missing notebook data"}, + } + ) + return + nb = execution_data["nb"] + self._executor = executor = VoilaExecutor( + nb, + km=km, + config=execution_data["config"], + show_tracebacks=execution_data["show_tracebacks"], + ) + executor.kc = await executor.async_start_new_kernel_client() + total_cell = len(nb.cells) + for cell_idx, input_cell in enumerate(nb.cells): + try: + output_cell = await executor.execute_cell( + input_cell, None, cell_idx, store_history=False + ) + except TimeoutError: + output_cell = input_cell + + except CellExecutionError: + self.log.exception( + "Error at server while executing cell: %r", input_cell + ) + if executor.should_strip_error(): + strip_code_cell_warnings(input_cell) + executor.strip_code_cell_errors(input_cell) + output_cell = input_cell + + except Exception as e: + self.log.exception( + "Error at server while executing cell: %r", input_cell + ) + output_cell = nbformat.v4.new_code_cell() + if executor.should_strip_error(): + output_cell.outputs = [ + { + "output_type": "stream", + "name": "stderr", + "text": "An exception occurred at the server (not the notebook). {}".format( + executor.cell_error_instruction + ), + } + ] + else: + output_cell.outputs = [ + { + "output_type": "error", + "ename": type(e).__name__, + "evalue": str(e), + "traceback": traceback.format_exception( + *sys.exc_info() + ), + } + ] + finally: + output_cell.pop("source", None) + await self.write_message( + { + "action": "execution_result", + "payload": { + "output_cell": output_cell, + "cell_index": cell_idx, + "total_cell": total_cell, + }, + } + ) + + def on_close(self) -> None: + if self._executor and self._executor.kc: + asyncio.create_task(ensure_async(self._executor.kc.stop_channels())) + +else: + + class ExecutionRequestHandler: + pass diff --git a/voila/tornado/kernel_websocket_handler.py b/voila/tornado/kernel_websocket_handler.py new file mode 100644 index 000000000..67c4a86e6 --- /dev/null +++ b/voila/tornado/kernel_websocket_handler.py @@ -0,0 +1,43 @@ +import json +from typing import Any, Dict, Optional, Union + +try: + from jupyter_server.services.kernels.websocket import ( + KernelWebsocketHandler as WebsocketHandler, + ) +except ImportError: + from jupyter_server.services.kernels.handlers import ( + ZMQChannelsHandler as WebsocketHandler, + ) + + +def read_header_from_binary_message(ws_msg: bytes) -> Optional[Dict]: + """Read message header using the v1 protocol.""" + + offset_number = int.from_bytes(ws_msg[:8], "little") + offsets = [ + int.from_bytes(ws_msg[8 * (i + 1) : 8 * (i + 2)], "little") + for i in range(offset_number) + ] + try: + header = ws_msg[offsets[1] : offsets[2]].decode("utf-8") + return json.loads(header) + except Exception: + return + + +class VoilaKernelWebsocketHandler(WebsocketHandler): + def write_message( + self, message: Union[bytes, Dict[str, Any]], binary: bool = False + ): + if isinstance(message, bytes): + header = read_header_from_binary_message(message) + elif isinstance(message, dict): + header = message.get("header", None) + else: + header = None + + if header and header.get("msg_type", None) == "execute_input": + return # Ignore execute_input message + + return super().write_message(message, binary) diff --git a/voila/utils.py b/voila/utils.py index c17bb160e..3878c9561 100644 --- a/voila/utils.py +++ b/voila/utils.py @@ -99,6 +99,7 @@ def get_page_config(base_url, settings, log, voila_configuration: VoilaConfigura "fullStaticUrl": url_path_join(base_url, "voila/static"), "fullLabextensionsUrl": url_path_join(base_url, "voila/labextensions"), "extensionConfig": voila_configuration.extension_config, + "progressiveRendering": voila_configuration.progressive_rendering, } mathjax_config = settings.get("mathjax_config", "TeX-AMS_CHTML-full,Safe") mathjax_url = settings.get(