Compare commits

..

12 Commits
main ... 7.0.x

Author SHA1 Message Date
jtpio 0211c255df Publish 7.0.8
2 years ago
Jeremy Tuloup 7b4415ca64
Add upper bound on `jupyterlab<4.1` (#7249)
2 years ago
Lumberbot (aka Jack) 99db9423e3
Backport PR #7244 on branch 7.0.x (Add documentation for updating `notebook` imports) (#7245)
2 years ago
Lumberbot (aka Jack) 9d2cbd8387
Backport PR #7235: Fix link in `CONTRIBUTING.md` (#7236)
2 years ago
Lumberbot (aka Jack) c467adf2e4
Backport PR #7219: Fix `check_links` on CI (#7220)
2 years ago
jtpio 80e992e9f4 Publish 7.0.7
2 years ago
Michał Krassowski 089c78c48f
Update to JupyterLab 4.0.11 (#7215)
2 years ago
Lumberbot (aka Jack) 109ba75788
Backport PR #7176: Update publish-release workflow for PyPI trusted publisher (#7179)
2 years ago
Jeremy Tuloup d252423198
Update ruff config and typing (#7145) (#7186)
2 years ago
Lumberbot (aka Jack) d2ef92f0b3
Backport PR #7142: Clean up lint handling (#7185)
2 years ago
Lumberbot (aka Jack) 8e9390d9af
Backport PR #7132: Adopt ruff format (#7184)
2 years ago
Jeremy Tuloup 4d07f1ee9b
Install stable JupyterLab 4.0 in the releaser hook (#7183)
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

@ -32,13 +32,13 @@ runs:
sha256sum * | tee SHA256SUMS
- name: Upload distributions
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: notebook-dist-${{ github.run_number }}
path: ./dist
- name: Upload distributions
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: notebook-pkgs-${{ github.run_number }}
path: ./pkgs

@ -4,10 +4,6 @@ updates:
directory: '/'
schedule:
interval: 'weekly'
groups:
actions:
patterns:
- "*"
- package-ecosystem: 'pip'
directory: '/'
schedule:

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

@ -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@v4
with:
python-version: ${{ matrix.python }}
architecture: 'x64'
allow-prereleases: true
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v3
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'
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.0.2,<4.1" 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@v4
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.0.2,<4.1" 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@v3
with:
name: notebook-jupyter-releaser-dist-${{ github.run_number }}
path: .jupyter_releaser_checkout/dist

@ -14,7 +14,7 @@ jobs:
issues: write
pull-requests: write
steps:
- uses: dessant/lock-threads@v5
- uses: dessant/lock-threads@v4
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: '180'

@ -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@v3
with:
name: notebook-dist-${{ github.run_number }}
path: ./dist

@ -1,33 +1,29 @@
name: "Step 1: Prep Release"
name: 'Step 1: Prep Release'
on:
workflow_dispatch:
inputs:
version_spec:
description: "New Version Specifier"
default: "next"
description: 'New Version Specifier'
default: 'next'
required: false
branch:
description: "The branch to target"
description: 'The branch to target'
required: false
post_version_spec:
description: "Post Version Specifier"
description: 'Post Version Specifier'
required: false
silent:
description: "Set a placeholder in the changelog and don't publish the release."
required: false
type: boolean
since:
description: "Use PRs with activity since this date or git reference"
description: 'Use PRs with activity since this date or git reference'
required: false
since_last_stable:
description: "Use PRs with activity since the last stable git tag"
description: 'Use PRs with activity since the last stable git tag'
required: false
type: boolean
permissions:
contents: read
jobs:
prep_release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
@ -35,15 +31,14 @@ jobs:
id: prep-release
uses: jupyter-server/jupyter_releaser/.github/actions/prep-release@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
token: ${{ secrets.ADMIN_GITHUB_TOKEN }}
version_spec: ${{ github.event.inputs.version_spec }}
silent: ${{ github.event.inputs.silent }}
post_version_spec: ${{ github.event.inputs.post_version_spec }}
target: ${{ github.event.inputs.target }}
branch: ${{ github.event.inputs.branch }}
since: ${{ github.event.inputs.since }}
since_last_stable: ${{ github.event.inputs.since_last_stable }}
- name: "** Next Step **"
- name: '** Next Step **'
run: |
echo "Optional): Review Draft Release: ${{ steps.prep-release.outputs.release_url }}"

@ -1,34 +0,0 @@
name: "Publish Changelog"
on:
release:
types: [published]
workflow_dispatch:
inputs:
branch:
description: "The branch to target"
required: false
jobs:
publish_changelog:
runs-on: ubuntu-latest
environment: release
steps:
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Publish changelog
id: publish-changelog
uses: jupyter-server/jupyter_releaser/.github/actions/publish-changelog@v2
with:
token: ${{ steps.app-token.outputs.token }}
branch: ${{ github.event.inputs.branch }}
- name: "** Next Step **"
run: |
echo "Merge the changelog update PR: ${{ steps.publish-changelog.outputs.pr_url }}"

@ -1,39 +1,32 @@
name: "Step 2: Publish Release"
name: 'Step 2: Publish Release'
on:
workflow_dispatch:
inputs:
branch:
description: "The target branch"
description: 'The target branch'
required: false
release_url:
description: "The URL of the draft GitHub release"
description: 'The URL of the draft GitHub release'
required: false
steps_to_skip:
description: "Comma separated list of steps to skip"
description: 'Comma separated list of steps to skip'
required: false
jobs:
publish_release:
runs-on: ubuntu-latest
environment: release
permissions:
# This is useful if you want to use PyPI trusted publisher
# and NPM provenance
id-token: write
steps:
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
with:
node_version: '24'
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Populate Release
id: populate-release
uses: jupyter-server/jupyter_releaser/.github/actions/populate-release@v2
with:
token: ${{ steps.app-token.outputs.token }}
token: ${{ secrets.ADMIN_GITHUB_TOKEN }}
branch: ${{ github.event.inputs.branch }}
release_url: ${{ github.event.inputs.release_url }}
steps_to_skip: ${{ github.event.inputs.steps_to_skip }}
@ -44,16 +37,16 @@ jobs:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
uses: jupyter-server/jupyter_releaser/.github/actions/finalize-release@v2
with:
token: ${{ steps.app-token.outputs.token }}
token: ${{ secrets.ADMIN_GITHUB_TOKEN }}
release_url: ${{ steps.populate-release.outputs.release_url }}
- name: "** Next Step **"
- name: '** Next Step **'
if: ${{ success() }}
run: |
echo "Verify the final release"
echo ${{ steps.finalize-release.outputs.release_url }}
- name: "** Failure Message **"
- name: '** Failure Message **'
if: ${{ failure() }}
run: |
echo "Failed to Publish the Draft Release Url:"

@ -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@v3
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@v3
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@v3
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@v3
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,36 @@ repos:
- id: trailing-whitespace
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.30.0
rev: 0.27.0
hooks:
- id: check-github-workflows
- repo: https://github.com/adamchainz/blacken-docs
rev: '1.16.0'
hooks:
- id: blacken-docs
additional_dependencies: [black==23.7.0]
- 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.6.1"
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.0,<4.1"]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: 'v1.10.0'
@ -55,7 +60,7 @@ repos:
- id: rst-inline-touching-normal
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.6
rev: v0.1.5
hooks:
- id: ruff
types_or: [ python, jupyter ]
@ -66,7 +71,7 @@ repos:
exclude: '^docs/source/examples/Notebook/Importing Notebooks.ipynb'
- repo: https://github.com/scientific-python/cookie
rev: '2024.08.19'
rev: '2023.10.27'
hooks:
- id: sp-repo-review
additional_dependencies: ['repo-review[cli]']
@ -83,4 +88,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
@ -70,39 +66,6 @@ Then start Jupyter Notebook with:
jupyter notebook
```
### Local changes in Notebook dependencies
The development installation described above fetches JavaScript dependencies from `npm`.
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.
- Install yalc globally in your environment:
`npm install -g yalc`
- Publish your 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
_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
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:\
`jlpm install && jlpm build`
Changes in the dependency must then be built and pushed using `jlpm build && yalc push` (from the package root directory),
and fetched from Notebook using `yarn install`.
**Warning**: you need to make sure that the dependencies of Notebook and the local package match correctly,
otherwise there will be errors with webpack during build.\
In the previous example, both _@jupyterlab/ui-components_ and Notebook depend on _@jupyterlab/coreutils_. We
strongly advise you to depend on the same version.
## Running Tests
To run the tests:
@ -131,11 +94,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 +135,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 +174,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 +202,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.
@ -11,12 +12,13 @@ computing.
## Maintained versions
We maintain the **two most recently released major versions of Jupyter Notebook**,
Classic Notebook v6 and Notebook v7. Notebook v5 is no longer maintained.
All Notebook v5 users are strongly advised to upgrade to Classic Notebook v6 as soon as possible.
We maintain the **two most recently released major versions of Jupyter Notebook**, Notebook v5 and Classic Notebook v6. After Notebook v7.0 is released, we will no longer maintain Notebook v5. All Notebook v5 users are strongly advised to upgrade to Classic Notebook v6 as soon as possible.
Upgrading to Notebook v7 may require more work, if you use custom extensions, as extensions written
for Notebook v5 or Classic Notebook v6 are not compatible with Notebook v7.
The Jupyter Notebook project is currently undertaking a transition to a more modern code base built from the ground-up using JupyterLab components and extensions.
There is new stream of work which was submitted and then accepted as a Jupyter Enhancement Proposal (JEP) as part of the next version (v7): https://jupyter.org/enhancement-proposals/79-notebook-v7/notebook-v7.html
There is also a plan to continue maintaining Notebook v6 with bug and security fixes only, to ease the transition to Notebook v7: https://github.com/jupyter/notebook-team-compass/issues/5#issuecomment-1085254000
### Notebook v7
@ -31,8 +33,9 @@ To learn more about Notebook v7: https://jupyter.org/enhancement-proposals/79-no
### Classic Notebook v6
Maintenance and security-related issues [only](https://github.com/jupyter/notebook-team-compass/issues/5#issuecomment-1085254000) are now being addressed in the [`6.5.x`](https://github.com/jupyter/notebook/tree/6.5.x) branch.
It depends on [`nbclassic`](https://github.com/jupyter/nbclassic) for the HTML/JavaScript/CSS assets.
Maintenance and security-related issues are now being addressed in the [`6.4.x`](https://github.com/jupyter/notebook/tree/6.4.x) branch.
A `6.5.x` branch will be soon created and will depend on [`nbclassic`](https://github.com/jupyter/nbclassic) for the HTML/JavaScript/CSS assets.
New features and continuous improvement is now focused on Notebook v7 (see section above).

@ -5,8 +5,6 @@
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
import { PluginRegistry } from '@lumino/coreutils';
require('./style.js');
require('./extraStyle.js');
@ -35,9 +33,7 @@ async function loadComponent(url, scope) {
async function createModule(scope, module) {
try {
const factory = await window._JUPYTERLAB[scope].get(module);
const instance = factory();
instance.__scope__ = scope;
return instance;
return factory();
} catch (e) {
console.warn(
`Failed to create module: package: ${scope}; module: ${module}`
@ -83,7 +79,6 @@ async function main() {
// populate the list of disabled extensions
const disabled = [];
const availablePlugins = [];
/**
* Iterate over active plugins in an extension.
@ -103,18 +98,7 @@ async function main() {
let plugins = Array.isArray(exports) ? exports : [exports];
for (let plugin of plugins) {
const isDisabled = PageConfig.Extension.isDisabled(plugin.id);
availablePlugins.push({
id: plugin.id,
description: plugin.description,
requires: plugin.requires ?? [],
optional: plugin.optional ?? [],
provides: plugin.provides ?? null,
autoStart: plugin.autoStart,
enabled: !isDisabled,
extension: extension.__scope__
});
if (isDisabled) {
if (PageConfig.Extension.isDisabled(plugin.id)) {
disabled.push(plugin.id);
continue;
}
@ -215,20 +199,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 });
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,196 @@
{
"name": "@jupyter-notebook/app",
"version": "7.6.0-alpha.0",
"version": "7.0.8",
"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.15.3",
"@jupyter-notebook/application": "~7.0.8",
"@jupyter-notebook/application-extension": "~7.0.8",
"@jupyter-notebook/console-extension": "~7.0.8",
"@jupyter-notebook/docmanager-extension": "~7.0.8",
"@jupyter-notebook/documentsearch-extension": "~7.0.8",
"@jupyter-notebook/help-extension": "~7.0.8",
"@jupyter-notebook/notebook-extension": "~7.0.8",
"@jupyter-notebook/terminal-extension": "~7.0.8",
"@jupyter-notebook/tree": "~7.0.8",
"@jupyter-notebook/tree-extension": "~7.0.8",
"@jupyter-notebook/ui-components": "~7.0.8",
"@jupyter/ydoc": "~1.1.1",
"@jupyterlab/application": "~4.0.11",
"@jupyterlab/application-extension": "~4.0.11",
"@jupyterlab/apputils": "~4.1.11",
"@jupyterlab/apputils-extension": "~4.0.11",
"@jupyterlab/attachments": "~4.0.11",
"@jupyterlab/cell-toolbar": "~4.0.11",
"@jupyterlab/cell-toolbar-extension": "~4.0.11",
"@jupyterlab/celltags-extension": "~4.0.11",
"@jupyterlab/codeeditor": "~4.0.11",
"@jupyterlab/codemirror": "~4.0.11",
"@jupyterlab/codemirror-extension": "~4.0.11",
"@jupyterlab/completer": "~4.0.11",
"@jupyterlab/completer-extension": "~4.0.11",
"@jupyterlab/console": "~4.0.11",
"@jupyterlab/console-extension": "~4.0.11",
"@jupyterlab/coreutils": "~6.0.11",
"@jupyterlab/csvviewer-extension": "~4.0.11",
"@jupyterlab/debugger": "~4.0.11",
"@jupyterlab/debugger-extension": "~4.0.11",
"@jupyterlab/docmanager": "~4.0.11",
"@jupyterlab/docmanager-extension": "~4.0.11",
"@jupyterlab/documentsearch": "~4.0.11",
"@jupyterlab/documentsearch-extension": "~4.0.11",
"@jupyterlab/extensionmanager": "~4.0.11",
"@jupyterlab/extensionmanager-extension": "~4.0.11",
"@jupyterlab/filebrowser": "~4.0.11",
"@jupyterlab/filebrowser-extension": "~4.0.11",
"@jupyterlab/fileeditor": "~4.0.11",
"@jupyterlab/fileeditor-extension": "~4.0.11",
"@jupyterlab/htmlviewer": "~4.0.11",
"@jupyterlab/htmlviewer-extension": "~4.0.11",
"@jupyterlab/hub-extension": "~4.0.11",
"@jupyterlab/imageviewer": "~4.0.11",
"@jupyterlab/imageviewer-extension": "~4.0.11",
"@jupyterlab/javascript-extension": "~4.0.11",
"@jupyterlab/json-extension": "~4.0.11",
"@jupyterlab/lsp": "~4.0.11",
"@jupyterlab/lsp-extension": "~4.0.11",
"@jupyterlab/mainmenu": "~4.0.11",
"@jupyterlab/mainmenu-extension": "~4.0.11",
"@jupyterlab/markdownviewer": "~4.0.11",
"@jupyterlab/markdownviewer-extension": "~4.0.11",
"@jupyterlab/markedparser-extension": "~4.0.11",
"@jupyterlab/mathjax-extension": "~4.0.11",
"@jupyterlab/metadataform": "~4.0.11",
"@jupyterlab/metadataform-extension": "~4.0.11",
"@jupyterlab/notebook": "~4.0.11",
"@jupyterlab/notebook-extension": "~4.0.11",
"@jupyterlab/observables": "~5.0.11",
"@jupyterlab/outputarea": "~4.0.11",
"@jupyterlab/pdf-extension": "~4.0.11",
"@jupyterlab/rendermime": "~4.0.11",
"@jupyterlab/rendermime-interfaces": "~3.8.11",
"@jupyterlab/running-extension": "~4.0.11",
"@jupyterlab/services": "~7.0.11",
"@jupyterlab/settingeditor": "~4.0.11",
"@jupyterlab/settingeditor-extension": "~4.0.11",
"@jupyterlab/settingregistry": "~4.0.11",
"@jupyterlab/shortcuts-extension": "~4.0.11",
"@jupyterlab/statedb": "~4.0.11",
"@jupyterlab/statusbar": "~4.0.11",
"@jupyterlab/terminal": "~4.0.11",
"@jupyterlab/terminal-extension": "~4.0.11",
"@jupyterlab/theme-dark-extension": "~4.0.11",
"@jupyterlab/theme-light-extension": "~4.0.11",
"@jupyterlab/toc-extension": "~6.0.11",
"@jupyterlab/tooltip": "~4.0.11",
"@jupyterlab/tooltip-extension": "~4.0.11",
"@jupyterlab/translation": "~4.0.11",
"@jupyterlab/translation-extension": "~4.0.11",
"@jupyterlab/ui-components": "~4.0.11",
"@jupyterlab/ui-components-extension": "~4.0.11",
"@jupyterlab/vega5-extension": "~4.0.11",
"@lezer/common": "~1.0.3",
"@lezer/highlight": "~1.1.6",
"@lumino/algorithm": "~2.0.1",
"@lumino/application": "~2.2.1",
"@lumino/commands": "~2.1.3",
"@lumino/coreutils": "~2.1.2",
"@lumino/disposable": "~2.1.2",
"@lumino/domutils": "~2.0.1",
"@lumino/dragdrop": "~2.1.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.0",
"react": "~18.2.0",
"react-dom": "~18.2.0",
"yjs": "~13.6.8"
"yjs": "~13.6.7"
},
"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.0.8",
"@jupyter-notebook/application-extension": "^7.0.8",
"@jupyter-notebook/console-extension": "^7.0.8",
"@jupyter-notebook/docmanager-extension": "^7.0.8",
"@jupyter-notebook/documentsearch-extension": "^7.0.8",
"@jupyter-notebook/help-extension": "^7.0.8",
"@jupyter-notebook/notebook-extension": "^7.0.8",
"@jupyter-notebook/terminal-extension": "^7.0.8",
"@jupyter-notebook/tree": "^7.0.8",
"@jupyter-notebook/tree-extension": "^7.0.8",
"@jupyter-notebook/ui-components": "^7.0.8",
"@jupyterlab/application-extension": "^4.0.11",
"@jupyterlab/apputils-extension": "^4.0.11",
"@jupyterlab/attachments": "^4.0.11",
"@jupyterlab/cell-toolbar-extension": "^4.0.11",
"@jupyterlab/celltags-extension": "^4.0.11",
"@jupyterlab/codemirror": "^4.0.11",
"@jupyterlab/codemirror-extension": "^4.0.11",
"@jupyterlab/completer-extension": "^4.0.11",
"@jupyterlab/console-extension": "^4.0.11",
"@jupyterlab/coreutils": "^6.0.11",
"@jupyterlab/csvviewer-extension": "^4.0.11",
"@jupyterlab/debugger-extension": "^4.0.11",
"@jupyterlab/docmanager-extension": "^4.0.11",
"@jupyterlab/documentsearch-extension": "^4.0.11",
"@jupyterlab/extensionmanager-extension": "^4.0.11",
"@jupyterlab/filebrowser-extension": "^4.0.11",
"@jupyterlab/fileeditor-extension": "^4.0.11",
"@jupyterlab/htmlviewer-extension": "^4.0.11",
"@jupyterlab/hub-extension": "^4.0.11",
"@jupyterlab/imageviewer-extension": "^4.0.11",
"@jupyterlab/javascript-extension": "^4.0.11",
"@jupyterlab/json-extension": "^4.0.11",
"@jupyterlab/lsp": "^4.0.11",
"@jupyterlab/lsp-extension": "^4.0.11",
"@jupyterlab/mainmenu-extension": "^4.0.11",
"@jupyterlab/markdownviewer-extension": "^4.0.11",
"@jupyterlab/markedparser-extension": "^4.0.11",
"@jupyterlab/mathjax-extension": "^4.0.11",
"@jupyterlab/metadataform-extension": "^4.0.11",
"@jupyterlab/notebook-extension": "^4.0.11",
"@jupyterlab/pdf-extension": "^4.0.11",
"@jupyterlab/running-extension": "^4.0.11",
"@jupyterlab/settingeditor": "^4.0.11",
"@jupyterlab/settingeditor-extension": "^4.0.11",
"@jupyterlab/shortcuts-extension": "^4.0.11",
"@jupyterlab/terminal-extension": "^4.0.11",
"@jupyterlab/theme-dark-extension": "^4.0.11",
"@jupyterlab/theme-light-extension": "^4.0.11",
"@jupyterlab/toc-extension": "^6.0.11",
"@jupyterlab/tooltip-extension": "^4.0.11",
"@jupyterlab/translation-extension": "^4.0.11",
"@jupyterlab/ui-components-extension": "^4.0.11",
"@jupyterlab/vega5-extension": "^4.0.11",
"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.0.11",
"@jupyterlab/buildutils": "^4.0.11",
"@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 +220,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,17 +231,12 @@
"@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",
"@jupyterlab/completer-extension:inline-completer",
"@jupyterlab/completer-extension:inline-completer-factory",
"@jupyterlab/completer-extension:inline-history",
"@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,47 +257,33 @@
"@jupyterlab/filebrowser-extension:default-file-browser"
],
"@jupyterlab/fileeditor-extension": [
"@jupyterlab/fileeditor-extension:plugin",
"@jupyterlab/fileeditor-extension:widget-factory"
],
"@jupyterlab/help-extension": [
"@jupyterlab/help-extension:resources"
"@jupyterlab/fileeditor-extension:plugin"
],
"@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",
"@jupyterlab/notebook-extension:tracker",
"@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 +291,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 +342,6 @@
"@codemirror/state",
"@codemirror/view",
"@jupyter-notebook/tree",
"@jupyter/react-components",
"@jupyter/web-components",
"@jupyter/ydoc",
"@jupyterlab/application",
"@jupyterlab/apputils",
@ -405,7 +362,6 @@
"@jupyterlab/lsp",
"@jupyterlab/mainmenu",
"@jupyterlab/markdownviewer",
"@jupyterlab/mermaid",
"@jupyterlab/metadataform",
"@jupyterlab/notebook",
"@jupyterlab/observables",

@ -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.0.8",
"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.0.11",
"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();

@ -128,16 +128,6 @@ commander
} else if (prev.indexOf('rc') !== -1) {
pySpec = 'rc';
}
} else if (spec === 'major' || spec === 'minor') {
if (prev.indexOf('a') !== -1) {
pySpec = `${spec},beta`;
} else if (prev.indexOf('b') !== -1) {
pySpec = `${spec},rc`;
} else if (prev.indexOf('rc') !== -1) {
pySpec = `${spec},release`;
} else {
pySpec = `${spec},alpha`;
}
}
utils.run(`hatch version ${pySpec}`);

@ -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

@ -1,3 +1,5 @@
#!/usr/bin/env python3
#
# Jupyter Notebook documentation build configuration file, created by
# sphinx-quickstart on Mon Apr 13 09:51:11 2015.
#
@ -71,7 +73,7 @@ extensions = [
]
try:
import enchant # noqa: F401
import enchant # type:ignore # noqa
extensions += ["sphinxcontrib.spelling"]
except ImportError:
@ -95,7 +97,7 @@ master_doc = "index"
# General information about the project.
project = "Jupyter Notebook"
copyright = "2015, Jupyter Team, https://jupyter.org"
copyright = "2015, Jupyter Team, https://jupyter.org" # noqa
author = "The Jupyter Team"
# ghissue config
@ -107,9 +109,9 @@ github_project_url = "https://github.com/jupyter/notebook"
#
_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
exec(compile(open(_version_py).read(), _version_py, "exec"), version_ns) # noqa
# 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 +174,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 +192,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 +400,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

@ -185,7 +185,7 @@
"source": [
"The first idea of mouse based navigation is that **cells can be selected by clicking on them.** The currently selected cell gets a grey or green border depending on whether the notebook is in edit or command mode. If you click inside a cell's editor area, you will enter edit mode. If you click on the prompt or output area of a cell you will enter command mode.\n",
"\n",
"If you are running this notebook in a live session (not on https://nbviewer.jupyter.org) try selecting different cells and going between edit and command mode. Try typing into a cell."
"If you are running this notebook in a live session (not on http://nbviewer.jupyter.org) try selecting different cells and going between edit and command mode. Try typing into a cell."
]
},
{

@ -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

@ -6,6 +6,7 @@ Prior to Notebook 7, the Classic Notebook server included the server modules in
```python
from notebook.auth import passwd
passwd("foo")
```
@ -13,6 +14,7 @@ Or:
```python
from notebook import notebookapp
notebookapp.list_running_servers()
```
@ -20,6 +22,7 @@ In Notebook 7, these server modules are now exposed by the `jupyter_server` pack
```python
from jupyter_server.auth import passwd
passwd("foo")
```
@ -27,6 +30,7 @@ And:
```python
from jupyter_server import serverapp
serverapp.list_running_servers()
```

@ -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
}

@ -2,7 +2,7 @@ from __future__ import annotations
from typing import Any
from ._version import __version__, version_info # noqa: F401
from ._version import __version__ # noqa
def _jupyter_server_extension_paths() -> list[dict[str, str]]:

@ -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.0.8"
# PEP440 version parser
_version_regex = re.compile(
@ -24,7 +23,7 @@ _version_regex = re.compile(
_version_fields = _version_regex.match(__version__).groupdict() # type:ignore[union-attr]
VersionInfo = namedtuple("VersionInfo", ["major", "minor", "micro", "releaselevel", "serial"]) # noqa: PYI024
VersionInfo = namedtuple("VersionInfo", ["major", "minor", "micro", "releaselevel", "serial"])
version_info = VersionInfo(
*[

@ -1,11 +1,10 @@
"""Jupyter notebook application."""
from __future__ import annotations
import os
import re
import typing as t
from pathlib import Path
from os.path import join as pjoin
from jupyter_client.utils import ensure_async # type:ignore[attr-defined]
from jupyter_core.application import base_aliases
@ -37,11 +36,11 @@ from traitlets.config.loader import Config
from ._version import __version__
HERE = Path(__file__).parent.resolve()
HERE = os.path.dirname(__file__)
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())
app_dir = get_app_dir()
version = __version__
# mypy: disable-error-code="no-untyped-call"
@ -73,7 +72,7 @@ class NotebookBaseHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, Jup
server_root = self.settings.get("server_root_dir", "")
server_root = server_root.replace(os.sep, "/")
server_root = os.path.normpath(Path(server_root).expanduser())
server_root = os.path.normpath(os.path.expanduser(server_root))
try:
# Remove the server_root from pref dir
if self.serverapp.preferred_dir != server_root:
@ -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
@ -156,7 +149,7 @@ class TreeHandler(NotebookBaseHandler):
tpl = self.render_template("tree.html", page_config=page_config)
return self.write(tpl)
if await ensure_async(cm.file_exists(path)):
elif await ensure_async(cm.file_exists(path)):
# it's not a directory, we have redirecting to do
model = await ensure_async(cm.get(path, content=False))
if model["type"] == "notebook":
@ -166,15 +159,15 @@ class TreeHandler(NotebookBaseHandler):
url = ujoin(self.base_url, "files", url_escape(path))
self.log.debug("Redirecting %s to %s", self.request.path, url)
self.redirect(url)
return None
raise web.HTTPError(404)
else:
raise web.HTTPError(404)
class ConsoleHandler(NotebookBaseHandler):
"""A console page handler."""
@web.authenticated
def get(self, path: str | None = None) -> t.Any: # noqa: ARG002
def get(self, path: str | None = None) -> t.Any:
"""Get the console page."""
tpl = self.render_template("consoles.html", page_config=self.get_page_config())
return self.write(tpl)
@ -184,7 +177,7 @@ class TerminalHandler(NotebookBaseHandler):
"""A terminal page handler."""
@web.authenticated
def get(self, path: str | None = None) -> t.Any: # noqa: ARG002
def get(self, path: str | None = None) -> t.Any:
"""Get the terminal page."""
tpl = self.render_template("terminals.html", page_config=self.get_page_config())
return self.write(tpl)
@ -194,7 +187,7 @@ class FileHandler(NotebookBaseHandler):
"""A file page handler."""
@web.authenticated
def get(self, path: str | None = None) -> t.Any: # noqa: ARG002
def get(self, path: str | None = None) -> t.Any:
"""Get the file page."""
tpl = self.render_template("edit.html", page_config=self.get_page_config())
return self.write(tpl)
@ -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:
"""Get the notebook page."""
tpl = self.render_template("notebooks.html", page_config=self.get_page_config())
return self.write(tpl)
@ -229,13 +214,13 @@ class CustomCssHandler(NotebookBaseHandler):
page_config = self.get_page_config()
custom_css_file = f"{page_config['jupyterConfigDir']}/custom/custom.css"
if not Path(custom_css_file).is_file():
if not os.path.isfile(custom_css_file):
static_path_root = re.match("^(.*?)static", page_config["staticDir"])
if static_path_root is not None:
custom_dir = static_path_root.groups()[0]
custom_css_file = f"{custom_dir}custom/custom.css"
with Path(custom_css_file).open() as css_f:
with open(custom_css_file) as css_f:
return self.write(css_f.read())
@ -284,23 +269,23 @@ class JupyterNotebookApp(NotebookConfigShimMixin, LabServerApp): # type:ignore[
@default("static_dir")
def _default_static_dir(self) -> str:
return str(HERE / "static")
return os.path.join(HERE, "static")
@default("templates_dir")
def _default_templates_dir(self) -> str:
return str(HERE / "templates")
return os.path.join(HERE, "templates")
@default("app_settings_dir")
def _default_app_settings_dir(self) -> str:
return str(app_dir / "settings")
return pjoin(app_dir, "settings")
@default("schemas_dir")
def _default_schemas_dir(self) -> str:
return str(app_dir / "schemas")
return pjoin(app_dir, "schemas")
@default("themes_dir")
def _default_themes_dir(self) -> str:
return str(app_dir / "themes")
return pjoin(app_dir, "themes")
@default("user_settings_dir")
def _default_user_settings_dir(self) -> str:
@ -358,7 +343,7 @@ class JupyterNotebookApp(NotebookConfigShimMixin, LabServerApp): # type:ignore[
self.handlers.append(("/custom/custom.css", CustomCssHandler))
super().initialize_handlers()
def initialize(self, argv: list[str] | None = None) -> None: # noqa: ARG002
def initialize(self, argv: list[str] | None = None) -> None:
"""Subclass because the ExtensionApp.initialize() method does not take arguments"""
super().initialize()

@ -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.0.11",
"@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.0.8",
"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.0.8",
"@jupyter-notebook/application-extension": "^7.0.8",
"@jupyter-notebook/console-extension": "^7.0.8",
"@jupyter-notebook/docmanager-extension": "^7.0.8",
"@jupyter-notebook/documentsearch-extension": "^7.0.8",
"@jupyter-notebook/help-extension": "^7.0.8",
"@jupyter-notebook/lab-extension": "^7.0.8",
"@jupyter-notebook/notebook-extension": "^7.0.8",
"@jupyter-notebook/terminal-extension": "^7.0.8",
"@jupyter-notebook/tree": "^7.0.8",
"@jupyter-notebook/tree-extension": "^7.0.8",
"@jupyter-notebook/ui-components": "^7.0.8"
},
"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.0.8",
"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.0.8",
"@jupyter-notebook/ui-components": "^7.0.8",
"@jupyterlab/application": "^4.0.11",
"@jupyterlab/apputils": "^4.1.11",
"@jupyterlab/codeeditor": "^4.0.11",
"@jupyterlab/console": "^4.0.11",
"@jupyterlab/coreutils": "^6.0.11",
"@jupyterlab/docmanager": "^4.0.11",
"@jupyterlab/docregistry": "^4.0.11",
"@jupyterlab/mainmenu": "^4.0.11",
"@jupyterlab/rendermime": "^4.0.11",
"@jupyterlab/settingregistry": "^4.0.11",
"@jupyterlab/translation": "^4.0.11",
"@lumino/coreutils": "^2.1.2",
"@lumino/disposable": "^2.1.2",
"@lumino/widgets": "^2.3.0"
},
"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,9 +9,7 @@
"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" }
"Markdown Preview": { "area": "right" }
}
}
},

@ -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
*/
@ -136,8 +129,6 @@ namespace CommandIDs {
*/
const dirty: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:dirty',
description:
'Check if the application is dirty before closing the browser tab.',
autoStart: true,
requires: [ILabStatus, ITranslator],
activate: (
@ -161,27 +152,11 @@ 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.
*/
const logo: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:logo',
description: 'The logo plugin.',
autoStart: true,
activate: (app: JupyterFrontEnd) => {
const baseUrl = PageConfig.getBaseUrl();
@ -210,7 +185,6 @@ const logo: JupyterFrontEndPlugin<void> = {
*/
const opener: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:opener',
description: 'A plugin to open documents in the main area.',
autoStart: true,
requires: [IRouter, IDocumentManager],
optional: [ISettingRegistry],
@ -279,7 +253,6 @@ const opener: JupyterFrontEndPlugin<void> = {
*/
const menus: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:menus',
description: 'A plugin to customize menus.',
requires: [IMainMenu],
autoStart: true,
activate: (app: JupyterFrontEnd, menu: IMainMenu) => {
@ -310,7 +283,6 @@ const menus: JupyterFrontEndPlugin<void> = {
*/
const menuSpacer: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:menu-spacer',
description: 'A plugin to provide a spacer at rank 900 in the menu area.',
autoStart: true,
activate: (app: JupyterFrontEnd) => {
const menu = new Widget();
@ -325,7 +297,6 @@ const menuSpacer: JupyterFrontEndPlugin<void> = {
*/
const pages: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:pages',
description: 'Add commands to open the tree and running pages.',
autoStart: true,
requires: [ITranslator],
optional: [ICommandPalette],
@ -368,7 +339,6 @@ const pages: JupyterFrontEndPlugin<void> = {
*/
const pathOpener: JupyterFrontEndPlugin<INotebookPathOpener> = {
id: '@jupyter-notebook/application-extension:path-opener',
description: 'A plugin to open paths in new browser tabs.',
autoStart: true,
provides: INotebookPathOpener,
activate: (app: JupyterFrontEnd): INotebookPathOpener => {
@ -381,7 +351,6 @@ const pathOpener: JupyterFrontEndPlugin<INotebookPathOpener> = {
*/
const paths: JupyterFrontEndPlugin<JupyterFrontEnd.IPaths> = {
id: '@jupyter-notebook/application-extension:paths',
description: 'The default paths for a Jupyter Notebook app.',
autoStart: true,
provides: JupyterFrontEnd.IPaths,
activate: (app: JupyterFrontEnd): JupyterFrontEnd.IPaths => {
@ -397,9 +366,9 @@ const paths: JupyterFrontEndPlugin<JupyterFrontEnd.IPaths> = {
*/
const rendermime: JupyterFrontEndPlugin<IRenderMimeRegistry> = {
id: '@jupyter-notebook/application-extension:rendermime',
description: 'A plugin providing a rendermime registry.',
autoStart: true,
provides: IRenderMimeRegistry,
description: 'Provides the render mime registry.',
optional: [
IDocumentManager,
ILatexTypesetter,
@ -470,7 +439,6 @@ const rendermime: JupyterFrontEndPlugin<IRenderMimeRegistry> = {
*/
const shell: JupyterFrontEndPlugin<INotebookShell> = {
id: '@jupyter-notebook/application-extension:shell',
description: 'The default Jupyter Notebook application shell.',
autoStart: true,
provides: INotebookShell,
optional: [ISettingRegistry],
@ -537,7 +505,6 @@ const splash: JupyterFrontEndPlugin<ISplashScreen> = {
*/
const status: JupyterFrontEndPlugin<ILabStatus> = {
id: '@jupyter-notebook/application-extension:status',
description: 'The default JupyterLab application status provider.',
autoStart: true,
provides: ILabStatus,
activate: (app: JupyterFrontEnd) => {
@ -553,8 +520,6 @@ const status: JupyterFrontEndPlugin<ILabStatus> = {
*/
const tabTitle: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:tab-title',
description:
'A plugin to display the document title in the browser tab title.',
autoStart: true,
requires: [INotebookShell],
activate: (app: JupyterFrontEnd, shell: INotebookShell) => {
@ -591,7 +556,6 @@ const tabTitle: JupyterFrontEndPlugin<void> = {
*/
const title: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:title',
description: 'A plugin to display and rename the title of a file.',
autoStart: true,
requires: [INotebookShell, ITranslator],
optional: [IDocumentManager, IRouter, IToolbarWidgetRegistry],
@ -637,20 +601,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 +609,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;
}
@ -713,7 +654,6 @@ const title: JupyterFrontEndPlugin<void> = {
*/
const topVisibility: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:top',
description: 'Plugin to toggle the top header visibility.',
requires: [INotebookShell, ITranslator],
optional: [ISettingRegistry, ICommandPalette],
activate: (
@ -795,7 +735,6 @@ const topVisibility: JupyterFrontEndPlugin<void> = {
*/
const sidePanelVisibility: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:sidepanel',
description: 'Plugin to toggle the visibility of left or right side panel.',
requires: [INotebookShell, ITranslator],
optional: [IMainMenu, ICommandPalette],
autoStart: true,
@ -1006,26 +945,11 @@ 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.
*/
const tree: JupyterFrontEndPlugin<JupyterFrontEnd.ITreeResolver> = {
id: '@jupyter-notebook/application-extension:tree-resolver',
description: 'The default tree route resolver plugin.',
autoStart: true,
requires: [IRouter],
provides: JupyterFrontEnd.ITreeResolver,
@ -1083,12 +1007,8 @@ const tree: JupyterFrontEndPlugin<JupyterFrontEnd.ITreeResolver> = {
},
};
/**
* Plugin to update tree path.
*/
const treePathUpdater: JupyterFrontEndPlugin<ITreePathUpdater> = {
id: '@jupyter-notebook/application-extension:tree-updater',
description: 'Plugin to update tree path.',
requires: [IRouter],
provides: ITreePathUpdater,
activate: (app: JupyterFrontEnd, router: IRouter) => {
@ -1109,12 +1029,8 @@ const treePathUpdater: JupyterFrontEndPlugin<ITreePathUpdater> = {
autoStart: true,
};
/**
* Translator plugin
*/
const translator: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:translator',
description: 'Translator plugin',
requires: [INotebookShell, ITranslator],
autoStart: true,
activate: (
@ -1131,7 +1047,6 @@ const translator: JupyterFrontEndPlugin<void> = {
*/
const zen: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/application-extension:zen',
description: 'Zen mode plugin.',
autoStart: true,
requires: [ITranslator],
optional: [ICommandPalette, INotebookShell],
@ -1188,7 +1103,6 @@ const zen: JupyterFrontEndPlugin<void> = {
*/
const plugins: JupyterFrontEndPlugin<any>[] = [
dirty,
info,
logo,
menus,
menuSpacer,
@ -1199,7 +1113,6 @@ const plugins: JupyterFrontEndPlugin<any>[] = [
rendermime,
shell,
sidePanelVisibility,
shortcuts,
splash,
status,
tabTitle,

@ -38,8 +38,3 @@
/* bring logo to the front so it is selectable by tab*/
z-index: 10;
}
/* Hide the notification status item */
.jp-Notification-Status {
display: none;
}

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/application",
"version": "7.6.0-alpha.0",
"version": "7.0.8",
"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.0.11",
"@jupyterlab/coreutils": "^6.0.11",
"@jupyterlab/docregistry": "^4.0.11",
"@jupyterlab/rendermime-interfaces": "^3.8.11",
"@jupyterlab/ui-components": "^4.0.11",
"@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.0"
},
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.12.1",
"@jupyterlab/testutils": "~4.6.0-alpha.0",
"@jupyterlab/testutils": "^4.0.11",
"@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"

@ -2,7 +2,6 @@
// Distributed under the terms of the Modified BSD License.
import {
JupyterLab,
JupyterFrontEnd,
JupyterFrontEndPlugin,
} from '@jupyterlab/application';
@ -41,17 +40,6 @@ export class NotebookApp extends JupyterFrontEnd<INotebookShell> {
}
}
// Create an IInfo dictionary from the options to override the defaults.
const info = Object.keys(JupyterLab.defaultInfo).reduce((acc, val) => {
if (val in options) {
(acc as any)[val] = JSON.parse(JSON.stringify((options as any)[val]));
}
return acc;
}, {} as Partial<JupyterLab.IInfo>);
// Populate application info.
this._info = { ...JupyterLab.defaultInfo, ...info };
this.restored = this.shell.restored;
this.restored.then(() => this._formatter.invoke());
@ -83,13 +71,6 @@ export class NotebookApp extends JupyterFrontEnd<INotebookShell> {
readonly version = PageConfig.getOption('appVersion') ?? 'unknown';
/**
* The NotebookApp application information dictionary.
*/
get info(): JupyterLab.IInfo {
return this._info;
}
/**
* The JupyterLab application paths dictionary.
*/
@ -168,7 +149,6 @@ export class NotebookApp extends JupyterFrontEnd<INotebookShell> {
});
}
private _info: JupyterLab.IInfo = JupyterLab.defaultInfo;
private _formatter = new Throttler(() => {
Private.setFormat(this);
}, 250);
@ -193,11 +173,6 @@ export namespace NotebookApp {
* The mime renderer extensions.
*/
readonly mimeExtensions: IRenderMime.IExtensionModule[];
/**
* The information about available plugins.
*/
readonly availablePlugins: JupyterLab.IPluginInfo[];
}
/**

@ -165,20 +165,17 @@ export class SidePanelHandler extends PanelHandler {
* if there is no most recently used.
*/
expand(id?: string): void {
if (this._currentWidget) {
this.collapse();
}
if (id) {
if (this._currentWidget && this._currentWidget.id === id) {
this.collapse();
this.hide();
} else {
this.collapse();
this.hide();
this.activate(id);
this.show();
this.activate(id);
} else {
const visibleWidget = this.currentWidget;
if (visibleWidget) {
this._currentWidget = visibleWidget;
this.activate(visibleWidget.id);
}
} else if (this.currentWidget) {
this._currentWidget = this.currentWidget;
this.activate(this._currentWidget.id);
this.show();
}
}

@ -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.0.8",
"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.0.8",
"@jupyterlab/application": "^4.0.11",
"@jupyterlab/console": "^4.0.11",
"@jupyterlab/coreutils": "^6.0.11",
"@lumino/algorithm": "^2.0.1"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -25,7 +25,6 @@ const opener: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/console-extension:opener',
requires: [IRouter],
autoStart: true,
description: 'A plugin to open consoles in a new tab',
activate: (app: JupyterFrontEnd, router: IRouter) => {
const { commands } = app;
const consolePattern = new RegExp('/consoles/(.*)');
@ -60,7 +59,6 @@ const redirect: JupyterFrontEndPlugin<void> = {
requires: [IConsoleTracker],
optional: [INotebookPathOpener],
autoStart: true,
description: 'Open consoles in a new tab',
activate: (
app: JupyterFrontEnd,
tracker: IConsoleTracker,

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/docmanager-extension",
"version": "7.6.0-alpha.0",
"version": "7.0.8",
"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.0.8",
"@jupyterlab/application": "^4.0.11",
"@jupyterlab/coreutils": "^6.0.11",
"@jupyterlab/docmanager": "^4.0.11",
"@jupyterlab/docregistry": "^4.0.11",
"@jupyterlab/services": "^7.0.11",
"@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"

@ -29,7 +29,6 @@ const opener: JupyterFrontEndPlugin<IDocumentWidgetOpener> = {
autoStart: true,
optional: [INotebookPathOpener, INotebookShell],
provides: IDocumentWidgetOpener,
description: 'Open documents in a new browser tab',
activate: (
app: JupyterFrontEnd,
notebookPathOpener: INotebookPathOpener,
@ -40,10 +39,7 @@ const opener: JupyterFrontEndPlugin<IDocumentWidgetOpener> = {
const pathOpener = notebookPathOpener ?? defaultNotebookPathOpener;
let id = 0;
return new (class {
async open(
widget: IDocumentWidget,
options?: DocumentRegistry.IOpenOptions
) {
open(widget: IDocumentWidget, options?: DocumentRegistry.IOpenOptions) {
const widgetName = options?.type ?? '';
const ref = options?.ref;
// check if there is an setting override and if it would add the widget in the main area
@ -57,11 +53,6 @@ const opener: JupyterFrontEndPlugin<IDocumentWidgetOpener> = {
(widgetName === 'default' && ext === '.ipynb') ||
widgetName.includes('Notebook')
) {
// make sure to save the notebook before opening it in a new tab
// so the kernel info is saved (if created from the New dropdown)
if (widget.context.sessionContext.kernelPreference.name) {
await widget.context.save();
}
route = 'notebooks';
}
// append ?factory only if it's not the default

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/documentsearch-extension",
"version": "7.6.0-alpha.0",
"version": "7.0.8",
"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.0.8",
"@jupyterlab/application": "^4.0.11",
"@jupyterlab/documentsearch": "^4.0.11",
"@lumino/widgets": "^2.3.0"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -18,7 +18,6 @@ const notebookShellWidgetListener: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/documentsearch-extension:notebookShellWidgetListener',
requires: [INotebookShell, ISearchProviderRegistry],
autoStart: true,
description: 'A plugin to add document search functionalities',
activate: (
app: JupyterFrontEnd,
notebookShell: INotebookShell,

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/help-extension",
"version": "7.6.0-alpha.0",
"version": "7.0.8",
"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.0.8",
"@jupyterlab/application": "^4.0.11",
"@jupyterlab/apputils": "^4.1.11",
"@jupyterlab/mainmenu": "^4.0.11",
"@jupyterlab/translation": "^4.0.11",
"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"

@ -49,7 +49,6 @@ namespace CommandIDs {
const open: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/help-extension:open',
autoStart: true,
description: 'A plugin to open the about section with resources',
activate: (app: JupyterFrontEnd): void => {
const { commands } = app;
@ -71,8 +70,6 @@ const about: JupyterFrontEndPlugin<void> = {
autoStart: true,
requires: [ITranslator],
optional: [IMainMenu, ICommandPalette],
description:
'Plugin to add a command to show an About Jupyter Notebook and Markdown Reference',
activate: (
app: JupyterFrontEnd,
translator: ITranslator,

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/lab-extension",
"version": "7.6.0-alpha.0",
"version": "7.0.8",
"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.0.8",
"@jupyterlab/application": "^4.0.11",
"@jupyterlab/apputils": "^4.1.11",
"@jupyterlab/coreutils": "^6.0.11",
"@jupyterlab/docregistry": "^4.0.11",
"@jupyterlab/notebook": "^4.0.11",
"@jupyterlab/translation": "^4.0.11",
"@jupyterlab/ui-components": "^4.0.11",
"@lumino/commands": "^2.1.3",
"@lumino/disposable": "^2.1.2"
},
"devDependencies": {
"@jupyterlab/builder": "~4.6.0-alpha.0",
"@jupyterlab/builder": "^4.0.11",
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -67,11 +67,9 @@ interface ISwitcherChoice {
*/
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 +79,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');
@ -225,7 +218,6 @@ const interfaceSwitcher: JupyterFrontEndPlugin<void> = {
*/
const launchNotebookTree: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/lab-extension:launch-tree',
description: 'A plugin to add a command to open the Jupyter Notebook Tree.',
autoStart: true,
requires: [ITranslator],
optional: [ICommandPalette],

@ -14,10 +14,12 @@
vertical-align: sub;
}
.jp-nb-interface-switcher-button > .jp-ToolbarButtonComponent::part(content) {
.jp-nb-interface-switcher-button > .jp-ToolbarButtonComponent {
flex-direction: row-reverse;
}
.jp-nb-interface-switcher-button > .jp-ToolbarButtonComponent > svg {
.jp-nb-interface-switcher-button
> .jp-ToolbarButtonComponent
> .jp-ToolbarButtonComponent-icon {
padding-left: 3px;
}

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/notebook-extension",
"version": "7.6.0-alpha.0",
"version": "7.0.8",
"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.0.8",
"@jupyterlab/application": "^4.0.11",
"@jupyterlab/apputils": "^4.1.11",
"@jupyterlab/cells": "^4.0.11",
"@jupyterlab/docmanager": "^4.0.11",
"@jupyterlab/notebook": "^4.0.11",
"@jupyterlab/settingregistry": "^4.0.11",
"@jupyterlab/translation": "^4.0.11",
"@lumino/polling": "^2.1.2",
"@lumino/widgets": "^2.3.0",
"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"
}

@ -1,37 +0,0 @@
{
"title": "Jupyter Notebook Menu Entries",
"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": [
{
"type": "separator",
"rank": 8.5
},
{
"command": "notebook:edit-metadata",
"rank": 8.5
},
{
"type": "separator",
"rank": 8.5
}
]
}
]
},
"properties": {},
"additionalProperties": false,
"type": "object"
}

@ -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"
}

@ -10,7 +10,6 @@ import {
ISessionContext,
DOMUtils,
IToolbarWidgetRegistry,
ICommandPalette,
} from '@jupyterlab/apputils';
import { Cell, CodeCell } from '@jupyterlab/cells';
@ -19,8 +18,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,42 +63,20 @@ 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.
*/
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';
}
/**
* A plugin for the checkpoint indicator
*/
const checkpoints: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/notebook-extension:checkpoints',
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 +91,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 +112,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',
});
},
};
@ -227,8 +133,6 @@ const checkpoints: JupyterFrontEndPlugin<void> = {
*/
const closeTab: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/notebook-extension:close-tab',
description:
'Add a command to close the browser tab when clicking on "Close and Shut Down".',
autoStart: true,
requires: [IMainMenu],
optional: [ITranslator],
@ -245,8 +149,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,114 +162,11 @@ 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.
*/
const kernelLogo: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/notebook-extension:kernel-logo',
description: 'The kernel logo plugin.',
autoStart: true,
requires: [INotebookShell],
optional: [IToolbarWidgetRegistry],
@ -430,7 +230,6 @@ const kernelLogo: JupyterFrontEndPlugin<void> = {
*/
const kernelStatus: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/notebook-extension:kernel-status',
description: 'A plugin to display the kernel status.',
autoStart: true,
requires: [INotebookShell, ITranslator],
activate: (
@ -495,7 +294,6 @@ const kernelStatus: JupyterFrontEndPlugin<void> = {
*/
const scrollOutput: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/notebook-extension:scroll-output',
description: 'A plugin to enable scrolling for outputs by default.',
autoStart: true,
requires: [INotebookTracker],
optional: [ISettingRegistry],
@ -511,7 +309,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;
@ -582,7 +379,6 @@ const scrollOutput: JupyterFrontEndPlugin<void> = {
*/
const notebookToolsWidget: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/notebook-extension:notebook-tools',
description: 'A plugin to add the NotebookTools to the side panel.',
autoStart: true,
requires: [INotebookShell],
optional: [INotebookTools],
@ -611,7 +407,6 @@ const notebookToolsWidget: JupyterFrontEndPlugin<void> = {
*/
const tabIcon: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/notebook-extension:tab-icon',
description: 'A plugin to update the tab icon based on the kernel status.',
autoStart: true,
requires: [INotebookTracker],
activate: (app: JupyterFrontEnd, tracker: INotebookTracker) => {
@ -661,7 +456,6 @@ const tabIcon: JupyterFrontEndPlugin<void> = {
*/
const trusted: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/notebook-extension:trusted',
description: 'A plugin that adds a Trusted indicator to the menu area.',
autoStart: true,
requires: [INotebookShell, ITranslator],
activate: (
@ -688,76 +482,12 @@ const trusted: JupyterFrontEndPlugin<void> = {
},
};
/**
* Add a command to open right sidebar for Editing Notebook Metadata when clicking on "Edit Notebook Metadata" under Edit menu
*/
const editNotebookMetadata: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/notebook-extension:edit-notebook-metadata',
description:
'Add a command to open right sidebar for Editing Notebook Metadata when clicking on "Edit Notebook Metadata" under Edit menu',
autoStart: true,
optional: [ICommandPalette, ITranslator, INotebookTools],
activate: (
app: JupyterFrontEnd,
palette: ICommandPalette | null,
translator: ITranslator | null,
notebookTools: INotebookTools | null
) => {
const { commands, shell } = app;
translator = translator ?? nullTranslator;
const trans = translator.load('notebook');
commands.addCommand(CommandIDs.openEditNotebookMetadata, {
label: trans.__('Edit Notebook Metadata'),
execute: async () => {
const command = 'application:toggle-panel';
const args = {
side: 'right',
title: 'Show Notebook Tools',
id: 'notebook-tools',
};
// Check if Show Notebook Tools (Right Sidebar) is open (expanded)
if (!commands.isToggled(command, args)) {
await commands.execute(command, args).then((_) => {
// For expanding the 'Advanced Tools' section (default: collapsed)
if (notebookTools) {
const tools = (notebookTools?.layout as any).widgets;
tools.forEach((tool: any) => {
if (
tool.widget.title.label === trans.__('Advanced Tools') &&
tool.collapsed
) {
tool.toggle();
}
});
}
});
}
},
isVisible: () =>
shell.currentWidget !== null &&
shell.currentWidget instanceof NotebookPanel,
});
if (palette) {
palette.addItem({
command: CommandIDs.openEditNotebookMetadata,
category: 'Notebook Operations',
});
}
},
};
/**
* Export the plugins as default.
*/
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 {
@ -33,38 +23,35 @@ body[data-notebook='notebooks'] .jp-NotebookPanel-toolbar {
padding-right: calc(calc(100% - var(--jp-notebook-max-width)) * 0.5);
}
body[data-notebook='notebooks'] .jp-WindowedPanel-outer {
width: unset !important;
body[data-notebook='notebooks'] .jp-Notebook {
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) */
body[data-notebook='notebooks']
.jp-Notebook.jp-mod-scrollPastEnd
.jp-WindowedPanel-outer::after {
body[data-notebook='notebooks'] .jp-Notebook.jp-mod-scrollPastEnd::after {
min-height: 100px;
}
/* Fix background colors */
body[data-notebook='notebooks'] .jp-WindowedPanel-outer > * {
body[data-notebook='notebooks'] .jp-Notebook > * {
background: var(--jp-layout-color0);
}
@ -74,6 +61,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-window > *: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 +90,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 +124,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 */
@ -127,7 +135,7 @@ body[data-format='mobile'] .jp-NotebookCheckpoint {
display: none;
}
body[data-format='mobile'] .jp-WindowedPanel-outer > *:first-child {
body[data-format='mobile'] .jp-Notebook > *:first-child {
margin-top: 0;
}
@ -135,17 +143,18 @@ body[data-format='mobile'] .jp-ToolbarButton .jp-DebuggerBugButton {
display: none;
}
body[data-notebook='notebooks'] .jp-WindowedPanel-viewport {
background: var(--jp-layout-color0);
box-shadow: var(--jp-elevation-z4);
/* Virtual Notebook fixes */
/* 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));
body[data-notebook='notebooks'] .jp-WindowedPanel-window {
background: var(--jp-layout-color0);
}
/* Notebook box shadow */
body[data-notebook='notebooks'] .jp-Notebook > *:first-child:not(:last-child) {
box-shadow: var(--jp-elevation-z4);
}
body[data-notebook='notebooks']
.jp-Notebook
> *:first-child:last-child::before {
@ -158,6 +167,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.0.8",
"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.0.8",
"@jupyterlab/application": "^4.0.11",
"@jupyterlab/coreutils": "^6.0.11",
"@jupyterlab/terminal": "^4.0.11",
"@lumino/algorithm": "^2.0.1"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -23,7 +23,6 @@ import { find } from '@lumino/algorithm';
*/
const opener: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/terminal-extension:opener',
description: 'A plugin to open terminals in a new tab.',
requires: [IRouter, ITerminalTracker],
autoStart: true,
activate: (
@ -63,7 +62,6 @@ const opener: JupyterFrontEndPlugin<void> = {
*/
const redirect: JupyterFrontEndPlugin<void> = {
id: '@jupyter-notebook/terminal-extension:redirect',
description: 'Open terminals in a new tab.',
requires: [ITerminalTracker],
optional: [INotebookPathOpener],
autoStart: true,

@ -1,6 +1,6 @@
{
"name": "@jupyter-notebook/tree-extension",
"version": "7.6.0-alpha.0",
"version": "7.0.8",
"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.0.8",
"@jupyter-notebook/tree": "^7.0.8",
"@jupyterlab/application": "^4.0.11",
"@jupyterlab/apputils": "^4.1.11",
"@jupyterlab/coreutils": "^6.0.11",
"@jupyterlab/docmanager": "^4.0.11",
"@jupyterlab/filebrowser": "^4.0.11",
"@jupyterlab/mainmenu": "^4.0.11",
"@jupyterlab/services": "^7.0.11",
"@jupyterlab/settingeditor": "^4.0.11",
"@jupyterlab/settingregistry": "^4.0.11",
"@jupyterlab/statedb": "^4.0.11",
"@jupyterlab/translation": "^4.0.11",
"@jupyterlab/ui-components": "^4.0.11",
"@lumino/algorithm": "^2.0.1",
"@lumino/commands": "^2.1.3",
"@lumino/widgets": "^2.3.0"
},
"devDependencies": {
"rimraf": "^3.0.2",
"typescript": "~5.5.4"
"typescript": "~5.0.2"
},
"publishConfig": {
"access": "public"

@ -2,14 +2,7 @@
"title": "File Browser Widget - File Actions",
"description": "File Browser widget - File Actions settings.",
"jupyter.lab.toolbars": {
"FileBrowser": [
{ "name": "fileAction-placeholder", "rank": 0 },
{ "name": "fileAction-open", "rank": 1 },
{ "name": "fileAction-download", "rank": 2 },
{ "name": "fileAction-rename", "rank": 3 },
{ "name": "fileAction-duplicate", "rank": 4 },
{ "name": "fileAction-delete", "rank": 5 }
]
"FileBrowser": [{ "name": "fileActions", "rank": 0 }]
},
"properties": {},
"additionalProperties": false,

@ -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 }

@ -4,6 +4,7 @@
import {
CommandToolbarButtonComponent,
ReactWidget,
UseSignal,
} from '@jupyterlab/apputils';
import { FileBrowser } from '@jupyterlab/filebrowser';
@ -16,75 +17,113 @@ import { ISignal } from '@lumino/signaling';
import React from 'react';
export class FilesActionButtons {
/**
* The constructor of FilesActionButtons.
* @param options
*/
constructor(options: {
commands: CommandRegistry;
browser: FileBrowser;
selectionChanged: ISignal<FileBrowser, void>;
translator: ITranslator;
}) {
this._browser = options.browser;
const { commands, selectionChanged, translator } = options;
const trans = translator.load('notebook');
/**
* A React component to display the list of command toolbar buttons.
*
*/
const Commands = ({
commands,
browser,
translator,
}: {
commands: CommandRegistry;
browser: FileBrowser;
translator: ITranslator;
}): JSX.Element => {
const trans = translator.load('notebook');
const selection = Array.from(browser.selectedItems());
const oneFolder = selection.some((item) => item.type === 'directory');
const multipleFiles =
selection.filter((item) => item.type === 'file').length > 1;
if (selection.length === 0) {
return <div>{trans.__('Select items to perform actions on them.')}</div>;
} else {
const buttons = ['delete'];
if (!oneFolder) {
buttons.unshift('duplicate');
if (!multipleFiles) {
buttons.unshift('rename');
}
buttons.unshift('download');
buttons.unshift('open');
} else if (selection.length === 1) {
buttons.unshift('rename');
}
// Placeholder, when no file is selected.
const placeholder = ReactWidget.create(
<div key={'placeholder'}>
{trans.__('Select items to perform actions on them.')}
</div>
return (
<>
{buttons.map((action) => (
<CommandToolbarButtonComponent
key={action}
commands={commands}
id={`filebrowser:${action}`}
args={{ toolbar: true }}
icon={undefined}
/>
))}
</>
);
placeholder.id = 'fileAction-placeholder';
this._widgets.set('placeholder', placeholder);
}
};
// The action buttons.
const actions = ['open', 'download', 'rename', 'duplicate', 'delete'];
actions.forEach((action) => {
const widget = ReactWidget.create(
<CommandToolbarButtonComponent
key={action}
/**
* A React component to display the file action buttons in the file browser toolbar.
*
* @param translator The Translation service
*/
const FileActions = ({
commands,
browser,
selectionChanged,
translator,
}: {
commands: CommandRegistry;
browser: FileBrowser;
selectionChanged: ISignal<FileBrowser, void>;
translator: ITranslator;
}): JSX.Element => {
return (
<UseSignal signal={selectionChanged} shouldUpdate={() => true}>
{(): JSX.Element => (
<Commands
commands={commands}
id={`filebrowser:${action}`}
args={{ toolbar: true }}
icon={undefined}
browser={browser}
translator={translator}
/>
);
widget.id = `fileAction-${action}`;
widget.addClass('jp-ToolbarButton');
widget.addClass('jp-FileAction');
this._widgets.set(action, widget);
});
selectionChanged.connect(this._onSelectionChanged, this);
this._onSelectionChanged();
}
/**
* Return an iterator with all the action widgets.
*/
get widgets(): IterableIterator<ReactWidget> {
return this._widgets.values();
}
)}
</UseSignal>
);
};
/**
* A namespace for FileActionsComponent static functions.
*/
export namespace FileActionsComponent {
/**
* Triggered when the selection change in file browser.
* Create a new FileActionsComponent
*
* @param translator The translator
*/
private _onSelectionChanged = () => {
const selectedItems = Array.from(this._browser.selectedItems());
const selection = selectedItems.length > 0;
const oneFolder = selectedItems.some((item) => item.type === 'directory');
this._widgets.get('placeholder')?.setHidden(selection);
this._widgets.get('delete')?.setHidden(!selection);
this._widgets.get('duplicate')?.setHidden(!selection || oneFolder);
this._widgets.get('download')?.setHidden(!selection || oneFolder);
this._widgets.get('open')?.setHidden(!selection || oneFolder);
this._widgets.get('rename')?.setHidden(selectedItems.length !== 1);
export const create = ({
commands,
browser,
selectionChanged,
translator,
}: {
commands: CommandRegistry;
browser: FileBrowser;
selectionChanged: ISignal<FileBrowser, void>;
translator: ITranslator;
}): ReactWidget => {
const widget = ReactWidget.create(
<FileActions
commands={commands}
browser={browser}
selectionChanged={selectionChanged}
translator={translator}
/>
);
widget.addClass('jp-FileActions');
return widget;
};
private _browser: FileBrowser;
private _widgets = new Map<string, ReactWidget>();
}

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

Loading…
Cancel
Save