upgrade
ci/woodpecker/push/woodpecker Pipeline was successful Details

This commit is contained in:
Malte Grosse 2024-02-12 13:37:00 +00:00
parent 6c1ece8fac
commit c839323c7a
37 changed files with 6156 additions and 10527 deletions

19
.copier-answers.yml Normal file
View File

@ -0,0 +1,19 @@
# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
_commit: v4.2.5
_src_path: https://github.com/jupyterlab/extension-template
author_email: grosse@hdm-stuttgart.de
author_name: Sandbox Theme
data_format: string
file_extension: ''
has_binder: false
has_settings: false
kind: theme
labextension_name: sandbox_theme
mimetype: ''
mimetype_name: ''
project_short_description: Sandbox Theme for JupyterLab
python_name: sandbox_theme
repository: https://git.sandbox.iuk.hdm-stuttgart.de/grosse/jupyterlab_sandbox_theme
test: false
viewer_name: ''

View File

@ -0,0 +1,4 @@
{
"image": "quay.io/jupyter/scipy-notebook:lab-4.0.12",
"postCreateCommand": "pip install 'copier~=7.2' jinja2-time 'pydantic<2.0.0'"
}

View File

@ -1,8 +0,0 @@
node_modules
dist
coverage
**/*.d.ts
tests
**/__tests__
ui-tests

View File

@ -1,39 +0,0 @@
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended'
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module'
},
plugins: ['@typescript-eslint'],
rules: {
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'interface',
format: ['PascalCase'],
custom: {
regex: '^I[A-Z]',
match: true
}
}
],
'@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/quotes': [
'error',
'single',
{ avoidEscape: true, allowTemplateLiterals: false }
],
curly: ['error', 'all'],
eqeqeq: 'error',
'prefer-arrow-callback': 'error'
}
};

View File

@ -6,6 +6,10 @@ on:
pull_request: pull_request:
branches: '*' branches: '*'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -18,7 +22,7 @@ jobs:
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Install dependencies - name: Install dependencies
run: python -m pip install -U jupyterlab~=3.5.2 run: python -m pip install -U "jupyterlab>=4.0.0,<5"
- name: Lint the extension - name: Lint the extension
run: | run: |
@ -26,18 +30,13 @@ jobs:
jlpm jlpm
jlpm run lint:check jlpm run lint:check
- name: Test the extension
run: |
set -eux
jlpm run test
- name: Build the extension - name: Build the extension
run: | run: |
set -eux set -eux
python -m pip install .[test] python -m pip install .[test]
jupyter labextension list jupyter labextension list
jupyter labextension list 2>&1 | grep -ie "jupyterlab_sandbox_theme.*OK" jupyter labextension list 2>&1 | grep -ie "sandbox_theme.*OK"
python -m jupyterlab.browser_check python -m jupyterlab.browser_check
- name: Package the extension - name: Package the extension
@ -46,13 +45,13 @@ jobs:
pip install build pip install build
python -m build python -m build
pip uninstall -y "jupyterlab_sandbox_theme" jupyterlab pip uninstall -y "sandbox_theme" jupyterlab
- name: Upload extension packages - name: Upload extension packages
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: extension-artifacts name: extension-artifacts
path: dist/jupyterlab_sandbox_theme* path: dist/sandbox_theme*
if-no-files-found: error if-no-files-found: error
test_isolated: test_isolated:
@ -60,8 +59,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Python - name: Install Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
@ -77,68 +74,13 @@ jobs:
sudo rm -rf $(which node) sudo rm -rf $(which node)
sudo rm -rf $(which node) sudo rm -rf $(which node)
pip install "jupyterlab~=3.1" jupyterlab_sandbox_theme*.whl pip install "jupyterlab>=4.0.0,<5" sandbox_theme*.whl
jupyter labextension list jupyter labextension list
jupyter labextension list 2>&1 | grep -ie "jupyterlab_sandbox_theme.*OK" jupyter labextension list 2>&1 | grep -ie "sandbox_theme.*OK"
python -m jupyterlab.browser_check --no-chrome-test python -m jupyterlab.browser_check --no-browser-test
integration-tests:
name: Integration tests
needs: build
runs-on: ubuntu-latest
env:
PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/pw-browsers
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Download extension package
uses: actions/download-artifact@v3
with:
name: extension-artifacts
- name: Install the extension
run: |
set -eux
python -m pip install "jupyterlab~=3.1" jupyterlab_sandbox_theme*.whl
- name: Install dependencies
working-directory: ui-tests
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
run: jlpm install
- name: Set up browser cache
uses: actions/cache@v3
with:
path: |
${{ github.workspace }}/pw-browsers
key: ${{ runner.os }}-${{ hashFiles('ui-tests/yarn.lock') }}
- name: Install browser
run: jlpm playwright install chromium
working-directory: ui-tests
- name: Execute integration tests
working-directory: ui-tests
run: |
jlpm playwright test
- name: Upload Playwright Test report
if: always()
uses: actions/upload-artifact@v3
with:
name: jupyterlab_sandbox_theme-playwright-tests
path: |
ui-tests/test-results
ui-tests/playwright-report
check_links: check_links:
name: Check Links name: Check Links

View File

