├── .yarnrc.yml
├── style
├── index.js
├── index.css
├── base.css
└── js.svg
├── setup.py
├── src
├── svg.d.ts
├── logLevelSwitcher.tsx
└── index.ts
├── .prettierignore
├── install.json
├── .github
└── workflows
│ ├── binder-on-pr.yml
│ ├── enforce-label.yml
│ ├── check-release.yml
│ ├── deploy.yml
│ ├── prep-release.yml
│ ├── publish-release.yml
│ └── build.yml
├── .copier-answers.yml
├── binder
├── environment.yml
└── postBuild
├── tsconfig.json
├── jupyterlab_js_logs
└── __init__.py
├── LICENSE
├── .gitignore
├── pyproject.toml
├── RELEASE.md
├── README.md
├── CHANGELOG.md
└── package.json
/.yarnrc.yml:
--------------------------------------------------------------------------------
1 | nodeLinker: node-modules
2 |
--------------------------------------------------------------------------------
/style/index.js:
--------------------------------------------------------------------------------
1 | import './base.css';
2 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | __import__("setuptools").setup()
2 |
--------------------------------------------------------------------------------
/style/index.css:
--------------------------------------------------------------------------------
1 | @import url('base.css');
2 |
--------------------------------------------------------------------------------
/src/svg.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.svg' {
2 | const value: string;
3 | export default value;
4 | }
5 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | **/node_modules
3 | **/lib
4 | **/package.json
5 | !/package.json
6 | jupyterlab_js_logs
7 |
--------------------------------------------------------------------------------
/style/base.css:
--------------------------------------------------------------------------------
1 | /*
2 | See the JupyterLab Developer Guide for useful CSS Patterns:
3 |
4 | https://jupyterlab.readthedocs.io/en/stable/developer/css.html
5 | */
6 |
--------------------------------------------------------------------------------
/install.json:
--------------------------------------------------------------------------------
1 | {
2 | "packageManager": "python",
3 | "packageName": "jupyterlab_js_logs",
4 | "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package jupyterlab-js-logs"
5 | }
6 |
--------------------------------------------------------------------------------
/.github/workflows/binder-on-pr.yml:
--------------------------------------------------------------------------------
1 | name: Binder Badge
2 | on:
3 | pull_request_target:
4 | types: [opened]
5 |
6 | jobs:
7 | binder:
8 | runs-on: ubuntu-latest
9 | permissions:
10 | pull-requests: write
11 | steps:
12 | - uses: jupyterlab/maintainer-tools/.github/actions/binder-link@v1
13 | with:
14 | github_token: ${{ secrets.GITHUB_TOKEN }}
15 |
--------------------------------------------------------------------------------
/.github/workflows/enforce-label.yml:
--------------------------------------------------------------------------------
1 | name: Enforce PR label
2 |
3 | on:
4 | pull_request:
5 | types: [labeled, unlabeled, opened, edited, synchronize]
6 | jobs:
7 | enforce-label:
8 | runs-on: ubuntu-latest
9 | permissions:
10 | pull-requests: write
11 | steps:
12 | - name: enforce-triage-label
13 | uses: jupyterlab/maintainer-tools/.github/actions/enforce-label@v1
14 |
--------------------------------------------------------------------------------
/.copier-answers.yml:
--------------------------------------------------------------------------------
1 | # Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
2 | _commit: v4.3.5
3 | _src_path: https://github.com/jupyterlab/extension-template
4 | author_email: ''
5 | author_name: jupyterlab-js-logs contributors
6 | has_binder: true
7 | has_settings: false
8 | kind: frontend
9 | labextension_name: jupyterlab-js-logs
10 | project_short_description: JupyterLab extension to show the js logs from the browser
11 | dev tools console
12 | python_name: jupyterlab_js_logs
13 | repository: https://github.com/jupyterlab-contrib/jupyterlab-js-logs.git
14 | test: false
15 |
16 |
--------------------------------------------------------------------------------
/binder/environment.yml:
--------------------------------------------------------------------------------
1 | # a mybinder.org-ready environment for demoing jupyterlab_js_logs
2 | # this environment may also be used locally on Linux/MacOS/Windows, e.g.
3 | #
4 | # conda env update --file binder/environment.yml
5 | # conda activate jupyterlab-js-logs-demo
6 | #
7 | name: jupyterlab-js-logs-demo
8 |
9 | channels:
10 | - conda-forge
11 |
12 | dependencies:
13 | # runtime dependencies
14 | - python >=3.10,<3.11.0a0
15 | - jupyterlab >=4.0.0,<5
16 | # labextension build dependencies
17 | - nodejs >=18,<19
18 | - pip
19 | - wheel
20 | # additional packages for demos
21 | # - ipywidgets
22 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "composite": true,
5 | "declaration": true,
6 | "esModuleInterop": true,
7 | "incremental": true,
8 | "jsx": "react",
9 | "module": "esnext",
10 | "moduleResolution": "node",
11 | "noEmitOnError": true,
12 | "noImplicitAny": true,
13 | "noUnusedLocals": true,
14 | "preserveWatchOutput": true,
15 | "resolveJsonModule": true,
16 | "outDir": "lib",
17 | "rootDir": "src",
18 | "strict": true,
19 | "strictNullChecks": true,
20 | "target": "ES2018"
21 | },
22 | "include": ["src/*"]
23 | }
24 |
--------------------------------------------------------------------------------
/jupyterlab_js_logs/__init__.py:
--------------------------------------------------------------------------------
1 | try:
2 | from ._version import __version__
3 | except ImportError:
4 | # Fallback when using the package in dev mode without installing
5 | # in editable mode with pip. It is highly recommended to install
6 | # the package from a stable release or in editable mode: https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs
7 | import warnings
8 | warnings.warn("Importing 'jupyterlab_js_logs' outside a proper installation.")
9 | __version__ = "dev"
10 |
11 |
12 | def _jupyter_labextension_paths():
13 | return [{
14 | "src": "labextension",
15 | "dest": "jupyterlab-js-logs"
16 | }]
17 |
--------------------------------------------------------------------------------
/style/js.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/workflows/check-release.yml:
--------------------------------------------------------------------------------
1 | name: Check Release
2 | on:
3 | push:
4 | branches: ["main"]
5 | pull_request:
6 | branches: ["*"]
7 |
8 | concurrency:
9 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
10 | cancel-in-progress: true
11 |
12 | jobs:
13 | check_release:
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Checkout
17 | uses: actions/checkout@v4
18 | - name: Base Setup
19 | uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
20 | - name: Check Release
21 | uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2
22 | with:
23 |
24 | token: ${{ secrets.GITHUB_TOKEN }}
25 |
26 | - name: Upload Distributions
27 | uses: actions/upload-artifact@v4
28 | with:
29 | name: jupyterlab_js_logs-releaser-dist-${{ github.run_number }}
30 | path: .jupyter_releaser_checkout/dist
31 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Build and Deploy
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - '*'
10 |
11 | jobs:
12 | build:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Checkout
16 | uses: actions/checkout@v4
17 | - name: Setup Python
18 | uses: actions/setup-python@v5
19 | with:
20 | python-version: '3.11'
21 | - name: Install the dependencies
22 | run: |
23 | python -m pip install jupyterlite-core jupyterlite-pyodide-kernel .
24 | - name: Build the JupyterLite site
25 | run: |
26 | jupyter lite build --output-dir dist
27 | - name: Upload artifact
28 | uses: actions/upload-pages-artifact@v3
29 | with:
30 | path: ./dist
31 |
32 | deploy:
33 | needs: build
34 | if: github.ref == 'refs/heads/main'
35 | permissions:
36 | pages: write
37 | id-token: write
38 |
39 | environment:
40 | name: github-pages
41 | url: ${{ steps.deployment.outputs.page_url }}
42 |
43 | runs-on: ubuntu-latest
44 | steps:
45 | - name: Deploy to GitHub Pages
46 | id: deployment
47 | uses: actions/deploy-pages@v4
48 |
--------------------------------------------------------------------------------
/binder/postBuild:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """ perform a development install of jupyterlab_js_logs
3 |
4 | On Binder, this will run _after_ the environment has been fully created from
5 | the environment.yml in this directory.
6 |
7 | This script should also run locally on Linux/MacOS/Windows:
8 |
9 | python3 binder/postBuild
10 | """
11 | import subprocess
12 | import sys
13 | from pathlib import Path
14 |
15 |
16 | ROOT = Path.cwd()
17 |
18 | def _(*args, **kwargs):
19 | """ Run a command, echoing the args
20 |
21 | fails hard if something goes wrong
22 | """
23 | print("\n\t", " ".join(args), "\n")
24 | return_code = subprocess.call(args, **kwargs)
25 | if return_code != 0:
26 | print("\nERROR", return_code, " ".join(args))
27 | sys.exit(return_code)
28 |
29 | # verify the environment is self-consistent before even starting
30 | _(sys.executable, "-m", "pip", "check")
31 |
32 | # install the labextension
33 | _(sys.executable, "-m", "pip", "install", "-e", ".")
34 | _(sys.executable, "-m", "jupyter", "labextension", "develop", "--overwrite", ".")
35 |
36 | # verify the environment the extension didn't break anything
37 | _(sys.executable, "-m", "pip", "check")
38 |
39 | # list the extensions
40 | _("jupyter", "server", "extension", "list")
41 |
42 | # initially list installed extensions to determine if there are any surprises
43 | _("jupyter", "labextension", "list")
44 |
45 |
46 | print("JupyterLab with jupyterlab_js_logs is ready to run with:\n")
47 | print("\tjupyter lab\n")
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2020, jupyterlab-js-logs contributors All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | * Neither the name of the copyright holder nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/.github/workflows/prep-release.yml:
--------------------------------------------------------------------------------
1 | name: "Step 1: Prep Release"
2 | on:
3 | workflow_dispatch:
4 | inputs:
5 | version_spec:
6 | description: "New Version Specifier"
7 | default: "next"
8 | required: false
9 | branch:
10 | description: "The branch to target"
11 | required: false
12 | post_version_spec:
13 | description: "Post Version Specifier"
14 | required: false
15 | # silent:
16 | # description: "Set a placeholder in the changelog and don't publish the release."
17 | # required: false
18 | # type: boolean
19 | since:
20 | description: "Use PRs with activity since this date or git reference"
21 | required: false
22 | since_last_stable:
23 | description: "Use PRs with activity since the last stable git tag"
24 | required: false
25 | type: boolean
26 | jobs:
27 | prep_release:
28 | runs-on: ubuntu-latest
29 | permissions:
30 | contents: write
31 | steps:
32 | - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
33 |
34 | - name: Prep Release
35 | id: prep-release
36 | uses: jupyter-server/jupyter_releaser/.github/actions/prep-release@v2
37 | with:
38 | token: ${{ secrets.GITHUB_TOKEN }}
39 | version_spec: ${{ github.event.inputs.version_spec }}
40 | # silent: ${{ github.event.inputs.silent }}
41 | post_version_spec: ${{ github.event.inputs.post_version_spec }}
42 | branch: ${{ github.event.inputs.branch }}
43 | since: ${{ github.event.inputs.since }}
44 | since_last_stable: ${{ github.event.inputs.since_last_stable }}
45 |
46 | - name: "** Next Step **"
47 | run: |
48 | echo "Optional): Review Draft Release: ${{ steps.prep-release.outputs.release_url }}"
49 |
--------------------------------------------------------------------------------
/.github/workflows/publish-release.yml:
--------------------------------------------------------------------------------
1 | name: "Step 2: Publish Release"
2 | on:
3 | workflow_dispatch:
4 | inputs:
5 | branch:
6 | description: "The target branch"
7 | required: false
8 | release_url:
9 | description: "The URL of the draft GitHub release"
10 | required: false
11 | steps_to_skip:
12 | description: "Comma separated list of steps to skip"
13 | required: false
14 |
15 | jobs:
16 | publish_release:
17 | runs-on: ubuntu-latest
18 | environment: release
19 | permissions:
20 | id-token: write
21 | steps:
22 | - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
23 |
24 | - uses: actions/create-github-app-token@v1
25 | id: app-token
26 | with:
27 | app-id: ${{ vars.APP_ID }}
28 | private-key: ${{ secrets.APP_PRIVATE_KEY }}
29 |
30 | - name: Populate Release
31 | id: populate-release
32 | uses: jupyter-server/jupyter_releaser/.github/actions/populate-release@v2
33 | with:
34 | token: ${{ steps.app-token.outputs.token }}
35 | branch: ${{ github.event.inputs.branch }}
36 | release_url: ${{ github.event.inputs.release_url }}
37 | steps_to_skip: ${{ github.event.inputs.steps_to_skip }}
38 |
39 | - name: Finalize Release
40 | id: finalize-release
41 | env:
42 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
43 | uses: jupyter-server/jupyter_releaser/.github/actions/finalize-release@v2
44 | with:
45 | token: ${{ steps.app-token.outputs.token }}
46 | release_url: ${{ steps.populate-release.outputs.release_url }}
47 |
48 | - name: "** Next Step **"
49 | if: ${{ success() }}
50 | run: |
51 | echo "Verify the final release"
52 | echo ${{ steps.finalize-release.outputs.release_url }}
53 |
54 | - name: "** Failure Message **"
55 | if: ${{ failure() }}
56 | run: |
57 | echo "Failed to Publish the Draft Release Url:"
58 | echo ${{ steps.populate-release.outputs.release_url }}
59 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.bundle.*
2 | lib/
3 | node_modules/
4 | *.log
5 | .eslintcache
6 | .stylelintcache
7 | *.egg-info/
8 | .ipynb_checkpoints
9 | *.tsbuildinfo
10 | jupyterlab_js_logs/labextension
11 | # Version file is handled by hatchling
12 | jupyterlab_js_logs/_version.py
13 |
14 | # Created by https://www.gitignore.io/api/python
15 | # Edit at https://www.gitignore.io/?templates=python
16 |
17 | ### Python ###
18 | # Byte-compiled / optimized / DLL files
19 | __pycache__/
20 | *.py[cod]
21 | *$py.class
22 |
23 | # C extensions
24 | *.so
25 |
26 | # Distribution / packaging
27 | .Python
28 | build/
29 | develop-eggs/
30 | dist/
31 | downloads/
32 | eggs/
33 | .eggs/
34 | lib/
35 | lib64/
36 | parts/
37 | sdist/
38 | var/
39 | wheels/
40 | pip-wheel-metadata/
41 | share/python-wheels/
42 | .installed.cfg
43 | *.egg
44 | MANIFEST
45 |
46 | # PyInstaller
47 | # Usually these files are written by a python script from a template
48 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
49 | *.manifest
50 | *.spec
51 |
52 | # Installer logs
53 | pip-log.txt
54 | pip-delete-this-directory.txt
55 |
56 | # Unit test / coverage reports
57 | htmlcov/
58 | .tox/
59 | .nox/
60 | .coverage
61 | .coverage.*
62 | .cache
63 | nosetests.xml
64 | coverage/
65 | coverage.xml
66 | *.cover
67 | .hypothesis/
68 | .pytest_cache/
69 |
70 | # Translations
71 | *.mo
72 | *.pot
73 |
74 | # Scrapy stuff:
75 | .scrapy
76 |
77 | # Sphinx documentation
78 | docs/_build/
79 |
80 | # PyBuilder
81 | target/
82 |
83 | # pyenv
84 | .python-version
85 |
86 | # celery beat schedule file
87 | celerybeat-schedule
88 |
89 | # SageMath parsed files
90 | *.sage.py
91 |
92 | # Spyder project settings
93 | .spyderproject
94 | .spyproject
95 |
96 | # Rope project settings
97 | .ropeproject
98 |
99 | # Mr Developer
100 | .mr.developer.cfg
101 | .project
102 | .pydevproject
103 |
104 | # mkdocs documentation
105 | /site
106 |
107 | # mypy
108 | .mypy_cache/
109 | .dmypy.json
110 | dmypy.json
111 |
112 | # Pyre type checker
113 | .pyre/
114 |
115 | # End of https://www.gitignore.io/api/python
116 |
117 | # OSX files
118 | .DS_Store
119 |
120 | # Yarn cache
121 | .yarn/
122 |
123 | # Upgrade script
124 | _temp_extension
125 |
126 | # Jupyter
127 | Untitled*.ipynb
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches: main
6 | pull_request:
7 | branches: '*'
8 |
9 | concurrency:
10 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
11 | cancel-in-progress: true
12 |
13 | jobs:
14 | build:
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - name: Checkout
19 | uses: actions/checkout@v4
20 |
21 | - name: Base Setup
22 | uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
23 |
24 | - name: Install dependencies
25 | run: python -m pip install -U "jupyterlab>=4.0.0,<5"
26 |
27 | - name: Lint the extension
28 | run: |
29 | set -eux
30 | jlpm
31 | jlpm run lint:check
32 |
33 | - name: Build the extension
34 | run: |
35 | set -eux
36 | python -m pip install .[test]
37 |
38 | jupyter labextension list
39 | jupyter labextension list 2>&1 | grep -ie "jupyterlab-js-logs.*OK"
40 | python -m jupyterlab.browser_check
41 |
42 | - name: Package the extension
43 | run: |
44 | set -eux
45 |
46 | pip install build
47 | python -m build
48 | pip uninstall -y "jupyterlab_js_logs" jupyterlab
49 |
50 | - name: Upload extension packages
51 | uses: actions/upload-artifact@v4
52 | with:
53 | name: extension-artifacts
54 | path: dist/jupyterlab_js_logs*
55 | if-no-files-found: error
56 |
57 | test_isolated:
58 | needs: build
59 | runs-on: ubuntu-latest
60 |
61 | steps:
62 | - name: Install Python
63 | uses: actions/setup-python@v5
64 | with:
65 | python-version: '3.9'
66 | architecture: 'x64'
67 | - uses: actions/download-artifact@v4
68 | with:
69 | name: extension-artifacts
70 | - name: Install and Test
71 | run: |
72 | set -eux
73 | # Remove NodeJS, twice to take care of system and locally installed node versions.
74 | sudo rm -rf $(which node)
75 | sudo rm -rf $(which node)
76 |
77 | pip install "jupyterlab>=4.0.0,<5" jupyterlab_js_logs*.whl
78 |
79 |
80 | jupyter labextension list
81 | jupyter labextension list 2>&1 | grep -ie "jupyterlab-js-logs.*OK"
82 | python -m jupyterlab.browser_check --no-browser-test
83 |
84 |
85 | check_links:
86 | name: Check Links
87 | runs-on: ubuntu-latest
88 | timeout-minutes: 15
89 | steps:
90 | - uses: actions/checkout@v4
91 | - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
92 | - uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1
93 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["hatchling>=1.5.0", "jupyterlab>=4.0.0,<5", "hatch-nodejs-version>=0.3.2"]
3 | build-backend = "hatchling.build"
4 |
5 | [project]
6 | name = "jupyterlab_js_logs"
7 | readme = "README.md"
8 | license = { file = "LICENSE" }
9 | requires-python = ">=3.8"
10 | classifiers = [
11 | "Framework :: Jupyter",
12 | "Framework :: Jupyter :: JupyterLab",
13 | "Framework :: Jupyter :: JupyterLab :: 4",
14 | "Framework :: Jupyter :: JupyterLab :: Extensions",
15 | "Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt",
16 | "License :: OSI Approved :: BSD License",
17 | "Programming Language :: Python",
18 | "Programming Language :: Python :: 3",
19 | "Programming Language :: Python :: 3.8",
20 | "Programming Language :: Python :: 3.9",
21 | "Programming Language :: Python :: 3.10",
22 | "Programming Language :: Python :: 3.11",
23 | "Programming Language :: Python :: 3.12",
24 | ]
25 | dependencies = [
26 | ]
27 | dynamic = ["version", "description", "authors", "urls", "keywords"]
28 |
29 | [tool.hatch.version]
30 | source = "nodejs"
31 |
32 | [tool.hatch.metadata.hooks.nodejs]
33 | fields = ["description", "authors", "urls", "keywords"]
34 |
35 | [tool.hatch.build.targets.sdist]
36 | artifacts = ["jupyterlab_js_logs/labextension"]
37 | exclude = [".github", "binder"]
38 |
39 | [tool.hatch.build.targets.wheel.shared-data]
40 | "jupyterlab_js_logs/labextension" = "share/jupyter/labextensions/jupyterlab-js-logs"
41 | "install.json" = "share/jupyter/labextensions/jupyterlab-js-logs/install.json"
42 |
43 | [tool.hatch.build.hooks.version]
44 | path = "jupyterlab_js_logs/_version.py"
45 |
46 | [tool.hatch.build.hooks.jupyter-builder]
47 | dependencies = ["hatch-jupyter-builder>=0.5"]
48 | build-function = "hatch_jupyter_builder.npm_builder"
49 | ensured-targets = [
50 | "jupyterlab_js_logs/labextension/static/style.js",
51 | "jupyterlab_js_logs/labextension/package.json",
52 | ]
53 | skip-if-exists = ["jupyterlab_js_logs/labextension/static/style.js"]
54 |
55 | [tool.hatch.build.hooks.jupyter-builder.build-kwargs]
56 | build_cmd = "build:prod"
57 | npm = ["jlpm"]
58 |
59 | [tool.hatch.build.hooks.jupyter-builder.editable-build-kwargs]
60 | build_cmd = "install:extension"
61 | npm = ["jlpm"]
62 | source_dir = "src"
63 | build_dir = "jupyterlab_js_logs/labextension"
64 |
65 | [tool.jupyter-releaser.options]
66 | version_cmd = "hatch version"
67 |
68 | [tool.jupyter-releaser.hooks]
69 | before-build-npm = [
70 | "python -m pip install 'jupyterlab>=4.0.0,<5'",
71 | "jlpm",
72 | "jlpm build:prod"
73 | ]
74 | before-build-python = ["jlpm clean:all"]
75 |
76 | [tool.check-wheel-contents]
77 | ignore = ["W002"]
78 |
--------------------------------------------------------------------------------
/RELEASE.md:
--------------------------------------------------------------------------------
1 | # Making a new release of jupyterlab_js_logs
2 |
3 | The extension can be published to `PyPI` and `npm` manually or using the [Jupyter Releaser](https://github.com/jupyter-server/jupyter_releaser).
4 |
5 | ## Manual release
6 |
7 | ### Python package
8 |
9 | This extension can be distributed as Python packages. All of the Python
10 | packaging instructions are in the `pyproject.toml` file to wrap your extension in a
11 | Python package. Before generating a package, you first need to install some tools:
12 |
13 | ```bash
14 | pip install build twine hatch
15 | ```
16 |
17 | Bump the version using `hatch`. By default this will create a tag.
18 | See the docs on [hatch-nodejs-version](https://github.com/agoose77/hatch-nodejs-version#semver) for details.
19 |
20 | ```bash
21 | hatch version
22 | ```
23 |
24 | Make sure to clean up all the development files before building the package:
25 |
26 | ```bash
27 | jlpm clean:all
28 | ```
29 |
30 | You could also clean up the local git repository:
31 |
32 | ```bash
33 | git clean -dfX
34 | ```
35 |
36 | To create a Python source package (`.tar.gz`) and the binary package (`.whl`) in the `dist/` directory, do:
37 |
38 | ```bash
39 | python -m build
40 | ```
41 |
42 | > `python setup.py sdist bdist_wheel` is deprecated and will not work for this package.
43 |
44 | Then to upload the package to PyPI, do:
45 |
46 | ```bash
47 | twine upload dist/*
48 | ```
49 |
50 | ### NPM package
51 |
52 | To publish the frontend part of the extension as a NPM package, do:
53 |
54 | ```bash
55 | npm login
56 | npm publish --access public
57 | ```
58 |
59 | ## Automated releases with the Jupyter Releaser
60 |
61 | The extension repository should already be compatible with the Jupyter Releaser. But
62 | the GitHub repository and the package managers need to be properly set up. Please
63 | follow the instructions of the Jupyter Releaser [checklist](https://jupyter-releaser.readthedocs.io/en/latest/how_to_guides/convert_repo_from_repo.html).
64 |
65 | Here is a summary of the steps to cut a new release:
66 |
67 | - Go to the Actions panel
68 | - Run the "Step 1: Prep Release" workflow
69 | - Check the draft changelog
70 | - Run the "Step 2: Publish Release" workflow
71 |
72 | > [!NOTE]
73 | > Check out the [workflow documentation](https://jupyter-releaser.readthedocs.io/en/latest/get_started/making_release_from_repo.html)
74 | > for more information.
75 |
76 | ## Publishing to `conda-forge`
77 |
78 | If the package is not on conda forge yet, check the documentation to learn how to add it: https://conda-forge.org/docs/maintainer/adding_pkgs.html
79 |
80 | Otherwise a bot should pick up the new version publish to PyPI, and open a new PR on the feedstock repository automatically.
81 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # jupyterlab-js-logs
2 |
3 | [](https://jupyterlab-contrib.github.io/)
4 | 
5 | [](https://jupyterlab-contrib.github.io/jupyterlab-js-logs)
6 | [](https://mybinder.org/v2/gh/jupyterlab-contrib/jupyterlab-js-logs/main?urlpath=lab)
7 |
8 | JupyterLab extension to show the console logs from the browser dev tools console.
9 |
10 | https://github.com/user-attachments/assets/8d907bf6-8363-4b67-8431-22fca19f7d1e
11 |
12 | ## Requirements
13 |
14 | - JupyterLab >= 2.0
15 |
16 | ## Motivation
17 |
18 | The main purpose for this extension is to provide a way to surface the console logs from the browser dev tools console in the JupyterLab interface.
19 | Especially for users that are not familiar with the browser dev tools, this extension can be very useful to debug and understand the logs generated by the JavaScript code running in the browser.
20 |
21 | ## Install
22 |
23 | ```bash
24 | jupyter labextension install jupyterlab-js-logs
25 | ```
26 |
27 | ## Contributing
28 |
29 | This extension was bootstrapped from the [custom-log-console](https://github.com/jupyterlab/extension-examples/tree/master/custom-log-console) example contributed by [Carlos Herrero](https://github.com/hbcarlos), from the [`jupyterlab-extension-examples`](https://github.com/jupyterlab/extension-examples) repository.
30 |
31 | ### Install
32 |
33 | The `jlpm` command is JupyterLab's pinned version of
34 | [yarn](https://yarnpkg.com/) that is installed with JupyterLab. You may use
35 | `yarn` or `npm` in lieu of `jlpm` below.
36 |
37 | ```bash
38 | # Clone the repo to your local environment
39 | # Move to jupyterlab-js-logs directory
40 |
41 | # Install dependencies
42 | jlpm
43 | # Build Typescript source
44 | jlpm build
45 | # Link your development version of the extension with JupyterLab
46 | jupyter labextension install .
47 | # Rebuild Typescript source after making changes
48 | jlpm build
49 | # Rebuild JupyterLab after making any changes
50 | jupyter lab build
51 | ```
52 |
53 | You can watch the source directory and run JupyterLab in watch mode to watch for changes in the extension's source and automatically rebuild the extension and application.
54 |
55 | ```bash
56 | # Watch the source directory in another terminal tab
57 | jlpm watch
58 | # Run jupyterlab in watch mode in one terminal tab
59 | jupyter lab --watch
60 | ```
61 |
62 | Now every change will be built locally and bundled into JupyterLab. Be sure to refresh your browser page after saving file changes to reload the extension (note: you'll need to wait for webpack to finish, which can take 10s+ at times).
63 |
64 | ### Uninstall
65 |
66 | ```bash
67 |
68 | jupyter labextension uninstall jupyterlab-js-logs
69 | ```
70 |
--------------------------------------------------------------------------------
/src/logLevelSwitcher.tsx:
--------------------------------------------------------------------------------
1 | import { ReactWidget } from '@jupyterlab/apputils';
2 |
3 | import { LogConsolePanel, LogLevel } from '@jupyterlab/logconsole';
4 |
5 | import { HTMLSelect } from '@jupyterlab/ui-components';
6 |
7 | import { IChangedArgs } from '@jupyterlab/coreutils';
8 |
9 | import { UUID } from '@lumino/coreutils';
10 |
11 | import React from 'react';
12 |
13 | /**
14 | * A toolbar widget that switches log levels.
15 | */
16 | export default class LogLevelSwitcher extends ReactWidget {
17 | /**
18 | * Construct a new cell type switcher.
19 | *
20 | * @param widget The log console panel
21 | */
22 | constructor(widget: LogConsolePanel) {
23 | super();
24 | this.addClass('jp-LogConsole-toolbarLogLevel');
25 | this._logConsole = widget;
26 | if (this._logConsole.logger) {
27 | this._logConsole.logger.level = 'debug';
28 | }
29 | if (widget.source) {
30 | this.update();
31 | }
32 | widget.sourceChanged.connect(this._updateSource, this);
33 | }
34 |
35 | private _updateSource(
36 | sender: LogConsolePanel,
37 | { oldValue, newValue }: IChangedArgs
38 | ): void {
39 | // Transfer stateChanged handler to new source logger
40 | if (oldValue !== null) {
41 | const logger = sender.loggerRegistry.getLogger(oldValue);
42 | logger.stateChanged.disconnect(this.update, this);
43 | }
44 | if (newValue !== null) {
45 | const logger = sender.loggerRegistry.getLogger(newValue);
46 | logger.stateChanged.connect(this.update, this);
47 | }
48 | this.update();
49 | }
50 |
51 | /**
52 | * Handle `change` events for the HTMLSelect component.
53 | *
54 | * @param event The HTML select event.
55 | */
56 | handleChange = (event: React.ChangeEvent): void => {
57 | if (this._logConsole.logger) {
58 | this._logConsole.logger.level = event.target.value as LogLevel;
59 | }
60 | this.update();
61 | };
62 |
63 | /**
64 | * Handle `keydown` events for the HTMLSelect component.
65 | *
66 | * @param event The keyboard event.
67 | */
68 | handleKeyDown = (event: React.KeyboardEvent): void => {
69 | if (event.keyCode === 13) {
70 | this._logConsole.activate();
71 | }
72 | };
73 |
74 | render(): JSX.Element {
75 | const logger = this._logConsole.logger;
76 | return (
77 | <>
78 |
88 | ({ label, value: label.toLowerCase() })
101 | )
102 | }
103 | />
104 | >
105 | );
106 | }
107 | private _logConsole: LogConsolePanel;
108 | private _id = `level-${UUID.uuid4()}`;
109 | }
110 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 |
4 |
5 | ## 0.2.6
6 |
7 | ([Full Changelog](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/compare/v0.2.5...854af201b8186f50ce781096fc46ccec758adce0))
8 |
9 | ### Enhancements made
10 |
11 | - Improve Check Release workflow [#23](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/pull/23) ([@hbcarlos](https://github.com/hbcarlos))
12 |
13 | ### Bugs fixed
14 |
15 | - Remove prepare script and revert PR #20 [#24](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/pull/24) ([@hbcarlos](https://github.com/hbcarlos))
16 |
17 | ### Maintenance and upkeep improvements
18 |
19 | - Upload artifacts only on Check Release [#25](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/pull/25) ([@hbcarlos](https://github.com/hbcarlos))
20 | - Remove prepare script and revert PR #20 [#24](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/pull/24) ([@hbcarlos](https://github.com/hbcarlos))
21 | - Improve Check Release workflow [#23](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/pull/23) ([@hbcarlos](https://github.com/hbcarlos))
22 |
23 | ### Contributors to this release
24 |
25 | ([GitHub contributors page for this release](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/graphs/contributors?from=2022-01-21&to=2022-01-25&type=c))
26 |
27 | [@hbcarlos](https://github.com/search?q=repo%3AQuantStack%2Fjupyterlab-js-logs+involves%3Ahbcarlos+updated%3A2022-01-21..2022-01-25&type=Issues) | [@jtpio](https://github.com/search?q=repo%3AQuantStack%2Fjupyterlab-js-logs+involves%3Ajtpio+updated%3A2022-01-21..2022-01-25&type=Issues)
28 |
29 |
30 |
31 | ## 0.2.5
32 |
33 | ([Full Changelog](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/compare/v0.2.4...2b893318a9ee85a3c649fcb92f1ded9ba732a00d))
34 |
35 | ### Merged PRs
36 |
37 | - Build js in prod mode for the release [#20](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/pull/20) ([@hbcarlos](https://github.com/hbcarlos))
38 |
39 | ### Contributors to this release
40 |
41 | ([GitHub contributors page for this release](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/graphs/contributors?from=2021-09-15&to=2022-01-21&type=c))
42 |
43 | [@hbcarlos](https://github.com/search?q=repo%3AQuantStack%2Fjupyterlab-js-logs+involves%3Ahbcarlos+updated%3A2021-09-15..2022-01-21&type=Issues)
44 |
45 | ## 0.2.4
46 |
47 | ([Full Changelog](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/compare/v0.2.3...62cef996ed0c8434147907aa3a8bdb7bf6ffc9a6))
48 |
49 | ### Maintenance and upkeep improvements
50 |
51 | - Set name as jupyterlab-js-logs [#17](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/pull/17) ([@jtpio](https://github.com/jtpio))
52 |
53 | ### Documentation improvements
54 |
55 | - Update Binder link to point to the `main` branch [#16](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/pull/16) ([@jtpio](https://github.com/jtpio))
56 |
57 | ### Contributors to this release
58 |
59 | ([GitHub contributors page for this release](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/graphs/contributors?from=2021-09-14&to=2021-09-15&type=c))
60 |
61 | [@jtpio](https://github.com/search?q=repo%3AQuantStack%2Fjupyterlab-js-logs+involves%3Ajtpio+updated%3A2021-09-14..2021-09-15&type=Issues)
62 |
63 | ## 0.2.3
64 |
65 | ([Full Changelog](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/compare/0.2.2...14e59dc4e5d15a3a6246d8bb1967e18fddac9b10))
66 |
67 | ### Bugs fixed
68 |
69 | - Remove circular references when stringifying an object [#11](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/pull/11) ([@hbcarlos](https://github.com/hbcarlos))
70 |
71 | ### Maintenance and upkeep improvements
72 |
73 | - Add `publishConfig` to `package.json` [#13](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/pull/13) ([@jtpio](https://github.com/jtpio))
74 | - Add github action to check release [#12](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/pull/12) ([@hbcarlos](https://github.com/hbcarlos))
75 |
76 | ### Contributors to this release
77 |
78 | ([GitHub contributors page for this release](https://github.com/jupyterlab-contrib/jupyterlab-js-logs/graphs/contributors?from=2021-08-06&to=2021-09-14&type=c))
79 |
80 | [@hbcarlos](https://github.com/search?q=repo%3AQuantStack%2Fjupyterlab-js-logs+involves%3Ahbcarlos+updated%3A2021-08-06..2021-09-14&type=Issues) | [@jtpio](https://github.com/search?q=repo%3AQuantStack%2Fjupyterlab-js-logs+involves%3Ajtpio+updated%3A2021-08-06..2021-09-14&type=Issues)
81 |
82 | ## 0.2.2
83 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jupyterlab-js-logs",
3 | "version": "0.2.6",
4 | "description": "JupyterLab extension to show the js logs from the browser dev tools console",
5 | "keywords": [
6 | "jupyter",
7 | "jupyterlab",
8 | "jupyterlab-extension"
9 | ],
10 | "homepage": "https://github.com/jupyterlab-contrib/jupyterlab-js-logs",
11 | "bugs": {
12 | "url": "https://github.com/jupyterlab-contrib/jupyterlab-js-logs/issues"
13 | },
14 | "license": "BSD-3-Clause",
15 | "author": {
16 | "name": "JupyterLab Contrib Team",
17 | "email": ""
18 | },
19 | "files": [
20 | "lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
21 | "style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
22 | "style/index.js"
23 | ],
24 | "main": "lib/index.js",
25 | "types": "lib/index.d.ts",
26 | "style": "style/index.css",
27 | "styleModule": "style/index.js",
28 | "repository": {
29 | "type": "git",
30 | "url": "https://github.com/jupyterlab-contrib/jupyterlab-js-logs.git"
31 | },
32 | "scripts": {
33 | "build": "jlpm build:lib && jlpm build:labextension:dev",
34 | "build:labextension": "jupyter labextension build .",
35 | "build:labextension:dev": "jupyter labextension build --development True .",
36 | "build:lib": "tsc --sourceMap",
37 | "build:lib:prod": "tsc",
38 | "build:prod": "jlpm clean && jlpm build:lib:prod && jlpm build:labextension",
39 | "clean": "jlpm clean:lib",
40 | "clean:all": "jlpm clean:lib && jlpm clean:labextension && jlpm clean:lintcache",
41 | "clean:labextension": "rimraf jupyterlab_js_logs/labextension jupyterlab_js_logs/_version.py",
42 | "clean:lib": "rimraf lib tsconfig.tsbuildinfo",
43 | "clean:lintcache": "rimraf .eslintcache .stylelintcache",
44 | "eslint": "jlpm eslint:check --fix",
45 | "eslint:check": "eslint . --cache --ext .ts,.tsx",
46 | "install:extension": "jlpm build",
47 | "lint": "jlpm stylelint && jlpm prettier && jlpm eslint",
48 | "lint:check": "jlpm stylelint:check && jlpm prettier:check && jlpm eslint:check",
49 | "prettier": "jlpm prettier:base --write --list-different",
50 | "prettier:base": "prettier \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
51 | "prettier:check": "jlpm prettier:base --check",
52 | "stylelint": "jlpm stylelint:check --fix",
53 | "stylelint:check": "stylelint --cache \"style/**/*.css\"",
54 | "watch": "run-p watch:src watch:labextension",
55 | "watch:labextension": "jupyter labextension watch .",
56 | "watch:src": "tsc -w --sourceMap"
57 | },
58 | "dependencies": {
59 | "@jupyterlab/application": "^4.2.5",
60 | "@jupyterlab/apputils": "^4.3.5",
61 | "@jupyterlab/coreutils": "^6.2.5",
62 | "@jupyterlab/logconsole": "^4.2.5",
63 | "@jupyterlab/mainmenu": "^4.2.5",
64 | "@jupyterlab/nbformat": "^4.2.5",
65 | "@jupyterlab/rendermime": "^4.2.5",
66 | "@jupyterlab/ui-components": "^4.2.5",
67 | "@lumino/coreutils": "^2.2.0",
68 | "@lumino/widgets": "^2.5.0"
69 | },
70 | "devDependencies": {
71 | "@jupyterlab/builder": "^4.0.0",
72 | "@types/json-schema": "^7.0.11",
73 | "@types/react": "^18.0.26",
74 | "@types/react-addons-linked-state-mixin": "^0.14.22",
75 | "@typescript-eslint/eslint-plugin": "^6.1.0",
76 | "@typescript-eslint/parser": "^6.1.0",
77 | "css-loader": "^6.7.1",
78 | "eslint": "^8.36.0",
79 | "eslint-config-prettier": "^8.8.0",
80 | "eslint-plugin-prettier": "^5.0.0",
81 | "npm-run-all": "^4.1.5",
82 | "prettier": "^3.0.0",
83 | "rimraf": "^5.0.1",
84 | "source-map-loader": "^1.0.2",
85 | "style-loader": "^3.3.1",
86 | "stylelint": "^15.10.1",
87 | "stylelint-config-recommended": "^13.0.0",
88 | "stylelint-config-standard": "^34.0.0",
89 | "stylelint-csstree-validator": "^3.0.0",
90 | "stylelint-prettier": "^4.0.0",
91 | "typescript": "~5.0.2",
92 | "yjs": "^13.5.40"
93 | },
94 | "sideEffects": [
95 | "style/*.css",
96 | "style/index.js"
97 | ],
98 | "jupyterlab": {
99 | "extension": true,
100 | "outputDir": "jupyterlab_js_logs/labextension"
101 | },
102 | "publishConfig": {
103 | "access": "public"
104 | },
105 | "eslintConfig": {
106 | "extends": [
107 | "eslint:recommended",
108 | "plugin:@typescript-eslint/eslint-recommended",
109 | "plugin:@typescript-eslint/recommended",
110 | "plugin:prettier/recommended"
111 | ],
112 | "parser": "@typescript-eslint/parser",
113 | "parserOptions": {
114 | "project": "tsconfig.json",
115 | "sourceType": "module"
116 | },
117 | "plugins": [
118 | "@typescript-eslint"
119 | ],
120 | "rules": {
121 | "@typescript-eslint/naming-convention": [
122 | "error",
123 | {
124 | "selector": "interface",
125 | "format": [
126 | "PascalCase"
127 | ],
128 | "custom": {
129 | "regex": "^I[A-Z]",
130 | "match": true
131 | }
132 | }
133 | ],
134 | "@typescript-eslint/no-unused-vars": [
135 | "warn",
136 | {
137 | "args": "none"
138 | }
139 | ],
140 | "@typescript-eslint/no-explicit-any": "off",
141 | "@typescript-eslint/no-namespace": "off",
142 | "@typescript-eslint/no-use-before-define": "off",
143 | "@typescript-eslint/quotes": [
144 | "error",
145 | "single",
146 | {
147 | "avoidEscape": true,
148 | "allowTemplateLiterals": false
149 | }
150 | ],
151 | "curly": [
152 | "error",
153 | "all"
154 | ],
155 | "eqeqeq": "error",
156 | "prefer-arrow-callback": "error"
157 | }
158 | },
159 | "eslintIgnore": [
160 | "node_modules",
161 | "dist",
162 | "coverage",
163 | "**/*.d.ts"
164 | ],
165 | "prettier": {
166 | "singleQuote": true,
167 | "trailingComma": "none",
168 | "arrowParens": "avoid",
169 | "endOfLine": "auto",
170 | "overrides": [
171 | {
172 | "files": "package.json",
173 | "options": {
174 | "tabWidth": 4
175 | }
176 | }
177 | ]
178 | },
179 | "stylelint": {
180 | "extends": [
181 | "stylelint-config-recommended",
182 | "stylelint-config-standard",
183 | "stylelint-prettier/recommended"
184 | ],
185 | "plugins": [
186 | "stylelint-csstree-validator"
187 | ],
188 | "rules": {
189 | "csstree/validator": true,
190 | "property-no-vendor-prefix": null,
191 | "selector-class-pattern": "^([a-z][A-z\\d]*)(-[A-z\\d]+)*$",
192 | "selector-no-vendor-prefix": null,
193 | "value-no-vendor-prefix": null
194 | }
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | JupyterFrontEnd,
3 | JupyterFrontEndPlugin,
4 | ILayoutRestorer
5 | } from '@jupyterlab/application';
6 |
7 | import {
8 | ICommandPalette,
9 | MainAreaWidget,
10 | WidgetTracker,
11 | CommandToolbarButton
12 | } from '@jupyterlab/apputils';
13 |
14 | import { LoggerRegistry, LogConsolePanel } from '@jupyterlab/logconsole';
15 |
16 | import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
17 |
18 | import { addIcon, clearIcon, LabIcon } from '@jupyterlab/ui-components';
19 |
20 | import LogLevelSwitcher from './logLevelSwitcher';
21 |
22 | import jsIconStr from '../style/js.svg';
23 |
24 | /**
25 | * The command IDs used by the js-logs plugin.
26 | */
27 | export namespace CommandIDs {
28 | export const checkpoint = 'js-logs:checkpoint';
29 |
30 | export const clear = 'js-logs:clear';
31 |
32 | export const level = 'js-logs:level';
33 |
34 | export const open = 'js-logs:open';
35 | }
36 |
37 | /**
38 | * The main jupyterlab-js-logs plugin.
39 | */
40 | const extension: JupyterFrontEndPlugin = {
41 | id: 'js-logs',
42 | autoStart: true,
43 | requires: [IRenderMimeRegistry],
44 | optional: [ICommandPalette, ILayoutRestorer],
45 | activate: (
46 | app: JupyterFrontEnd,
47 | rendermime: IRenderMimeRegistry,
48 | palette: ICommandPalette | null,
49 | restorer: ILayoutRestorer | null
50 | ) => {
51 | const { commands } = app;
52 |
53 | let logConsolePanel: LogConsolePanel | null = null;
54 | let logConsoleWidget: MainAreaWidget | null = null;
55 |
56 | const tracker = new WidgetTracker>({
57 | namespace: 'jupyterlab-js-logs'
58 | });
59 |
60 | const jsIcon = new LabIcon({
61 | name: 'js-logs:js-icon',
62 | svgstr: jsIconStr
63 | });
64 |
65 | const createLogConsoleWidget = (): void => {
66 | logConsolePanel = new LogConsolePanel(
67 | new LoggerRegistry({
68 | defaultRendermime: rendermime,
69 | maxLength: 1000
70 | })
71 | );
72 |
73 | logConsolePanel.source = 'js-logs';
74 |
75 | logConsoleWidget = new MainAreaWidget({
76 | content: logConsolePanel
77 | });
78 | logConsoleWidget.addClass('jp-LogConsole');
79 | logConsoleWidget.title.label = 'Dev Tools Console Logs';
80 | logConsoleWidget.title.icon = jsIcon;
81 |
82 | logConsoleWidget.toolbar.addItem(
83 | 'checkpoint',
84 | new CommandToolbarButton({
85 | commands,
86 | id: CommandIDs.checkpoint
87 | })
88 | );
89 |
90 | logConsoleWidget.toolbar.addItem(
91 | 'clear',
92 | new CommandToolbarButton({
93 | commands,
94 | id: CommandIDs.clear
95 | })
96 | );
97 |
98 | logConsoleWidget.toolbar.addItem(
99 | 'level',
100 | new LogLevelSwitcher(logConsoleWidget.content)
101 | );
102 |
103 | logConsoleWidget.disposed.connect(() => {
104 | logConsoleWidget = null;
105 | logConsolePanel = null;
106 | commands.notifyCommandChanged();
107 | });
108 |
109 | app.shell.add(logConsoleWidget, 'main', { mode: 'split-bottom' });
110 | void tracker.add(logConsoleWidget);
111 |
112 | logConsoleWidget.update();
113 | commands.notifyCommandChanged();
114 | };
115 |
116 | commands.addCommand(CommandIDs.checkpoint, {
117 | execute: () => logConsolePanel?.logger?.checkpoint(),
118 | icon: addIcon,
119 | isEnabled: () => logConsolePanel?.source !== null,
120 | label: 'Add Checkpoint'
121 | });
122 |
123 | commands.addCommand(CommandIDs.clear, {
124 | execute: () => logConsolePanel?.logger?.clear(),
125 | icon: clearIcon,
126 | isEnabled: () => logConsolePanel?.source !== null,
127 | label: 'Clear Log'
128 | });
129 |
130 | commands.addCommand(CommandIDs.level, {
131 | execute: (args: any) => {
132 | if (logConsolePanel?.logger) {
133 | logConsolePanel.logger.level = args.level;
134 | }
135 | },
136 | isEnabled: () => logConsolePanel?.source !== null,
137 | label: args => `Set Log Level to ${args.level as string}`
138 | });
139 |
140 | commands.addCommand(CommandIDs.open, {
141 | label: 'Show Dev Tools Console Logs',
142 | caption: 'Show Dev Tools Console Logs',
143 | isToggled: () => logConsoleWidget !== null,
144 | execute: () => {
145 | if (logConsoleWidget) {
146 | logConsoleWidget.dispose();
147 | } else {
148 | createLogConsoleWidget();
149 | }
150 | }
151 | });
152 |
153 | window.onerror = (msg, url, lineNo, columnNo, error): boolean => {
154 | logConsolePanel?.logger?.log({
155 | type: 'text',
156 | level: 'critical',
157 | data: `${url}:${lineNo}:${columnNo} ${msg}\n${error}`
158 | });
159 | return false;
160 | };
161 |
162 | const _debug = console.debug;
163 | const _log = console.log;
164 | const _info = console.info;
165 | const _warn = console.warn;
166 | const _error = console.error;
167 |
168 | // const _exception = console.exception;
169 | const _trace = console.trace;
170 | const _table = console.table;
171 |
172 | // https://stackoverflow.com/a/11616993
173 | // We need to clear cache after each use.
174 | let cache: any = [];
175 | const refReplacer = (key: any, value: any) => {
176 | if (typeof value === 'object' && value !== null) {
177 | if (cache.indexOf(value) !== -1) {
178 | return;
179 | }
180 | cache.push(value);
181 | }
182 | return value;
183 | };
184 |
185 | const parseArgs = (args: any[]): string => {
186 | let data = '';
187 | args.forEach(arg => {
188 | try {
189 | if (arg instanceof Error) {
190 | data += arg.stack || arg.message || arg;
191 | } else {
192 | data +=
193 | (typeof arg === 'object' && arg !== null
194 | ? JSON.stringify(arg)
195 | : arg) + ' ';
196 | }
197 | } catch (e) {
198 | try {
199 | const msg =
200 | 'This error contains a object with a circular reference. Duplicated attributes might have been dropped during the process of removing the reference.\n';
201 | const obj = JSON.stringify(arg, refReplacer);
202 | cache = [];
203 | console.error(msg, obj);
204 | data += obj;
205 | } catch (e) {
206 | data += ' ';
207 | }
208 | }
209 | });
210 | return data;
211 | };
212 |
213 | window.console.debug = (...args: any[]): void => {
214 | logConsolePanel?.logger?.log({
215 | type: 'text',
216 | level: 'debug',
217 | data: parseArgs(args)
218 | });
219 | _debug(...args);
220 | };
221 |
222 | window.console.log = (...args: any[]): void => {
223 | logConsolePanel?.logger?.log({
224 | type: 'text',
225 | level: 'debug',
226 | data: parseArgs(args)
227 | });
228 | _log(...args);
229 | };
230 |
231 | window.console.info = (...args: any[]): void => {
232 | logConsolePanel?.logger?.log({
233 | type: 'text',
234 | level: 'info',
235 | data: parseArgs(args)
236 | });
237 | _info(...args);
238 | };
239 |
240 | window.console.warn = (...args: any[]): void => {
241 | logConsolePanel?.logger?.log({
242 | type: 'text',
243 | level: 'warning',
244 | data: parseArgs(args)
245 | });
246 | _warn(...args);
247 | };
248 |
249 | window.console.error = (...args: any[]): void => {
250 | logConsolePanel?.logger?.log({
251 | type: 'text',
252 | level: 'critical',
253 | data: parseArgs(args)
254 | });
255 | _error(...args);
256 | };
257 |
258 | // window.console.exception = (message?: string, ...args: any[]): void => {
259 | // logConsolePanel?.logger?.log({
260 | // type: 'text',
261 | // level: 'critical',
262 | // data: `Exception: ${message}\n${parseArgs(args)}`
263 | // });
264 | // _exception(...args);
265 | // };
266 |
267 | window.console.trace = (...args: any[]): void => {
268 | logConsolePanel?.logger?.log({
269 | type: 'text',
270 | level: 'info',
271 | data: parseArgs(args)
272 | });
273 | _trace(...args);
274 | };
275 |
276 | window.console.table = (...args: any[]): void => {
277 | logConsolePanel?.logger?.log({
278 | type: 'text',
279 | level: 'info',
280 | data: parseArgs(args)
281 | });
282 | _table(...args);
283 | };
284 |
285 | if (palette) {
286 | palette.addItem({
287 | command: CommandIDs.open,
288 | category: 'Developer'
289 | });
290 | }
291 |
292 | if (restorer) {
293 | restorer.restore(tracker, {
294 | command: CommandIDs.open,
295 | name: () => 'js-logs'
296 | });
297 | }
298 | }
299 | };
300 |
301 | export default extension;
302 |
--------------------------------------------------------------------------------