Compare commits

..

3 Commits
main ... 7.1.x

Author SHA1 Message Date
jtpio 48690a3f13 Publish 7.1.3
2 years ago
Lumberbot (aka Jack) c1453abee5
Backport PR #7327: Fix scrollbar always showing up by default (#7328)
2 years ago
Lumberbot (aka Jack) 22eedd39e0
Backport PR #7308: Ignore links to GitHub user and organisation profiles (#7309)
2 years ago

@ -1,13 +0,0 @@
FROM mcr.microsoft.com/devcontainers/base:jammy
ARG PIXI_VERSION=v0.42.1
RUN curl -L -o /usr/local/bin/pixi -fsSL --compressed "https://github.com/prefix-dev/pixi/releases/download/${PIXI_VERSION}/pixi-$(uname -m)-unknown-linux-musl" \
&& chmod +x /usr/local/bin/pixi \
&& pixi info
# set some user and workdir settings to work nicely with vscode
USER vscode
WORKDIR /home/vscode
RUN echo 'eval "$(pixi completion -s bash)"' >> /home/vscode/.bashrc

@ -1,21 +0,0 @@
{
"name": "Jupyter Notebook",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
"forwardPorts": [8888],
"customizations": {
"vscode": {
"settings": {},
"extensions": ["ms-python.python", "charliermarsh.ruff", "GitHub.copilot"]
}
},
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"mounts": [
"source=${localWorkspaceFolderBasename}-pixi,target=${containerWorkspaceFolder}/.pixi,type=volume"
],
"postCreateCommand": "sudo chown vscode .pixi && pixi install && pixi run develop && pixi run pre-commit install -f"
}

@ -18,6 +18,3 @@ app/index.template.js
# ms IDE stuff
.history/
.vscode/
# Pixi environments
.pixi

2
.gitattributes vendored

@ -1,2 +0,0 @@
# SCM syntax highlighting & preventing 3-way merges
pixi.lock merge=binary linguist-language=YAML linguist-generated=true

@ -3,11 +3,11 @@ contact_links:
- name: Is this a common issue? See our Docs.
url: https://jupyter-notebook.readthedocs.io/en/latest/troubleshooting.html#what-to-do-when-things-go-wrong
about: Before opening an issue, make sure your issue hasn't already been addressed in the documentation.
- name: 🤔 Support and all other questions, including if you're not sure what to do.
- name: \U0001F914 Support and all other questions, including if you're not sure what to do.
url: https://discourse.jupyter.org/c/notebook/31
about: If you have a question or you're having issues installing Jupyter Notebook, try posting on Discourse.
- name: 💬 Chat with the devs
url: https://jupyter.zulipchat.com/
- name: "\U0001F4AC Chat with the devs"
url: https://app.gitter.im/#/room/#jupyter_notebook:gitter.im
about: Ask short questions about using Jupyter Notebook
- name: 📝 Do you have a feature request that may be applied upstream? See JupyterLab.
url: https://github.com/jupyterlab/jupyterlab

@ -14,4 +14,4 @@ jobs:
permissions:
pull-requests: write
steps:
- uses: toshimaru/auto-author-assign@v2.1.1
- uses: toshimaru/auto-author-assign@v2.1.0

@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Build
uses: ./.github/actions/build-dist
@ -38,10 +38,10 @@ jobs:
fail-fast: false
matrix:
# used by the jupyterlab/maintainer-tools base-setup action
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
@ -68,7 +68,7 @@ jobs:
needs:
- test
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/report-coverage@v1
with:
fail_under: 78
@ -77,7 +77,7 @@ jobs:
name: Test Docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- run: |
sudo apt-get update
@ -92,7 +92,7 @@ jobs:
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
with:
dependency_type: minimum
@ -106,7 +106,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
with:
dependency_type: pre
@ -122,13 +122,13 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python: ['3.9', '3.11', '3.13']
python: ['3.8', '3.11', '3.12']
include:
- python: '3.9'
- python: '3.8'
dist: 'notebook*.tar.gz'
- python: '3.11'
dist: 'notebook*.whl'
- python: '3.13'
- python: '3.12'
dist: 'notebook*.whl'
- os: windows-latest
py_cmd: python
@ -138,11 +138,12 @@ jobs:
py_cmd: python
steps:
- name: Install Python
uses: actions/setup-python@v6
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
architecture: 'x64'
allow-prereleases: true
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v4
with:
name: notebook-dist-${{ github.run_number }}
path: ./dist
@ -170,18 +171,18 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1
with:
ignore_links: 'https://playwright.dev/docs/test-cli/ https://blog.jupyter.org/.* https://mybinder.org/v2/gh/jupyter/notebook/main https://nbviewer.jupyter.org https://stackoverflow.com https://github.com/[^/]+/?$'
ignore_links: 'https://playwright.dev/docs/test-cli/ https://blog.jupyter.org/the-big-split-9d7b88a031a7 https://blog.jupyter.org/jupyter-ascending-1bf5b362d97e https://mybinder.org/v2/gh/jupyter/notebook/main https://nbviewer.jupyter.org https://stackoverflow.com https://github.com/[^/]+/?$'
ignore_glob: 'ui-tests/test/notebooks/*'
test_lint:
name: Test Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Run Linters
run: |

@ -22,14 +22,14 @@ jobs:
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Install dependencies
run: |
python -m pip install -U "jupyterlab>=4.6.0a0,<4.7" hatch
python -m pip install -U "jupyterlab>=4.1.1,<4.2" hatch
jlpm
jlpm run build
@ -69,16 +69,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Install Python
uses: actions/setup-python@v6
uses: actions/setup-python@v5
with:
python-version: '3.10'
python-version: '3.9'
architecture: 'x64'
- name: Install dependencies
run: |
python -m pip install -U "jupyterlab>=4.6.0a0,<4.7" pip
python -m pip install -U "jupyterlab>=4.1.1,<4.2" pip
jlpm
jlpm run build

@ -17,7 +17,7 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Check Release
@ -27,7 +27,7 @@ jobs:
version_spec: next
- name: Upload Distributions
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: notebook-jupyter-releaser-dist-${{ github.run_number }}
path: .jupyter_releaser_checkout/dist

@ -9,19 +9,7 @@ permissions:
jobs:
update-snapshots:
if: >
(
github.event.issue.author_association == 'OWNER' ||
github.event.issue.author_association == 'COLLABORATOR' ||
github.event.issue.author_association == 'MEMBER' ||
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 playwright snapshots') ||
contains(github.event.comment.body, 'please update galata snapshots') ||
contains(github.event.comment.body, 'please update snapshots')
)
if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, 'update playwright snapshots') }}
runs-on: ubuntu-latest
permissions:
# Required by actions/update-snapshots
@ -34,7 +22,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: React to the triggering comment
run: |
@ -42,43 +30,14 @@ jobs:
env:
GITHUB_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 }}
- name: Checkout the branch from the PR that triggered the job
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
# PR branch remote must be checked out using https URL
git config --global hub.protocol https
- name: Checkout the branch from the PR that triggered the job
gh 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
@ -86,7 +45,7 @@ jobs:
- name: Build
uses: ./.github/actions/build-dist
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v4
with:
name: notebook-dist-${{ github.run_number }}
path: ./dist

@ -16,7 +16,7 @@ jobs:
steps:
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- uses: actions/create-github-app-token@v2
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.APP_ID }}

@ -20,10 +20,8 @@ jobs:
id-token: write
steps:
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
with:
node_version: '24'
- uses: actions/create-github-app-token@v2
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.APP_ID }}

@ -19,14 +19,14 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Build
uses: ./.github/actions/build-dist
ui-tests:
needs: [build]
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
timeout-minutes: 20
strategy:
fail-fast: false
@ -34,12 +34,12 @@ jobs:
browser: [firefox, chromium]
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v4
with:
name: notebook-dist-${{ github.run_number }}
path: ./dist
@ -62,7 +62,7 @@ jobs:
- name: Upload Playwright Test assets
if: always()
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: notebook-${{ matrix.browser }}-test-assets
path: |
@ -70,7 +70,7 @@ jobs:
- name: Upload Playwright Test report
if: always()
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: notebook-${{ matrix.browser }}-test-report
path: |
@ -87,7 +87,7 @@ jobs:
- name: Upload updated snapshots
if: failure()
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: notebook-${{ matrix.browser }}-updated-snapshots
path: ui-tests/test