@ -5,6 +5,10 @@ on:
pull_request: pull_request:
branches: ["*"] branches: ["*"]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs: jobs:
check_release: check_release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -13,9 +17,6 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Base Setup - name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Install Dependencies
run: |
pip install -e .
- name: Check Release - name: Check Release
uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2 uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2
with: with:
@ -25,5 +26,5 @@ jobs:
- name: Upload Distributions - name: Upload Distributions
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: jupyterlab_sandbox_theme-releaser-dist-${{ github.run_number }} name: sandbox_theme-releaser-dist-${{ github.run_number }}
path: .jupyter_releaser_checkout/dist path: .jupyter_releaser_checkout/dist

13
.github/workflows/enforce-label.yml vendored Normal file
View File

@ -0,0 +1,13 @@
name: Enforce PR label
on:
pull_request:
types: [labeled, unlabeled, opened, edited, synchronize]
jobs:
enforce-label:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: enforce-triage-label
uses: jupyterlab/maintainer-tools/.github/actions/enforce-label@v1

46
.github/workflows/prep-release.yml vendored Normal file
View File

@ -0,0 +1,46 @@
name: "Step 1: Prep Release"
on:
workflow_dispatch:
inputs:
version_spec:
description: "New Version Specifier"
default: "next"
required: false
branch:
description: "The branch to target"
required: false
post_version_spec:
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"
required: false
since_last_stable:
description: "Use PRs with activity since the last stable git tag"
required: false
type: boolean
jobs:
prep_release:
runs-on: ubuntu-latest
steps:
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Prep Release
id: prep-release
uses: jupyter-server/jupyter_releaser/.github/actions/prep-release@v2
with:
token: ${{ secrets.ADMIN_GITHUB_TOKEN }}
version_spec: ${{ github.event.inputs.version_spec }}
post_version_spec: ${{ github.event.inputs.post_version_spec }}
branch: ${{ github.event.inputs.branch }}
# silent: ${{ github.event.inputs.silent }}
since: ${{ github.event.inputs.since }}
since_last_stable: ${{ github.event.inputs.since_last_stable }}
- name: "** Next Step **"
run: |
echo "Optional): Review Draft Release: ${{ steps.prep-release.outputs.release_url }}"

57
.github/workflows/publish-release.yml vendored Normal file
View File

@ -0,0 +1,57 @@
name: "Step 2: Publish Release"
on:
workflow_dispatch:
inputs:
branch:
description: "The target branch"
required: false
release_url:
description: "The URL of the draft GitHub release"
required: false
steps_to_skip:
description: "Comma separated list of steps to skip"
required: false
jobs:
publish_release:
runs-on: ubuntu-latest
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
- name: Populate Release
id: populate-release
uses: jupyter-server/jupyter_releaser/.github/actions/populate-release@v2
with:
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 }}
- name: Finalize Release
id: finalize-release
env:
# The following are needed if you use legacy PyPI set up
# PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
# PYPI_TOKEN_MAP: ${{ secrets.PYPI_TOKEN_MAP }}
# TWINE_USERNAME: __token__
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
uses: jupyter-server/jupyter_releaser/.github/actions/finalize-release@v2
with:
token: ${{ secrets.ADMIN_GITHUB_TOKEN }}
release_url: ${{ steps.populate-release.outputs.release_url }}
- name: "** Next Step **"
if: ${{ success() }}
run: |
echo "Verify the final release"
echo ${{ steps.finalize-release.outputs.release_url }}
- name: "** Failure Message **"
if: ${{ failure() }}
run: |
echo "Failed to Publish the Draft Release Url:"
echo ${{ steps.populate-release.outputs.release_url }}

View File

@ -1,50 +0,0 @@
name: Update Playwright Snapshots
on:
issue_comment:
types: [created, edited]
permissions:
contents: write
pull-requests: write
jobs:
update-snapshots:
if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, 'please update playwright snapshots') }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Configure git to use https
run: git config --global hub.protocol https
- name: Checkout the branch from the PR that triggered the job
run: hub pr checkout ${{ github.event.issue.number }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- name: Install dependencies
run: python -m pip install -U jupyterlab~=3.1
- name: Install extension
run: |
set -eux
jlpm
python -m pip install .
- uses: jupyterlab/maintainer-tools/.github/actions/update-snapshots@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# Playwright knows how to start JupyterLab server
start_server_script: 'null'
test_folder: ui-tests

11
.gitignore vendored
View File

@ -7,13 +7,9 @@ node_modules/
*.egg-info/ *.egg-info/
.ipynb_checkpoints .ipynb_checkpoints
*.tsbuildinfo *.tsbuildinfo
jupyterlab_sandbox_theme/labextension sandbox_theme/labextension
# Version file is handled by hatchling # Version file is handled by hatchling
jupyterlab_sandbox_theme/_version.py sandbox_theme/_version.py
# Integration tests
ui-tests/test-results/
ui-tests/playwright-report/
# Created by https://www.gitignore.io/api/python # Created by https://www.gitignore.io/api/python
# Edit at https://www.gitignore.io/?templates=python # Edit at https://www.gitignore.io/?templates=python
@ -120,3 +116,6 @@ dmypy.json
# OSX files # OSX files
.DS_Store .DS_Store
# Yarn cache
.yarn/

View File

@ -3,4 +3,4 @@ node_modules
**/lib **/lib
**/package.json **/package.json
!/package.json !/package.json
jupyterlab_sandbox_theme sandbox_theme

View File

@ -1,6 +0,0 @@
{
"singleQuote": true,
"trailingComma": "none",
"arrowParens": "avoid",
"endOfLine": "auto"
}

View File

@ -1,14 +0,0 @@
{
"extends": [
"stylelint-config-recommended",
"stylelint-config-standard",
"stylelint-prettier/recommended"
],
"rules": {
"property-no-vendor-prefix": null,
"selector-no-vendor-prefix": null,
"value-no-vendor-prefix": null,
"alpha-value-notation": null,
"color-function-notation": null
}
}

View File

@ -1,10 +1,9 @@
pipeline: steps:
build-package: build-package:
image: nikolaik/python-nodejs:python3.7-nodejs19 image: nikolaik/python-nodejs:python3.10-nodejs21-alpine
commands: commands:
- apt update && apt install build-essential -y - apk update && apk add build-base gcc python3-dev musl-dev linux-headers
- python -m pip install -U jupyterlab~=3.5.2 build twine - python -m pip install -U jupyterlab~=4.0.12 build twine
- python -m build -s - python -m build -s
- python -m twine upload dist/* --repository-url=$TWINE_REPOSITORY_URL - python -m twine upload dist/* --repository-url=$TWINE_REPOSITORY_URL
secrets: [ TWINE_USERNAME, TWINE_PASSWORD, TWINE_REPOSITORY, TWINE_REPOSITORY_URL] secrets: [ TWINE_USERNAME, TWINE_PASSWORD, TWINE_REPOSITORY, TWINE_REPOSITORY_URL]

1
.yarnrc.yml Normal file
View File

@ -0,0 +1 @@
nodeLinker: node-modules

View File

@ -1,6 +1,6 @@
BSD 3-Clause License BSD 3-Clause License
Copyright (c) 2023, Malte Grosse Copyright (c) 2024, Sandbox Theme
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -1,17 +1,18 @@
# jupyterlab_sandbox_theme # sandbox_theme
[![status-badge](https://ci.sandbox.iuk.hdm-stuttgart.de/api/badges/grosse/jupyterlab_sandbox_theme/status.svg)](https://ci.sandbox.iuk.hdm-stuttgart.de/grosse/jupyterlab_sandbox_theme) [![Github Actions Status](https://git.sandbox.iuk.hdm-stuttgart.de/grosse/jupyterlab_sandbox_theme/workflows/Build/badge.svg)](https://git.sandbox.iuk.hdm-stuttgart.de/grosse/jupyterlab_sandbox_theme/actions/workflows/build.yml)
Sandbox Theme for JupyterLab
## Requirements ## Requirements
- JupyterLab >= 3.0 - JupyterLab >= 4.0.0
## Install ## Install
To install the extension, execute: To install the extension, execute:
```bash ```bash
pip install jupyterlab_sandbox_theme pip install sandbox_theme
``` ```
## Uninstall ## Uninstall
@ -19,7 +20,7 @@ pip install jupyterlab_sandbox_theme
To remove the extension, execute: To remove the extension, execute:
```bash ```bash
pip uninstall jupyterlab_sandbox_theme pip uninstall sandbox_theme
``` ```
## Contributing ## Contributing
@ -34,7 +35,7 @@ The `jlpm` command is JupyterLab's pinned version of
```bash ```bash
# Clone the repo to your local environment # Clone the repo to your local environment
# Change directory to the jupyterlab_sandbox_theme directory # Change directory to the sandbox_theme directory
# Install package in development mode # Install package in development mode
pip install -e "." pip install -e "."
# Link your development version of the extension with JupyterLab # Link your development version of the extension with JupyterLab
@ -63,32 +64,12 @@ jupyter lab build --minimize=False
### Development uninstall ### Development uninstall
```bash ```bash
pip uninstall jupyterlab_sandbox_theme pip uninstall sandbox_theme
``` ```
In development mode, you will also need to remove the symlink created by `jupyter labextension develop` In development mode, you will also need to remove the symlink created by `jupyter labextension develop`
command. To find its location, you can run `jupyter labextension list` to figure out where the `labextensions` command. To find its location, you can run `jupyter labextension list` to figure out where the `labextensions`
folder is located. Then you can remove the symlink named `jupyterlab_sandbox_theme` within that folder. folder is located. Then you can remove the symlink named `sandbox_theme` within that folder.
### Testing the extension
#### Frontend tests
This extension is using [Jest](https://jestjs.io/) for JavaScript code testing.
To execute them, execute:
```sh
jlpm
jlpm test
```
#### Integration tests
This extension uses [Playwright](https://playwright.dev/docs/intro/) for the integration tests (aka user level tests).
More precisely, the JupyterLab helper [Galata](https://github.com/jupyterlab/jupyterlab/tree/master/galata) is used to handle testing the extension in JupyterLab.
More information are provided within the [ui-tests](./ui-tests/README.md) README.
### Packaging the extension ### Packaging the extension

View File

@ -1,4 +1,4 @@
# Making a new release of jupyterlab_sandbox_theme # Making a new release of sandbox_theme
The extension can be published to `PyPI` and `npm` manually or using the [Jupyter Releaser](https://github.com/jupyter-server/jupyter_releaser). The extension can be published to `PyPI` and `npm` manually or using the [Jupyter Releaser](https://github.com/jupyter-server/jupyter_releaser).
@ -6,10 +6,9 @@ The extension can be published to `PyPI` and `npm` manually or using the [Jupyte
### Python package ### Python package
This extension can be distributed as Python This extension can be distributed as Python packages. All of the Python
packages. All of the Python packaging instructions are in the `pyproject.toml` file to wrap your extension in a
packaging instructions in the `pyproject.toml` file to wrap your extension in a Python package. Before generating a package, you first need to install some tools:
Python package. Before generating a package, we first need to install `build`.
```bash ```bash
pip install build twine hatch pip install build twine hatch
@ -22,6 +21,18 @@ See the docs on [hatch-nodejs-version](https://github.com/agoose77/hatch-nodejs-
hatch version <new-version> hatch version <new-version>
``` ```
Make sure to clean up all the development files before building the package:
```bash
jlpm clean:all
```
You could also clean up the local git repository:
```bash
git clean -dfX
```
To create a Python source package (`.tar.gz`) and the binary package (`.whl`) in the `dist/` directory, do: To create a Python source package (`.tar.gz`) and the binary package (`.whl`) in the `dist/` directory, do:
```bash ```bash
@ -49,17 +60,49 @@ npm publish --access public
The extension repository should already be compatible with the Jupyter Releaser. The extension repository should already be compatible with the Jupyter Releaser.
Check out the [workflow documentation](https://github.com/jupyter-server/jupyter_releaser#typical-workflow) for more information. Check out the [workflow documentation](https://jupyter-releaser.readthedocs.io/en/latest/get_started/making_release_from_repo.html) for more information.
Here is a summary of the steps to cut a new release: Here is a summary of the steps to cut a new release:
- Fork the [`jupyter-releaser` repo](https://github.com/jupyter-server/jupyter_releaser) - Add tokens to the [Github Secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets) in the repository:
- Add `ADMIN_GITHUB_TOKEN`, `PYPI_TOKEN` and `NPM_TOKEN` to the Github Secrets in the fork - `ADMIN_GITHUB_TOKEN` (with "public_repo" and "repo:status" permissions); see the [documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
- `NPM_TOKEN` (with "automation" permission); see the [documentation](https://docs.npmjs.com/creating-and-viewing-access-tokens)
- Set up PyPI
<details><summary>Using PyPI trusted publisher (modern way)</summary>
- Set up your PyPI project by [adding a trusted publisher](https://docs.pypi.org/trusted-publishers/adding-a-publisher/)
- The _workflow name_ is `publish-release.yml` and the _environment_ should be left blank.
- Ensure the publish release job as `permissions`: `id-token : write` (see the [documentation](https://docs.pypi.org/trusted-publishers/using-a-publisher/))
</details>
<details><summary>Using PyPI token (legacy way)</summary>
- If the repo generates PyPI release(s), create a scoped PyPI [token](https://packaging.python.org/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/#saving-credentials-on-github). We recommend using a scoped token for security reasons.
- You can store the token as `PYPI_TOKEN` in your fork's `Secrets`.
- Advanced usage: if you are releasing multiple repos, you can create a secret named `PYPI_TOKEN_MAP` instead of `PYPI_TOKEN` that is formatted as follows:
```text
owner1/repo1,token1
owner2/repo2,token2
```
If you have multiple Python packages in the same repository, you can point to them as follows:
```text
owner1/repo1/path/to/package1,token1
owner1/repo1/path/to/package2,token2
```
</details>
- Go to the Actions panel - Go to the Actions panel
- Run the "Draft Changelog" workflow - Run the "Step 1: Prep Release" workflow
- Merge the Changelog PR - Check the draft changelog
- Run the "Draft Release" workflow - Run the "Step 2: Publish Release" workflow
- Run the "Publish Release" workflow
## Publishing to `conda-forge` ## Publishing to `conda-forge`

View File

@ -1 +0,0 @@
module.exports = require('@jupyterlab/testutils/lib/babel.config');

View File

@ -1,5 +1,5 @@
{ {
"packageManager": "python", "packageManager": "python",
"packageName": "jupyterlab_sandbox_theme", "packageName": "sandbox_theme",
"uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package jupyterlab_sandbox_theme" "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package sandbox_theme"
} }

View File

@ -1,46 +0,0 @@
const jestJupyterLab = require('@jupyterlab/testutils/lib/jest-config');
const esModules = [
'@jupyterlab/',
'lib0',
'y\\-protocols',
'y\\-websocket',
'yjs'
].join('|');
const jlabConfig = jestJupyterLab(__dirname);
const {
moduleFileExtensions,
moduleNameMapper,
preset,
setupFilesAfterEnv,
setupFiles,
testPathIgnorePatterns,
transform
} = jlabConfig;
module.exports = {
moduleFileExtensions,
moduleNameMapper,
preset,
setupFilesAfterEnv,
setupFiles,
testPathIgnorePatterns,
transform,
automock: false,
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/**/*.d.ts',
'!src/**/.ipynb_checkpoints/*'
],
coverageDirectory: 'coverage',
coverageReporters: ['lcov', 'text'],
globals: {
'ts-jest': {
tsconfig: 'tsconfig.json'
}
},
testRegex: 'src/.*/.*.spec.ts[x]?$',
transformIgnorePatterns: [`/node_modules/(?!${esModules}).+`]
};