@ -1,128 +0,0 @@
name: Check for latest JupyterLab releases
on:
# schedule:
# - cron: 30 17 * * *
workflow_dispatch:
inputs:
version:
description: 'JupyterLab version'
default: latest
required: true
type: string
branch:
description: 'The branch to target'
default: main
required: false
type: string
target_repo:
description: 'Target repository'
required: false
default: jupyter/notebook
type: string
env:
version_tag: 'latest'
permissions:
actions: write
contents: write
pull-requests: write
jobs:
check_for_lab_updates:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
ref: ${{ inputs.branch || 'main' }}
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install Node
uses: actions/setup-node@v6
with:
node-version: '20.x'
- name: Install npm dependencies and build buildutils
run: |
python -m pip install -e ".[dev]"
jlpm
jlpm run build:utils
- name: Check for new releases and update
shell: bash
run: |
set -eux
for version in ${{ inputs.version || env.version_tag }}
do
if [[ "${version}" == "latest" ]]; then
export LATEST=$(jlpm run get:lab:version --set-version ${version})
else
export LATEST=${version}
fi
done
echo "latest=${LATEST}" >> $GITHUB_ENV
jlpm upgrade:lab:dependencies --set-version ${LATEST}
if [[ ! -z "$(git status --porcelain package.json)" ]]; then
jlpm
jlpm deduplicate
cd ui-tests
jlpm
jlpm deduplicate
fi
- uses: prefix-dev/setup-pixi@v0.9.3
with:
pixi-version: v0.41.4
manifest-path: pyproject.toml
locked: false
- name: Update pixi.lock
run: pixi install
- name: Create a PR
env:
GITHUB_TOKEN: ${{ secrets.PERSONAL_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
run: |
set -eux
export LATEST=${{ env.latest }}
export BRANCH_NAME=update-to-v${LATEST}
# if resulted in any change:
if [[ ! -z "$(git status --porcelain package.json)" ]]; then
# if branch already exists.
if git ls-remote --heads origin | grep "refs/heads/${BRANCH_NAME}$" > /dev/null; then
echo "Branch '${BRANCH_NAME}' exists."
else
# new branch is created
git checkout -b "${BRANCH_NAME}"
git config user.name "github-actions[bot]"
git config user.email 'github-actions[bot]@users.noreply.github.com'
git commit . -m "Update to JupyterLab v${LATEST}"
git push --set-upstream origin "${BRANCH_NAME}"
PR_ARGS=(
--base "${{ inputs.branch || 'main' }}"
--title "Update to JupyterLab v${LATEST}"
--body "New JupyterLab release [v${LATEST}](https://github.com/jupyterlab/jupyterlab/releases/tag/v${LATEST}) is available. Please review the lock file carefully."
)
# Add --repo flag only if target_repo is specified
if [[ -n "${{ inputs.target_repo }}" ]]; then
PR_ARGS+=(--repo "${{ inputs.target_repo }}")
fi
gh pr create "${PR_ARGS[@]}"
fi
fi

13
.gitignore vendored

@ -135,16 +135,3 @@ ui-tests/playwright-report
.pnp.*
ui-tests/.yarn/*
ui-tests/.pnp.*
# keep potential upstream patches
!.yarn/patches
# generated html
notebook/templates/*.html
# pixi environments
.pixi
*.egg-info
# Temporary files used for testing
tmp/

@ -0,0 +1,58 @@
github:
prebuilds:
master: true
pullRequests: true
pullRequestsFromForks: true
addCheck: false
addComment: false
addBadge: false
addLabel: false
tasks:
- name: setup
init: |
pushd /workspace
wget -qO- https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba
popd
# bootstrap activation commands for other tasks to reuse
cat <<EOT > /workspace/bin/activate-env.sh
export MAMBA_ROOT_PREFIX=/workspace/.micromamba
export MAMBA_EXE=/workspace/bin/micromamba
$(/workspace/bin/micromamba shell hook --shell=bash)
export JUPYTER_PREFER_ENV_PATH=1
export TZ=UTC
micromamba activate
EOT
source /workspace/bin/activate-env.sh
micromamba install -n base -y -c conda-forge python=3.11 nodejs=18
source /workspace/bin/activate-env.sh
python -m pip install -e ".[dev,test]" && jlpm run build && jlpm develop
gp sync-done setup
command: |
gp sync-done setup
source /workspace/bin/activate-env.sh
jupyter notebook --no-browser --ServerApp.token='' --ServerApp.allow_remote_access=True
- name: auto-activate
command: |
gp sync-await setup
source /workspace/bin/activate-env.sh
jlpm watch
- name: shell
command: |
gp sync-await setup
echo "source /workspace/bin/activate-env.sh" >> ~/.bashrc
source /workspace/bin/activate-env.sh
- name: docs
command: |
gp sync-await setup
sudo apt-get update
sudo apt install enchant-2 -y
wget https://github.com/jgm/pandoc/releases/download/2.14.2/pandoc-2.14.2-1-amd64.deb -O /tmp/pandoc.deb && sudo dpkg -i /tmp/pandoc.deb
source /workspace/bin/activate-env.sh
hatch run docs:build
hatch run docs:serve
ports:
- port: 8888

@ -4,7 +4,7 @@ ci:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
rev: v4.5.0
hooks:
- id: check-case-conflict
- id: check-ast
@ -21,31 +21,30 @@ repos:
- id: trailing-whitespace
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.30.0
rev: 0.27.4
hooks:
- id: check-github-workflows
- repo: https://github.com/codespell-project/codespell
rev: 'v2.3.0'
rev: 'v2.2.6'
hooks:
- id: codespell
args: ['-L', 'hart,noteable', '--skip', "*.spec.ts"]
args: ['-L', 'hart,noteable']
exclude: |
(?x)^(
yarn.lock|
pixi.lock|
binder/example.ipynb|
docs/source/examples/images/FrontendKernel.graffle/data.plist|
)$
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.14.1"
rev: "v1.8.0"
hooks:
- id: mypy
files: "^notebook"
stages: [manual]
args: ["--install-types", "--non-interactive"]
additional_dependencies: ["traitlets>=5.13", "tornado", "jupyter_server>=2.10", "jupyterlab_server>=2.25", "jupyterlab>=4.6.0a0,<4.7"]
additional_dependencies: ["traitlets>=5.13", "tornado", "jupyter_server>=2.10", "jupyterlab_server>=2.25", "jupyterlab>=4.1.1,<4.2"]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: 'v1.10.0'
@ -55,7 +54,7 @@ repos:
- id: rst-inline-touching-normal
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.6
rev: v0.2.0
hooks:
- id: ruff
types_or: [ python, jupyter ]
@ -66,7 +65,7 @@ repos:
exclude: '^docs/source/examples/Notebook/Importing Notebooks.ipynb'
- repo: https://github.com/scientific-python/cookie
rev: '2024.08.19'
rev: '2024.01.24'
hooks:
- id: sp-repo-review
additional_dependencies: ['repo-review[cli]']
@ -83,4 +82,4 @@ repos:
name: integrity
entry: 'npm run integrity --force'
language: node
stages: [pre-push]
stages: [push]

@ -9,4 +9,3 @@ node_modules
build
CHANGELOG.md
app/index.template.js
.pixi

File diff suppressed because it is too large Load Diff

@ -2,7 +2,7 @@
Thanks for contributing to Jupyter Notebook!
Make sure to follow [Project Jupyter's Code of Conduct](https://jupyter.org/governance/conduct/code-of-conduct)
Make sure to follow [Project Jupyter's Code of Conduct](https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md)
for a friendly and welcoming collaborative environment.
## Setting up a development environment
@ -12,7 +12,7 @@ Note: You will need NodeJS to build the extension package.
The `jlpm` command is JupyterLab's pinned version of [yarn](https://yarnpkg.com/) that is installed with JupyterLab. You may use
`yarn` or `npm` in lieu of `jlpm` below.
**Note**: we recommend using `mamba` to speed up the creation of the environment.
**Note**: we recommend using `mamba` to speed the creating of the environment.
```bash
# create a new environment
@ -22,11 +22,7 @@ mamba create -n notebook -c conda-forge python nodejs -y
mamba activate notebook
# Install package in development mode
pip install -e ".[dev,docs,test]"
# Install dependencies and build packages
jlpm
jlpm build
pip install -e ".[dev,test]"
# Link the notebook extension and @jupyter-notebook schemas
jlpm develop
@ -72,24 +68,25 @@ jupyter notebook
### Local changes in Notebook dependencies
The development installation described above fetches JavaScript dependencies from `npm`.
The development installation described above fetches JavaScript dependencies from [npmjs](https://www.npmjs.com/),
according to the versions in the _package.json_ file.
However, it is sometimes useful to be able to test changes in Notebook, with dependencies (e.g. `@jupyterlab` packages) that have not yet
been published.
[yalc](https://github.com/wclr/yalc) can help you use local JavaScript packages when building Notebook, acting as a local package repository.
[yalc](https://github.com/wclr/yalc) can help use local JavaScript packages in your build of
Notebook, acting as a local package repository.
- Install yalc globally in your environment:
- Install yalc globally in you environment:
`npm install -g yalc`
- Publish your dependency package:\
- Publish you dependency package:\
`yalc publish`, from the package root directory.\
For instance, if you are developing on _@jupyterlab/ui-components_, this command must be executed from
For instance, if you have are developing on _@jupyterlab/ui-components_, this command must be executed from
_path_to_jupyterlab/packages/ui-components_.
- Depend on this local repository in Notebook:
- from the Notebook root directory:\
`yalc add your_package` : this will create a _dependencies_ entry in the main _package.json_ file.\
With the previous example, it would be `yalc add @jupyterlab/ui-components`.
- Notebook is a monorepo, so we want this dependency to be 'linked' as a resolution (for all sub-packages) instead
- Notebook is a monerepo, so we want this dependency to be 'linked' as a resolution (for all sub-packages) instead
of a dependency.\
The easiest way is to manually move the new entry in _package.json_ from _dependencies_ to _resolutions_.
- Build Notebook with the local dependency:\
@ -131,11 +128,11 @@ jlpm test
The `test` script calls the Playwright test runner. You can pass additional arguments to `playwright` by appending parameters to the command. For example to run the test in headed mode, `jlpm test --headed`.
Check out the [Playwright Command Line Reference](https://playwright.dev/docs/test-cli/) for more information about the available command line options.
Checkout the [Playwright Command Line Reference](https://playwright.dev/docs/test-cli/) for more information about the available command line options.
Running the end to end tests in headful mode will trigger something like the following:
![playwright-headed-demo](https://user-images.githubusercontent.com/591645/141274633-ca9f9c2f-eef6-430e-9228-a35827f8133d.gif)
![playwight-headed-demo](https://user-images.githubusercontent.com/591645/141274633-ca9f9c2f-eef6-430e-9228-a35827f8133d.gif)
## Tasks caching
@ -172,11 +169,11 @@ This will trigger a GitHub Action that will run the UI tests automatically and p
## Code Styling
All non-python source code is formatted using [prettier](https://prettier.io) and python source code is formatted using [black](https://github.com/psf/black).
All non-python source code is formatted using [prettier](https://prettier.io) and python source code is formatted using [black](https://github.com/psf/black)s
When code is modified and committed, all staged files will be
automatically formatted using pre-commit git hooks (with help from
[pre-commit](https://github.com/pre-commit/pre-commit). The benefit of
using code formatters like `prettier` and `black` is that it removes the topic of
using a code formatters like `prettier` and `black` is that it removes the topic of
code style from the conversation when reviewing pull requests, thereby
speeding up the review process.
@ -211,7 +208,7 @@ yourself after that.
You may also use the prettier npm script (e.g. `npm run prettier` or
`yarn prettier` or `jlpm prettier`) to format the entire code base.
We recommend installing a prettier extension for your code editor and
configuring it to format your code with a keyboard shortcut, or
configuring it to format your code with a keyboard shortcut or
automatically on save.
Some of the hooks only run on CI by default, but you can invoke them by
@ -239,9 +236,6 @@ Now open a web browser and navigate to `http://localhost:8000` to access the doc
Alternatively you can also contribute to Jupyter Notebook without setting up a local environment, directly from a web browser:
- [GitHub CodeSpaces](https://github.com/codespaces) is directly integrated into GitHub. This repository uses the [pixi](https://pixi.sh/) package manager to set up the development environment. To contribute after the Codespace is started:
- Run `pixi shell` in a terminal to activate the development environment
- Use the commands above for building the extension and running the tests, for example: `jlpm build`
- To start the application: `pixi run start`. A popup should appear with a button to open the Jupyter Notebook in a new browser tab. If the popup does not appear, you can navigate to the "Forwarded ports" panel to find the URL to the application.
- GitHub's [built-in editor](https://docs.github.com/en/repositories/working-with-files/managing-files/editing-files) is suitable for contributing small fixes.
- A more advanced [github.dev](https://docs.github.com/en/codespaces/the-githubdev-web-based-editor) editor can be accessed by pressing the dot (.) key while in the Jupyter Notebook GitHub repository
- [Gitpod](https://gitpod.io/#https://github.com/jupyter/notebook) integration is enabled. The Gitpod config automatically builds the Jupyter Notebook application and the documentation.
- GitHubs [built-in editor](https://docs.github.com/en/repositories/working-with-files/managing-files/editing-files) is suitable for contributing small fixes
- A more advanced [github.dev](https://docs.github.com/en/codespaces/the-githubdev-web-based-editor) editor can be accessed by pressing the dot (.) key while in the Jupyter Notebook GitHub repository,

@ -3,6 +3,7 @@
![Github Actions Status](https://github.com/jupyter/notebook/workflows/Build/badge.svg)
[![Documentation Status](https://readthedocs.org/projects/jupyter-notebook/badge/?version=latest)](https://jupyter-notebook.readthedocs.io/en/latest/?badge=latest)
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jupyter/notebook/main?urlpath=tree)
[![Gitpod](https://img.shields.io/badge/gitpod_editor-open-blue.svg)](https://gitpod.io/#https://github.com/jupyter/notebook)
The Jupyter notebook is a web-based notebook environment for interactive
computing.

@ -5,8 +5,6 @@
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
import { PluginRegistry } from '@lumino/coreutils';
require('./style.js');
require('./extraStyle.js');
@ -215,20 +213,10 @@ async function main() {
// plugin even if the debugger is only loaded on the notebook page.
PageConfig.setOption('allPlugins', '{{{ json notebook_plugins }}}');
const pluginRegistry = new PluginRegistry();
const NotebookApp = require('@jupyter-notebook/application').NotebookApp;
const app = new NotebookApp({ mimeExtensions, availablePlugins });
pluginRegistry.registerPlugins(mods);
const IServiceManager = require('@jupyterlab/services').IServiceManager;
const serviceManager = await pluginRegistry.resolveRequiredService(IServiceManager);
const app = new NotebookApp({
pluginRegistry,
serviceManager,
mimeExtensions,
availablePlugins
});
app.registerPluginModules(mods);
// Expose global app instance when in dev mode or when toggled explicitly.
const exposeAppInBrowser =

@ -1,210 +1,203 @@
{
"name": "@jupyter-notebook/app",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"private": true,
"scripts": {
"build": "rspack",
"build:prod": "rspack --config ./rspack.prod.config.js",
"build": "webpack",
"build:prod": "webpack --mode=production",
"clean": "rimraf build && jlpm run clean:static",
"clean:static": "rimraf -g \"../notebook/static/!(favicons)\"",
"watch": "rspack --watch --config rspack.config.js"
"watch": "webpack --config ./webpack.config.watch.js"
},
"resolutions": {
"@codemirror/state": "~6.5.2",
"@codemirror/view": "~6.38.1",
"@jupyter-notebook/application": "~7.6.0-alpha.0",
"@jupyter-notebook/application-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/console-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/docmanager-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/documentsearch-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/help-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/notebook-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/terminal-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/tree": "~7.6.0-alpha.0",
"@jupyter-notebook/tree-extension": "~7.6.0-alpha.0",
"@jupyter-notebook/ui-components": "~7.6.0-alpha.0",
"@jupyter/react-components": "~0.16.7",
"@jupyter/web-components": "~0.16.7",
"@jupyter/ydoc": "~3.1.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/application-extension": "~4.6.0-alpha.0",
"@jupyterlab/apputils": "~4.7.0-alpha.0",
"@jupyterlab/apputils-extension": "~4.6.0-alpha.0",
"@jupyterlab/attachments": "~4.6.0-alpha.0",
"@jupyterlab/audio-extension": "~4.6.0-alpha.0",
"@jupyterlab/cell-toolbar": "~4.6.0-alpha.0",
"@jupyterlab/cell-toolbar-extension": "~4.6.0-alpha.0",
"@jupyterlab/celltags-extension": "~4.6.0-alpha.0",
"@jupyterlab/codeeditor": "~4.6.0-alpha.0",
"@jupyterlab/codemirror": "~4.6.0-alpha.0",
"@jupyterlab/codemirror-extension": "~4.6.0-alpha.0",
"@jupyterlab/completer": "~4.6.0-alpha.0",
"@jupyterlab/completer-extension": "~4.6.0-alpha.0",
"@jupyterlab/console": "~4.6.0-alpha.0",
"@jupyterlab/console-extension": "~4.6.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@jupyterlab/csvviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/debugger": "~4.6.0-alpha.0",
"@jupyterlab/debugger-extension": "~4.6.0-alpha.0",
"@jupyterlab/docmanager": "~4.6.0-alpha.0",
"@jupyterlab/docmanager-extension": "~4.6.0-alpha.0",
"@jupyterlab/documentsearch": "~4.6.0-alpha.0",
"@jupyterlab/documentsearch-extension": "~4.6.0-alpha.0",
"@jupyterlab/extensionmanager": "~4.6.0-alpha.0",
"@jupyterlab/extensionmanager-extension": "~4.6.0-alpha.0",
"@jupyterlab/filebrowser": "~4.6.0-alpha.0",
"@jupyterlab/filebrowser-extension": "~4.6.0-alpha.0",
"@jupyterlab/fileeditor": "~4.6.0-alpha.0",
"@jupyterlab/fileeditor-extension": "~4.6.0-alpha.0",
"@jupyterlab/help-extension": "~4.6.0-alpha.0",
"@jupyterlab/htmlviewer": "~4.6.0-alpha.0",
"@jupyterlab/htmlviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/hub-extension": "~4.6.0-alpha.0",
"@jupyterlab/imageviewer": "~4.6.0-alpha.0",
"@jupyterlab/imageviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/javascript-extension": "~4.6.0-alpha.0",
"@jupyterlab/json-extension": "~4.6.0-alpha.0",
"@jupyterlab/logconsole-extension": "~4.6.0-alpha.0",
"@jupyterlab/lsp": "~4.6.0-alpha.0",
"@jupyterlab/lsp-extension": "~4.6.0-alpha.0",
"@jupyterlab/mainmenu": "~4.6.0-alpha.0",
"@jupyterlab/mainmenu-extension": "~4.6.0-alpha.0",
"@jupyterlab/markdownviewer": "~4.6.0-alpha.0",
"@jupyterlab/markdownviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/markedparser-extension": "~4.6.0-alpha.0",
"@jupyterlab/mathjax-extension": "~4.6.0-alpha.0",
"@jupyterlab/mermaid": "~4.6.0-alpha.0",
"@jupyterlab/mermaid-extension": "~4.6.0-alpha.0",
"@jupyterlab/metadataform": "~4.6.0-alpha.0",
"@jupyterlab/metadataform-extension": "~4.6.0-alpha.0",
"@jupyterlab/notebook": "~4.6.0-alpha.0",
"@jupyterlab/notebook-extension": "~4.6.0-alpha.0",
"@jupyterlab/observables": "~5.6.0-alpha.0",
"@jupyterlab/outputarea": "~4.6.0-alpha.0",
"@jupyterlab/pdf-extension": "~4.6.0-alpha.0",
"@jupyterlab/pluginmanager-extension": "~4.6.0-alpha.0",
"@jupyterlab/rendermime": "~4.6.0-alpha.0",
"@jupyterlab/rendermime-interfaces": "~3.14.0-alpha.0",
"@jupyterlab/running-extension": "~4.6.0-alpha.0",
"@jupyterlab/services": "~7.6.0-alpha.0",
"@jupyterlab/services-extension": "~4.6.0-alpha.0",
"@jupyterlab/settingeditor": "~4.6.0-alpha.0",
"@jupyterlab/settingeditor-extension": "~4.6.0-alpha.0",
"@jupyterlab/settingregistry": "~4.6.0-alpha.0",
"@jupyterlab/shortcuts-extension": "~5.4.0-alpha.0",
"@jupyterlab/statedb": "~4.6.0-alpha.0",
"@jupyterlab/statusbar": "~4.6.0-alpha.0",
"@jupyterlab/terminal": "~4.6.0-alpha.0",
"@jupyterlab/terminal-extension": "~4.6.0-alpha.0",
"@jupyterlab/theme-dark-extension": "~4.6.0-alpha.0",
"@jupyterlab/theme-dark-high-contrast-extension": "~4.6.0-alpha.0",
"@jupyterlab/theme-light-extension": "~4.6.0-alpha.0",
"@jupyterlab/toc-extension": "~6.6.0-alpha.0",
"@jupyterlab/tooltip": "~4.6.0-alpha.0",
"@jupyterlab/tooltip-extension": "~4.6.0-alpha.0",
"@jupyterlab/translation": "~4.6.0-alpha.0",
"@jupyterlab/translation-extension": "~4.6.0-alpha.0",
"@jupyterlab/ui-components": "~4.6.0-alpha.0",
"@jupyterlab/ui-components-extension": "~4.6.0-alpha.0",
"@jupyterlab/vega5-extension": "~4.6.0-alpha.0",
"@jupyterlab/video-extension": "~4.6.0-alpha.0",
"@lezer/common": "~1.2.1",
"@lezer/highlight": "~1.2.0",
"@lumino/algorithm": "~2.0.4",
"@lumino/application": "~2.4.5",
"@lumino/commands": "~2.3.3",
"@lumino/coreutils": "~2.2.2",
"@lumino/disposable": "~2.1.5",
"@lumino/domutils": "~2.0.4",
"@lumino/dragdrop": "~2.1.7",
"@lumino/messaging": "~2.0.4",
"@lumino/properties": "~2.0.4",
"@lumino/signaling": "~2.1.5",
"@lumino/virtualdom": "~2.0.4",
"@lumino/widgets": "~2.7.2",
"@codemirror/state": "~6.2.1",
"@codemirror/view": "~6.21.3",
"@jupyter-notebook/application": "~7.1.3",
"@jupyter-notebook/application-extension": "~7.1.3",
"@jupyter-notebook/console-extension": "~7.1.3",
"@jupyter-notebook/docmanager-extension": "~7.1.3",
"@jupyter-notebook/documentsearch-extension": "~7.1.3",
"@jupyter-notebook/help-extension": "~7.1.3",
"@jupyter-notebook/notebook-extension": "~7.1.3",
"@jupyter-notebook/terminal-extension": "~7.1.3",
"@jupyter-notebook/tree": "~7.1.3",
"@jupyter-notebook/tree-extension": "~7.1.3",
"@jupyter-notebook/ui-components": "~7.1.3",
"@jupyter/ydoc": "~1.1.1",
"@jupyterlab/application": "~4.1.5",
"@jupyterlab/application-extension": "~4.1.5",
"@jupyterlab/apputils": "~4.2.5",
"@jupyterlab/apputils-extension": "~4.1.5",
"@jupyterlab/attachments": "~4.1.5",
"@jupyterlab/cell-toolbar": "~4.1.5",
"@jupyterlab/cell-toolbar-extension": "~4.1.5",
"@jupyterlab/celltags-extension": "~4.1.5",
"@jupyterlab/codeeditor": "~4.1.5",
"@jupyterlab/codemirror": "~4.1.5",
"@jupyterlab/codemirror-extension": "~4.1.5",
"@jupyterlab/completer": "~4.1.5",
"@jupyterlab/completer-extension": "~4.1.5",
"@jupyterlab/console": "~4.1.5",
"@jupyterlab/console-extension": "~4.1.5",
"@jupyterlab/coreutils": "~6.1.5",
"@jupyterlab/csvviewer-extension": "~4.1.5",
"@jupyterlab/debugger": "~4.1.5",
"@jupyterlab/debugger-extension": "~4.1.5",
"@jupyterlab/docmanager": "~4.1.5",
"@jupyterlab/docmanager-extension": "~4.1.5",
"@jupyterlab/documentsearch": "~4.1.5",
"@jupyterlab/documentsearch-extension": "~4.1.5",
"@jupyterlab/extensionmanager": "~4.1.5",
"@jupyterlab/extensionmanager-extension": "~4.1.5",
"@jupyterlab/filebrowser": "~4.1.5",
"@jupyterlab/filebrowser-extension": "~4.1.5",
"@jupyterlab/fileeditor": "~4.1.5",
"@jupyterlab/fileeditor-extension": "~4.1.5",
"@jupyterlab/help-extension": "~4.1.5",
"@jupyterlab/htmlviewer": "~4.1.5",
"@jupyterlab/htmlviewer-extension": "~4.1.5",
"@jupyterlab/hub-extension": "~4.1.5",
"@jupyterlab/imageviewer": "~4.1.5",
"@jupyterlab/imageviewer-extension": "~4.1.5",
"@jupyterlab/javascript-extension": "~4.1.5",
"@jupyterlab/json-extension": "~4.1.5",
"@jupyterlab/lsp": "~4.1.5",
"@jupyterlab/lsp-extension": "~4.1.5",
"@jupyterlab/mainmenu": "~4.1.5",
"@jupyterlab/mainmenu-extension": "~4.1.5",
"@jupyterlab/markdownviewer": "~4.1.5",
"@jupyterlab/markdownviewer-extension": "~4.1.5",
"@jupyterlab/markedparser-extension": "~4.1.5",
"@jupyterlab/mathjax-extension": "~4.1.5",
"@jupyterlab/mermaid": "~4.1.5",
"@jupyterlab/mermaid-extension": "~4.1.5",
"@jupyterlab/metadataform": "~4.1.5",
"@jupyterlab/metadataform-extension": "~4.1.5",
"@jupyterlab/notebook": "~4.1.5",
"@jupyterlab/notebook-extension": "~4.1.5",
"@jupyterlab/observables": "~5.1.5",
"@jupyterlab/outputarea": "~4.1.5",
"@jupyterlab/pdf-extension": "~4.1.5",
"@jupyterlab/pluginmanager-extension": "~4.1.5",
"@jupyterlab/rendermime": "~4.1.5",
"@jupyterlab/rendermime-interfaces": "~3.9.5",
"@jupyterlab/running-extension": "~4.1.5",
"@jupyterlab/services": "~7.1.5",
"@jupyterlab/settingeditor": "~4.1.5",
"@jupyterlab/settingeditor-extension": "~4.1.5",
"@jupyterlab/settingregistry": "~4.1.5",
"@jupyterlab/shortcuts-extension": "~4.1.5",
"@jupyterlab/statedb": "~4.1.5",
"@jupyterlab/statusbar": "~4.1.5",
"@jupyterlab/terminal": "~4.1.5",
"@jupyterlab/terminal-extension": "~4.1.5",
"@jupyterlab/theme-dark-extension": "~4.1.5",
"@jupyterlab/theme-light-extension": "~4.1.5",
"@jupyterlab/toc-extension": "~6.1.5",
"@jupyterlab/tooltip": "~4.1.5",
"@jupyterlab/tooltip-extension": "~4.1.5",
"@jupyterlab/translation": "~4.1.5",
"@jupyterlab/translation-extension": "~4.1.5",
"@jupyterlab/ui-components": "~4.1.5",
"@jupyterlab/ui-components-extension": "~4.1.5",
"@jupyterlab/vega5-extension": "~4.1.5",
"@lezer/common": "~1.1.0",
"@lezer/highlight": "~1.1.6",
"@lumino/algorithm": "~2.0.1",
"@lumino/application": "~2.3.0",
"@lumino/commands": "~2.2.0",
"@lumino/coreutils": "~2.1.2",
"@lumino/disposable": "~2.1.2",
"@lumino/domutils": "~2.0.1",
"@lumino/dragdrop": "~2.1.4",
"@lumino/messaging": "~2.0.1",
"@lumino/properties": "~2.0.1",
"@lumino/signaling": "~2.1.2",
"@lumino/virtualdom": "~2.0.1",
"@lumino/widgets": "~2.3.1",
"react": "~18.2.0",
"react-dom": "~18.2.0",
"yjs": "~13.6.8"
},
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyter-notebook/application-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/console-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/docmanager-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/documentsearch-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/help-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/notebook-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/terminal-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/tree": "^7.6.0-alpha.0",
"@jupyter-notebook/tree-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/ui-components": "^7.6.0-alpha.0",
"@jupyterlab/application-extension": "~4.6.0-alpha.0",
"@jupyterlab/apputils-extension": "~4.6.0-alpha.0",
"@jupyterlab/attachments": "~4.6.0-alpha.0",
"@jupyterlab/audio-extension": "~4.6.0-alpha.0",
"@jupyterlab/cell-toolbar-extension": "~4.6.0-alpha.0",
"@jupyterlab/celltags-extension": "~4.6.0-alpha.0",
"@jupyterlab/codemirror": "~4.6.0-alpha.0",
"@jupyterlab/codemirror-extension": "~4.6.0-alpha.0",
"@jupyterlab/completer-extension": "~4.6.0-alpha.0",
"@jupyterlab/console-extension": "~4.6.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@jupyterlab/csvviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/debugger-extension": "~4.6.0-alpha.0",
"@jupyterlab/docmanager-extension": "~4.6.0-alpha.0",
"@jupyterlab/documentsearch-extension": "~4.6.0-alpha.0",
"@jupyterlab/extensionmanager-extension": "~4.6.0-alpha.0",
"@jupyterlab/filebrowser-extension": "~4.6.0-alpha.0",
"@jupyterlab/fileeditor-extension": "~4.6.0-alpha.0",
"@jupyterlab/help-extension": "~4.6.0-alpha.0",
"@jupyterlab/htmlviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/hub-extension": "~4.6.0-alpha.0",
"@jupyterlab/imageviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/javascript-extension": "~4.6.0-alpha.0",
"@jupyterlab/json-extension": "~4.6.0-alpha.0",
"@jupyterlab/logconsole-extension": "~4.6.0-alpha.0",
"@jupyterlab/lsp": "~4.6.0-alpha.0",
"@jupyterlab/lsp-extension": "~4.6.0-alpha.0",
"@jupyterlab/mainmenu-extension": "~4.6.0-alpha.0",
"@jupyterlab/markdownviewer-extension": "~4.6.0-alpha.0",
"@jupyterlab/markedparser-extension": "~4.6.0-alpha.0",
"@jupyterlab/mathjax-extension": "~4.6.0-alpha.0",
"@jupyterlab/mermaid-extension": "~4.6.0-alpha.0",
"@jupyterlab/metadataform-extension": "~4.6.0-alpha.0",
"@jupyterlab/notebook-extension": "~4.6.0-alpha.0",
"@jupyterlab/pdf-extension": "~4.6.0-alpha.0",
"@jupyterlab/pluginmanager-extension": "~4.6.0-alpha.0",
"@jupyterlab/running-extension": "~4.6.0-alpha.0",
"@jupyterlab/services-extension": "~4.6.0-alpha.0",
"@jupyterlab/settingeditor": "~4.6.0-alpha.0",
"@jupyterlab/settingeditor-extension": "~4.6.0-alpha.0",
"@jupyterlab/shortcuts-extension": "~5.4.0-alpha.0",
"@jupyterlab/terminal-extension": "~4.6.0-alpha.0",
"@jupyterlab/theme-dark-extension": "~4.6.0-alpha.0",
"@jupyterlab/theme-dark-high-contrast-extension": "~4.6.0-alpha.0",
"@jupyterlab/theme-light-extension": "~4.6.0-alpha.0",
"@jupyterlab/toc-extension": "~6.6.0-alpha.0",
"@jupyterlab/tooltip-extension": "~4.6.0-alpha.0",
"@jupyterlab/translation-extension": "~4.6.0-alpha.0",
"@jupyterlab/ui-components-extension": "~4.6.0-alpha.0",
"@jupyterlab/vega5-extension": "~4.6.0-alpha.0",
"@jupyterlab/video-extension": "~4.6.0-alpha.0",
"@lumino/coreutils": "~2.2.2",
"@jupyter-notebook/application": "^7.1.3",
"@jupyter-notebook/application-extension": "^7.1.3",
"@jupyter-notebook/console-extension": "^7.1.3",
"@jupyter-notebook/docmanager-extension": "^7.1.3",
"@jupyter-notebook/documentsearch-extension": "^7.1.3",
"@jupyter-notebook/help-extension": "^7.1.3",
"@jupyter-notebook/notebook-extension": "^7.1.3",
"@jupyter-notebook/terminal-extension": "^7.1.3",
"@jupyter-notebook/tree": "^7.1.3",
"@jupyter-notebook/tree-extension": "^7.1.3",
"@jupyter-notebook/ui-components": "^7.1.3",
"@jupyterlab/application-extension": "~4.1.5",
"@jupyterlab/apputils-extension": "~4.1.5",
"@jupyterlab/attachments": "~4.1.5",
"@jupyterlab/cell-toolbar-extension": "~4.1.5",
"@jupyterlab/celltags-extension": "~4.1.5",
"@jupyterlab/codemirror": "~4.1.5",
"@jupyterlab/codemirror-extension": "~4.1.5",
"@jupyterlab/completer-extension": "~4.1.5",
"@jupyterlab/console-extension": "~4.1.5",
"@jupyterlab/coreutils": "~6.1.5",
"@jupyterlab/csvviewer-extension": "~4.1.5",
"@jupyterlab/debugger-extension": "~4.1.5",
"@jupyterlab/docmanager-extension": "~4.1.5",
"@jupyterlab/documentsearch-extension": "~4.1.5",
"@jupyterlab/extensionmanager-extension": "~4.1.5",
"@jupyterlab/filebrowser-extension": "~4.1.5",
"@jupyterlab/fileeditor-extension": "~4.1.5",
"@jupyterlab/help-extension": "~4.1.5",
"@jupyterlab/htmlviewer-extension": "~4.1.5",
"@jupyterlab/hub-extension": "~4.1.5",
"@jupyterlab/imageviewer-extension": "~4.1.5",
"@jupyterlab/javascript-extension": "~4.1.5",
"@jupyterlab/json-extension": "~4.1.5",
"@jupyterlab/lsp": "~4.1.5",
"@jupyterlab/lsp-extension": "~4.1.5",
"@jupyterlab/mainmenu-extension": "~4.1.5",
"@jupyterlab/markdownviewer-extension": "~4.1.5",
"@jupyterlab/markedparser-extension": "~4.1.5",
"@jupyterlab/mathjax-extension": "~4.1.5",
"@jupyterlab/mermaid-extension": "~4.1.5",
"@jupyterlab/metadataform-extension": "~4.1.5",
"@jupyterlab/notebook-extension": "~4.1.5",
"@jupyterlab/pdf-extension": "~4.1.5",
"@jupyterlab/pluginmanager-extension": "~4.1.5",
"@jupyterlab/running-extension": "~4.1.5",
"@jupyterlab/settingeditor": "~4.1.5",
"@jupyterlab/settingeditor-extension": "~4.1.5",
"@jupyterlab/shortcuts-extension": "~4.1.5",
"@jupyterlab/terminal-extension": "~4.1.5",
"@jupyterlab/theme-dark-extension": "~4.1.5",
"@jupyterlab/theme-light-extension": "~4.1.5",
"@jupyterlab/toc-extension": "~6.1.5",
"@jupyterlab/tooltip-extension": "~4.1.5",
"@jupyterlab/translation-extension": "~4.1.5",
"@jupyterlab/ui-components-extension": "~4.1.5",
"@jupyterlab/vega5-extension": "~4.1.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"yjs": "^13.5.40"
},
"devDependencies": {
"@jupyterlab/builder": "~4.6.0-alpha.0",
"@jupyterlab/buildutils": "~4.6.0-alpha.0",
"@rspack/cli": "^1.1.8",
"@rspack/core": "^1.1.8",
"@jupyterlab/builder": "~4.1.5",
"@jupyterlab/buildutils": "~4.1.5",
"@types/rimraf": "^3.0.2",
"css-loader": "~5.0.1",
"extra-watch-webpack-plugin": "^1.0.3",
"fs-extra": "^8.1.0",
"glob": "~7.1.6",
"handlebars": "^4.7.7",
"mini-css-extract-plugin": "~0.9.0",
"rimraf": "^3.0.2",
"style-loader": "~1.0.1",
"svg-url-loader": "~6.0.0",
"watch": "~1.0.2",
"webpack": "^5.76.1",
"webpack-bundle-analyzer": "^4.8.0",
"webpack-cli": "^5.0.1",
"webpack-merge": "^5.8.0",
"whatwg-fetch": "^3.0.0"
},
@ -234,7 +227,6 @@
"@jupyterlab/application-extension:top-spacer"
],
"@jupyterlab/apputils-extension": [
"@jupyterlab/apputils-extension:kernels-settings",
"@jupyterlab/apputils-extension:palette",
"@jupyterlab/apputils-extension:notification",
"@jupyterlab/apputils-extension:sanitizer",
@ -246,7 +238,6 @@
"@jupyterlab/apputils-extension:toolbar-registry",
"@jupyterlab/apputils-extension:utilityCommands"
],
"@jupyterlab/audio-extension": true,
"@jupyterlab/codemirror-extension": true,
"@jupyterlab/completer-extension": [
"@jupyterlab/completer-extension:base-service",
@ -256,7 +247,6 @@
"@jupyterlab/completer-extension:manager"
],
"@jupyterlab/console-extension": [
"@jupyterlab/console-extension:cell-executor",
"@jupyterlab/console-extension:completer",
"@jupyterlab/console-extension:factory",
"@jupyterlab/console-extension:foreign",
@ -277,24 +267,19 @@
"@jupyterlab/filebrowser-extension:default-file-browser"
],
"@jupyterlab/fileeditor-extension": [
"@jupyterlab/fileeditor-extension:plugin",
"@jupyterlab/fileeditor-extension:widget-factory"
"@jupyterlab/fileeditor-extension:plugin"
],
"@jupyterlab/help-extension": [
"@jupyterlab/help-extension:resources"
],
"@jupyterlab/htmlviewer-extension": true,
"@jupyterlab/hub-extension": true,
"@jupyterlab/imageviewer-extension": true,
"@jupyterlab/lsp-extension": true,
"@jupyterlab/mainmenu-extension": [
"@jupyterlab/mainmenu-extension:plugin"
],
"@jupyterlab/mainmenu-extension": true,
"@jupyterlab/markedparser-extension": true,
"@jupyterlab/mathjax-extension": true,
"@jupyterlab/mermaid-extension": true,
"@jupyterlab/notebook-extension": [
"@jupyterlab/notebook-extension:cell-executor",
"@jupyterlab/notebook-extension:code-console",
"@jupyterlab/notebook-extension:export",
"@jupyterlab/notebook-extension:factory",
@ -302,22 +287,18 @@
"@jupyterlab/notebook-extension:widget-factory"
],
"@jupyterlab/pluginmanager-extension": true,
"@jupyterlab/services-extension": true,
"@jupyterlab/shortcuts-extension": true,
"@jupyterlab/terminal-extension": true,
"@jupyterlab/theme-light-extension": true,
"@jupyterlab/theme-dark-extension": true,
"@jupyterlab/theme-dark-high-contrast-extension": true,
"@jupyterlab/translation-extension": true,
"@jupyterlab/ui-components-extension": true,
"@jupyterlab/video-extension": true
"@jupyterlab/hub-extension": true
},
"/tree": {
"@jupyterlab/cell-toolbar-extension": true,
"@jupyterlab/extensionmanager-extension": true,
"@jupyterlab/filebrowser-extension": [
"@jupyterlab/filebrowser-extension:browser",
"@jupyterlab/filebrowser-extension:create-new-language-file",
"@jupyterlab/filebrowser-extension:download",
"@jupyterlab/filebrowser-extension:file-upload-status",
"@jupyterlab/filebrowser-extension:open-with",
@ -325,31 +306,24 @@
"@jupyterlab/filebrowser-extension:share-file"
],
"@jupyter-notebook/tree-extension": true,
"@jupyterlab/running-extension": [
"@jupyterlab/running-extension:plugin"
],
"@jupyterlab/running-extension": true,
"@jupyterlab/settingeditor-extension": true
},
"/notebooks": {
"@jupyterlab/celltags-extension": true,
"@jupyterlab/cell-toolbar-extension": true,
"@jupyterlab/debugger-extension": [
"@jupyterlab/debugger-extension:completions",
"@jupyterlab/debugger-extension:config",
"@jupyterlab/debugger-extension:debug-console",
"@jupyterlab/debugger-extension:main",
"@jupyterlab/debugger-extension:notebooks",
"@jupyterlab/debugger-extension:service",
"@jupyterlab/debugger-extension:sidebar",
"@jupyterlab/debugger-extension:sources",
"@jupyterlab/debugger-extension:display-registry"
"@jupyterlab/debugger-extension:sources"
],
"@jupyterlab/logconsole-extension": true,
"@jupyterlab/metadataform-extension": true,
"@jupyterlab/notebook-extension": [
"@jupyterlab/notebook-extension:active-cell-tool",
"@jupyterlab/notebook-extension:completer",
"@jupyterlab/notebook-extension:copy-output",
"@jupyterlab/notebook-extension:metadata-editor",
"@jupyterlab/notebook-extension:search",
"@jupyterlab/notebook-extension:toc",
@ -383,8 +357,6 @@
"@codemirror/state",
"@codemirror/view",
"@jupyter-notebook/tree",
"@jupyter/react-components",
"@jupyter/web-components",
"@jupyter/ydoc",
"@jupyterlab/application",
"@jupyterlab/apputils",

@ -1,15 +0,0 @@
/*
* Copyright (c) Jupyter Development Team.
* Distributed under the terms of the Modified BSD License.
*/
const base = require('./rspack.config');
module.exports = [
{
...base[0],
bail: false,
watch: true,
},
...base.slice(1),
];

@ -1,29 +0,0 @@
/*
* Copyright (c) Jupyter Development Team.
* Distributed under the terms of the Modified BSD License.
*/
const merge = require('webpack-merge').default;
const config = require('./rspack.config');
const WPPlugin = require('@jupyterlab/builder').WPPlugin;
config[0] = merge(config[0], {
mode: 'production',
devtool: 'source-map',
output: {
// Add version argument when in production so the Jupyter server
// allows caching of files (i.e., does not set the CacheControl header to no-cache to prevent caching static files)
filename: '[name].[contenthash].js?v=[contenthash]',
},
optimization: {
minimize: false,
},
plugins: [
new WPPlugin.JSONLicenseWebpackPlugin({
excludedPackageTest: (packageName) =>
packageName === '@jupyter-notebook/app',
}),
],
});
module.exports = config;

@ -1,45 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{page_config['appName'] | e}} - Console</title>
{% block favicon %}
<link
rel="icon"
type="image/x-icon"
href="{{ page_config['fullStaticUrl'] | e }}/favicons/favicon-console.ico"
class="favicon"
/>
{% endblock %} {% if custom_css %}
<link
rel="stylesheet"
type="text/css"
href="{{ base_url | escape }}custom/custom.css"
/>
{% endif %}
</head>
<body class="jp-ThemedContainer">
{# Copy so we do not modify the page_config with updates. #} {% set
page_config_full = page_config.copy() %} {# Set a dummy variable - we just
want the side effect of the update. #} {% set _ =
page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} {# Sentinel value
to say that we are on the tree page #} {% set _ =
page_config_full.update(notebookPage='consoles') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({}, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -1,39 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{page_config['appName'] | e}} - Edit</title>
{% block favicon %}
<link
rel="icon"
type="image/x-icon"
href="{{ base_url | escape }}static/favicons/favicon-file.ico"
class="favicon"
/>
{% endblock %}
</head>
<body class="jp-ThemedContainer" data-notebook="edit">
{# Copy so we do not modify the page_config with updates. #} {% set
page_config_full = page_config.copy() %} {# Set a dummy variable - we just
want the side effect of the update. #} {% set _ =
page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} {# Sentinel value
to say that we are on the tree page #} {% set _ =
page_config_full.update(notebookPage='edit') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({}, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -1,45 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{page_config['appName'] | e}} - Notebook</title>
{% block favicon %}
<link
rel="icon"
type="image/x-icon"
href="{{ base_url | escape }}static/favicons/favicon-notebook.ico"
class="favicon"
/>
{% endblock %} {% if custom_css %}
<link
rel="stylesheet"
type="text/css"
href="{{ base_url | escape }}custom/custom.css"
/>
{% endif %}
</head>
<body class="jp-ThemedContainer" data-notebook="notebooks">
{# Copy so we do not modify the page_config with updates. #} {% set
page_config_full = page_config.copy() %} {# Set a dummy variable - we just
want the side effect of the update. #} {% set _ =
page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} {# Sentinel value
to say that we are on the tree page #} {% set _ =
page_config_full.update(notebookPage='notebooks') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({}, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -1,45 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{page_config['appName'] | e}} - Terminal</title>
{% block favicon %}
<link
rel="icon"
type="image/x-icon"
href="{{ base_url | escape }}static/favicons/favicon-terminal.ico"
class="favicon"
/>
{% endblock %} {% if custom_css %}
<link
rel="stylesheet"
type="text/css"
href="{{ base_url | escape }}custom/custom.css"
/>
{% endif %}
</head>
<body class="jp-ThemedContainer">
{# Copy so we do not modify the page_config with updates. #} {% set
page_config_full = page_config.copy() %} {# Set a dummy variable - we just
want the side effect of the update. #} {% set _ =
page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} {# Sentinel value
to say that we are on the tree page #} {% set _ =
page_config_full.update(notebookPage='terminals') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({}, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -1,45 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Home</title>
{% block favicon %}
<link
rel="icon"
type="image/x-icon"
href="{{ base_url | escape }}static/favicons/favicon.ico"
class="favicon"
/>
{% endblock %} {% if custom_css %}
<link
rel="stylesheet"
type="text/css"
href="{{ base_url | escape }}custom/custom.css"
/>
{% endif %}
</head>
<body class="jp-ThemedContainer">
{# Copy so we do not modify the page_config with updates. #} {% set
page_config_full = page_config.copy() %} {# Set a dummy variable - we just
want the side effect of the update. #} {% set _ =
page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %} {# Sentinel value
to say that we are on the tree page #} {% set _ =
page_config_full.update(notebookPage='tree') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({}, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -2,20 +2,19 @@
// Distributed under the terms of the Modified BSD License.
// Heavily inspired (and slightly tweaked) from:
// https://github.com/jupyterlab/jupyterlab/blob/master/examples/federated/core_package/rspack.config.js
// https://github.com/jupyterlab/jupyterlab/blob/master/examples/federated/core_package/webpack.config.js
const fs = require('fs-extra');
const path = require('path');
const rspack = require('@rspack/core');
const webpack = require('webpack');
const merge = require('webpack-merge').default;
const Handlebars = require('handlebars');
const { ModuleFederationPlugin } = rspack.container;
const { ModuleFederationPlugin } = webpack.container;
const BundleAnalyzerPlugin =
require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const Build = require('@jupyterlab/builder').Build;
const WPPlugin = require('@jupyterlab/builder').WPPlugin;
const HtmlWebpackPlugin = require('html-webpack-plugin');
const baseConfig = require('@jupyterlab/builder/lib/webpack.config.base');
const data = require('./package.json');
@ -94,7 +93,7 @@ const extras = Build.ensureAssets({
});
/**
* Create the rspack ``shared`` configuration
* Create the webpack ``shared`` configuration
*/
function createShared(packageData) {
// Set up module federation sharing config
@ -205,55 +204,22 @@ if (process.argv.includes('--analyze')) {
extras.push(new BundleAnalyzerPlugin());
}
const htmlPlugins = [];
['consoles', 'edit', 'error', 'notebooks', 'terminals', 'tree'].forEach(
(name) => {
htmlPlugins.push(
new HtmlWebpackPlugin({
chunksSortMode: 'none',
template: path.join(
path.resolve('./templates'),
`${name}_template.html`
),
title: name,
filename: path.join(
path.resolve(__dirname, '..', 'notebook/templates'),
`${name}.html`
),
})
);
}
);
module.exports = [
merge(baseConfig, {
mode: 'development',
entry: ['./publicpath.js', './' + path.relative(__dirname, entryPoint)],
output: {
path: path.resolve(__dirname, '..', 'notebook/static/'),
publicPath: '{{page_config.fullStaticUrl}}/',
library: {
type: 'var',
name: ['_JUPYTERLAB', 'CORE_OUTPUT'],
},
filename: '[name].[contenthash].js',
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
jlab_core: {
test: /[\\/]node_modules[\\/]@(jupyterlab|jupyter-notebook|lumino(?!\/datagrid))[\\/]/,
name: 'notebook_core',
},
},
},
filename: 'bundle.js',
},
resolve: {
fallback: { util: false },
},
plugins: [
...htmlPlugins,
new WPPlugin.JSONLicenseWebpackPlugin({
excludedPackageTest: (packageName) =>
packageName === '@jupyter-notebook/app',
@ -269,6 +235,3 @@ module.exports = [
],
}),
].concat(extras);
const logPath = path.join(buildDir, 'build_log.json');
fs.writeFileSync(logPath, JSON.stringify(module.exports, null, ' '));

@ -0,0 +1,17 @@
const base = require('./webpack.config');
const ExtraWatchWebpackPlugin = require('extra-watch-webpack-plugin');
module.exports = [
{
...base[0],
bail: false,
watch: true,
plugins: [
...base[0].plugins,
new ExtraWatchWebpackPlugin({
files: ['../packages/_metapackage/tsconfig.tsbuildinfo'],
}),
],
},
...base.slice(1),
];

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/buildutils",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"private": true,
"description": "Jupyter Notebook - Build Utilities",
"homepage": "https://github.com/jupyter/notebook",
@ -29,16 +29,14 @@
"watch": "tsc -w --listEmittedFiles"
},
"dependencies": {
"@jupyterlab/buildutils": "~4.6.0-alpha.0",
"@jupyterlab/buildutils": "~4.1.5",
"commander": "^6.2.0",
"fs-extra": "^9.1.0",
"semver": "^7.6.3",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"devDependencies": {
"@types/fs-extra": "^9.0.10",
"@types/node": "^22.13.4",
"@types/semver": "^7.5.8",
"@types/node": "^14.6.1",
"rimraf": "^3.0.2"
}
}

@ -1,86 +0,0 @@
import * as fs from 'fs-extra';
import * as semver from 'semver';
function convertPythonVersion(version: string): string {
return version
.replace('a', '-alpha')
.replace('b', '-beta')
.replace('rc', '-rc');
}
function extractVersionFromReleases(
releases: any,
versionTag: string,
currentVersion: string
): string | null {
const npmCurrentVersion = convertPythonVersion(currentVersion);
const isCurrentPreRelease = semver.prerelease(npmCurrentVersion) !== null;
if (versionTag === 'latest') {
// Find first version that is newer than current and matches pre-release criteria
const release = releases.find((r: any) => {
const version = r['tag_name'].substring(1); // Remove 'v' prefix for semver
const npmVersion = convertPythonVersion(version);
return (
(isCurrentPreRelease || !r['prerelease']) &&
semver.gte(npmVersion, npmCurrentVersion)
);
});
return release ? release['tag_name'] : null;
} else {
// Find exact version match
const release = releases.find((r: any) => r['tag_name'] === versionTag);
return release ? release['tag_name'] : null;
}
}
function extractCurrentJupyterLabVersion(): string {
const toml = fs.readFileSync('pyproject.toml', 'utf8');
const match = toml.match(/jupyterlab>=([^,]+)/);
if (!match) {
throw new Error('Could not find JupyterLab version in pyproject.toml');
}
return match[1];
}
async function findVersion(versionTag: string): Promise<string> {
const url = 'https://api.github.com/repos/jupyterlab/jupyterlab/releases';
const response = await fetch(url);
if (!response.ok) {
const error_message = `Failed to fetch package.json from ${url}. HTTP status code: ${response.status}`;
throw new Error(error_message);
}
const currentVersion = extractCurrentJupyterLabVersion();
const releases: any = await response.json();
const version: string | null = extractVersionFromReleases(
releases,
versionTag,
currentVersion
);
if (version === null) {
const error_message = 'Invalid release tag';
throw new Error(error_message);
}
return version.substring(1);
}
async function getLatestLabVersion(): Promise<void> {
const args: string[] = process.argv.slice(2);
if (args.length !== 2 || args[0] !== '--set-version') {
console.error('Usage: node script.js --set-version <version>');
process.exit(1);
}
const version_tag: string = args[1];
try {
const result: string = await findVersion(version_tag);
console.log(result);
} catch (error: any) {
console.error('Error:', error.message);
process.exit(1);
}
}
getLatestLabVersion();

@ -1,170 +0,0 @@
import fs from 'fs';
import path from 'path';
const PACKAGE_JSON_PATHS: string[] = [
'app/package.json',
'buildutils/package.json',
'package.json',
'packages/application-extension/package.json',
'packages/application/package.json',
'packages/console-extension/package.json',
'packages/docmanager-extension/package.json',
'packages/documentsearch-extension/package.json',
'packages/help-extension/package.json',
'packages/lab-extension/package.json',
'packages/notebook-extension/package.json',
'packages/terminal-extension/package.json',
'packages/tree-extension/package.json',
'packages/tree/package.json',
'packages/ui-components/package.json',
'ui-tests/package.json',
];
const DEPENDENCY_GROUP = '@jupyterlab';
interface IVersion {
major: number;
minor: number;
patch: number;
preRelease?: string;
}
function parseVersion(version: string): IVersion {
const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:(a|b|rc)(\d+))?$/);
if (!match) {
throw new Error(`Invalid version format: ${version}`);
}
const [, major, minor, patch, type, preVersion] = match;
const baseVersion = {
major: parseInt(major, 10),
minor: parseInt(minor, 10),
patch: parseInt(patch, 10),
};
if (type && preVersion) {
return {
...baseVersion,
preRelease: `${type}${preVersion}`,
};
}
return baseVersion;
}
function getVersionRange(version: IVersion): string {
const baseVersion = `${version.major}.${version.minor}.${version.patch}${
version.preRelease ?? ''
}`;
return `>=${baseVersion},<${version.major}.${version.minor + 1}`;
}
function updateVersionInFile(
filePath: string,
pattern: RegExp,
version: IVersion
): void {
const content = fs.readFileSync(filePath, 'utf-8');
const versionRange = getVersionRange(version);
const updatedContent = content.replace(pattern, `$1${versionRange}`);
fs.writeFileSync(filePath, updatedContent);
}
async function updatePackageJson(newVersion: string): Promise<void> {
const url = `https://raw.githubusercontent.com/jupyterlab/jupyterlab/v${newVersion}/jupyterlab/staging/package.json`;
const response = await fetch(url);
if (!response.ok) {
const errorMessage = `Failed to fetch package.json from ${url}. HTTP status code: ${response.status}`;
throw new Error(errorMessage);
}
// fetch the new galata version
const galataUrl = `https://raw.githubusercontent.com/jupyterlab/jupyterlab/v${newVersion}/galata/package.json`;
const galataResponse = await fetch(galataUrl);
if (!galataResponse.ok) {
const errorMessage = `Failed to fetch galata/package.json from ${galataUrl}. HTTP status code: ${galataResponse.status}`;
throw new Error(errorMessage);
}
const newPackageJson = await response.json();
const galataPackageJson = await galataResponse.json();
for (const packageJsonPath of PACKAGE_JSON_PATHS) {
const filePath: string = path.resolve(packageJsonPath);
const existingPackageJson = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
const newDependencies = {
...newPackageJson.devDependencies,
...newPackageJson.resolutions,
[galataPackageJson.name]: galataPackageJson.version,
};
updateDependencyVersion(existingPackageJson, newDependencies);
fs.writeFileSync(
filePath,
JSON.stringify(existingPackageJson, null, 2) + '\n'
);
}
}
function updateDependencyVersion(existingJson: any, newJson: any): void {
if (!existingJson) {
return;
}
const sectionPaths: string[] = [
'resolutions',
'dependencies',
'devDependencies',
];
for (const section of sectionPaths) {
if (!existingJson[section]) {
continue;
}
const updated = existingJson[section];
for (const [pkg, version] of Object.entries<string>(
existingJson[section]
)) {
if (pkg.startsWith(DEPENDENCY_GROUP) && pkg in newJson) {
if (version[0] === '^' || version[0] === '~') {
updated[pkg] = version[0] + absoluteVersion(newJson[pkg]);
} else {
updated[pkg] = absoluteVersion(newJson[pkg]);
}
}
}
}
}
function absoluteVersion(version: string): string {
if (version.length > 0 && (version[0] === '^' || version[0] === '~')) {
return version.substring(1);
}
return version;
}
const versionPattern = /(jupyterlab)(>=[\d.]+(?:[a|b|rc]\d+)?,<[\d.]+)/g;
const FILES_TO_UPDATE = ['pyproject.toml', '.pre-commit-config.yaml'];
async function upgradeLabDependencies(): Promise<void> {
const args: string[] = process.argv.slice(2);
if (args.length < 2) {
throw new Error('Please provide the set-version flag and version');
}
const version = parseVersion(args[1]);
await updatePackageJson(args[1]); // Keep original string version for package.json
for (const file of FILES_TO_UPDATE) {
updateVersionInFile(path.resolve(file), versionPattern, version);
}
}
upgradeLabDependencies();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

File diff suppressed because one or more lines are too long

@ -109,7 +109,7 @@ _version_py = os.path.join(here, "../../notebook/_version.py")
version_ns = {}
exec(compile(open(_version_py).read(), _version_py, "exec"), version_ns) # noqa: S102, SIM115
# The short X.Y version.
version = "{}.{}".format(*version_ns["version_info"][:2])
version = "%i.%i" % version_ns["version_info"][:2]
# The full version, including alpha/beta/rc tags.
release = version_ns["__version__"]
@ -172,7 +172,6 @@ html_theme = "pydata_sphinx_theme"
# further. For a list of options available for each theme, see the
# documentation.
html_theme_options = {
"header_links_before_dropdown": 5,
"icon_links": [
{
"name": "jupyter.org",
@ -191,10 +190,9 @@ html_theme_options = {
"icon": "fab fa-discourse",
},
{
"name": "Zulip",
"url": "https://jupyter.zulipchat.com/",
"icon": "_static/zulip-icon-square.svg",
"type": "local",
"name": "Gitter",
"url": "https://gitter.im/jupyter/jupyter",
"icon": "fab fa-gitter",
},
],
"logo": {
@ -400,7 +398,3 @@ intersphinx_mapping = {
spelling_lang = "en_US"
spelling_word_list_filename = "spelling_wordlist.txt"
def setup(app):
app.add_css_file("https://docs.jupyter.org/en/latest/_static/jupyter.css")

@ -1,4 +1,4 @@
# Contributing
# Contributor
```{toctree}
:caption: Contributor Documentation

@ -1,4 +1,4 @@
# Migrating
# Migrating to Notebook 7
_Updated 2023-05-17_

@ -8,7 +8,7 @@ This is for example the case for community contributed themes such as [jupyter-t
Fortunately installing a custom theme for Notebook 7 is very easy. It is the same process as installing a regular extension.
For example let's say you want to install the [JupyterLab Night](https://github.com/jupyterlab-contrib/jupyterlab-night) theme. You can do so by running the following command:
For exampe let's say you want to install the [JupyterLab Night](https://github.com/martinRenou/jupyterlab-night) theme. You can do so by running the following command:
```bash
pip install jupyterlab-night

@ -45,7 +45,7 @@ notebook and its dependencies.
### Notebook documents
Notebook documents contain the inputs and outputs of an interactive session as
Notebook documents contains the inputs and outputs of a interactive session as
well as additional text that accompanies the code but is not meant for
execution. In this way, notebook files can serve as a complete computational
record of a session, interleaving executable code with explanatory text,
@ -355,7 +355,7 @@ Specific plotting library integration is a feature of the kernel.
## Installing kernels
For information on how to install a Python kernel, refer to the
[IPython install page](https://ipython.org/install).
[IPython install page](https://ipython.org/install.html).
The Jupyter wiki has a long list of [Kernels for other languages](https://github.com/jupyter/jupyter/wiki/Jupyter-kernels).
They usually come with instructions on how to make the kernel available

@ -110,7 +110,17 @@ However a version compatible with Notebook 7 will be available before the final
### RISE
The RISE extension is another popular JupyterLab extension that has been ported to work with Notebook 7. It allows you to turn your Jupyter Notebooks into a slideshow. See the [installation instructions](https://github.com/jupyterlab-contrib/rise#install).
```{warning}
The RISE extension is still under active development and a version compatible with Notebook 7 is not yet available on PyPI.
```
The RISE extension is another popular JupyterLab extension that is being ported to work with Notebook 7. It allows you to turn your Jupyter Notebooks into a slideshow.
The extension is still under [active development](https://github.com/jupyterlab-contrib/rise). When ready, it will be possible to install it with `pip`:
```bash
pip install jupyterlab-rise
```
## A document-centric user experience

@ -1,4 +1,4 @@
# Documentation
# User Documentation
Use this page to navigate to different parts of the user documentation.

@ -1,4 +1,5 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"version": "independent"
"version": "independent",
"useWorkspaces": true
}

@ -1,5 +1,4 @@
"""CLI entry point for notebook."""
import sys
from notebook.app import main

@ -1,12 +1,11 @@
"""Version info for notebook."""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import re
from collections import namedtuple
# Use "hatch version xx.yy.zz" to handle version changes
__version__ = "7.6.0a0"
__version__ = "7.1.3"
# PEP440 version parser
_version_regex = re.compile(

@ -1,5 +1,4 @@
"""Jupyter notebook application."""
from __future__ import annotations
import os
@ -39,7 +38,7 @@ from ._version import __version__
HERE = Path(__file__).parent.resolve()
Flags = dict[t.Union[str, tuple[str, ...]], tuple[t.Union[dict[str, t.Any], Config], str]]
Flags = t.Dict[t.Union[str, t.Tuple[str, ...]], t.Tuple[t.Union[t.Dict[str, t.Any], Config], str]]
app_dir = Path(get_app_dir())
version = __version__
@ -121,12 +120,6 @@ class NotebookBaseHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, Jup
logger=self.log,
),
)
# modify page config with custom hook
page_config_hook = self.settings.get("page_config_hook", None)
if page_config_hook:
page_config = page_config_hook(self, page_config)
return page_config
@ -204,16 +197,8 @@ class NotebookHandler(NotebookBaseHandler):
"""A notebook page handler."""
@web.authenticated
async def get(self, path: str = "") -> t.Any:
"""Get the notebook page. Redirect if it's a directory."""
path = path.strip("/")
cm = self.contents_manager
if await ensure_async(cm.dir_exists(path=path)):
url = ujoin(self.base_url, "tree", url_escape(path))
self.log.debug("Redirecting %s to %s since path is a directory", self.request.path, url)
self.redirect(url)
return None
def get(self, path: str | None = None) -> t.Any: # noqa: ARG002
"""Get the notebook page."""
tpl = self.render_template("notebooks.html", page_config=self.get_page_config())
return self.write(tpl)

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{page_config['appName'] | e}} - Console</title>
{% block favicon %}
<link rel="icon" type="image/x-icon" href="{{ page_config['fullStaticUrl'] | e }}/favicons/favicon-console.ico" class="favicon">
{% endblock %}
{% if custom_css %}
<link rel="stylesheet" type="text/css" href="{{ base_url | escape }}custom/custom.css">
{% endif %}
</head>
<body>
{# Copy so we do not modify the page_config with updates. #}
{% set page_config_full = page_config.copy() %}
{# Set a dummy variable - we just want the side effect of the update. #}
{% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %}
{# Sentinel value to say that we are on the tree page #}
{% set _ = page_config_full.update(notebookPage='consoles') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script src="{{page_config['fullStaticUrl'] | e}}/bundle.js" main="index"></script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({ }, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{page_config['appName'] | e}} - Edit</title>
{% block favicon %}
<link rel="icon" type="image/x-icon" href="{{ base_url | escape }}static/favicons/favicon-file.ico" class="favicon">
{% endblock %}
</head>
<body data-notebook="edit">
{# Copy so we do not modify the page_config with updates. #}
{% set page_config_full = page_config.copy() %}
{# Set a dummy variable - we just want the side effect of the update. #}
{% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %}
{# Sentinel value to say that we are on the tree page #}
{% set _ = page_config_full.update(notebookPage='edit') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script src="{{page_config['fullStaticUrl'] | e}}/bundle.js" main="index"></script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({ }, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -14,7 +14,7 @@ Distributed under the terms of the Modified BSD License.
</head>
<body class="jp-ThemedContainer">
<body>
{% block stylesheet %}
<style type="text/css">

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{page_config['appName'] | e}} - Notebook</title>
{% block favicon %}
<link rel="icon" type="image/x-icon" href="{{ base_url | escape }}static/favicons/favicon-notebook.ico" class="favicon">
{% endblock %}
{% if custom_css %}
<link rel="stylesheet" type="text/css" href="{{ base_url | escape }}custom/custom.css">
{% endif %}
</head>
<body data-notebook="notebooks">
{# Copy so we do not modify the page_config with updates. #}
{% set page_config_full = page_config.copy() %}
{# Set a dummy variable - we just want the side effect of the update. #}
{% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %}
{# Sentinel value to say that we are on the tree page #}
{% set _ = page_config_full.update(notebookPage='notebooks') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script src="{{page_config['fullStaticUrl'] | e}}/bundle.js" main="index"></script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({ }, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{page_config['appName'] | e}} - Terminal</title>
{% block favicon %}
<link rel="icon" type="image/x-icon" href="{{ base_url | escape }}static/favicons/favicon-terminal.ico" class="favicon">
{% endblock %}
{% if custom_css %}
<link rel="stylesheet" type="text/css" href="{{ base_url | escape }}custom/custom.css">
{% endif %}
</head>
<body>
{# Copy so we do not modify the page_config with updates. #}
{% set page_config_full = page_config.copy() %}
{# Set a dummy variable - we just want the side effect of the update. #}
{% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %}
{# Sentinel value to say that we are on the tree page #}
{% set _ = page_config_full.update(notebookPage='terminals') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script src="{{page_config['fullStaticUrl'] | e}}/bundle.js" main="index"></script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({ }, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Home</title>
{% block favicon %}
<link rel="icon" type="image/x-icon" href="{{ base_url | escape }}static/favicons/favicon.ico" class="favicon">
{% endblock %}
{% if custom_css %}
<link rel="stylesheet" type="text/css" href="{{ base_url | escape }}custom/custom.css">
{% endif %}
</head>
<body>
{# Copy so we do not modify the page_config with updates. #}
{% set page_config_full = page_config.copy() %}
{# Set a dummy variable - we just want the side effect of the update. #}
{% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %}
{# Sentinel value to say that we are on the tree page #}
{% set _ = page_config_full.update(notebookPage='tree') %}
<script id="jupyter-config-data" type="application/json">
{{ page_config_full | tojson }}
</script>
<script src="{{page_config['fullStaticUrl'] | e}}/bundle.js" main="index"></script>
<script type="text/javascript">
/* Remove token from URL. */
(function () {
var parsedUrl = new URL(window.location.href);
if (parsedUrl.searchParams.get('token')) {
parsedUrl.searchParams.delete('token');
window.history.replaceState({ }, '', parsedUrl.href);
}
})();
</script>
</body>
</html>

@ -31,7 +31,6 @@
"eslint": "eslint . --ext .ts,.tsx --fix",
"eslint:check": "eslint . --ext .ts,.tsx",
"eslint:files": "eslint --fix",
"get:lab:version": "node ./buildutils/lib/get-latest-lab-version.js",
"integrity": "node buildutils/lib/ensure-repo.js",
"prettier": "prettier --write \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
"prettier:check": "prettier --list-different \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
@ -40,7 +39,6 @@
"release:patch": "node ./buildutils/lib/release-patch.js",
"test": "lerna run test",
"update:dependency": "node ./node_modules/@jupyterlab/buildutils/lib/update-dependency.js --lerna",
"upgrade:lab:dependencies": "node ./buildutils/lib/upgrade-lab-dependencies.js",
"watch": "run-p watch:lib watch:app",
"watch:app": "lerna exec --stream --scope \"@jupyter-notebook/app\" jlpm watch",
"watch:lib": "lerna exec --stream --scope @jupyter-notebook/metapackage jlpm watch"
@ -51,7 +49,7 @@
"yjs": "^13.5.40"
},
"devDependencies": {
"@jupyterlab/buildutils": "~4.6.0-alpha.0",
"@jupyterlab/buildutils": "~4.1.5",
"@typescript-eslint/eslint-plugin": "^5.55.0",
"@typescript-eslint/parser": "^5.55.0",
"eslint": "^8.36.0",
@ -59,12 +57,11 @@
"eslint-plugin-jest": "^27.2.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2",
"html-webpack-plugin": "^5.6.3",
"lerna": "^7.1.4",
"lerna": "^6.6.2",
"npm-run-all": "^4.1.5",
"prettier": "^2.8.5",
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"nx": {}
}

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/metapackage",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"private": true,
"description": "Jupyter Notebook - Metapackage",
"homepage": "https://github.com/jupyter/notebook",
@ -20,20 +20,20 @@
"watch": "tsc -b -w --preserveWatchOutput"
},
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyter-notebook/application-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/console-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/docmanager-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/documentsearch-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/help-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/lab-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/notebook-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/terminal-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/tree": "^7.6.0-alpha.0",
"@jupyter-notebook/tree-extension": "^7.6.0-alpha.0",
"@jupyter-notebook/ui-components": "^7.6.0-alpha.0"
"@jupyter-notebook/application": "^7.1.3",
"@jupyter-notebook/application-extension": "^7.1.3",
"@jupyter-notebook/console-extension": "^7.1.3",
"@jupyter-notebook/docmanager-extension": "^7.1.3",
"@jupyter-notebook/documentsearch-extension": "^7.1.3",
"@jupyter-notebook/help-extension": "^7.1.3",
"@jupyter-notebook/lab-extension": "^7.1.3",
"@jupyter-notebook/notebook-extension": "^7.1.3",
"@jupyter-notebook/terminal-extension": "^7.1.3",
"@jupyter-notebook/tree": "^7.1.3",
"@jupyter-notebook/tree-extension": "^7.1.3",
"@jupyter-notebook/ui-components": "^7.1.3"
},
"devDependencies": {
"typescript": "~5.5.4"
"typescript": "~5.0.2"
}
}

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/application-extension",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"description": "Jupyter Notebook - Application Extension",
"homepage": "https://github.com/jupyter/notebook",
"bugs": {
@ -38,26 +38,26 @@
"watch": "tsc -b --watch"
},
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyter-notebook/ui-components": "^7.6.0-alpha.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/apputils": "~4.7.0-alpha.0",
"@jupyterlab/codeeditor": "~4.6.0-alpha.0",
"@jupyterlab/console": "~4.6.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@jupyterlab/docmanager": "~4.6.0-alpha.0",
"@jupyterlab/docregistry": "~4.6.0-alpha.0",
"@jupyterlab/mainmenu": "~4.6.0-alpha.0",
"@jupyterlab/rendermime": "~4.6.0-alpha.0",
"@jupyterlab/settingregistry": "~4.6.0-alpha.0",
"@jupyterlab/translation": "~4.6.0-alpha.0",
"@lumino/coreutils": "^2.2.2",
"@lumino/disposable": "^2.1.5",
"@lumino/widgets": "^2.7.2"
"@jupyter-notebook/application": "^7.1.3",
"@jupyter-notebook/ui-components": "^7.1.3",
"@jupyterlab/application": "~4.1.5",
"@jupyterlab/apputils": "~4.2.5",
"@jupyterlab/codeeditor": "~4.1.5",
"@jupyterlab/console": "~4.1.5",
"@jupyterlab/coreutils": "~6.1.5",
"@jupyterlab/docmanager": "~4.1.5",
"@jupyterlab/docregistry": "~4.1.5",
"@jupyterlab/mainmenu": "~4.1.5",
"@jupyterlab/rendermime": "~4.1.5",
"@jupyterlab/settingregistry": "~4.1.5",
"@jupyterlab/translation": "~4.1.5",
"@lumino/coreutils": "^2.1.2",
"@lumino/disposable": "^2.1.2",
"@lumino/widgets": "^2.3.1"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -10,10 +10,6 @@
"command": "application:rename",
"rank": 4.5
},
{
"command": "application:duplicate",
"rank": 4.8
},
{
"command": "notebook:trust",
"rank": 20

@ -9,7 +9,6 @@
"title": "Customize shell widget positioning",
"description": "Overrides default widget position in the application layout",
"default": {
"Debugger Console": { "area": "down" },
"Markdown Preview": { "area": "right" },
"Plugins": { "area": "left" }
}

@ -1,16 +0,0 @@
{
"jupyter.lab.setting-icon": "notebook-ui-components:jupyter",
"jupyter.lab.setting-icon-label": "Jupyter Notebook shortcuts",
"title": "Jupyter Notebook Shortcuts",
"description": "Keyboard shortcuts for Jupyter Notebook",
"jupyter.lab.shortcuts": [
{
"args": {},
"command": "notebook:toggle-cell-outputs",
"keys": ["O"],
"selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) :focus"
}
],
"additionalProperties": false,
"type": "object"
}

@ -7,7 +7,6 @@ import {
ITreePathUpdater,
JupyterFrontEnd,
JupyterFrontEndPlugin,
JupyterLab,
} from '@jupyterlab/application';
import {
@ -16,7 +15,6 @@ import {
ISanitizer,
ISplashScreen,
IToolbarWidgetRegistry,
showErrorMessage,
} from '@jupyterlab/apputils';
import { ConsolePanel } from '@jupyterlab/console';
@ -85,11 +83,6 @@ const JUPYTERLAB_DOCMANAGER_PLUGIN_ID =
* The command IDs used by the application plugin.
*/
namespace CommandIDs {
/**
* Duplicate the current document and open the new document
*/
export const duplicate = 'application:duplicate';
/**
* Handle local links
*/
@ -161,21 +154,6 @@ const dirty: JupyterFrontEndPlugin<void> = {
},
};
/**
* The application info.
*/
const info: JupyterFrontEndPlugin<JupyterLab.IInfo> = {
id: '@jupyter-notebook/application-extension:info',
autoStart: true,
provides: JupyterLab.IInfo,
activate: (app: JupyterFrontEnd): JupyterLab.IInfo => {
if (!(app instanceof NotebookApp)) {
throw new Error(`${info.id} must be activated in Jupyter Notebook.`);
}
return app.info;
},
};
/**
* The logo plugin.
*/
@ -637,20 +615,6 @@ const title: JupyterFrontEndPlugin<void> = {
return !!(currentWidget && docManager.contextForWidget(currentWidget));
};
commands.addCommand(CommandIDs.duplicate, {
label: () => trans.__('Duplicate'),
isEnabled,
execute: async () => {
if (!isEnabled()) {
return;
}
// Duplicate the file, and open the new file.
const result = await docManager.duplicate(current.context.path);
await commands.execute('docmanager:open', { path: result.path });
},
});
commands.addCommand(CommandIDs.rename, {
label: () => trans.__('Rename…'),
isEnabled,
@ -659,23 +623,14 @@ const title: JupyterFrontEndPlugin<void> = {
return;
}
try {
const result = await renameDialog(docManager, current.context);
const result = await renameDialog(docManager, current.context);
// activate the current widget to bring the focus
if (current) {
current.activate();
}
// activate the current widget to bring the focus
if (current) {
current.activate();
}
if (result === null) {
return;
}
} catch (error) {
showErrorMessage(
trans.__('Rename Error'),
(error as Error).message ||
trans.__('An error occurred while renaming the file.')
);
if (result === null) {
return;
}
@ -1006,20 +961,6 @@ const sidePanelVisibility: JupyterFrontEndPlugin<void> = {
},
};
/**
* A plugin for defining keyboard shortcuts specific to the notebook application.
*/
const shortcuts: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:shortcuts',
description:
'A plugin for defining keyboard shortcuts specific to the notebook application.',
autoStart: true,
activate: (app: JupyterFrontEnd) => {
// for now this plugin is mostly useful for defining keyboard shortcuts
// specific to the notebook application
},
};
/**
* The default tree route resolver plugin.
*/
@ -1188,7 +1129,6 @@ const zen: JupyterFrontEndPlugin<void> = {
*/
const plugins: JupyterFrontEndPlugin<any>[] = [
dirty,
info,
logo,
menus,
menuSpacer,
@ -1199,7 +1139,6 @@ const plugins: JupyterFrontEndPlugin<any>[] = [
rendermime,
shell,
sidePanelVisibility,
shortcuts,
splash,
status,
tabTitle,

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/application",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"description": "Jupyter Notebook - Application",
"homepage": "https://github.com/jupyter/notebook",
"bugs": {
@ -42,27 +42,27 @@
"watch": "tsc -b --watch"
},
"dependencies": {
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@jupyterlab/docregistry": "~4.6.0-alpha.0",
"@jupyterlab/rendermime-interfaces": "~3.14.0-alpha.0",
"@jupyterlab/ui-components": "~4.6.0-alpha.0",
"@lumino/algorithm": "^2.0.4",
"@lumino/coreutils": "^2.2.2",
"@lumino/messaging": "^2.0.4",
"@lumino/polling": "^2.1.5",
"@lumino/signaling": "^2.1.5",
"@lumino/widgets": "^2.7.2"
"@jupyterlab/application": "~4.1.5",
"@jupyterlab/coreutils": "~6.1.5",
"@jupyterlab/docregistry": "~4.1.5",
"@jupyterlab/rendermime-interfaces": "~3.9.5",
"@jupyterlab/ui-components": "~4.1.5",
"@lumino/algorithm": "^2.0.1",
"@lumino/coreutils": "^2.1.2",
"@lumino/messaging": "^2.0.1",
"@lumino/polling": "^2.1.2",
"@lumino/signaling": "^2.1.2",
"@lumino/widgets": "^2.3.1"
},
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.12.1",
"@jupyterlab/testutils": "~4.6.0-alpha.0",
"@jupyterlab/testutils": "~4.1.5",
"@types/jest": "^29.2.5",
"jest": "^29.3.1",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -15,7 +15,7 @@ class DefaultNotebookPathOpener implements INotebookPathOpener {
open(options: INotebookPathOpener.IOpenOptions): WindowProxy | null {
const { prefix, path, searchParams, target, features } = options;
const url = new URL(
URLExt.join(prefix, URLExt.encodeParts(path ?? '')),
URLExt.join(prefix, path ?? ''),
window.location.origin
);
if (searchParams) {

@ -9,16 +9,8 @@ import { find } from '@lumino/algorithm';
import { JSONExt, PromiseDelegate, Token } from '@lumino/coreutils';
import { ISignal, Signal } from '@lumino/signaling';
import {
BoxLayout,
FocusTracker,
Panel,
SplitPanel,
TabPanel,
Widget,
} from '@lumino/widgets';
import { BoxLayout, Panel, SplitPanel, Widget } from '@lumino/widgets';
import { PanelHandler, SidePanelHandler } from './panelhandler';
import { TabPanelSvg } from '@jupyterlab/ui-components';
/**
* The Jupyter Notebook application shell token.
@ -39,7 +31,7 @@ export namespace INotebookShell {
/**
* The areas of the application shell where widgets can reside.
*/
export type Area = 'main' | 'top' | 'menu' | 'left' | 'right' | 'down';
export type Area = 'main' | 'top' | 'menu' | 'left' | 'right';
/**
* Widget position
@ -136,18 +128,6 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
middlePanel.addWidget(this._spacer_bottom);
middlePanel.layout = middleLayout;
const vsplitPanel = new SplitPanel();
vsplitPanel.id = 'jp-main-vsplit-panel';
vsplitPanel.spacing = 1;
vsplitPanel.orientation = 'vertical';
SplitPanel.setStretch(vsplitPanel, 1);
const downPanel = new TabPanelSvg({
tabsMovable: true,
});
this._downPanel = downPanel;
this._downPanel.id = 'jp-down-stack';
// TODO: Consider storing this as an attribute this._hsplitPanel if saving/restoring layout needed
const hsplitPanel = new SplitPanel();
hsplitPanel.id = 'main-split-panel';
@ -167,21 +147,8 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
// panel.
hsplitPanel.setRelativeSizes([1, 2.5, 1]);
vsplitPanel.addWidget(hsplitPanel);
vsplitPanel.addWidget(downPanel);
rootLayout.spacing = 0;
rootLayout.addWidget(vsplitPanel);
// initially hiding the down panel
this._downPanel.hide();
// Connect down panel change listeners
this._downPanel.tabBar.tabMoved.connect(this._onTabPanelChanged, this);
this._downPanel.stackedPanel.widgetRemoved.connect(
this._onTabPanelChanged,
this
);
rootLayout.addWidget(hsplitPanel);
this.layout = rootLayout;
@ -196,10 +163,7 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
/**
* A signal emitted when the current widget changes.
*/
get currentChanged(): ISignal<
JupyterFrontEnd.IShell,
FocusTracker.IChangedArgs<Widget>
> {
get currentChanged(): ISignal<NotebookShell, void> {
return this._currentChanged;
}
@ -294,7 +258,7 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
*/
activateById(id: string): void {
// Search all areas that can have widgets for this widget, starting with main.
for (const area of ['main', 'top', 'left', 'right', 'menu', 'down']) {
for (const area of ['main', 'top', 'left', 'right', 'menu']) {
const widget = find(
this.widgets(area as INotebookShell.Area),
(w) => w.id === id
@ -304,9 +268,6 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
this.expandLeft(id);
} else if (area === 'right') {
this.expandRight(id);
} else if (area === 'down') {
this._downPanel.show();
widget.activate();
} else {
widget.activate();
}
@ -353,27 +314,20 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
case 'menu':
return this._menuHandler.addWidget(widget, rank);
case 'main':
case undefined: {
case undefined:
if (this._main.widgets.length > 0) {
// do not add the widget if there is already one
return;
}
const previousWidget = this.currentWidget;
this._main.addWidget(widget);
this._main.update();
this._currentChanged.emit({
newValue: widget,
oldValue: previousWidget,
});
this._currentChanged.emit(void 0);
this._mainWidgetLoaded.resolve();
break;
}
case 'left':
return this._leftHandler.addWidget(widget, rank);
case 'right':
return this._rightHandler.addWidget(widget, rank);
case 'down':
return this._downPanel.addWidget(widget);
default:
console.warn(`Cannot add widget to area: ${area}`);
}
@ -417,9 +371,6 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
case 'right':
yield* this._rightHandler.widgets;
return;
case 'down':
yield* this._downPanel.widgets;
return;
default:
console.error(`This shell has no area called "${area}"`);
return;
@ -467,15 +418,6 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
this._userLayout = configuration;
}
/**
* Handle a change on the down panel widgets
*/
private _onTabPanelChanged(): void {
if (this._downPanel.stackedPanel.widgets.length === 0) {
this._downPanel.hide();
}
}
private _topWrapper: Panel;
private _topHandler: PanelHandler;
private _menuWrapper: Panel;
@ -486,11 +428,8 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
private _spacer_bottom: Widget;
private _skipLinkWidgetHandler: Private.SkipLinkWidgetHandler;
private _main: Panel;
private _downPanel: TabPanel;
private _translator: ITranslator = nullTranslator;
private _currentChanged = new Signal<this, FocusTracker.IChangedArgs<Widget>>(
this
);
private _currentChanged = new Signal<this, void>(this);
private _mainWidgetLoaded = new PromiseDelegate<void>();
private _userLayout: INotebookShell.IUserLayout;
}

@ -10,23 +10,18 @@
--jp-notebook-max-width: 1200px;
}
/*
Override the default background
See https://github.com/jupyterlab/jupyterlab/pull/16519 for more information
*/
body.jp-ThemedContainer {
body {
margin: 0;
padding: 0;
background: var(--jp-layout-color2);
}
#main.jp-ThemedContainer {
#main {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--jp-layout-color2);
}
#top-panel-wrapper {

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/console-extension",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"description": "Jupyter Notebook - Console Extension",
"homepage": "https://github.com/jupyter/notebook",
"bugs": {
@ -38,15 +38,15 @@
"watch": "tsc -b --watch"
},
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/console": "~4.6.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@lumino/algorithm": "^2.0.4"
"@jupyter-notebook/application": "^7.1.3",
"@jupyterlab/application": "~4.1.5",
"@jupyterlab/console": "~4.1.5",
"@jupyterlab/coreutils": "~6.1.5",
"@lumino/algorithm": "^2.0.1"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/docmanager-extension",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"description": "Jupyter Notebook - Document Manager Extension",
"homepage": "https://github.com/jupyter/notebook",
"bugs": {
@ -38,18 +38,18 @@
"watch": "tsc -b --watch"
},
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@jupyterlab/docmanager": "~4.6.0-alpha.0",
"@jupyterlab/docregistry": "~4.6.0-alpha.0",
"@jupyterlab/services": "~7.6.0-alpha.0",
"@lumino/algorithm": "^2.0.4",
"@lumino/signaling": "^2.1.5"
"@jupyter-notebook/application": "^7.1.3",
"@jupyterlab/application": "~4.1.5",
"@jupyterlab/coreutils": "~6.1.5",
"@jupyterlab/docmanager": "~4.1.5",
"@jupyterlab/docregistry": "~4.1.5",
"@jupyterlab/services": "~7.1.5",
"@lumino/algorithm": "^2.0.1",
"@lumino/signaling": "^2.1.2"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/documentsearch-extension",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"description": "Jupyter Notebook - Document Search Extension",
"homepage": "https://github.com/jupyter/notebook",
"bugs": {
@ -38,14 +38,14 @@
"watch": "tsc -b --watch"
},
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/documentsearch": "~4.6.0-alpha.0",
"@lumino/widgets": "^2.7.2"
"@jupyter-notebook/application": "^7.1.3",
"@jupyterlab/application": "~4.1.5",
"@jupyterlab/documentsearch": "~4.1.5",
"@lumino/widgets": "^2.3.1"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/help-extension",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"description": "Jupyter Notebook - Help Extension",
"homepage": "https://github.com/jupyter/notebook",
"bugs": {
@ -38,17 +38,17 @@
"watch": "tsc -b --watch"
},
"dependencies": {
"@jupyter-notebook/ui-components": "^7.6.0-alpha.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/apputils": "~4.7.0-alpha.0",
"@jupyterlab/mainmenu": "~4.6.0-alpha.0",
"@jupyterlab/translation": "~4.6.0-alpha.0",
"@jupyter-notebook/ui-components": "^7.1.3",
"@jupyterlab/application": "~4.1.5",
"@jupyterlab/apputils": "~4.2.5",
"@jupyterlab/mainmenu": "~4.1.5",
"@jupyterlab/translation": "~4.1.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/lab-extension",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"description": "Jupyter Notebook - Lab Extension",
"homepage": "https://github.com/jupyter/notebook",
"bugs": {
@ -43,21 +43,21 @@
"watch:src": "tsc -w"
},
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/apputils": "~4.7.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@jupyterlab/docregistry": "~4.6.0-alpha.0",
"@jupyterlab/notebook": "~4.6.0-alpha.0",
"@jupyterlab/translation": "~4.6.0-alpha.0",
"@jupyterlab/ui-components": "~4.6.0-alpha.0",
"@lumino/commands": "^2.3.3",
"@lumino/disposable": "^2.1.5"
"@jupyter-notebook/application": "^7.1.3",
"@jupyterlab/application": "~4.1.5",
"@jupyterlab/apputils": "~4.2.5",
"@jupyterlab/coreutils": "~6.1.5",
"@jupyterlab/docregistry": "~4.1.5",
"@jupyterlab/notebook": "~4.1.5",
"@jupyterlab/translation": "~4.1.5",
"@jupyterlab/ui-components": "~4.1.5",
"@lumino/commands": "^2.2.0",
"@lumino/disposable": "^2.1.2"
},
"devDependencies": {
"@jupyterlab/builder": "~4.6.0-alpha.0",
"@jupyterlab/builder": "~4.1.5",
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -69,9 +69,8 @@ const interfaceSwitcher: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/lab-extension:interface-switcher',
description: 'A plugin to add custom toolbar items to the notebook page.',
autoStart: true,
requires: [ITranslator],
requires: [ITranslator, INotebookTracker],
optional: [
INotebookTracker,
ICommandPalette,
INotebookPathOpener,
INotebookShell,
@ -81,18 +80,13 @@ const interfaceSwitcher: JupyterFrontEndPlugin<void> = {
activate: (
app: JupyterFrontEnd,
translator: ITranslator,
notebookTracker: INotebookTracker | null,
notebookTracker: INotebookTracker,
palette: ICommandPalette | null,
notebookPathOpener: INotebookPathOpener | null,
notebookShell: INotebookShell | null,
labShell: ILabShell | null,
toolbarRegistry: IToolbarWidgetRegistry | null
) => {
if (!notebookTracker) {
// bail if trying to use this plugin without a notebook tracker
return;
}
const { commands, shell } = app;
const baseUrl = PageConfig.getBaseUrl();
const trans = translator.load('notebook');

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/notebook-extension",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"description": "Jupyter Notebook - Notebook Extension",
"homepage": "https://github.com/jupyter/notebook",
"bugs": {
@ -38,22 +38,22 @@
"watch": "tsc -b --watch"
},
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/apputils": "~4.7.0-alpha.0",
"@jupyterlab/cells": "~4.6.0-alpha.0",
"@jupyterlab/docmanager": "~4.6.0-alpha.0",
"@jupyterlab/notebook": "~4.6.0-alpha.0",
"@jupyterlab/settingregistry": "~4.6.0-alpha.0",
"@jupyterlab/translation": "~4.6.0-alpha.0",
"@lumino/polling": "^2.1.5",
"@lumino/widgets": "^2.7.2",
"@jupyter-notebook/application": "^7.1.3",
"@jupyterlab/application": "~4.1.5",
"@jupyterlab/apputils": "~4.2.5",
"@jupyterlab/cells": "~4.1.5",
"@jupyterlab/docmanager": "~4.1.5",
"@jupyterlab/notebook": "~4.1.5",
"@jupyterlab/settingregistry": "~4.1.5",
"@jupyterlab/translation": "~4.1.5",
"@lumino/polling": "^2.1.2",
"@lumino/widgets": "^2.3.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -4,15 +4,7 @@
"jupyter.lab.toolbars": {
"TopBar": [{ "name": "checkpoint", "rank": 20 }]
},
"properties": {
"checkpointPollingInterval": {
"type": "number",
"title": "Checkpoint Polling Interval (seconds)",
"description": "How often to check for checkpoints (in seconds). Set to 0 to disable polling.",
"default": 30,
"minimum": 0
}
},
"properties": {},
"additionalProperties": false,
"type": "object"
}

@ -3,15 +3,6 @@
"description": "Jupyter Notebook Menu Entries",
"jupyter.lab.menus": {
"main": [
{
"id": "jp-mainmenu-file",
"items": [
{
"command": "notebook:open-tree-tab",
"rank": 1
}
]
},
{
"id": "jp-mainmenu-edit",
"items": [

@ -1,27 +0,0 @@
{
"title": "Jupyter Notebook Full Width Notebook",
"description": "Jupyter Notebook Notebook With settings",
"jupyter.lab.menus": {
"main": [
{
"id": "jp-mainmenu-view",
"items": [
{
"command": "notebook:toggle-full-width",
"rank": 4
}
]
}
]
},
"properties": {
"fullWidthNotebook": {
"type": "boolean",
"title": "Full Width Notebook",
"description": "Whether to the notebook should take up the full width of the application",
"default": false
}
},
"additionalProperties": false,
"type": "object"
}

@ -19,8 +19,6 @@ import { PageConfig, Text, Time, URLExt } from '@jupyterlab/coreutils';
import { IDocumentManager } from '@jupyterlab/docmanager';
import { DocumentRegistry } from '@jupyterlab/docregistry';
import { IMainMenu } from '@jupyterlab/mainmenu';
import {
@ -66,11 +64,6 @@ const KERNEL_STATUS_FADE_OUT_CLASS = 'jp-NotebookKernelStatus-fade';
*/
const SCROLLED_OUTPUTS_CLASS = 'jp-mod-outputsScrolled';
/**
* The class for the full width notebook
*/
const FULL_WIDTH_NOTEBOOK_CLASS = 'jp-mod-fullwidth';
/**
* The command IDs used by the notebook plugins.
*/
@ -79,11 +72,6 @@ namespace CommandIDs {
* A command to open right sidebar for Editing Notebook Metadata
*/
export const openEditNotebookMetadata = 'notebook:edit-metadata';
/**
* A command to toggle full width of the notebook
*/
export const toggleFullWidth = 'notebook:toggle-full-width';
}
/**
@ -94,14 +82,13 @@ const checkpoints: JupyterFrontEndPlugin<void> = {
description: 'A plugin for the checkpoint indicator.',
autoStart: true,
requires: [IDocumentManager, ITranslator],
optional: [INotebookShell, IToolbarWidgetRegistry, ISettingRegistry],
optional: [INotebookShell, IToolbarWidgetRegistry],
activate: (
app: JupyterFrontEnd,
docManager: IDocumentManager,
translator: ITranslator,
notebookShell: INotebookShell | null,
toolbarRegistry: IToolbarWidgetRegistry | null,
settingRegistry: ISettingRegistry | null
toolbarRegistry: IToolbarWidgetRegistry | null
) => {
const { shell } = app;
const trans = translator.load('notebook');
@ -116,26 +103,18 @@ const checkpoints: JupyterFrontEndPlugin<void> = {
});
}
const getCurrent = () => {
const onChange = async () => {
const current = shell.currentWidget;
if (!current) {
return null;
return;
}
const context = docManager.contextForWidget(current);
if (!context) {
return null;
}
return context;
};
const updateCheckpointDisplay = async () => {
const current = getCurrent();
if (!current) {
return;
}
const checkpoints = await current.listCheckpoints();
if (!checkpoints || !checkpoints.length) {
node.textContent = '';
context?.fileChanged.disconnect(onChange);
context?.fileChanged.connect(onChange);
const checkpoints = await context?.listCheckpoints();
if (!checkpoints) {
return;
}
const checkpoint = checkpoints[checkpoints.length - 1];
@ -145,80 +124,19 @@ const checkpoints: JupyterFrontEndPlugin<void> = {
);
};
const onSaveState = async (
sender: DocumentRegistry.IContext<DocumentRegistry.IModel>,
state: DocumentRegistry.SaveState
) => {
if (state !== 'completed') {
return;
}
// Add a small artificial delay so that the UI can pick up the newly created checkpoint.
// Since the save state signal is emitted after a file save, but not after a checkpoint has been created.
setTimeout(() => {
void updateCheckpointDisplay();
}, 500);
};
const onChange = async () => {
const context = getCurrent();
if (!context) {
return;
}
context.saveState.disconnect(onSaveState);
context.saveState.connect(onSaveState);
await updateCheckpointDisplay();
};
if (notebookShell) {
notebookShell.currentChanged.connect(onChange);
}
let checkpointPollingInterval = 30; // Default 30 seconds
let poll: Poll | null = null;
const createPoll = () => {
if (poll) {
poll.dispose();
}
if (checkpointPollingInterval > 0) {
poll = new Poll({
auto: true,
factory: () => updateCheckpointDisplay(),
frequency: {
interval: checkpointPollingInterval * 1000,
backoff: false,
},
standby: 'when-hidden',
});
}
};
const updateSettings = (settings: ISettingRegistry.ISettings): void => {
checkpointPollingInterval = settings.get('checkpointPollingInterval')
.composite as number;
createPoll();
};
if (settingRegistry) {
const loadSettings = settingRegistry.load(checkpoints.id);
Promise.all([loadSettings, app.restored])
.then(([settings]) => {
updateSettings(settings);
settings.changed.connect(updateSettings);
})
.catch((reason: Error) => {
console.error(
`Failed to load settings for ${checkpoints.id}: ${reason.message}`
);
// Fall back to creating poll with default settings
createPoll();
});
} else {
// Create poll with default settings
createPoll();
}
new Poll({
auto: true,
factory: () => onChange(),
frequency: {
interval: 2000,
backoff: false,
},
standby: 'when-hidden',
});
},
};
@ -245,8 +163,7 @@ const closeTab: JupyterFrontEndPlugin<void> = {
commands.addCommand(id, {
label: trans.__('Close and Shut Down Notebook'),
execute: async () => {
// Shut the kernel down, without confirmation
await commands.execute('notebook:shutdown-kernel', { activate: false });
await commands.execute('notebook:close-and-shutdown');
window.close();
},
});
@ -259,108 +176,6 @@ const closeTab: JupyterFrontEndPlugin<void> = {
},
};
/**
* Add a command to open the tree view from the notebook view
*/
const openTreeTab: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/notebook-extension:open-tree-tab',
description:
'Add a command to open a browser tab on the tree view when clicking "Open...".',
autoStart: true,
optional: [ITranslator],
activate: (app: JupyterFrontEnd, translator: ITranslator | null) => {
const { commands } = app;
translator = translator ?? nullTranslator;
const trans = translator.load('notebook');
const id = 'notebook:open-tree-tab';
commands.addCommand(id, {
label: trans.__('Open…'),
execute: async () => {
const url = URLExt.join(PageConfig.getBaseUrl(), 'tree');
window.open(url);
},
});
},
};
/**
* A plugin to set the notebook to full width.
*/
const fullWidthNotebook: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/notebook-extension:full-width-notebook',
description: 'A plugin to set the notebook to full width.',
autoStart: true,
requires: [INotebookTracker],
optional: [ICommandPalette, ISettingRegistry, ITranslator],
activate: (
app: JupyterFrontEnd,
tracker: INotebookTracker,
palette: ICommandPalette | null,
settingRegistry: ISettingRegistry | null,
translator: ITranslator | null
) => {
const trans = (translator ?? nullTranslator).load('notebook');
let fullWidth = false;
const toggleFullWidth = () => {
const current = tracker.currentWidget;
fullWidth = !fullWidth;
if (!current) {
return;
}
const content = current;
content.toggleClass(FULL_WIDTH_NOTEBOOK_CLASS, fullWidth);
};
let notebookSettings: ISettingRegistry.ISettings;
if (settingRegistry) {
const loadSettings = settingRegistry.load(fullWidthNotebook.id);
const updateSettings = (settings: ISettingRegistry.ISettings): void => {
const newFullWidth = settings.get('fullWidthNotebook')
.composite as boolean;
if (newFullWidth !== fullWidth) {
toggleFullWidth();
}
};
Promise.all([loadSettings, app.restored])
.then(([settings]) => {
notebookSettings = settings;
updateSettings(settings);
settings.changed.connect((settings) => {
updateSettings(settings);
});
})
.catch((reason: Error) => {
console.error(reason.message);
});
}
app.commands.addCommand(CommandIDs.toggleFullWidth, {
label: trans.__('Enable Full Width Notebook'),
execute: () => {
toggleFullWidth();
if (notebookSettings) {
notebookSettings.set('fullWidthNotebook', fullWidth);
}
},
isEnabled: () => tracker.currentWidget !== null,
isToggled: () => fullWidth,
});
if (palette) {
palette.addItem({
command: CommandIDs.toggleFullWidth,
category: 'Notebook Operations',
});
}
},
};
/**
* The kernel logo plugin.
*/
@ -511,7 +326,6 @@ const scrollOutput: JupyterFrontEndPlugin<void> = {
const autoScroll = (cell: CodeCell) => {
if (!autoScrollOutputs) {
// bail if disabled via the settings
cell.removeClass(SCROLLED_OUTPUTS_CLASS);
return;
}
const { outputArea } = cell;
@ -755,9 +569,7 @@ const editNotebookMetadata: JupyterFrontEndPlugin<void> = {
const plugins: JupyterFrontEndPlugin<any>[] = [
checkpoints,
closeTab,
openTreeTab,
editNotebookMetadata,
fullWidthNotebook,
kernelLogo,
kernelStatus,
notebookToolsWidget,

@ -16,16 +16,6 @@
- compact view on mobile
*/
/* Make the notebook take up the full width of the page when jp-mod-fullwidth is set */
body[data-notebook='notebooks']
.jp-NotebookPanel.jp-mod-fullwidth
.jp-WindowedPanel-outer {
padding-left: unset;
padding-right: unset !important;
width: unset;
}
/* Keep the notebook centered on the page */
body[data-notebook='notebooks'] .jp-NotebookPanel-toolbar {
@ -34,25 +24,24 @@ body[data-notebook='notebooks'] .jp-NotebookPanel-toolbar {
}
body[data-notebook='notebooks'] .jp-WindowedPanel-outer {
width: unset !important;
padding-top: unset;
padding-left: calc(calc(100% - var(--jp-notebook-max-width)) * 0.5);
padding-right: calc(
calc(
100% - var(--jp-notebook-max-width) - var(--jp-notebook-padding-offset)
) * 0.5
) !important;
);
background: var(--jp-layout-color2);
}
body[data-notebook='notebooks'] .jp-WindowedPanel-inner {
margin-top: var(--jp-notebook-toolbar-margin-bottom);
/* Adjustments for the extra top and bottom notebook padding */
margin-bottom: calc(4 * var(--jp-notebook-padding));
}
body[data-notebook='notebooks'] .jp-Notebook-cell {
background: var(--jp-layout-color0);
padding-left: calc(2 * var(--jp-cell-padding));
padding-right: calc(2 * var(--jp-cell-padding));
}
/* Empty space at the bottom of the notebook (similar to classic) */
@ -74,6 +63,18 @@ body[data-notebook='notebooks']
background: var(--jp-layout-color0) !important;
}
/**
Extra padding to the first and and last cell of the notebook.
TODO: revisit when https://github.com/jupyterlab/jupyterlab/issues/13151 is fixed
*/
.jp-Notebook-cell[data-windowed-list-index='0'] {
padding-top: calc(2 * var(--jp-notebook-padding));
}
body[data-notebook='notebooks'] .jp-WindowedPanel-viewport > *:last-child {
padding-bottom: calc(2 * var(--jp-notebook-padding));
}
body[data-notebook='notebooks']
.jp-Notebook
.jp-Notebook-cell:not(:first-child)::before {
@ -91,6 +92,15 @@ body[data-notebook='notebooks'] .jp-cell-toolbar {
box-shadow: unset;
}
body[data-notebook='notebooks']
.jp-RawCell[data-windowed-list-index='0']
.jp-cell-toolbar,
body[data-notebook='notebooks']
.jp-MarkdownCell[data-windowed-list-index='0']
.jp-cell-toolbar {
top: calc(2 * var(--jp-notebook-padding));
}
/** first code cell on mobile
(keep the selector above the media query)
*/
@ -116,9 +126,9 @@ body[data-notebook='notebooks']
/* Tweak the notebook footer (to add a new cell) */
body[data-notebook='notebooks'] .jp-Notebook-footer {
background: unset;
width: 100%;
margin-left: unset;
background: unset;
}
/* Mobile View */
@ -135,17 +145,21 @@ body[data-format='mobile'] .jp-ToolbarButton .jp-DebuggerBugButton {
display: none;
}
/* Virtual Notebook fixes */
body[data-notebook='notebooks'] .jp-WindowedPanel-viewport {
background: var(--jp-layout-color0);
box-shadow: var(--jp-elevation-z4);
/* Extra padding at the top and bottom so the notebook looks nicer */
padding-top: calc(2 * var(--jp-notebook-padding));
padding-bottom: calc(2 * var(--jp-notebook-padding));
padding: unset;
}
/* Notebook box shadow */
body[data-notebook='notebooks']
.jp-WindowedPanel-outer
> *:first-child:not(:last-child) {
box-shadow: var(--jp-elevation-z4);
}
body[data-notebook='notebooks']
.jp-Notebook
> *:first-child:last-child::before {
@ -158,6 +172,19 @@ body[data-notebook='notebooks']
box-shadow: 0px 0px 12px 1px var(--jp-shadow-umbra-color);
}
body[data-notebook='notebooks']
.jp-Notebook
.jp-Notebook-cell:not(:first-child)::after,
body[data-notebook='notebooks']
.jp-Notebook
.jp-Notebook-cell:not(:first-child)::before {
content: ' ';
height: 100%;
position: absolute;
top: 0;
width: 11px;
}
/* Additional customizations of the components on the notebook page */
.jp-NotebookKernelLogo {

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/terminal-extension",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"description": "Jupyter Notebook - Terminal Extension",
"homepage": "https://github.com/jupyter/notebook",
"bugs": {
@ -38,15 +38,15 @@
"watch": "tsc -b --watch"
},
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@jupyterlab/terminal": "~4.6.0-alpha.0",
"@lumino/algorithm": "^2.0.4"
"@jupyter-notebook/application": "^7.1.3",
"@jupyterlab/application": "~4.1.5",
"@jupyterlab/coreutils": "~6.1.5",
"@jupyterlab/terminal": "~4.1.5",
"@lumino/algorithm": "^2.0.1"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/tree-extension",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"description": "Jupyter Notebook - Tree Extension",
"homepage": "https://github.com/jupyter/notebook",
"bugs": {
@ -38,27 +38,27 @@
"watch": "tsc -b --watch"
},
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyter-notebook/tree": "^7.6.0-alpha.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/apputils": "~4.7.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@jupyterlab/docmanager": "~4.6.0-alpha.0",
"@jupyterlab/filebrowser": "~4.6.0-alpha.0",
"@jupyterlab/mainmenu": "~4.6.0-alpha.0",
"@jupyterlab/services": "~7.6.0-alpha.0",
"@jupyterlab/settingeditor": "~4.6.0-alpha.0",
"@jupyterlab/settingregistry": "~4.6.0-alpha.0",
"@jupyterlab/statedb": "~4.6.0-alpha.0",
"@jupyterlab/translation": "~4.6.0-alpha.0",
"@jupyterlab/ui-components": "~4.6.0-alpha.0",
"@lumino/algorithm": "^2.0.4",
"@lumino/commands": "^2.3.3",
"@lumino/widgets": "^2.7.2"
"@jupyter-notebook/application": "^7.1.3",
"@jupyter-notebook/tree": "^7.1.3",
"@jupyterlab/application": "~4.1.5",
"@jupyterlab/apputils": "~4.2.5",
"@jupyterlab/coreutils": "~6.1.5",
"@jupyterlab/docmanager": "~4.1.5",
"@jupyterlab/filebrowser": "~4.1.5",
"@jupyterlab/mainmenu": "~4.1.5",
"@jupyterlab/services": "~7.1.5",
"@jupyterlab/settingeditor": "~4.1.5",
"@jupyterlab/settingregistry": "~4.1.5",
"@jupyterlab/statedb": "~4.1.5",
"@jupyterlab/translation": "~4.1.5",
"@jupyterlab/ui-components": "~4.1.5",
"@lumino/algorithm": "^2.0.1",
"@lumino/commands": "^2.2.0",
"@lumino/widgets": "^2.3.1"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -4,12 +4,7 @@
"jupyter.lab.toolbars": {
"FileBrowser": [
{ "name": "spacer", "type": "spacer", "rank": 900 },
{
"name": "toggle-file-filter",
"label": "",
"command": "filebrowser:toggle-file-filter",
"rank": 990
},
{ "name": "fileNameSearcher", "rank": 950, "disabled": true },
{ "name": "new-dropdown", "rank": 1000 },
{ "name": "uploader", "rank": 1010 },
{ "name": "refresh", "command": "filebrowser:refresh", "rank": 1020 }

@ -7,7 +7,6 @@ import {
} from '@jupyterlab/application';
import {
ICommandPalette,
IToolbarWidgetRegistry,
createToolbarFactory,
setToolbar,
@ -35,10 +34,14 @@ import { ITranslator } from '@jupyterlab/translation';
import {
caretDownIcon,
FilenameSearcher,
folderIcon,
IScore,
runningIcon,
} from '@jupyterlab/ui-components';
import { Signal } from '@lumino/signaling';
import { Menu, MenuBar } from '@lumino/widgets';
import { NotebookTreeWidget, INotebookTree } from '@jupyter-notebook/tree';
@ -55,15 +58,17 @@ const FILE_BROWSER_FACTORY = 'FileBrowser';
*/
const FILE_BROWSER_PLUGIN_ID = '@jupyterlab/filebrowser-extension:browser';
/**
* The class name added to the filebrowser filterbox node.
*/
const FILTERBOX_CLASS = 'jp-FileBrowser-filterBox';
/**
* The namespace for command IDs.
*/
namespace CommandIDs {
// The command to activate the filebrowser widget in tree view.
export const activate = 'filebrowser:activate';
// Activate the file filter in the file browser
export const toggleFileFilter = 'filebrowser:toggle-file-filter';
}
/**
@ -153,10 +158,25 @@ const fileActions: JupyterFrontEndPlugin<void> = {
toolbarRegistry: IToolbarWidgetRegistry,
translator: ITranslator
) => {
// TODO: use upstream signal when available to detect selection changes
// https://github.com/jupyterlab/jupyterlab/issues/14598
const selectionChanged = new Signal<FileBrowser, void>(browser);
const methods = [
'_selectItem',
'_handleMultiSelect',
'handleFileSelect',
] as const;
methods.forEach((method: (typeof methods)[number]) => {
const original = browser['listing'][method];
browser['listing'][method] = (...args: any[]) => {
original.call(browser['listing'], ...args);
selectionChanged.emit(void 0);
};
});
// Create a toolbar item that adds buttons to the file browser toolbar
// to perform actions on the files
const { commands } = app;
const { selectionChanged } = browser;
const fileActions = new FilesActionButtons({
commands,
browser,
@ -169,76 +189,6 @@ const fileActions: JupyterFrontEndPlugin<void> = {
},
};
/**
* A plugin to set the default file browser settings.
*/
const fileBrowserSettings: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/tree-extension:settings',
description: 'Set up the default file browser settings',
requires: [IDefaultFileBrowser],
optional: [ISettingRegistry],
autoStart: true,
activate: (
app: JupyterFrontEnd,
browser: IDefaultFileBrowser,
settingRegistry: ISettingRegistry | null
) => {
// Default config for notebook.
// This is a different set of defaults than JupyterLab.
const defaultFileBrowserConfig = {
navigateToCurrentDirectory: false,
singleClickNavigation: true,
showLastModifiedColumn: true,
showFileSizeColumn: true,
showHiddenFiles: false,
showFileCheckboxes: true,
sortNotebooksFirst: true,
showFullPath: false,
};
// Apply defaults on plugin activation
let key: keyof typeof defaultFileBrowserConfig;
for (key in defaultFileBrowserConfig) {
browser[key] = defaultFileBrowserConfig[key];
}
if (settingRegistry) {
void settingRegistry.load(FILE_BROWSER_PLUGIN_ID).then((settings) => {
function onSettingsChanged(settings: ISettingRegistry.ISettings): void {
let key: keyof typeof defaultFileBrowserConfig;
for (key in defaultFileBrowserConfig) {
const value = settings.get(key).user as boolean;
// only set the setting if it is defined by the user
if (value !== undefined) {
browser[key] = value;
}
}
}
settings.changed.connect(onSettingsChanged);
onSettingsChanged(settings);
});
}
},
};
/**
* A plugin to add the file filter toggle command to the palette
*/
const fileFilterCommand: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/tree-extension:file-filter-command',
description: 'A plugin to add file filter command to the palette.',
autoStart: true,
optional: [ICommandPalette],
activate: (app: JupyterFrontEnd, palette: ICommandPalette | null) => {
if (palette) {
palette.addItem({
command: CommandIDs.toggleFileFilter,
category: 'File Browser',
});
}
},
};
/**
* Plugin to load the default plugins that are loaded on all the Notebook pages
* (tree, edit, view, etc.) so they are visible in the settings editor.
@ -280,22 +230,20 @@ const loadPlugins: JupyterFrontEndPlugin<void> = {
app.restored.then(async () => {
const plugins = await connector.list('all');
await Promise.all(
plugins.ids.map(async (id: string) => {
const [extension] = id.split(':');
// load the plugin if it is built-in the notebook application explicitly
// either included as an extension or as a plugin directly
const hasPlugin = pluginsSet.has(extension) || pluginsSet.has(id);
if (!hasPlugin || isDisabled(id) || id in settingRegistry.plugins) {
return;
}
try {
await settingRegistry.load(id);
} catch (error) {
console.warn(`Settings failed to load for (${id})`, error);
}
})
);
plugins.ids.forEach(async (id: string) => {
const [extension] = id.split(':');
// load the plugin if it is built-in the notebook application explicitly
// either included as an extension or as a plugin directly
const hasPlugin = pluginsSet.has(extension) || pluginsSet.has(id);
if (!hasPlugin || isDisabled(id) || id in settingRegistry.plugins) {
return;
}
try {
await settingRegistry.load(id);
} catch (error) {
console.warn(`Settings failed to load for (${id})`, error);
}
});
});
},
};
@ -377,6 +325,28 @@ const notebookTreeWidget: JupyterFrontEndPlugin<INotebookTree> = {
})
);
toolbarRegistry.addFactory(
FILE_BROWSER_FACTORY,
'fileNameSearcher',
(browser: FileBrowser) => {
const searcher = FilenameSearcher({
updateFilter: (
filterFn: (item: string) => Partial<IScore> | null,
query?: string
) => {
browser.model.setFilter((value) => {
return filterFn(value.name.toLowerCase());
});
},
useFuzzyFilter: true,
placeholder: trans.__('Filter files by name'),
forceRefresh: true,
});
searcher.addClass(FILTERBOX_CLASS);
return searcher;
}
);
setToolbar(
browser,
createToolbarFactory(
@ -397,6 +367,25 @@ const notebookTreeWidget: JupyterFrontEndPlugin<INotebookTree> = {
nbTreeWidget.tabBar.addTab(running.title);
}
const settings = settingRegistry.load(FILE_BROWSER_PLUGIN_ID);
Promise.all([settings, app.restored])
.then(([settings]) => {
// Set Notebook 7 defaults if there is no user setting override
[
'showFileCheckboxes',
'showFileSizeColumn',
'sortNotebooksFirst',
'showFullPath',
].forEach((setting) => {
if (settings.user[setting] === undefined) {
void settings.set(setting, true);
}
});
})
.catch((reason: Error) => {
console.error(reason.message);
});
app.shell.add(nbTreeWidget, 'main', { rank: 100 });
// add a separate tab for each setting editor
@ -421,9 +410,9 @@ const notebookTreeWidget: JupyterFrontEndPlugin<INotebookTree> = {
tracker['_pool'].current = browser;
};
tracker.widgetAdded.connect((sender, widget) => {
setCurrentToDefaultBrower();
});
tracker.widgetAdded.connect((sender, widget) =>
setCurrentToDefaultBrower()
);
setCurrentToDefaultBrower();
@ -437,8 +426,6 @@ const notebookTreeWidget: JupyterFrontEndPlugin<INotebookTree> = {
const plugins: JupyterFrontEndPlugin<any>[] = [
createNew,
fileActions,
fileBrowserSettings,
fileFilterCommand,
loadPlugins,
openFileBrowser,
notebookTreeWidget,

@ -32,6 +32,15 @@
background: inherit;
}
.jp-FileBrowser-filterBox {
padding: 0;
flex: 0 0 auto;
}
.jp-FileBrowser-filterBox input {
line-height: 24px;
}
.jp-DirListing-content .jp-DirListing-checkboxWrapper {
visibility: visible;
}
@ -57,7 +66,3 @@
margin: 1px;
min-height: var(--jp-private-toolbar-height);
}
body[data-format='mobile'] #fileAction-placeholder {
display: none;
}

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/tree",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"description": "Jupyter Notebook - Tree",
"homepage": "https://github.com/jupyter/notebook",
"bugs": {
@ -38,26 +38,26 @@
"watch": "tsc -b --watch"
},
"dependencies": {
"@jupyter-notebook/application": "^7.6.0-alpha.0",
"@jupyterlab/application": "~4.6.0-alpha.0",
"@jupyterlab/apputils": "~4.7.0-alpha.0",
"@jupyterlab/coreutils": "~6.6.0-alpha.0",
"@jupyterlab/docmanager": "~4.6.0-alpha.0",
"@jupyterlab/filebrowser": "~4.6.0-alpha.0",
"@jupyterlab/mainmenu": "~4.6.0-alpha.0",
"@jupyterlab/services": "~7.6.0-alpha.0",
"@jupyterlab/settingregistry": "~4.6.0-alpha.0",
"@jupyterlab/statedb": "~4.6.0-alpha.0",
"@jupyterlab/translation": "~4.6.0-alpha.0",
"@jupyterlab/ui-components": "~4.6.0-alpha.0",
"@lumino/algorithm": "^2.0.4",
"@lumino/commands": "^2.3.3",
"@lumino/coreutils": "^2.2.2",
"@lumino/widgets": "^2.7.2"
"@jupyter-notebook/application": "^7.1.3",
"@jupyterlab/application": "~4.1.5",
"@jupyterlab/apputils": "~4.2.5",
"@jupyterlab/coreutils": "~6.1.5",
"@jupyterlab/docmanager": "~4.1.5",
"@jupyterlab/filebrowser": "~4.1.5",
"@jupyterlab/mainmenu": "~4.1.5",
"@jupyterlab/services": "~7.1.5",
"@jupyterlab/settingregistry": "~4.1.5",
"@jupyterlab/statedb": "~4.1.5",
"@jupyterlab/translation": "~4.1.5",
"@jupyterlab/ui-components": "~4.1.5",
"@lumino/algorithm": "^2.0.1",
"@lumino/commands": "^2.2.0",
"@lumino/coreutils": "^2.1.2",
"@lumino/widgets": "^2.3.1"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/ui-components",
"version": "7.6.0-alpha.0",
"version": "7.1.3",
"description": "Jupyter Notebook - UI components",
"homepage": "https://github.com/jupyter/notebook",
"bugs": {
@ -42,20 +42,20 @@
"watch": "tsc -b --watch"
},
"dependencies": {
"@jupyterlab/ui-components": "~4.6.0-alpha.0",
"@jupyterlab/ui-components": "~4.1.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@babel/core": "^7.10.2",
"@babel/preset-env": "^7.10.2",
"@jupyterlab/testutils": "~4.6.0-alpha.0",
"@jupyterlab/testutils": "~4.1.5",
"@types/jest": "^29.2.5",
"babel-loader": "^8.0.6",
"jest": "^29.3.1",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

File diff suppressed because it is too large Load Diff

@ -1,9 +1,5 @@
[build-system]
requires = [
"hatchling>=1.11",
"hatch-jupyter-builder>=0.5",
"jupyterlab>=4.6.0a0,<4.7",
]
requires = ["hatchling>=1.11", "jupyterlab>=4.1.1,<4.2"]
build-backend = "hatchling.build"
[project]
@ -11,7 +7,7 @@ name = "notebook"
description = "Jupyter Notebook - A web-based notebook environment for interactive computing"
readme = "README.md"
license = { file = "LICENSE" }
requires-python = ">=3.9"
requires-python = ">=3.8"
authors = [
{ name = "Jupyter Development Team", email = "jupyter@googlegroups.com" },
]
@ -27,17 +23,17 @@ classifiers = [
"Intended Audience :: System Administrators",
"License :: OSI Approved :: BSD License",
"Programming Language :: Python",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Typing :: Typed",
]
dependencies = [
"jupyter_server>=2.4.0,<3",
"jupyterlab>=4.6.0a0,<4.7",
"jupyterlab_server>=2.28.0,<3",
"jupyterlab>=4.1.1,<4.2",
"jupyterlab_server>=2.22.1,<3",
"notebook_shim>=0.2,<0.3",
"tornado>=6.2.0",
]
@ -62,7 +58,7 @@ test = [
"pytest-console-scripts",
"ipykernel",
"jupyter_server[test]>=2.4.0,<3",
"jupyterlab_server[test]>=2.28.0,<3",
"jupyterlab_server[test]>=2.22.1,<3",
"importlib-resources>=5.0;python_version<\"3.10\"",
]
docs = [
@ -114,10 +110,6 @@ artifacts = [
"notebook/templates",
]
include = ["/notebook"]
exclude = [
"notebook/labextension",
"notebook/schemas/@jupyter-notebook",
]
[tool.hatch.envs.docs]
features = ["docs"]
@ -162,6 +154,7 @@ dependencies = ["hatch-jupyter-builder>=0.5"]
build-function = "hatch_jupyter_builder.npm_builder"
ensured-targets = [
"notebook/labextension/static/style.js",
"notebook/static/bundle.js"
]
install-pre-commit-hook = true
@ -182,7 +175,7 @@ version-cmd = "jlpm run release:bump --force --skip-commit"
[tool.jupyter-releaser.hooks]
before-bump-version = [
"python -m pip install -U \"jupyterlab>=4.6.0a0,<4.7\"",
"python -m pip install -U jupyterlab~=4.1.1",
"jlpm",
"jlpm run build:utils",
"python -m pip install hatch"
@ -236,7 +229,7 @@ source = ["notebook"]
[tool.mypy]
files = "notebook"
python_version = "3.9"
python_version = "3.8"
strict = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
warn_unreachable = true
@ -297,25 +290,3 @@ exclude = ["tests", "ui-tests", "docs", "node_modules", "setup.py"]
[tool.repo-review]
ignore = ["GH102", "PC180", "PC111"]
[tool.pixi.project]
channels = ["conda-forge"]
platforms = ["linux-64"]
[tool.pixi.pypi-dependencies]
notebook = { path = ".", editable = true, extras = ["dev", "docs"] }
[tool.pixi.environments]
default = { solve-group = "default" }
dev = { features = ["dev"], solve-group = "default" }
docs = { features = ["docs"], solve-group = "default" }
test = { features = ["test"], solve-group = "default" }
[tool.pixi.tasks]
develop = "jlpm develop"
start = "jupyter notebook --no-browser --ServerApp.token='' --ServerApp.allow_remote_access=True"
[tool.pixi.dependencies]
pip = ">=25.0.1,<26"
nodejs = "22.*"
python = ">=3.12.0,<3.14"

1
src

@ -1 +0,0 @@
undefined

@ -32,7 +32,7 @@ workspaces_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "workspaces"))
labextensions_dir = pytest.fixture(lambda tmp_path: mkdir(tmp_path, "labextensions_dir"))
@pytest.fixture
@pytest.fixture()
def make_notebook_app( # PLR0913
jp_root_dir,
jp_template_dir,
@ -131,7 +131,7 @@ def make_notebook_app( # PLR0913
return _make_notebook_app
@pytest.fixture
@pytest.fixture()
def notebookapp(jp_serverapp, make_notebook_app):
app = make_notebook_app()
app._link_jupyter_server_extension(jp_serverapp)

@ -3,10 +3,10 @@ import os
import pytest
from tornado.httpclient import HTTPClientError
from notebook.app import JupyterNotebookApp, NotebookHandler, TreeHandler
from notebook.app import JupyterNotebookApp, TreeHandler
@pytest.fixture
@pytest.fixture()
def notebooks(jp_create_notebook, notebookapp):
nbpaths = (
"notebook1.ipynb",
@ -32,16 +32,6 @@ async def test_notebook_handler(notebooks, jp_fetch):
html = r.body.decode()
assert "Jupyter Notebook" in html
redirected_url = None
def redirect(self, url):
nonlocal redirected_url
redirected_url = url
NotebookHandler.redirect = redirect
await jp_fetch("notebooks", "jlab_test_notebooks")
assert redirected_url == "/a%40b/tree/jlab_test_notebooks"
async def test_tree_handler(notebooks, notebookapp, jp_fetch):
app: JupyterNotebookApp = notebookapp

@ -16,7 +16,6 @@
"strict": true,
"strictNullChecks": true,
"target": "ES2018",
"types": [],
"lib": ["DOM", "DOM.Iterable", "ES2018", "ES2020.Intl"]
"types": []
}
}

@ -6,17 +6,17 @@
"license": "BSD-3-Clause",
"description": "Jupyter Notebook UI Tests",
"scripts": {
"deduplicate": "jlpm dlx yarn-berry-deduplicate -s fewerHighest && jlpm install",
"rimraf": "rimraf",
"start": "jupyter notebook --config test/jupyter_server_config.py",
"start:detached": "yarn run start&",
"test": "playwright test",
"test:debug": "PWDEBUG=1 playwright test",
"test:report": "http-server ./playwright-report -a localhost -o",
"test:update": "playwright test --update-snapshots"
},
"dependencies": {
"@jupyterlab/galata": "~5.6.0-alpha.0",
"@playwright/test": "~1.57.0",
"@jupyterlab/galata": "~5.1.0-rc.0",
"@playwright/test": "^1.33.0",
"rimraf": "^3.0.2"
}
}

@ -5,7 +5,7 @@ import path from 'path';
import { test } from './fixtures';
import { expect } from '@jupyterlab/galata';
import { expect } from '@playwright/test';
const FILE = 'environment.yml';

@ -3,7 +3,7 @@
import path from 'path';
import { expect } from '@jupyterlab/galata';
import { expect } from '@playwright/test';
import { test } from './fixtures';
@ -20,24 +20,22 @@ test.describe('File Browser', () => {
test('Select one folder', async ({ page, tmpPath }) => {
await page.filebrowser.refresh();
await page.keyboard.down('Control');
await page.getByText('folder1').last().click();
const toolbar = page.getByRole('toolbar');
expect(toolbar.getByText('Rename')).toBeVisible();
expect(toolbar.getByText('Move to Trash')).toBeVisible();
expect(toolbar.getByText('Delete')).toBeVisible();
});
test('Select one file', async ({ page, tmpPath }) => {
await page.filebrowser.refresh();
await page.keyboard.down('Control');
await page.getByText('empty.ipynb').last().click();
const toolbar = page.getByRole('toolbar');
['Rename', 'Open', 'Download', 'Move to Trash'].forEach(async (text) => {
['Rename', 'Delete', 'Open', 'Download', 'Delete'].forEach(async (text) => {
expect(toolbar.getByText(text)).toBeVisible();
});
});
@ -54,7 +52,7 @@ test.describe('File Browser', () => {
expect(toolbar.getByText('Rename')).toBeHidden();
expect(toolbar.getByText('Open')).toBeHidden();
expect(toolbar.getByText('Move to Trash')).toBeVisible();
expect(toolbar.getByText('Delete')).toBeVisible();
});
test('Select files and open', async ({ page, tmpPath }) => {

@ -3,11 +3,11 @@
import path from 'path';
import { expect } from '@jupyterlab/galata';
import { expect } from '@playwright/test';
import { test } from './fixtures';
import { waitForNotebook } from './utils';
import { hideAddCellButton, waitForKernelReady } from './utils';
test.describe('General', () => {
test('The notebook should render', async ({ page, tmpPath, browserName }) => {
@ -18,6 +18,23 @@ test.describe('General', () => {
);
await page.goto(`notebooks/${tmpPath}/${notebook}`);
// wait for the kernel status animations to be finished
await waitForKernelReady(page);
await page.waitForSelector(
".jp-Notebook-ExecutionIndicator[data-status='idle']"
);
const checkpointLocator = '.jp-NotebookCheckpoint';
// wait for the checkpoint indicator to be displayed
await page.waitForSelector(checkpointLocator);
// remove the amount of seconds manually since it might display strings such as "3 seconds ago"
await page
.locator(checkpointLocator)
.evaluate(
(element) => (element.innerHTML = 'Last Checkpoint: 3 seconds ago')
);
// check the notebook footer shows up on hover
const notebookFooter = '.jp-Notebook-footer';
await page.hover(notebookFooter);
@ -26,11 +43,11 @@ test.describe('General', () => {
// hover somewhere else to make the add cell disappear
await page.hover('#jp-top-bar');
// click to make the blue border around the cell disappear
await page.click('.jp-WindowedPanel-outer');
// wait for the notebook to be ready
await waitForNotebook(page, browserName);
// special case for firefox headless issue
// see https://github.com/jupyter/notebook/pull/6872#issuecomment-1549594166 for more details
if (browserName === 'firefox') {
await hideAddCellButton(page);
}
expect(await page.screenshot()).toMatchSnapshot('notebook.png');
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 41 KiB

@ -3,7 +3,7 @@
import path from 'path';
import { expect } from '@jupyterlab/galata';
import { expect } from '@playwright/test';
import { galata } from '@jupyterlab/galata';

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save