View File

@ -1,9 +0,0 @@
from ._version import __version__
def _jupyter_labextension_paths():
return [{
"src": "labextension",
"dest": "jupyterlab_sandbox_theme"
}]

View File

@ -1,7 +1,7 @@
{ {
"name": "jupyterlab_sandbox_theme", "name": "sandbox_theme",
"version": "0.1.2", "version": "0.1.3",
"description": "Sandbox Theme", "description": "Sandbox Theme for JupyterLab",
"keywords": [ "keywords": [
"jupyter", "jupyter",
"jupyterlab", "jupyterlab",
@ -13,13 +13,13 @@
}, },
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"author": { "author": {
"name": "Malte Grosse", "name": "Sandbox Theme",
"email": "grosse@hdm-stuttgart.de" "email": "grosse@hdm-stuttgart.de"
}, },
"files": [ "files": [
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
"style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}", "style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
"style/images/**/*.{jpg,svg,png}" "src/**/*.{ts,tsx}"
], ],
"main": "lib/index.js", "main": "lib/index.js",
"types": "lib/index.d.ts", "types": "lib/index.d.ts",
@ -37,7 +37,7 @@
"clean": "jlpm clean:lib", "clean": "jlpm clean:lib",
"clean:lib": "rimraf lib tsconfig.tsbuildinfo", "clean:lib": "rimraf lib tsconfig.tsbuildinfo",
"clean:lintcache": "rimraf .eslintcache .stylelintcache", "clean:lintcache": "rimraf .eslintcache .stylelintcache",
"clean:labextension": "rimraf jupyterlab_sandbox_theme/labextension jupyterlab_sandbox_theme/_version.py", "clean:labextension": "rimraf sandbox_theme/labextension sandbox_theme/_version.py",
"clean:all": "jlpm clean:lib && jlpm clean:labextension && jlpm clean:lintcache", "clean:all": "jlpm clean:lib && jlpm clean:labextension && jlpm clean:lintcache",
"eslint": "jlpm eslint:check --fix", "eslint": "jlpm eslint:check --fix",
"eslint:check": "eslint . --cache --ext .ts,.tsx", "eslint:check": "eslint . --cache --ext .ts,.tsx",
@ -49,39 +49,37 @@
"prettier:check": "jlpm prettier:base --check", "prettier:check": "jlpm prettier:base --check",
"stylelint": "jlpm stylelint:check --fix", "stylelint": "jlpm stylelint:check --fix",
"stylelint:check": "stylelint --cache \"style/**/*.css\"", "stylelint:check": "stylelint --cache \"style/**/*.css\"",
"test": "jest --coverage",
"watch": "run-p watch:src watch:labextension", "watch": "run-p watch:src watch:labextension",
"watch:src": "tsc -w", "watch:src": "tsc -w --sourceMap",
"watch:labextension": "jupyter labextension watch ." "watch:labextension": "jupyter labextension watch ."
}, },
"dependencies": { "dependencies": {
"@jupyterlab/application": "^3.5.2", "@jupyterlab/application": "^4.0.0",
"@jupyterlab/apputils": "^3.5.2", "@jupyterlab/apputils": "^4.0.0"
"@jupyterlab/ui-components": "^3.5.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.0.0", "@jupyterlab/builder": "^4.0.0",
"@babel/preset-env": "^7.0.0", "@types/json-schema": "^7.0.11",
"@jupyterlab/builder": "^3.1.0", "@types/react": "^18.0.26",
"@jupyterlab/testutils": "^3.0.0", "@types/react-addons-linked-state-mixin": "^0.14.22",
"@types/jest": "^26.0.0", "@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/eslint-plugin": "^4.8.1", "@typescript-eslint/parser": "^6.1.0",
"@typescript-eslint/parser": "^4.8.1", "css-loader": "^6.7.1",
"eslint": "^7.14.0", "eslint": "^8.36.0",
"eslint-config-prettier": "^6.15.0", "eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^3.1.4", "eslint-plugin-prettier": "^5.0.0",
"jest": "^26.0.0",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prettier": "^2.1.1", "prettier": "^3.0.0",
"rimraf": "^3.0.2", "rimraf": "^5.0.1",
"stylelint": "^14.3.0", "source-map-loader": "^1.0.2",
"stylelint-config-prettier": "^9.0.4", "style-loader": "^3.3.1",
"stylelint-config-recommended": "^6.0.0", "stylelint": "^15.10.1",
"stylelint-config-standard": "~24.0.0", "stylelint-config-recommended": "^13.0.0",
"stylelint-prettier": "^2.0.0", "stylelint-config-standard": "^34.0.0",
"ts-jest": "^26.0.0", "stylelint-csstree-validator": "^3.0.0",
"typescript": "~4.1.3" "stylelint-prettier": "^4.0.0",
"typescript": "~5.0.2",
"yjs": "^13.5.0"
}, },
"sideEffects": [ "sideEffects": [
"style/*.css" "style/*.css"
@ -91,7 +89,100 @@
}, },
"jupyterlab": { "jupyterlab": {
"extension": true, "extension": true,
"outputDir": "jupyterlab_sandbox_theme/labextension", "outputDir": "sandbox_theme/labextension",
"themePath": "style/index.css" "themePath": "style/index.css"
},
"eslintIgnore": [
"node_modules",
"dist",
"coverage",
"**/*.d.ts"
],
"eslintConfig": {
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "interface",
"format": [
"PascalCase"
],
"custom": {
"regex": "^I[A-Z]",
"match": true
}
}
],
"@typescript-eslint/no-unused-vars": [
"warn",
{
"args": "none"
}
],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/quotes": [
"error",
"single",
{
"avoidEscape": true,
"allowTemplateLiterals": false
}
],
"curly": [
"error",
"all"
],
"eqeqeq": "error",
"prefer-arrow-callback": "error"
}
},
"prettier": {
"singleQuote": true,
"trailingComma": "none",
"arrowParens": "avoid",
"endOfLine": "auto",
"overrides": [
{
"files": "package.json",
"options": {
"tabWidth": 4
}
}
]
},
"stylelint": {
"extends": [
"stylelint-config-recommended",
"stylelint-config-standard",
"stylelint-prettier/recommended"
],
"plugins": [
"stylelint-csstree-validator"
],
"rules": {
"csstree/validator": true,
"property-no-vendor-prefix": null,
"selector-class-pattern": "^([a-z][A-z\\d]*)(-[A-z\\d]+)*$",
"selector-no-vendor-prefix": null,
"value-no-vendor-prefix": null,
"alpha-value-notation": null,
"color-function-notation": null
}
} }
} }

View File

@ -1,26 +1,26 @@
[build-system] [build-system]
requires = ["hatchling>=1.4.0", "jupyterlab>=3.4.7,<4.0.0", "hatch-nodejs-version"] requires = ["hatchling>=1.5.0", "jupyterlab>=4.0.0,<5", "hatch-nodejs-version>=0.3.2"]
build-backend = "hatchling.build" build-backend = "hatchling.build"
[project] [project]
name = "jupyterlab_sandbox_theme" name = "sandbox_theme"
readme = "README.md" readme = "README.md"
license = { file = "LICENSE" } license = { file = "LICENSE" }
requires-python = ">=3.7" requires-python = ">=3.8"
classifiers = [ classifiers = [
"Framework :: Jupyter", "Framework :: Jupyter",
"Framework :: Jupyter :: JupyterLab", "Framework :: Jupyter :: JupyterLab",
"Framework :: Jupyter :: JupyterLab :: 3", "Framework :: Jupyter :: JupyterLab :: 4",
"Framework :: Jupyter :: JupyterLab :: Extensions", "Framework :: Jupyter :: JupyterLab :: Extensions",
"Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt", "Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt",
"License :: OSI Approved :: BSD License", "License :: OSI Approved :: BSD License",
"Programming Language :: Python", "Programming Language :: Python",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
] ]
dependencies = [ dependencies = [
] ]
@ -33,23 +33,23 @@ source = "nodejs"
fields = ["description", "authors", "urls"] fields = ["description", "authors", "urls"]
[tool.hatch.build.targets.sdist] [tool.hatch.build.targets.sdist]
artifacts = ["jupyterlab_sandbox_theme/labextension"] artifacts = ["sandbox_theme/labextension"]
exclude = [".github", "binder"] exclude = [".github", "binder"]
[tool.hatch.build.targets.wheel.shared-data] [tool.hatch.build.targets.wheel.shared-data]
"jupyterlab_sandbox_theme/labextension" = "share/jupyter/labextensions/jupyterlab_sandbox_theme" "sandbox_theme/labextension" = "share/jupyter/labextensions/sandbox_theme"
"install.json" = "share/jupyter/labextensions/jupyterlab_sandbox_theme/install.json" "install.json" = "share/jupyter/labextensions/sandbox_theme/install.json"
[tool.hatch.build.hooks.version] [tool.hatch.build.hooks.version]
path = "jupyterlab_sandbox_theme/_version.py" path = "sandbox_theme/_version.py"
[tool.hatch.build.hooks.jupyter-builder] [tool.hatch.build.hooks.jupyter-builder]
dependencies = ["hatch-jupyter-builder>=0.5"] dependencies = ["hatch-jupyter-builder>=0.5"]
build-function = "hatch_jupyter_builder.npm_builder" build-function = "hatch_jupyter_builder.npm_builder"
ensured-targets = [ ensured-targets = [
"jupyterlab_sandbox_theme/labextension/package.json", "sandbox_theme/labextension/package.json",
] ]
skip-if-exists = ["jupyterlab_sandbox_theme/labextension/static/style.js"] skip-if-exists = ["sandbox_theme/labextension/static/style.js"]
[tool.hatch.build.hooks.jupyter-builder.build-kwargs] [tool.hatch.build.hooks.jupyter-builder.build-kwargs]
build_cmd = "build:prod" build_cmd = "build:prod"
@ -59,13 +59,17 @@ npm = ["jlpm"]
build_cmd = "install:extension" build_cmd = "install:extension"
npm = ["jlpm"] npm = ["jlpm"]
source_dir = "src" source_dir = "src"
build_dir = "jupyterlab_sandbox_theme/labextension" build_dir = "sandbox_theme/labextension"
[tool.jupyter-releaser.options] [tool.jupyter-releaser.options]
version_cmd = "hatch version" version_cmd = "hatch version"
[tool.jupyter-releaser.hooks] [tool.jupyter-releaser.hooks]
before-build-npm = ["python -m pip install jupyterlab~=3.1", "jlpm", "jlpm build:prod"] before-build-npm = [
"python -m pip install 'jupyterlab>=4.0.0,<5'",
"jlpm",
"jlpm build:prod"
]
before-build-python = ["jlpm clean:all"] before-build-python = ["jlpm clean:all"]
[tool.check-wheel-contents] [tool.check-wheel-contents]

16
sandbox_theme/__init__.py Normal file
View File

@ -0,0 +1,16 @@
try:
from ._version import __version__
except ImportError:
# Fallback when using the package in dev mode without installing
# in editable mode with pip. It is highly recommended to install
# the package from a stable release or in editable mode: https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs
import warnings
warnings.warn("Importing 'sandbox_theme' outside a proper installation.")
__version__ = "dev"
def _jupyter_labextension_paths():
return [{
"src": "labextension",
"dest": "sandbox_theme"
}]

View File

@ -1 +1 @@
__import__('setuptools').setup() __import__("setuptools").setup()

View File

@ -1,9 +0,0 @@
/**
* Example of [Jest](https://jestjs.io/docs/getting-started) unit tests
*/
describe('jupyterlab_sandbox_theme', () => {
it('should be tested', () => {
expect(1 + 1).toEqual(2);
});
});

View File

@ -5,17 +5,19 @@ import { LabIcon, jupyterFaviconIcon, jupyterIcon, jupyterlabWordmarkIcon } from
import { Widget } from '@lumino/widgets'; import { Widget } from '@lumino/widgets';
import { Logo,FavIconIdle,FavIconBusy} from './images'; import { Logo,FavIconIdle,FavIconBusy} from './images';
/** /**
* Initialization data for the jupyterlab_sandbox_theme extension. * Initialization data for the sandbox_theme extension.
*/ */
const plugin: JupyterFrontEndPlugin<void> = { const plugin: JupyterFrontEndPlugin<void> = {
id: 'sandbox_theme:plugin',
id: 'jupyterlab_sandbox_theme:plugin', description: 'Sandbox Theme for JupyterLab',
autoStart: true,
requires: [IThemeManager,ILabShell,ISplashScreen], requires: [IThemeManager,ILabShell,ISplashScreen],
activate: (app: JupyterFrontEnd, manager: IThemeManager, shell: ILabShell) => { activate: (app: JupyterFrontEnd, manager: IThemeManager, shell: ILabShell) => {
// todo: https://github.com/jupyterlab/jupyterlab/blob/997f3af68396539136ab0cb8512c73c07e021e4a/packages/apputils-extension/src/index.ts#L156-L163 console.log('JupyterLab extension sandbox_theme is activated!');
const style = 'jupyterlab_sandbox_theme/index.css'; const style = 'sandbox_theme/index.css';
const logo_svg = Logo const logo_svg = Logo
const logo_icon = new LabIcon({ name: 'ui-components:sandbox', svgstr: logo_svg }); const logo_icon = new LabIcon({ name: 'ui-components:sandbox', svgstr: logo_svg });
@ -30,17 +32,14 @@ const plugin: JupyterFrontEndPlugin<void> = {
}); });
logo.id = 'jp-sandboxLogo'; logo.id = 'jp-sandboxLogo';
shell.add(logo, 'top', { rank: 0 }); shell.add(logo, 'top', { rank: 0 });
// Set the icons elsewhere // Set the icons elsewhere
jupyterFaviconIcon.svgstr = logo_svg; jupyterFaviconIcon.svgstr = logo_svg;
jupyterIcon.svgstr = logo_svg; jupyterIcon.svgstr = logo_svg;
jupyterlabWordmarkIcon.svgstr = logo_svg; jupyterlabWordmarkIcon.svgstr = logo_svg;
// Register the plugin
manager.register({ manager.register({
name: 'Sandbox', name: 'sandbox_theme',
isLight: true, isLight: true,
themeScrollbars: true,
load: () => manager.loadCSS(style), load: () => manager.loadCSS(style),
unload: () => Promise.resolve(undefined) unload: () => Promise.resolve(undefined)
}); });
@ -53,20 +52,14 @@ const plugin: JupyterFrontEndPlugin<void> = {
waitForElement('.busy',document.head).then((elm: any) => { waitForElement('.busy',document.head).then((elm: any) => {
elm.setAttribute("href",busy) elm.setAttribute("href",busy)
}); });
// waitForElement('title',document.head).then((elm: any) => {
// elm.innerHTML = "Sandbox"
// });
waitForElement('#jupyterlab-splash',document.body).then((elm: any) => { waitForElement('#jupyterlab-splash',document.body).then((elm: any) => {
let child = elm.firstChild let child = elm.firstChild
child.innerHTML = ' <div class="cube"> <div class="cube1"></div> <div class="cube2"></div></div>'; child.innerHTML = ' <div class="cube"> <div class="cube1"></div> <div class="cube2"></div></div>';
child.classList.add("spinner") child.classList.add("spinner")
}); });
}
},
autoStart: true
}; };
function waitForElement(selector: any, documentArea: any) { function waitForElement(selector: any, documentArea: any) {
return new Promise(resolve => { return new Promise(resolve => {
if (document.querySelector(selector)) { if (document.querySelector(selector)) {
@ -86,8 +79,4 @@ function waitForElement(selector: any, documentArea: any) {
}); });
}); });
} }
export default plugin; export default plugin;

View File

@ -1,4 +1,4 @@
@import './variables.css'; @import url('./variables.css');
/* Set the default typography for monospace elements */ /* Set the default typography for monospace elements */
tt, tt,

View File

@ -17,8 +17,7 @@
"rootDir": "src", "rootDir": "src",
"strict": true, "strict": true,
"strictNullChecks": true, "strictNullChecks": true,
"target": "es2017", "target": "ES2018"
"types": ["jest"]
}, },
"include": ["src/*"] "include": ["src/*"]
} }

View File

@ -1,148 +0,0 @@
# Integration Testing
This folder contains the integration tests of the extension.
They are defined using [Playwright](https://playwright.dev/docs/intro) test runner
and [Galata](https://github.com/jupyterlab/jupyterlab/tree/master/galata) helper.
The Playwright configuration is defined in [playwright.config.js](./playwright.config.js).
The JupyterLab server configuration to use for the integration test is defined
in [jupyter_server_test_config.py](./jupyter_server_test_config.py).
The default configuration will produce video for failing tests and an HTML report.
## Run the tests
> All commands are assumed to be executed from the root directory
To run the tests, you need to:
1. Compile the extension:
```sh
jlpm install
jlpm build:prod
```
> Check the extension is installed in JupyterLab.
2. Install test dependencies (needed only once):
```sh
cd ./ui-tests
jlpm install
jlpm playwright install
cd ..
```
3. Execute the [Playwright](https://playwright.dev/docs/intro) tests:
```sh
cd ./ui-tests
jlpm playwright test
```
Test results will be shown in the terminal. In case of any test failures, the test report
will be opened in your browser at the end of the tests execution; see
[Playwright documentation](https://playwright.dev/docs/test-reporters#html-reporter)
for configuring that behavior.
## Update the tests snapshots
> All commands are assumed to be executed from the root directory
If you are comparing snapshots to validate your tests, you may need to update
the reference snapshots stored in the repository. To do that, you need to:
1. Compile the extension:
```sh
jlpm install
jlpm build:prod
```
> Check the extension is installed in JupyterLab.
2. Install test dependencies (needed only once):
```sh
cd ./ui-tests
jlpm install
jlpm playwright install
cd ..
```
3. Execute the [Playwright](https://playwright.dev/docs/intro) command:
```sh
cd ./ui-tests
jlpm playwright test -u
```
> Some discrepancy may occurs between the snapshots generated on your computer and
> the one generated on the CI. To ease updating the snapshots on a PR, you can
> type `please update playwright snapshots` to trigger the update by a bot on the CI.
> Once the bot has computed new snapshots, it will commit them to the PR branch.
## Create tests
> All commands are assumed to be executed from the root directory
To create tests, the easiest way is to use the code generator tool of playwright:
1. Compile the extension:
```sh
jlpm install
jlpm build:prod
```
> Check the extension is installed in JupyterLab.
2. Install test dependencies (needed only once):
```sh
cd ./ui-tests
jlpm install
jlpm playwright install
cd ..
```
3. Execute the [Playwright code generator](https://playwright.dev/docs/codegen):
```sh
cd ./ui-tests
jlpm playwright codegen localhost:8888
```
## Debug tests
> All commands are assumed to be executed from the root directory
To debug tests, a good way is to use the inspector tool of playwright:
1. Compile the extension:
```sh
jlpm install
jlpm build:prod
```
> Check the extension is installed in JupyterLab.
2. Install test dependencies (needed only once):
```sh
cd ./ui-tests
jlpm install
jlpm playwright install
cd ..
```
3. Execute the Playwright tests in [debug mode](https://playwright.dev/docs/debug):
```sh
cd ./ui-tests
PWDEBUG=1 jlpm playwright test
```

View File

@ -1,20 +0,0 @@
"""Server configuration for integration tests.
!! Never use this configuration in production because it
opens the server to the world and provide access to JupyterLab
JavaScript objects through the global window variable.
"""
from tempfile import mkdtemp
c.ServerApp.port = 8888
c.ServerApp.port_retries = 0
c.ServerApp.open_browser = False
c.ServerApp.root_dir = mkdtemp(prefix='galata-test-')
c.ServerApp.token = ""
c.ServerApp.password = ""
c.ServerApp.disable_check_xsrf = True
c.LabApp.expose_app_in_browser = True
# Uncomment to set server log level to debug level
# c.ServerApp.log_level = "DEBUG"

View File

@ -1,14 +0,0 @@
{
"name": "jupyterlab_sandbox_theme-ui-tests",
"version": "1.0.0",
"description": "JupyterLab jupyterlab_sandbox_theme Integration Tests",
"private": true,
"scripts": {
"start": "jupyter lab --config jupyter_server_test_config.py",
"test": "jlpm playwright test",
"test:update": "jlpm playwright test --update-snapshots"
},
"devDependencies": {
"@jupyterlab/galata": "^4.3.0"
}
}

View File

@ -1,14 +0,0 @@
/**
* Configuration for Playwright using default from @jupyterlab/galata
*/
const baseConfig = require('@jupyterlab/galata/lib/playwright-config');
module.exports = {
...baseConfig,
webServer: {
command: 'jlpm start',
url: 'http://localhost:8888/lab',
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI
}
};

View File

@ -1,21 +0,0 @@
import { expect, test } from '@jupyterlab/galata';
/**
* Don't load JupyterLab webpage before running the tests.
* This is required to ensure we capture all log messages.
*/
test.use({ autoGoto: false });
test('should emit an activation console message', async ({ page }) => {
const logs: string[] = [];
page.on('console', message => {
logs.push(message.text());
});
await page.goto();
expect(
logs.filter(s => s === 'JupyterLab extension jupyterlab_sandbox_theme is activated!')
).toHaveLength(1);
});

15436
yarn.lock

File diff suppressed because it is too large Load Diff