mirror of
https://github.com/jupyter/notebook.git
synced 2024-11-27 03:20:27 +08:00
Initial commit
This commit is contained in:
commit
ddcf687a78
22
.eslintignore
Normal file
22
.eslintignore
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
lint-staged.config.js
|
||||||
|
.eslintrc.js
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
**/build
|
||||||
|
**/lib
|
||||||
|
**/node_modules
|
||||||
|
**/mock_packages
|
||||||
|
**/static
|
||||||
|
**/typings
|
||||||
|
**/schemas
|
||||||
|
**/themes
|
||||||
|
coverage
|
||||||
|
*.map.js
|
||||||
|
*.bundle.js
|
||||||
|
|
||||||
|
# jetbrains IDE stuff
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# ms IDE stuff
|
||||||
|
.history/
|
||||||
|
.vscode/
|
56
.eslintrc.js
Normal file
56
.eslintrc.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es6: true,
|
||||||
|
commonjs: true,
|
||||||
|
node: true,
|
||||||
|
'jest/globals': true
|
||||||
|
},
|
||||||
|
root: true,
|
||||||
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/eslint-recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'plugin:prettier/recommended',
|
||||||
|
'plugin:react/recommended',
|
||||||
|
'plugin:jest/recommended'
|
||||||
|
],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
project: 'tsconfig.eslint.json',
|
||||||
|
sourceType: 'module'
|
||||||
|
},
|
||||||
|
plugins: ['@typescript-eslint', 'jest'],
|
||||||
|
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-var-requires': 'off',
|
||||||
|
'@typescript-eslint/no-use-before-define': 'off',
|
||||||
|
'@typescript-eslint/no-empty-interface': 'off',
|
||||||
|
'@typescript-eslint/quotes': [
|
||||||
|
'error',
|
||||||
|
'single',
|
||||||
|
{ avoidEscape: true, allowTemplateLiterals: false }
|
||||||
|
],
|
||||||
|
curly: ['error', 'all'],
|
||||||
|
eqeqeq: 'error',
|
||||||
|
'prefer-arrow-callback': 'error'
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
react: {
|
||||||
|
version: 'detect'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
116
.gitignore
vendored
Normal file
116
.gitignore
vendored
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
*.bundle.*
|
||||||
|
lib/
|
||||||
|
node_modules/
|
||||||
|
*.egg-info/
|
||||||
|
.ipynb_checkpoints
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/python
|
||||||
|
# Edit at https://www.gitignore.io/?templates=python
|
||||||
|
|
||||||
|
### Python ###
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# Mr Developer
|
||||||
|
.mr.developer.cfg
|
||||||
|
.project
|
||||||
|
.pydevproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# OS X stuff
|
||||||
|
*.DS_Store
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/python
|
||||||
|
|
||||||
|
_temp_extension
|
||||||
|
junit.xml
|
||||||
|
[uU]ntitled*
|
||||||
|
jupyterlab_classic/static
|
5
.prettierignore
Normal file
5
.prettierignore
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
node_modules
|
||||||
|
**/node_modules
|
||||||
|
**/lib
|
||||||
|
**/package.json
|
||||||
|
**/static
|
3
.prettierrc
Normal file
3
.prettierrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
29
LICENSE
Normal file
29
LICENSE
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2020, Jeremy Tuloup
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
21
MANIFEST.in
Normal file
21
MANIFEST.in
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
include LICENSE
|
||||||
|
include README.md
|
||||||
|
include pyproject.toml
|
||||||
|
include jupyter-config/jupyterlab-classic.json
|
||||||
|
|
||||||
|
include package.json
|
||||||
|
include install.json
|
||||||
|
include ts*.json
|
||||||
|
|
||||||
|
# Javascript files
|
||||||
|
graft src
|
||||||
|
graft style
|
||||||
|
prune **/node_modules
|
||||||
|
prune lib
|
||||||
|
|
||||||
|
# Patterns to exclude from any directory
|
||||||
|
global-exclude *~
|
||||||
|
global-exclude *.pyc
|
||||||
|
global-exclude *.pyo
|
||||||
|
global-exclude .git
|
||||||
|
global-exclude .ipynb_checkpoints
|
60
README.md
Normal file
60
README.md
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# jupyterlab-classic
|
||||||
|
|
||||||
|
The next gen old-school Notebook UI.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
With `pip`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install jupyterlab-classic
|
||||||
|
```
|
||||||
|
|
||||||
|
With `conda`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
conda install -c conda-forge jupyterlab-classic
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
`jupyterlab-classic` can be started as a standalone app with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m jupyterlab_classic
|
||||||
|
```
|
||||||
|
|
||||||
|
Existing federated JupyterLab extensions listed via:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
jupyter labextension list
|
||||||
|
```
|
||||||
|
|
||||||
|
Should also be available when starting `jupyterlab-classic`.
|
||||||
|
|
||||||
|
## Motivation
|
||||||
|
|
||||||
|
JupyterLab is the next-gen UI for Project Jupyter. Approaching version 3.0, it is becoming more mature and provides and advanced computation environment, that can sometimes be compared to what traditional IDEs offer.
|
||||||
|
|
||||||
|
However in some cases, having a leaner, simpler, and more focused interface to work on a notebook is really useful.
|
||||||
|
|
||||||
|
The single document mode as currently implemented in JupyterLab helps address this issue, but still displays a couple of visual cues to the users that can be distracting.
|
||||||
|
|
||||||
|
The goal of the `jupyterlab-classic` project is to look as close to the classic notebook UI as possible, while leveraging the efforts put in the development of JupyterLab itself and its extension system.
|
||||||
|
|
||||||
|
Technically speaking, `jupyterlab-classic` reuses **many** of the existing plugins for JupyterLab (notebook, toolbar), and also supports pre-built (federated) third-party extensions using the new distribution system added in 3.0. That way, extensions built for JupyterLab should also be compatible with `jupyterlab-classic`, as long as they can be added to the application.
|
||||||
|
|
||||||
|
## Prior art
|
||||||
|
|
||||||
|
This project is mostly a reboot of the two previous attempts at making something similar:
|
||||||
|
|
||||||
|
- [simplest-notebook](https://github.com/yuvipanda/simplest-notebook)
|
||||||
|
- [jupyterlab-clarity-mode](https://github.com/jupytercalpoly/jupyterlab-clarity-mode)
|
||||||
|
|
||||||
|
These projects real expressed the need for a stripped down, minimal version of the Jupyter Notebook UI.
|
||||||
|
|
||||||
|
`jupyterlab-classic` contributes to that space With the added:
|
||||||
|
|
||||||
|
- Support for existing federated (prebuilt) JupyterLab extensions
|
||||||
|
- Repo structure, similar to JupyterLab
|
||||||
|
- Reusing as much as possible from upstream JupyterLab
|
154
builder/index.js
Normal file
154
builder/index.js
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
// Copyright (c) Jupyter Development Team.
|
||||||
|
// Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
|
||||||
|
|
||||||
|
// Promise.allSettled polyfill, until our supported browsers implement it
|
||||||
|
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
|
||||||
|
if (Promise.allSettled === undefined) {
|
||||||
|
Promise.allSettled = promises =>
|
||||||
|
Promise.all(
|
||||||
|
promises.map(promise =>
|
||||||
|
promise.then(
|
||||||
|
value => ({
|
||||||
|
status: 'fulfilled',
|
||||||
|
value
|
||||||
|
}),
|
||||||
|
reason => ({
|
||||||
|
status: 'rejected',
|
||||||
|
reason
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
require('./style.css');
|
||||||
|
|
||||||
|
function loadScript(url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const newScript = document.createElement('script');
|
||||||
|
newScript.onerror = reject;
|
||||||
|
newScript.onload = resolve;
|
||||||
|
newScript.async = true;
|
||||||
|
document.head.appendChild(newScript);
|
||||||
|
newScript.src = url;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async function loadComponent(url, scope) {
|
||||||
|
await loadScript(url);
|
||||||
|
|
||||||
|
// From MIT-licensed https://github.com/module-federation/module-federation-examples/blob/af043acd6be1718ee195b2511adf6011fba4233c/advanced-api/dynamic-remotes/app1/src/App.js#L6-L12
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
await __webpack_init_sharing__('default');
|
||||||
|
const container = window._JUPYTERLAB[scope];
|
||||||
|
// Initialize the container, it may provide shared modules and may need ours
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
await container.init(__webpack_share_scopes__.default);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createModule(scope, module) {
|
||||||
|
try {
|
||||||
|
const factory = await window._JUPYTERLAB[scope].get(module);
|
||||||
|
return factory();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(
|
||||||
|
`Failed to create module: package: ${scope}; module: ${module}`
|
||||||
|
);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main function
|
||||||
|
*/
|
||||||
|
async function main() {
|
||||||
|
const App = require('@jupyterlab-classic/application').App;
|
||||||
|
const app = new App();
|
||||||
|
const mods = [
|
||||||
|
require('@jupyterlab-classic/application-extension'),
|
||||||
|
require('@jupyterlab/apputils-extension').default.filter(({ id }) =>
|
||||||
|
['@jupyterlab/apputils-extension:settings'].includes(id)
|
||||||
|
),
|
||||||
|
require('@jupyterlab/codemirror-extension').default.filter(({ id }) =>
|
||||||
|
['@jupyterlab/codemirror-extension:services'].includes(id)
|
||||||
|
),
|
||||||
|
require('@jupyterlab/mainmenu-extension'),
|
||||||
|
require('@jupyterlab/rendermime-extension'),
|
||||||
|
require('@jupyterlab/notebook-extension').default.filter(({ id }) =>
|
||||||
|
[
|
||||||
|
'@jupyterlab/notebook-extension:factory',
|
||||||
|
'@jupyterlab/notebook-extension:widget-factory',
|
||||||
|
'@jupyterlab/notebook-extension:tracker'
|
||||||
|
].includes(id)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
const extension_data = JSON.parse(
|
||||||
|
PageConfig.getOption('federated_extensions')
|
||||||
|
);
|
||||||
|
|
||||||
|
const federatedExtensionPromises = [];
|
||||||
|
const federatedMimeExtensionPromises = [];
|
||||||
|
const federatedStylePromises = [];
|
||||||
|
|
||||||
|
const extensions = await Promise.allSettled(
|
||||||
|
extension_data.map(async data => {
|
||||||
|
await loadComponent(
|
||||||
|
`${URLExt.join(
|
||||||
|
PageConfig.getOption('fullLabextensionsUrl'),
|
||||||
|
data.name,
|
||||||
|
data.load
|
||||||
|
)}`,
|
||||||
|
data.name
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
extensions.forEach(p => {
|
||||||
|
if (p.status === 'rejected') {
|
||||||
|
// There was an error loading the component
|
||||||
|
console.error(p.reason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = p.value;
|
||||||
|
if (data.extension) {
|
||||||
|
federatedExtensionPromises.push(createModule(data.name, data.extension));
|
||||||
|
}
|
||||||
|
if (data.mimeExtension) {
|
||||||
|
federatedMimeExtensionPromises.push(
|
||||||
|
createModule(data.name, data.mimeExtension)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (data.style) {
|
||||||
|
federatedStylePromises.push(createModule(data.name, data.style));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add the federated extensions.
|
||||||
|
const federatedExtensions = await Promise.allSettled(
|
||||||
|
federatedExtensionPromises
|
||||||
|
);
|
||||||
|
federatedExtensions.forEach(p => {
|
||||||
|
if (p.status === 'fulfilled') {
|
||||||
|
mods.push(p.value);
|
||||||
|
} else {
|
||||||
|
console.error(p.reason);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load all federated component styles and log errors for any that do not
|
||||||
|
(await Promise.allSettled(federatedStylePromises))
|
||||||
|
.filter(({ status }) => status === 'rejected')
|
||||||
|
.forEach(({ reason }) => {
|
||||||
|
console.error(reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.registerPluginModules(mods);
|
||||||
|
|
||||||
|
await app.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', main);
|
207
builder/package.json
Normal file
207
builder/package.json
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
{
|
||||||
|
"name": "@jupyterlab-classic/builder",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack",
|
||||||
|
"build:prod": "webpack --mode=production",
|
||||||
|
"clean": "rimraf build",
|
||||||
|
"prepublishOnly": "yarn run build",
|
||||||
|
"watch": "webpack --watch"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@jupyterlab-classic/application": "^0.1.0",
|
||||||
|
"@jupyterlab-classic/application-extension": "^0.1.0",
|
||||||
|
"@jupyterlab-classic/ui-components": "^0.1.0",
|
||||||
|
"@jupyterlab/apputils-extension": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/codemirror-extension": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/mainmenu-extension": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/notebook-extension": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/rendermime-extension": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/theme-light-extension": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/coreutils": "~5.0.0-rc.10"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@jupyterlab/builder": "^3.0.0-rc.10",
|
||||||
|
"css-loader": "~3.2.0",
|
||||||
|
"file-loader": "~5.0.2",
|
||||||
|
"fs-extra": "^8.1.0",
|
||||||
|
"glob": "~7.1.6",
|
||||||
|
"mini-css-extract-plugin": "~0.9.0",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"raw-loader": "~4.0.0",
|
||||||
|
"rimraf": "~3.0.2",
|
||||||
|
"style-loader": "~1.0.1",
|
||||||
|
"svg-url-loader": "~6.0.0",
|
||||||
|
"url-loader": "~4.1.1",
|
||||||
|
"watch": "~1.0.2",
|
||||||
|
"webpack": "^5.7.0",
|
||||||
|
"webpack-bundle-analyzer": "^4.1.0",
|
||||||
|
"webpack-cli": "^4.2.0",
|
||||||
|
"webpack-merge": "^5.1.2",
|
||||||
|
"whatwg-fetch": "^3.0.0"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"@jupyterlab/application": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/application-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/apputils": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/apputils-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/attachments": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/cells": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/celltags": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/celltags-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/codeeditor": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/codemirror": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/codemirror-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/completer": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/completer-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/console": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/console-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/coreutils": "~5.0.0-rc.10",
|
||||||
|
"@jupyterlab/csvviewer": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/csvviewer-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/debugger": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/debugger-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/docmanager": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/docmanager-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/docregistry": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/documentsearch": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/documentsearch-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/extensionmanager": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/extensionmanager-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/filebrowser": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/filebrowser-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/fileeditor": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/fileeditor-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/help-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/htmlviewer": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/htmlviewer-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/hub-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/imageviewer": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/imageviewer-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/inspector": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/inspector-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/javascript-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/json-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/launcher": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/launcher-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/logconsole": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/logconsole-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/mainmenu": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/mainmenu-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/markdownviewer-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/mathjax2": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/mathjax2-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/metapackage": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/nbconvert-css": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/nbformat": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/notebook": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/notebook-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/observables": "~4.0.0-rc.10",
|
||||||
|
"@jupyterlab/outputarea": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/pdf-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/property-inspector": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/rendermime": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/rendermime-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/rendermime-interfaces": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/running": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/running-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/services": "~6.0.0-rc.10",
|
||||||
|
"@jupyterlab/settingeditor": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/settingeditor-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/settingregistry": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/shortcuts-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/statedb": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/statusbar": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/statusbar-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/terminal": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/terminal-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/theme-dark-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/theme-light-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/toc": "~5.0.0-rc.10",
|
||||||
|
"@jupyterlab/toc-extension": "~5.0.0-rc.10",
|
||||||
|
"@jupyterlab/tooltip": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/tooltip-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/translation": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/translation-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/ui-components": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/ui-components-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/vdom": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/vdom-extension": "~3.0.0-rc.10",
|
||||||
|
"@jupyterlab/vega5-extension": "~3.0.0-rc.10",
|
||||||
|
"@lumino/algorithm": "^1.2.3",
|
||||||
|
"@lumino/application": "^1.8.4",
|
||||||
|
"@lumino/commands": "^1.10.1",
|
||||||
|
"@lumino/coreutils": "^1.4.3",
|
||||||
|
"@lumino/disposable": "^1.3.5",
|
||||||
|
"@lumino/domutils": "^1.1.7",
|
||||||
|
"@lumino/dragdrop": "^1.5.1",
|
||||||
|
"@lumino/messaging": "^1.3.3",
|
||||||
|
"@lumino/properties": "^1.1.6",
|
||||||
|
"@lumino/signaling": "^1.3.5",
|
||||||
|
"@lumino/virtualdom": "^1.6.1",
|
||||||
|
"@lumino/widgets": "^1.14.0",
|
||||||
|
"react": "^17.0.1",
|
||||||
|
"react-dom": "^17.0.1"
|
||||||
|
},
|
||||||
|
"jupyterlab": {
|
||||||
|
"name": "JupyterLab Classic",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"extensions": {
|
||||||
|
"@jupyterlab-classic/application-extension": ""
|
||||||
|
},
|
||||||
|
"buildDir": "./static",
|
||||||
|
"outputDir": ".",
|
||||||
|
"singletonPackages": [
|
||||||
|
"@jupyterlab/application",
|
||||||
|
"@jupyterlab/apputils",
|
||||||
|
"@jupyterlab/codeeditor",
|
||||||
|
"@jupyterlab/codemirror",
|
||||||
|
"@jupyterlab/completer",
|
||||||
|
"@jupyterlab/console",
|
||||||
|
"@jupyterlab/coreutils",
|
||||||
|
"@jupyterlab/debugger",
|
||||||
|
"@jupyterlab/docmanager",
|
||||||
|
"@jupyterlab/documentsearch",
|
||||||
|
"@jupyterlab/extensionmanager",
|
||||||
|
"@jupyterlab/filebrowser",
|
||||||
|
"@jupyterlab/fileeditor",
|
||||||
|
"@jupyterlab/imageviewer",
|
||||||
|
"@jupyterlab/inspector",
|
||||||
|
"@jupyterlab/launcher",
|
||||||
|
"@jupyterlab/logconsole",
|
||||||
|
"@jupyterlab/mainmenu",
|
||||||
|
"@jupyterlab/markdownviewer",
|
||||||
|
"@jupyterlab/notebook",
|
||||||
|
"@jupyterlab/rendermime",
|
||||||
|
"@jupyterlab/rendermime-interfaces",
|
||||||
|
"@jupyterlab/services",
|
||||||
|
"@jupyterlab/settingeditor",
|
||||||
|
"@jupyterlab/settingregistry",
|
||||||
|
"@jupyterlab/statedb",
|
||||||
|
"@jupyterlab/statusbar",
|
||||||
|
"@jupyterlab/terminal",
|
||||||
|
"@jupyterlab/tooltip",
|
||||||
|
"@jupyterlab/translation",
|
||||||
|
"@jupyterlab/ui-components",
|
||||||
|
"@lumino/algorithm",
|
||||||
|
"@lumino/application",
|
||||||
|
"@lumino/commands",
|
||||||
|
"@lumino/coreutils",
|
||||||
|
"@lumino/disposable",
|
||||||
|
"@lumino/domutils",
|
||||||
|
"@lumino/dragdrop",
|
||||||
|
"@lumino/messaging",
|
||||||
|
"@lumino/properties",
|
||||||
|
"@lumino/signaling",
|
||||||
|
"@lumino/virtualdom",
|
||||||
|
"@lumino/widgets",
|
||||||
|
"react",
|
||||||
|
"react-dom"
|
||||||
|
],
|
||||||
|
"linkedPackages": {
|
||||||
|
"@jupyterlab-classic/application": "../packages/application",
|
||||||
|
"@jupyterlab-classic/application-extension": "../packages/application-extension"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
builder/publicpath.js
Normal file
37
builder/publicpath.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright (c) Jupyter Development Team.
|
||||||
|
// Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
// We dynamically set the webpack public path based on the page config
|
||||||
|
// settings from the JupyterLab app. We copy some of the pageconfig parsing
|
||||||
|
// logic in @jupyterlab/coreutils below, since this must run before any other
|
||||||
|
// files are loaded (including @jupyterlab/coreutils).
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get global configuration data for the Jupyter application.
|
||||||
|
*
|
||||||
|
* @param name - The name of the configuration option.
|
||||||
|
*
|
||||||
|
* @returns The config value or an empty string if not found.
|
||||||
|
*
|
||||||
|
* #### Notes
|
||||||
|
* All values are treated as strings.
|
||||||
|
* For browser based applications, it is assumed that the page HTML
|
||||||
|
* includes a script tag with the id `jupyter-config-data` containing the
|
||||||
|
* configuration as valid JSON. In order to support the classic Notebook,
|
||||||
|
* we fall back on checking for `body` data of the given `name`.
|
||||||
|
*/
|
||||||
|
function getOption(name) {
|
||||||
|
let configData = Object.create(null);
|
||||||
|
// Use script tag if available.
|
||||||
|
if (typeof document !== 'undefined' && document) {
|
||||||
|
const el = document.getElementById('jupyter-config-data');
|
||||||
|
|
||||||
|
if (el) {
|
||||||
|
configData = JSON.parse(el.textContent || '{}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return configData[name] || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
__webpack_public_path__ = getOption('fullStaticUrl') + '/';
|
7
builder/style.css
Normal file
7
builder/style.css
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@import url('~@jupyterlab-classic/application-extension/style/index.css');
|
||||||
|
@import url('~@jupyterlab-classic/ui-components/style/index.css');
|
||||||
|
|
||||||
|
@import url('~@jupyterlab/codemirror-extension/style/index.css');
|
||||||
|
@import url('~@jupyterlab/rendermime-extension/style/index.css');
|
||||||
|
@import url('~@jupyterlab/notebook-extension/style/index.css');
|
||||||
|
@import url('~@jupyterlab/theme-light-extension/style/index.css');
|
88
builder/webpack.config.js
Normal file
88
builder/webpack.config.js
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// Copyright (c) Jupyter Development Team.
|
||||||
|
// Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
// Heavily inspired (and slightly tweaked) from:
|
||||||
|
// https://github.com/jupyterlab/jupyterlab/blob/master/examples/federated/core_package/webpack.config.js
|
||||||
|
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const path = require('path');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const merge = require('webpack-merge').default;
|
||||||
|
const { ModuleFederationPlugin } = webpack.container;
|
||||||
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
|
||||||
|
.BundleAnalyzerPlugin;
|
||||||
|
|
||||||
|
const Build = require('@jupyterlab/builder').Build;
|
||||||
|
const baseConfig = require('@jupyterlab/builder/lib/webpack.config.base');
|
||||||
|
|
||||||
|
const data = require('./package.json');
|
||||||
|
|
||||||
|
const names = Object.keys(data.dependencies).filter(name => {
|
||||||
|
const packageData = require(path.join(name, 'package.json'));
|
||||||
|
return packageData.jupyterlab !== undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure a clear build directory.
|
||||||
|
const buildDir = path.resolve(__dirname, 'build');
|
||||||
|
if (fs.existsSync(buildDir)) {
|
||||||
|
fs.removeSync(buildDir);
|
||||||
|
}
|
||||||
|
fs.ensureDirSync(buildDir);
|
||||||
|
|
||||||
|
// Copy extra files
|
||||||
|
const index = path.resolve(__dirname, 'index.js');
|
||||||
|
const cssImports = path.resolve(__dirname, 'style.css');
|
||||||
|
fs.copySync(index, path.resolve(buildDir, 'index.js'));
|
||||||
|
fs.copySync(cssImports, path.resolve(buildDir, 'style.css'));
|
||||||
|
|
||||||
|
const extras = Build.ensureAssets({
|
||||||
|
packageNames: names,
|
||||||
|
output: buildDir
|
||||||
|
});
|
||||||
|
|
||||||
|
const singletons = {};
|
||||||
|
|
||||||
|
data.jupyterlab.singletonPackages.forEach(element => {
|
||||||
|
singletons[element] = { singleton: true };
|
||||||
|
});
|
||||||
|
|
||||||
|
// Make a bootstrap entrypoint
|
||||||
|
const entryPoint = path.join(buildDir, 'bootstrap.js');
|
||||||
|
const bootstrap = 'import("./index.js");';
|
||||||
|
fs.writeFileSync(entryPoint, bootstrap);
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
baseConfig.mode = 'production';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.argv.includes('--analyze')) {
|
||||||
|
extras.push(new BundleAnalyzerPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
merge(baseConfig, {
|
||||||
|
mode: 'development',
|
||||||
|
entry: ['./publicpath.js', './' + path.relative(__dirname, entryPoint)],
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, '..', 'jupyterlab_classic/static/'),
|
||||||
|
library: {
|
||||||
|
type: 'var',
|
||||||
|
name: ['_JUPYTERLAB', 'CORE_OUTPUT']
|
||||||
|
},
|
||||||
|
filename: 'bundle.js'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new ModuleFederationPlugin({
|
||||||
|
library: {
|
||||||
|
type: 'var',
|
||||||
|
name: ['_JUPYTERLAB', 'CORE_LIBRARY_FEDERATION']
|
||||||
|
},
|
||||||
|
name: 'CORE_FEDERATION',
|
||||||
|
shared: {
|
||||||
|
...data.resolutions,
|
||||||
|
...singletons
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
].concat(extras);
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"ServerApp": {
|
||||||
|
"jpserver_extensions": {
|
||||||
|
"jupyterlab_classic": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
jupyterlab_classic/__init__.py
Normal file
15
jupyterlab_classic/__init__.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from ._version import __version__
|
||||||
|
from .app import ClassicApp
|
||||||
|
from .serverextension import load_jupyter_server_extension
|
||||||
|
|
||||||
|
|
||||||
|
def _jupyter_server_extension_paths():
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'module': 'jupyterlab'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _jupyter_server_extension_points():
|
||||||
|
return [{"module": "jupyterlab_classic", "app": ClassicApp}]
|
4
jupyterlab_classic/__main__.py
Normal file
4
jupyterlab_classic/__main__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
from jupyterlab_classic.app import main
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.exit(main())
|
1
jupyterlab_classic/_version.py
Normal file
1
jupyterlab_classic/_version.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
__version__ = "0.1.0"
|
58
jupyterlab_classic/app.py
Normal file
58
jupyterlab_classic/app.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from jupyter_server.base.handlers import JupyterHandler
|
||||||
|
from jupyter_server.extension.handler import (
|
||||||
|
ExtensionHandlerMixin,
|
||||||
|
ExtensionHandlerJinjaMixin,
|
||||||
|
)
|
||||||
|
from jupyterlab import LabApp
|
||||||
|
from jupyter_server.utils import url_path_join as ujoin
|
||||||
|
from tornado import web
|
||||||
|
|
||||||
|
from ._version import __version__
|
||||||
|
|
||||||
|
HERE = os.path.dirname(__file__)
|
||||||
|
version = __version__
|
||||||
|
|
||||||
|
|
||||||
|
class ClassicHandler(ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler):
|
||||||
|
@web.authenticated
|
||||||
|
def get(self):
|
||||||
|
config_data = {
|
||||||
|
"appVersion": version,
|
||||||
|
"baseUrl": self.base_url,
|
||||||
|
"token": self.settings["token"],
|
||||||
|
"fullStaticUrl": ujoin(self.base_url, "static", self.name),
|
||||||
|
"frontendUrl": ujoin(self.base_url, "classic/"),
|
||||||
|
}
|
||||||
|
return self.write(
|
||||||
|
self.render_template(
|
||||||
|
"index.html",
|
||||||
|
static=self.static_url,
|
||||||
|
base_url=self.base_url,
|
||||||
|
token=self.settings["token"],
|
||||||
|
page_config=config_data,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ClassicApp(LabApp):
|
||||||
|
|
||||||
|
extension_url = '/classic'
|
||||||
|
app_url = "/classic"
|
||||||
|
load_other_extensions = True
|
||||||
|
name = __name__
|
||||||
|
app_name = 'JupyterLab Classic'
|
||||||
|
static_dir = os.path.join(HERE, 'static')
|
||||||
|
templates_dir = os.path.join(HERE, 'templates')
|
||||||
|
app_version = version
|
||||||
|
|
||||||
|
def initialize_handlers(self):
|
||||||
|
super().initialize_handlers()
|
||||||
|
self.handlers.append(('/classic', ClassicHandler))
|
||||||
|
|
||||||
|
|
||||||
|
main = launch_new_instance = ClassicApp.launch_instance
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
10
jupyterlab_classic/serverextension.py
Normal file
10
jupyterlab_classic/serverextension.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from .app import ClassicApp
|
||||||
|
|
||||||
|
|
||||||
|
def load_jupyter_server_extension(serverapp):
|
||||||
|
extension = ClassicApp()
|
||||||
|
extension.serverapp = serverapp
|
||||||
|
extension.load_config_file()
|
||||||
|
extension.update_config(serverapp.config)
|
||||||
|
extension.parse_command_line(serverapp.extra_args)
|
||||||
|
extension.initialize()
|
59
jupyterlab_classic/templates/error.html
Normal file
59
jupyterlab_classic/templates/error.html
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<!--
|
||||||
|
Copyright (c) Jupyter Development Team.
|
||||||
|
Distributed under the terms of the Modified BSD License.
|
||||||
|
-->
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
|
||||||
|
<title>{% block title %}{{page_title | e}}{% endblock %}</title>
|
||||||
|
|
||||||
|
{% block favicon %}<link rel="shortcut icon" type="image/x-icon" href="/static/favicons/favicon.ico">{% endblock %}
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
{% block stylesheet %}
|
||||||
|
<style type="text/css">
|
||||||
|
/* disable initial hide */
|
||||||
|
div#header, div#site {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
{% block site %}
|
||||||
|
|
||||||
|
<div class="error">
|
||||||
|
{% block h1_error %}
|
||||||
|
<h1>{{status_code | e}} : {{status_message | e}}</h1>
|
||||||
|
{% endblock h1_error %}
|
||||||
|
{% block error_detail %}
|
||||||
|
{% if message %}
|
||||||
|
<p>The error was:</p>
|
||||||
|
<div class="traceback-wrapper">
|
||||||
|
<pre class="traceback">{{message | e}}</pre>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block script %}
|
||||||
|
<script type='text/javascript'>
|
||||||
|
window.onload = function () {
|
||||||
|
var tb = document.getElementsByClassName('traceback')[0];
|
||||||
|
tb.scrollTop = tb.scrollHeight;
|
||||||
|
{% if message %}
|
||||||
|
console.error("{{message | e}}")
|
||||||
|
{% endif %}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
{% endblock script %}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
33
jupyterlab_classic/templates/index.html
Normal file
33
jupyterlab_classic/templates/index.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>{{page_config['appName'] | e}}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
{# Copy so we do not modify the page_config with updates. #}
|
||||||
|
{% set page_config_full = page_config.copy() %}
|
||||||
|
|
||||||
|
{# Set a dummy variable - we just want the side effect of the update. #}
|
||||||
|
{% set _ = page_config_full.update(baseUrl=base_url, wsUrl=ws_url) %}
|
||||||
|
|
||||||
|
<script id="jupyter-config-data" type="application/json">
|
||||||
|
{{ page_config_full | tojson }}
|
||||||
|
</script>
|
||||||
|
<script src="{{page_config['fullStaticUrl'] | e}}/bundle.js" main="index"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
/* Remove token from URL. */
|
||||||
|
(function () {
|
||||||
|
var parsedUrl = new URL(window.location.href);
|
||||||
|
if (parsedUrl.searchParams.get('token')) {
|
||||||
|
parsedUrl.searchParams.delete('token');
|
||||||
|
window.history.replaceState({ }, '', parsedUrl.href);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
5
lerna.json
Normal file
5
lerna.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"npmClient": "yarn",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"useWorkspaces": true
|
||||||
|
}
|
27
lint-staged.config.js
Normal file
27
lint-staged.config.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
const escape = require('shell-quote').quote;
|
||||||
|
const fs = require('fs');
|
||||||
|
const isWin = process.platform === 'win32';
|
||||||
|
|
||||||
|
const escapeFileNames = filenames =>
|
||||||
|
filenames
|
||||||
|
.filter(filename => fs.existsSync(filename))
|
||||||
|
.map(filename => `"${isWin ? filename : escape([filename])}"`)
|
||||||
|
.join(' ');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
'**/*{.css,.json,.md}': filenames => {
|
||||||
|
const escapedFileNames = escapeFileNames(filenames);
|
||||||
|
return [
|
||||||
|
`prettier --write ${escapedFileNames}`,
|
||||||
|
`git add -f ${escapedFileNames}`
|
||||||
|
];
|
||||||
|
},
|
||||||
|
'**/*{.ts,.tsx,.js,.jsx}': filenames => {
|
||||||
|
const escapedFileNames = escapeFileNames(filenames);
|
||||||
|
return [
|
||||||
|
`prettier --write ${escapedFileNames}`,
|
||||||
|
`eslint --fix ${escapedFileNames}`,
|
||||||
|
`git add -f ${escapedFileNames}`
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
161
package.json
Normal file
161
package.json
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"homepage": "https://github.com/jtpio/jupyterlab-classic",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/jtpio/jupyterlab-classic"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/jtpio/jupyterlab-classic/issues"
|
||||||
|
},
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"author": "Jeremy Tuloup",
|
||||||
|
"workspaces": {
|
||||||
|
"packages": [
|
||||||
|
"builder",
|
||||||
|
"packages/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "lerna run build",
|
||||||
|
"build:prod": "lerna run build:prod",
|
||||||
|
"build:test": "lerna run build:test",
|
||||||
|
"clean": "lerna run clean",
|
||||||
|
"install": "lerna bootstrap",
|
||||||
|
"eslint": "eslint . --ext .ts,.tsx --fix",
|
||||||
|
"eslint:check": "eslint . --ext .ts,.tsx",
|
||||||
|
"prettier": "prettier --write \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
|
||||||
|
"prettier:check": "prettier --list-different \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
|
||||||
|
"publish": "yarn run clean && yarn run build && lerna publish",
|
||||||
|
"test": "lerna run test"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.2.0",
|
||||||
|
"@typescript-eslint/parser": "^4.2.0",
|
||||||
|
"eslint": "^7.10.0",
|
||||||
|
"eslint-plugin-jest": "^24.1.3",
|
||||||
|
"eslint-config-prettier": "^6.15.0",
|
||||||
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
|
"eslint-plugin-react": "^7.21.5",
|
||||||
|
"husky": "^3",
|
||||||
|
"jest": "^26.4.2",
|
||||||
|
"jest-junit": "^11.1.0",
|
||||||
|
"jest-raw-loader": "^1.0.1",
|
||||||
|
"jest-summary-reporter": "^0.0.2",
|
||||||
|
"lerna": "^3.22.1",
|
||||||
|
"lint-staged": "^10.4.0",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"prettier": "^1.19.0",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"shell-quote": "^1.7.2",
|
||||||
|
"typescript": "~4.0.3"
|
||||||
|
},
|
||||||
|
"husky": {
|
||||||
|
"hooks": {
|
||||||
|
"pre-commit": "lint-staged"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"@jupyterlab/application": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/application-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/apputils": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/apputils-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/attachments": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/cells": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/celltags": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/celltags-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/codeeditor": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/codemirror": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/codemirror-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/completer": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/completer-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/console": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/console-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/coreutils": "5.0.0-rc.10",
|
||||||
|
"@jupyterlab/csvviewer": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/csvviewer-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/debugger": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/debugger-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/docmanager": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/docmanager-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/docregistry": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/documentsearch": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/documentsearch-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/extensionmanager": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/extensionmanager-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/filebrowser": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/filebrowser-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/fileeditor": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/fileeditor-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/help-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/htmlviewer": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/htmlviewer-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/hub-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/imageviewer": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/imageviewer-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/inspector": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/inspector-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/javascript-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/json-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/launcher": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/launcher-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/logconsole": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/logconsole-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/mainmenu": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/mainmenu-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/markdownviewer-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/mathjax2": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/mathjax2-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/metapackage": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/nbconvert-css": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/nbformat": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/notebook": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/notebook-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/observables": "4.0.0-rc.10",
|
||||||
|
"@jupyterlab/outputarea": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/pdf-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/property-inspector": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/rendermime": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/rendermime-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/rendermime-interfaces": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/running": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/running-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/services": "6.0.0-rc.10",
|
||||||
|
"@jupyterlab/settingeditor": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/settingeditor-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/settingregistry": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/shortcuts-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/statedb": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/statusbar": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/statusbar-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/terminal": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/terminal-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/theme-dark-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/theme-light-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/toc": "5.0.0-rc.10",
|
||||||
|
"@jupyterlab/toc-extension": "5.0.0-rc.10",
|
||||||
|
"@jupyterlab/tooltip": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/tooltip-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/translation": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/translation-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/ui-components": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/ui-components-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/vdom": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/vdom-extension": "3.0.0-rc.10",
|
||||||
|
"@jupyterlab/vega5-extension": "3.0.0-rc.10",
|
||||||
|
"@lumino/algorithm": "^1.2.3",
|
||||||
|
"@lumino/application": "^1.8.4",
|
||||||
|
"@lumino/commands": "^1.10.1",
|
||||||
|
"@lumino/coreutils": "^1.4.3",
|
||||||
|
"@lumino/disposable": "^1.3.5",
|
||||||
|
"@lumino/domutils": "^1.1.7",
|
||||||
|
"@lumino/dragdrop": "^1.5.1",
|
||||||
|
"@lumino/messaging": "^1.3.3",
|
||||||
|
"@lumino/properties": "^1.1.6",
|
||||||
|
"@lumino/signaling": "^1.3.5",
|
||||||
|
"@lumino/virtualdom": "^1.6.1",
|
||||||
|
"@lumino/widgets": "^1.14.0",
|
||||||
|
"react": "^17.0.1",
|
||||||
|
"react-dom": "^17.0.1"
|
||||||
|
}
|
||||||
|
}
|
61
packages/application-extension/package.json
Normal file
61
packages/application-extension/package.json
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"name": "@jupyterlab-classic/application-extension",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "JupyterLab Classic - Application Extension",
|
||||||
|
"homepage": "https://github.com/jtpio/jupyterlab-classic",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/jtpio/jupyterlab-classic/issues"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/jtpio/jupyterlab-classic.git"
|
||||||
|
},
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"author": "Project Jupyter",
|
||||||
|
"sideEffects": [
|
||||||
|
"style/**/*.css"
|
||||||
|
],
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"types": "lib/index.d.ts",
|
||||||
|
"style": "style/index.css",
|
||||||
|
"directories": {
|
||||||
|
"lib": "lib/"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib/*.d.ts",
|
||||||
|
"lib/*.js.map",
|
||||||
|
"lib/*.js",
|
||||||
|
"schema/*.json",
|
||||||
|
"style/**/*.css"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc -b",
|
||||||
|
"clean": "rimraf lib && rimraf tsconfig.tsbuildinfo",
|
||||||
|
"docs": "typedoc src",
|
||||||
|
"prepublishOnly": "npm run build",
|
||||||
|
"watch": "tsc -b --watch"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@jupyterlab-classic/application": "0.1.0",
|
||||||
|
"@jupyterlab-classic/ui-components": "0.1.0",
|
||||||
|
"@jupyterlab/application": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/apputils": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/codeeditor": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/codemirror": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/docregistry": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/docmanager": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/notebook": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/translation": "^3.0.0-rc.10",
|
||||||
|
"@lumino/widgets": "^1.14.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"rimraf": "~3.0.0",
|
||||||
|
"typescript": "~4.0.2"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"jupyterlab": {
|
||||||
|
"extension": true
|
||||||
|
}
|
||||||
|
}
|
367
packages/application-extension/src/index.ts
Normal file
367
packages/application-extension/src/index.ts
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
// Copyright (c) Jupyter Development Team.
|
||||||
|
// Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
import {
|
||||||
|
IRouter,
|
||||||
|
JupyterFrontEnd,
|
||||||
|
JupyterFrontEndPlugin,
|
||||||
|
Router
|
||||||
|
} from '@jupyterlab/application';
|
||||||
|
|
||||||
|
import {
|
||||||
|
sessionContextDialogs,
|
||||||
|
ISessionContextDialogs,
|
||||||
|
DOMUtils
|
||||||
|
} from '@jupyterlab/apputils';
|
||||||
|
|
||||||
|
import { PageConfig } from '@jupyterlab/coreutils';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DocumentManager,
|
||||||
|
IDocumentManager,
|
||||||
|
renameDialog
|
||||||
|
} from '@jupyterlab/docmanager';
|
||||||
|
|
||||||
|
import { DocumentRegistry } from '@jupyterlab/docregistry';
|
||||||
|
|
||||||
|
import { NotebookPanel } from '@jupyterlab/notebook';
|
||||||
|
|
||||||
|
import { ITranslator, TranslationManager } from '@jupyterlab/translation';
|
||||||
|
|
||||||
|
import {
|
||||||
|
App,
|
||||||
|
ClassicShell,
|
||||||
|
IClassicShell
|
||||||
|
} from '@jupyterlab-classic/application';
|
||||||
|
|
||||||
|
import { jupyterIcon } from '@jupyterlab-classic/ui-components';
|
||||||
|
|
||||||
|
import { Widget } from '@lumino/widgets';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default notebook factory.
|
||||||
|
*/
|
||||||
|
const NOTEBOOK_FACTORY = 'Notebook';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The command IDs used by the application plugin.
|
||||||
|
*/
|
||||||
|
namespace CommandIDs {
|
||||||
|
export const open = 'open';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A minimal document manager plugin.
|
||||||
|
* TODO: move to @jupyterlab-classic/docmanager-extension
|
||||||
|
*/
|
||||||
|
const doc: JupyterFrontEndPlugin<IDocumentManager> = {
|
||||||
|
id: '@jupyterlab-classic/application-extension:docmanager',
|
||||||
|
provides: IDocumentManager,
|
||||||
|
autoStart: true,
|
||||||
|
activate: (app: JupyterFrontEnd) => {
|
||||||
|
const opener = {
|
||||||
|
open: (widget: Widget, options: DocumentRegistry.IOpenOptions) => {
|
||||||
|
app.shell.add(widget, 'main', options);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const docManager = new DocumentManager({
|
||||||
|
registry: app.docRegistry,
|
||||||
|
manager: app.serviceManager,
|
||||||
|
opener
|
||||||
|
});
|
||||||
|
|
||||||
|
app.commands.addCommand(CommandIDs.open, {
|
||||||
|
label: 'Open a document',
|
||||||
|
execute: (args: any) => {
|
||||||
|
const path = args['path'] as string;
|
||||||
|
const factory = args['factory'] as string;
|
||||||
|
const options = args['options'] as DocumentRegistry.IOpenOptions;
|
||||||
|
const closable = args['closable'] as boolean;
|
||||||
|
const widget = docManager.open(path, factory, undefined, options);
|
||||||
|
if (widget) {
|
||||||
|
widget.title.closable = closable ?? true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return docManager;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The kernel logo plugin.
|
||||||
|
*/
|
||||||
|
const kernelLogo: JupyterFrontEndPlugin<void> = {
|
||||||
|
id: '@jupyterlab-classic/application-extension:kernelLogo',
|
||||||
|
autoStart: true,
|
||||||
|
requires: [IClassicShell],
|
||||||
|
activate: (app: JupyterFrontEnd, shell: IClassicShell) => {
|
||||||
|
const { serviceManager } = app;
|
||||||
|
const baseUrl = PageConfig.getBaseUrl();
|
||||||
|
|
||||||
|
let widget: Widget;
|
||||||
|
// TODO: this signal might not be needed if we assume there is always only
|
||||||
|
// one notebook in the main area
|
||||||
|
shell.currentChanged.connect(async () => {
|
||||||
|
if (widget) {
|
||||||
|
widget.dispose();
|
||||||
|
widget.parent = null;
|
||||||
|
}
|
||||||
|
const current = shell.currentWidget;
|
||||||
|
if (!(current instanceof NotebookPanel)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await current.sessionContext.ready;
|
||||||
|
|
||||||
|
const name = current.sessionContext.session?.kernel?.name ?? '';
|
||||||
|
const spec = serviceManager.kernelspecs?.specs?.kernelspecs[name];
|
||||||
|
if (!spec) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let kernelIconUrl = spec.resources['logo-64x64'];
|
||||||
|
if (!kernelIconUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = kernelIconUrl.indexOf('kernelspecs');
|
||||||
|
kernelIconUrl = baseUrl + kernelIconUrl.slice(index);
|
||||||
|
const node = document.createElement('div');
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = kernelIconUrl;
|
||||||
|
img.title = spec.display_name;
|
||||||
|
node.appendChild(img);
|
||||||
|
widget = new Widget({ node });
|
||||||
|
widget.addClass('jp-ClassicKernelLogo');
|
||||||
|
app.shell.add(widget, 'top', { rank: 10_010 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logo plugin.
|
||||||
|
*/
|
||||||
|
const logo: JupyterFrontEndPlugin<void> = {
|
||||||
|
id: '@jupyterlab-classic/application-extension:logo',
|
||||||
|
autoStart: true,
|
||||||
|
activate: (app: JupyterFrontEnd) => {
|
||||||
|
const logo = new Widget();
|
||||||
|
jupyterIcon.element({
|
||||||
|
container: logo.node,
|
||||||
|
elementPosition: 'center',
|
||||||
|
padding: '2px 2px 2px 8px',
|
||||||
|
height: '28px',
|
||||||
|
width: 'auto'
|
||||||
|
});
|
||||||
|
logo.id = 'jp-ClassicLogo';
|
||||||
|
app.shell.add(logo, 'top', { rank: 0 });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main plugin.
|
||||||
|
*/
|
||||||
|
const main: JupyterFrontEndPlugin<void> = {
|
||||||
|
id: '@jupyterlab-classic/application-extension:main',
|
||||||
|
autoStart: true,
|
||||||
|
activate: () => {
|
||||||
|
console.log(main.id, 'activated');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default paths for a JupyterLab Classic app.
|
||||||
|
*/
|
||||||
|
const paths: JupyterFrontEndPlugin<JupyterFrontEnd.IPaths> = {
|
||||||
|
id: '@jupyterlab-classic/application-extension:paths',
|
||||||
|
activate: (app: JupyterFrontEnd): JupyterFrontEnd.IPaths => {
|
||||||
|
if (!(app instanceof App)) {
|
||||||
|
throw new Error(`${paths.id} must be activated in JupyterLab Classic.`);
|
||||||
|
}
|
||||||
|
return app.paths;
|
||||||
|
},
|
||||||
|
autoStart: true,
|
||||||
|
provides: JupyterFrontEnd.IPaths
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default URL router provider.
|
||||||
|
*/
|
||||||
|
const router: JupyterFrontEndPlugin<IRouter> = {
|
||||||
|
id: '@jupyterlab-classic/application-extension:router',
|
||||||
|
requires: [JupyterFrontEnd.IPaths],
|
||||||
|
activate: (app: JupyterFrontEnd, paths: JupyterFrontEnd.IPaths) => {
|
||||||
|
const { commands } = app;
|
||||||
|
const base = paths.urls.base;
|
||||||
|
const router = new Router({ base, commands });
|
||||||
|
void app.started.then(() => {
|
||||||
|
// Route the very first request on load.
|
||||||
|
void router.route();
|
||||||
|
|
||||||
|
// Route all pop state events.
|
||||||
|
window.addEventListener('popstate', () => {
|
||||||
|
void router.route();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return router;
|
||||||
|
},
|
||||||
|
autoStart: true,
|
||||||
|
provides: IRouter
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default session dialogs plugin
|
||||||
|
*/
|
||||||
|
const sessionDialogs: JupyterFrontEndPlugin<ISessionContextDialogs> = {
|
||||||
|
id: '@jupyterlab-classic/application-extension:sessionDialogs',
|
||||||
|
provides: ISessionContextDialogs,
|
||||||
|
autoStart: true,
|
||||||
|
activate: () => sessionContextDialogs
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default JupyterLab Classic application shell.
|
||||||
|
*/
|
||||||
|
const shell: JupyterFrontEndPlugin<IClassicShell> = {
|
||||||
|
id: '@jupyterlab-classic/application-extension:shell',
|
||||||
|
activate: (app: JupyterFrontEnd) => {
|
||||||
|
if (!(app.shell instanceof ClassicShell)) {
|
||||||
|
throw new Error(`${shell.id} did not find a ClassicShell instance.`);
|
||||||
|
}
|
||||||
|
return app.shell;
|
||||||
|
},
|
||||||
|
autoStart: true,
|
||||||
|
provides: IClassicShell
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A plugin to provide a spacer at rank 10000 for flex panels
|
||||||
|
*/
|
||||||
|
const spacer: JupyterFrontEndPlugin<void> = {
|
||||||
|
id: '@jupyterlab-classic/application-extension:spacer',
|
||||||
|
autoStart: true,
|
||||||
|
activate: (app: JupyterFrontEnd) => {
|
||||||
|
const spacer = new Widget();
|
||||||
|
spacer.id = DOMUtils.createDomID();
|
||||||
|
spacer.addClass('jp-ClassicSpacer');
|
||||||
|
app.shell.add(spacer, 'top', { rank: 10000 });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A plugin to display the title of the notebook
|
||||||
|
*/
|
||||||
|
const title: JupyterFrontEndPlugin<void> = {
|
||||||
|
id: '@jupyterlab-classic/application-extension:title',
|
||||||
|
autoStart: true,
|
||||||
|
requires: [IClassicShell],
|
||||||
|
optional: [IDocumentManager, IRouter],
|
||||||
|
activate: (
|
||||||
|
app: JupyterFrontEnd,
|
||||||
|
shell: IClassicShell,
|
||||||
|
docManager: IDocumentManager | null,
|
||||||
|
router: IRouter | null
|
||||||
|
) => {
|
||||||
|
// TODO: this signal might not be needed if we assume there is always only
|
||||||
|
// one notebook in the main area
|
||||||
|
const widget = new Widget();
|
||||||
|
widget.id = 'jp-title';
|
||||||
|
app.shell.add(widget, 'top', { rank: 10 });
|
||||||
|
|
||||||
|
shell.currentChanged.connect(async () => {
|
||||||
|
const current = shell.currentWidget;
|
||||||
|
if (!(current instanceof NotebookPanel)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const h = document.createElement('h1');
|
||||||
|
h.textContent = current.title.label;
|
||||||
|
widget.node.appendChild(h);
|
||||||
|
widget.node.style.marginLeft = '10px';
|
||||||
|
if (docManager) {
|
||||||
|
widget.node.onclick = async () => {
|
||||||
|
const result = await renameDialog(
|
||||||
|
docManager,
|
||||||
|
current.sessionContext.path
|
||||||
|
);
|
||||||
|
if (result) {
|
||||||
|
h.textContent = result.path;
|
||||||
|
if (router) {
|
||||||
|
// TODO: better handle this
|
||||||
|
router.navigate(`/classic/tree/${result.path}`, {
|
||||||
|
skipRouting: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simplified Translator
|
||||||
|
*/
|
||||||
|
const translator: JupyterFrontEndPlugin<ITranslator> = {
|
||||||
|
id: '@jupyterlab-classic/application-extension:translator',
|
||||||
|
activate: (app: JupyterFrontEnd<JupyterFrontEnd.IShell>): ITranslator => {
|
||||||
|
const translationManager = new TranslationManager();
|
||||||
|
return translationManager;
|
||||||
|
},
|
||||||
|
autoStart: true,
|
||||||
|
provides: ITranslator
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default tree route resolver plugin.
|
||||||
|
*/
|
||||||
|
const tree: JupyterFrontEndPlugin<void> = {
|
||||||
|
id: '@jupyterlab-classic/application-extension:tree-resolver',
|
||||||
|
autoStart: true,
|
||||||
|
requires: [IRouter],
|
||||||
|
activate: (app: JupyterFrontEnd, router: IRouter): void => {
|
||||||
|
const { commands } = app;
|
||||||
|
const treePattern = new RegExp('/tree/(.*)');
|
||||||
|
|
||||||
|
const command = 'router:tree';
|
||||||
|
commands.addCommand(command, {
|
||||||
|
execute: (args: any) => {
|
||||||
|
const parsed = args as IRouter.ILocation;
|
||||||
|
const matches = parsed.path.match(treePattern);
|
||||||
|
if (!matches) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const [, path] = matches;
|
||||||
|
|
||||||
|
app.restored.then(() => {
|
||||||
|
commands.execute(CommandIDs.open, {
|
||||||
|
path,
|
||||||
|
factory: NOTEBOOK_FACTORY
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.register({ command, pattern: treePattern });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export the plugins as default.
|
||||||
|
*/
|
||||||
|
const plugins: JupyterFrontEndPlugin<any>[] = [
|
||||||
|
doc,
|
||||||
|
kernelLogo,
|
||||||
|
logo,
|
||||||
|
main,
|
||||||
|
paths,
|
||||||
|
router,
|
||||||
|
sessionDialogs,
|
||||||
|
shell,
|
||||||
|
spacer,
|
||||||
|
title,
|
||||||
|
translator,
|
||||||
|
tree
|
||||||
|
];
|
||||||
|
|
||||||
|
export default plugins;
|
38
packages/application-extension/style/base.css
Normal file
38
packages/application-extension/style/base.css
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
| Copyright (c) Jupyter Development Team.
|
||||||
|
|
|
||||||
|
| Distributed under the terms of the Modified BSD License.
|
||||||
|
|----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.jp-ClassicSpacer {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jp-ClassicKernelLogo {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jp-ClassicKernelLogo img {
|
||||||
|
max-width: 28px;
|
||||||
|
max-height: 28px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#jp-title h1 {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 18px;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
color: var(--jp-ui-font-color0);
|
||||||
|
font-family: var(--jp-ui-font-family);
|
||||||
|
line-height: calc(1.5 * var(--jp-private-title-panel-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
#jp-title h1:hover {
|
||||||
|
background: var(--jp-layout-color2);
|
||||||
|
}
|
4
packages/application-extension/style/index.css
Normal file
4
packages/application-extension/style/index.css
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@import url('~@jupyterlab-classic/application/style/index.css');
|
||||||
|
@import url('~@lumino/widgets/style/index.css');
|
||||||
|
|
||||||
|
@import url('./base.css');
|
13
packages/application-extension/tsconfig.json
Normal file
13
packages/application-extension/tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfigbase",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"include": ["src/*"],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../application"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1
packages/application/babel.config.js
Normal file
1
packages/application/babel.config.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('@jupyterlab/testutils/lib/babel.config');
|
22
packages/application/jest.config.js
Normal file
22
packages/application/jest.config.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
const func = require('@jupyterlab/testutils/lib/jest-config');
|
||||||
|
const upstream = func(__dirname);
|
||||||
|
|
||||||
|
let local = {
|
||||||
|
preset: 'ts-jest/presets/js-with-babel',
|
||||||
|
transformIgnorePatterns: ['/node_modules/(?!(@jupyterlab/.*)/)'],
|
||||||
|
globals: {
|
||||||
|
'ts-jest': {
|
||||||
|
tsconfig: './tsconfig.test.json'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
transform: {
|
||||||
|
'\\.(ts|tsx)?$': 'ts-jest',
|
||||||
|
'\\.svg$': 'jest-raw-loader'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.keys(local).forEach(option => {
|
||||||
|
upstream[option] = local[option];
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = upstream;
|
67
packages/application/package.json
Normal file
67
packages/application/package.json
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"name": "@jupyterlab-classic/application",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "JupyterLab Classic - Application",
|
||||||
|
"homepage": "https://github.com/jtpio/jupyterlab-classic",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/jtpio/jupyterlab-classic/issues"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/jtpio/jupyterlab-classic.git"
|
||||||
|
},
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"author": "Project Jupyter",
|
||||||
|
"sideEffects": [
|
||||||
|
"style/*.css"
|
||||||
|
],
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"types": "lib/index.d.ts",
|
||||||
|
"style": "style/index.css",
|
||||||
|
"directories": {
|
||||||
|
"lib": "lib/"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib/*.d.ts",
|
||||||
|
"lib/*.js.map",
|
||||||
|
"lib/*.js",
|
||||||
|
"style/*.css"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc -b",
|
||||||
|
"build:test": "tsc --build tsconfig.test.json",
|
||||||
|
"clean": "rimraf lib && rimraf tsconfig.tsbuildinfo",
|
||||||
|
"docs": "typedoc src",
|
||||||
|
"prepublishOnly": "npm run build",
|
||||||
|
"test": "jest",
|
||||||
|
"test:cov": "jest --collect-coverage",
|
||||||
|
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
|
||||||
|
"test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch",
|
||||||
|
"watch": "tsc -b --watch"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@jupyterlab/application": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/docregistry": "^3.0.0-rc.10",
|
||||||
|
"@jupyterlab/coreutils": "^5.0.0-rc.10",
|
||||||
|
"@jupyterlab/ui-components": "^3.0.0-rc.10",
|
||||||
|
"@lumino/algorithm": "^1.3.3",
|
||||||
|
"@lumino/coreutils": "^1.5.3",
|
||||||
|
"@lumino/messaging": "^1.4.3",
|
||||||
|
"@lumino/signaling": "^1.4.3",
|
||||||
|
"@lumino/widgets": "^1.14.0",
|
||||||
|
"es6-promise": "~4.2.8"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.11.6",
|
||||||
|
"@babel/preset-env": "^7.12.1",
|
||||||
|
"@jupyterlab/testutils": "^3.0.0-rc.10",
|
||||||
|
"@types/jest": "^26.0.10",
|
||||||
|
"jest": "^26.4.2",
|
||||||
|
"rimraf": "~3.0.0",
|
||||||
|
"ts-jest": "^26.3.0",
|
||||||
|
"typescript": "~4.0.3"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
}
|
||||||
|
}
|
129
packages/application/src/app.ts
Normal file
129
packages/application/src/app.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
// Copyright (c) Jupyter Development Team.
|
||||||
|
// Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
import {
|
||||||
|
JupyterFrontEnd,
|
||||||
|
JupyterFrontEndPlugin
|
||||||
|
} from '@jupyterlab/application';
|
||||||
|
|
||||||
|
import { PageConfig } from '@jupyterlab/coreutils';
|
||||||
|
|
||||||
|
import { IClassicShell, ClassicShell } from './shell';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App is the main application class. It is instantiated once and shared.
|
||||||
|
*/
|
||||||
|
export class App extends JupyterFrontEnd<IClassicShell> {
|
||||||
|
/**
|
||||||
|
* Construct a new App object.
|
||||||
|
*
|
||||||
|
* @param options The instantiation options for an application.
|
||||||
|
*/
|
||||||
|
constructor(options: App.IOptions = { shell: new ClassicShell() }) {
|
||||||
|
super({
|
||||||
|
shell: options.shell
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the application.
|
||||||
|
*/
|
||||||
|
readonly name = 'JupyterLab Custom App';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A namespace/prefix plugins may use to denote their provenance.
|
||||||
|
*/
|
||||||
|
readonly namespace = this.name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The version of the application.
|
||||||
|
*/
|
||||||
|
readonly version = 'unknown';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JupyterLab application paths dictionary.
|
||||||
|
*/
|
||||||
|
get paths(): JupyterFrontEnd.IPaths {
|
||||||
|
return {
|
||||||
|
urls: {
|
||||||
|
base: PageConfig.getOption('baseUrl'),
|
||||||
|
notFound: PageConfig.getOption('notFoundUrl'),
|
||||||
|
app: PageConfig.getOption('appUrl'),
|
||||||
|
static: PageConfig.getOption('staticUrl'),
|
||||||
|
settings: PageConfig.getOption('settingsUrl'),
|
||||||
|
themes: PageConfig.getOption('themesUrl'),
|
||||||
|
doc: PageConfig.getOption('docUrl'),
|
||||||
|
translations: PageConfig.getOption('translationsApiUrl'),
|
||||||
|
hubHost: PageConfig.getOption('hubHost') || undefined,
|
||||||
|
hubPrefix: PageConfig.getOption('hubPrefix') || undefined,
|
||||||
|
hubUser: PageConfig.getOption('hubUser') || undefined,
|
||||||
|
hubServerName: PageConfig.getOption('hubServerName') || undefined
|
||||||
|
},
|
||||||
|
directories: {
|
||||||
|
appSettings: PageConfig.getOption('appSettingsDir'),
|
||||||
|
schemas: PageConfig.getOption('schemasDir'),
|
||||||
|
static: PageConfig.getOption('staticDir'),
|
||||||
|
templates: PageConfig.getOption('templatesDir'),
|
||||||
|
themes: PageConfig.getOption('themesDir'),
|
||||||
|
userSettings: PageConfig.getOption('userSettingsDir'),
|
||||||
|
serverRoot: PageConfig.getOption('serverRoot'),
|
||||||
|
workspaces: PageConfig.getOption('workspacesDir')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register plugins from a plugin module.
|
||||||
|
*
|
||||||
|
* @param mod - The plugin module to register.
|
||||||
|
*/
|
||||||
|
registerPluginModule(mod: App.IPluginModule): void {
|
||||||
|
let data = mod.default;
|
||||||
|
// Handle commonjs exports.
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(mod, '__esModule')) {
|
||||||
|
data = mod as any;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(data)) {
|
||||||
|
data = [data];
|
||||||
|
}
|
||||||
|
data.forEach(item => {
|
||||||
|
try {
|
||||||
|
this.registerPlugin(item);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the plugins from multiple plugin modules.
|
||||||
|
*
|
||||||
|
* @param mods - The plugin modules to register.
|
||||||
|
*/
|
||||||
|
registerPluginModules(mods: App.IPluginModule[]): void {
|
||||||
|
mods.forEach(mod => {
|
||||||
|
this.registerPluginModule(mod);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A namespace for App statics.
|
||||||
|
*/
|
||||||
|
export namespace App {
|
||||||
|
/**
|
||||||
|
* The instantiation options for an App application.
|
||||||
|
*/
|
||||||
|
export type IOptions = JupyterFrontEnd.IOptions<IClassicShell>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface for a module that exports a plugin or plugins as
|
||||||
|
* the default value.
|
||||||
|
*/
|
||||||
|
export interface IPluginModule {
|
||||||
|
/**
|
||||||
|
* The default export.
|
||||||
|
*/
|
||||||
|
default: JupyterFrontEndPlugin<any> | JupyterFrontEndPlugin<any>[];
|
||||||
|
}
|
||||||
|
}
|
5
packages/application/src/index.ts
Normal file
5
packages/application/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// Copyright (c) Jupyter Development Team.
|
||||||
|
// Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
export * from './app';
|
||||||
|
export * from './shell';
|
237
packages/application/src/shell.ts
Normal file
237
packages/application/src/shell.ts
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
// Copyright (c) Jupyter Development Team.
|
||||||
|
// Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
import { JupyterFrontEnd } from '@jupyterlab/application';
|
||||||
|
|
||||||
|
import { DocumentRegistry } from '@jupyterlab/docregistry';
|
||||||
|
|
||||||
|
import { ArrayExt, IIterator, iter } from '@lumino/algorithm';
|
||||||
|
import { Token } from '@lumino/coreutils';
|
||||||
|
|
||||||
|
import { Message, MessageLoop, IMessageHandler } from '@lumino/messaging';
|
||||||
|
|
||||||
|
import { ISignal, Signal } from '@lumino/signaling';
|
||||||
|
|
||||||
|
import { Panel, Widget, BoxLayout } from '@lumino/widgets';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JupyterLab Classic application shell token.
|
||||||
|
*/
|
||||||
|
export const IClassicShell = new Token<IClassicShell>(
|
||||||
|
'@jupyterlab-classic/application:IClassicShell'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JupyterLab Classic application shell interface.
|
||||||
|
*/
|
||||||
|
export interface IClassicShell extends ClassicShell {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default rank for ranked panels.
|
||||||
|
*/
|
||||||
|
const DEFAULT_RANK = 900;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application shell.
|
||||||
|
*/
|
||||||
|
export class ClassicShell extends Widget implements JupyterFrontEnd.IShell {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.id = 'main';
|
||||||
|
|
||||||
|
const rootLayout = new BoxLayout();
|
||||||
|
|
||||||
|
this._topHandler = new Private.PanelHandler();
|
||||||
|
this._menu = new Panel();
|
||||||
|
this._main = new Panel();
|
||||||
|
|
||||||
|
this._topHandler.panel.id = 'top-panel';
|
||||||
|
this._menu.id = 'menu-panel';
|
||||||
|
this._main.id = 'main-panel';
|
||||||
|
|
||||||
|
BoxLayout.setStretch(this._topHandler.panel, 0);
|
||||||
|
BoxLayout.setStretch(this._menu, 0);
|
||||||
|
BoxLayout.setStretch(this._main, 1);
|
||||||
|
|
||||||
|
const spacer = new Widget();
|
||||||
|
spacer.node.style.minHeight = '16px';
|
||||||
|
|
||||||
|
rootLayout.spacing = 0;
|
||||||
|
rootLayout.addWidget(this._topHandler.panel);
|
||||||
|
rootLayout.addWidget(this._menu);
|
||||||
|
rootLayout.addWidget(spacer);
|
||||||
|
rootLayout.addWidget(this._main);
|
||||||
|
|
||||||
|
this.layout = rootLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
activateById(id: string): void {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a widget to the application shell.
|
||||||
|
*
|
||||||
|
* @param widget - The widget being added.
|
||||||
|
*
|
||||||
|
* @param area - Optional region in the shell into which the widget should
|
||||||
|
* be added.
|
||||||
|
*
|
||||||
|
* @param options - Optional open options.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
add(
|
||||||
|
widget: Widget,
|
||||||
|
area?: Shell.Area,
|
||||||
|
options?: DocumentRegistry.IOpenOptions
|
||||||
|
): void {
|
||||||
|
if (area === 'top') {
|
||||||
|
const rank = options?.rank ?? DEFAULT_RANK;
|
||||||
|
return this._topHandler.addWidget(widget, rank);
|
||||||
|
}
|
||||||
|
if (area === 'menu') {
|
||||||
|
return this._menu.addWidget(widget);
|
||||||
|
}
|
||||||
|
this._main.widgets.forEach(w => {
|
||||||
|
w.close();
|
||||||
|
});
|
||||||
|
this._main.addWidget(widget);
|
||||||
|
this._main.update();
|
||||||
|
this._currentChanged.emit(void 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A signal emitted when the current widget changes.
|
||||||
|
*/
|
||||||
|
get currentChanged(): ISignal<ClassicShell, void> {
|
||||||
|
return this._currentChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current widget in the shell's main area.
|
||||||
|
*/
|
||||||
|
get currentWidget(): Widget {
|
||||||
|
return this._main.widgets[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of widgets for the given area.
|
||||||
|
*
|
||||||
|
* @param area The area
|
||||||
|
*/
|
||||||
|
widgets(area: Shell.Area): IIterator<Widget> {
|
||||||
|
if (area === 'top') {
|
||||||
|
return iter(this._topHandler.panel.widgets);
|
||||||
|
}
|
||||||
|
if (area === 'menu') {
|
||||||
|
return iter(this._menu.widgets);
|
||||||
|
}
|
||||||
|
return iter(this._main.widgets);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _topHandler: Private.PanelHandler;
|
||||||
|
private _menu: Panel;
|
||||||
|
private _main: Panel;
|
||||||
|
private _currentChanged = new Signal<this, void>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A namespace for Shell statics
|
||||||
|
*/
|
||||||
|
export namespace Shell {
|
||||||
|
/**
|
||||||
|
* The areas of the application shell where widgets can reside.
|
||||||
|
*/
|
||||||
|
export type Area = 'main' | 'top' | 'menu';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A namespace for private module data.
|
||||||
|
*/
|
||||||
|
namespace Private {
|
||||||
|
/**
|
||||||
|
* An object which holds a widget and its sort rank.
|
||||||
|
*/
|
||||||
|
export interface IRankItem {
|
||||||
|
/**
|
||||||
|
* The widget for the item.
|
||||||
|
*/
|
||||||
|
widget: Widget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sort rank of the widget.
|
||||||
|
*/
|
||||||
|
rank: number;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* A less-than comparison function for side bar rank items.
|
||||||
|
*/
|
||||||
|
export function itemCmp(first: IRankItem, second: IRankItem): number {
|
||||||
|
return first.rank - second.rank;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class which manages a panel and sorts its widgets by rank.
|
||||||
|
*/
|
||||||
|
export class PanelHandler {
|
||||||
|
constructor() {
|
||||||
|
MessageLoop.installMessageHook(this._panel, this._panelChildHook);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the panel managed by the handler.
|
||||||
|
*/
|
||||||
|
get panel(): Panel {
|
||||||
|
return this._panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a widget to the panel.
|
||||||
|
*
|
||||||
|
* If the widget is already added, it will be moved.
|
||||||
|
*/
|
||||||
|
addWidget(widget: Widget, rank: number): void {
|
||||||
|
widget.parent = null;
|
||||||
|
const item = { widget, rank };
|
||||||
|
const index = ArrayExt.upperBound(this._items, item, Private.itemCmp);
|
||||||
|
ArrayExt.insert(this._items, index, item);
|
||||||
|
this._panel.insertWidget(index, widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message hook for child add/remove messages on the main area dock panel.
|
||||||
|
*/
|
||||||
|
private _panelChildHook = (
|
||||||
|
handler: IMessageHandler,
|
||||||
|
msg: Message
|
||||||
|
): boolean => {
|
||||||
|
switch (msg.type) {
|
||||||
|
case 'child-added':
|
||||||
|
{
|
||||||
|
const widget = (msg as Widget.ChildMessage).child;
|
||||||
|
// If we already know about this widget, we're done
|
||||||
|
if (this._items.find(v => v.widget === widget)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, add to the end by default
|
||||||
|
const rank = this._items[this._items.length - 1].rank;
|
||||||
|
this._items.push({ widget, rank });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'child-removed':
|
||||||
|
{
|
||||||
|
const widget = (msg as Widget.ChildMessage).child;
|
||||||
|
ArrayExt.removeFirstWhere(this._items, v => v.widget === widget);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _items = new Array<Private.IRankItem>();
|
||||||
|
private _panel = new Panel();
|
||||||
|
}
|
||||||
|
}
|
40
packages/application/style/base.css
Normal file
40
packages/application/style/base.css
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
| Copyright (c) Jupyter Development Team.
|
||||||
|
| Distributed under the terms of the Modified BSD License.
|
||||||
|
|----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: var(--jp-layout-color2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#main {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-width: 1200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#top-panel {
|
||||||
|
display: flex;
|
||||||
|
border-bottom: var(--jp-border-width) solid var(--jp-border-color0);
|
||||||
|
background: var(--jp-layout-color1);
|
||||||
|
min-height: calc(1.5 * var(--jp-private-menubar-height));
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-panel {
|
||||||
|
display: flex;
|
||||||
|
min-height: var(--jp-private-menu-panel-height);
|
||||||
|
background: var(--jp-layout-color1);
|
||||||
|
border-bottom: var(--jp-border-width) solid var(--jp-border-color0);
|
||||||
|
box-shadow: var(--jp-elevation-z1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-panel {
|
||||||
|
box-shadow: var(--jp-elevation-z4);
|
||||||
|
}
|
10
packages/application/style/index.css
Normal file
10
packages/application/style/index.css
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
| Copyright (c) Jupyter Development Team.
|
||||||
|
| Distributed under the terms of the Modified BSD License.
|
||||||
|
|----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
@import url('~@jupyterlab/application/style/index.css');
|
||||||
|
@import url('~@jupyterlab/mainmenu/style/index.css');
|
||||||
|
@import url('~@jupyterlab/ui-components/style/index.css');
|
||||||
|
|
||||||
|
@import url('./base.css');
|
13
packages/application/test/shell.spec.ts
Normal file
13
packages/application/test/shell.spec.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (c) Jupyter Development Team.
|
||||||
|
// Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
import { Shell } from '@jupyterlab-classic/application';
|
||||||
|
|
||||||
|
describe('Shell', () => {
|
||||||
|
describe('#constructor()', () => {
|
||||||
|
it('should create a LabShell instance', () => {
|
||||||
|
const shell = new Shell();
|
||||||
|
expect(shell).toBeInstanceOf(Shell);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
8
packages/application/tsconfig.json
Normal file
8
packages/application/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfigbase",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"]
|
||||||
|
}
|
9
packages/application/tsconfig.test.json
Normal file
9
packages/application/tsconfig.test.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfigbase.test",
|
||||||
|
"include": ["src/**/*", "test/**/*"],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1
packages/ui-components/babel.config.js
Normal file
1
packages/ui-components/babel.config.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('@jupyterlab/testutils/lib/babel.config');
|
2
packages/ui-components/jest.config.js
Normal file
2
packages/ui-components/jest.config.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
const func = require('@jupyterlab/testutils/lib/jest-config');
|
||||||
|
module.exports = func(__dirname);
|
60
packages/ui-components/package.json
Normal file
60
packages/ui-components/package.json
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"name": "@jupyterlab-classic/ui-components",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "JupyterLab Classic - UI components",
|
||||||
|
"homepage": "https://github.com/jtpio/jupyterlab-classic",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/jtpio/jupyterlab-classic/issues"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/jtpio/jupyterlab-classic.git"
|
||||||
|
},
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"author": "Project Jupyter",
|
||||||
|
"sideEffects": [
|
||||||
|
"style/**/*"
|
||||||
|
],
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"types": "lib/index.d.ts",
|
||||||
|
"style": "style/index.css",
|
||||||
|
"directories": {
|
||||||
|
"lib": "lib/"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
|
||||||
|
"style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc -b",
|
||||||
|
"build:test": "tsc --build tsconfig.test.json",
|
||||||
|
"clean": "rimraf lib && rimraf tsconfig.tsbuildinfo",
|
||||||
|
"cleansvg": "svgo --config svgo.yaml",
|
||||||
|
"docs": "typedoc src",
|
||||||
|
"docs:init": "bash docs/build.sh",
|
||||||
|
"prepublishOnly": "npm run build",
|
||||||
|
"storybook": "start-storybook -p 9001 -c .storybook",
|
||||||
|
"test": "jest",
|
||||||
|
"test:cov": "jest --collect-coverage",
|
||||||
|
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
|
||||||
|
"test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch",
|
||||||
|
"watch": "tsc -b --watch"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@jupyterlab/ui-components": "^3.0.0-rc.10"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.10.2",
|
||||||
|
"@babel/preset-env": "^7.10.2",
|
||||||
|
"@jupyterlab/testutils": "^3.0.0-rc.10",
|
||||||
|
"@types/jest": "^26.0.10",
|
||||||
|
"babel-loader": "^8.0.6",
|
||||||
|
"jest": "^26.4.2",
|
||||||
|
"rimraf": "~3.0.0",
|
||||||
|
"ts-jest": "^26.3.0",
|
||||||
|
"typescript": "~4.0.2"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
}
|
||||||
|
}
|
13
packages/ui-components/src/icon/iconimports.ts
Normal file
13
packages/ui-components/src/icon/iconimports.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
| Copyright (c) Jupyter Development Team.
|
||||||
|
| Distributed under the terms of the Modified BSD License.
|
||||||
|
|----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { LabIcon } from '@jupyterlab/ui-components';
|
||||||
|
|
||||||
|
import jupyterSvgstr from '../../style/icons/jupyter.svg';
|
||||||
|
|
||||||
|
export const jupyterIcon = new LabIcon({
|
||||||
|
name: 'classic-ui-components:jupyter',
|
||||||
|
svgstr: jupyterSvgstr
|
||||||
|
});
|
4
packages/ui-components/src/icon/index.ts
Normal file
4
packages/ui-components/src/icon/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// Copyright (c) Jupyter Development Team.
|
||||||
|
// Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
export * from './iconimports';
|
4
packages/ui-components/src/index.ts
Normal file
4
packages/ui-components/src/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// Copyright (c) Jupyter Development Team.
|
||||||
|
// Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
export * from './icon';
|
7
packages/ui-components/src/svg.d.ts
vendored
Normal file
7
packages/ui-components/src/svg.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// Copyright (c) Jupyter Development Team.
|
||||||
|
// Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
declare module '*.svg' {
|
||||||
|
const value: string;
|
||||||
|
export default value;
|
||||||
|
}
|
0
packages/ui-components/style/base.css
Normal file
0
packages/ui-components/style/base.css
Normal file
88
packages/ui-components/style/icons/jupyter.svg
Normal file
88
packages/ui-components/style/icons/jupyter.svg
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<svg width="189" height="51" viewBox="0 0 189 51" version="2.0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:figma="http://www.figma.com/figma/ns">
|
||||||
|
<title>logo.svg</title>
|
||||||
|
<desc>Created using Figma 0.90</desc>
|
||||||
|
<g id="Canvas" transform="translate(-1638 -2093)" figma:type="canvas">
|
||||||
|
<g id="logo" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="Group" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="g" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path0 fill" style="mix-blend-mode:normal;" figma:type="vector">
|
||||||
|
<use xlink:href="#path0_fill" transform="translate(1688.87 2106.23)" fill="#4E4E4E" style="mix-blend-mode:normal;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="path" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path1 fill" style="mix-blend-mode:normal;" figma:type="vector">
|
||||||
|
<use xlink:href="#path1_fill" transform="translate(1705.38 2106.19)" fill="#4E4E4E" style="mix-blend-mode:normal;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="path" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path2 fill" style="mix-blend-mode:normal;" figma:type="vector">
|
||||||
|
<use xlink:href="#path2_fill" transform="translate(1730.18 2105.67)" fill="#4E4E4E" style="mix-blend-mode:normal;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="path" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path3 fill" style="mix-blend-mode:normal;" figma:type="vector">
|
||||||
|
<use xlink:href="#path3_fill" transform="translate(1752.94 2106.21)" fill="#4E4E4E" style="mix-blend-mode:normal;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="path" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path4 fill" style="mix-blend-mode:normal;" figma:type="vector">
|
||||||
|
<use xlink:href="#path4_fill" transform="translate(1775.8 2100.04)" fill="#4E4E4E" style="mix-blend-mode:normal;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="path" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path5 fill" style="mix-blend-mode:normal;" figma:type="vector">
|
||||||
|
<use xlink:href="#path5_fill" transform="translate(1791.75 2105.71)" fill="#4E4E4E" style="mix-blend-mode:normal;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="path" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path6 fill" style="mix-blend-mode:normal;" figma:type="vector">
|
||||||
|
<use xlink:href="#path6_fill" transform="translate(1815.77 2105.72)" fill="#4E4E4E" style="mix-blend-mode:normal;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="g" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path7 fill" style="mix-blend-mode:normal;" figma:type="vector">
|
||||||
|
<use xlink:href="#path7_fill" transform="translate(1669.3 2093.31)" fill="#767677" style="mix-blend-mode:normal;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="path" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path8 fill" style="mix-blend-mode:normal;" figma:type="vector">
|
||||||
|
<use xlink:href="#path8_fill" transform="translate(1639.74 2123.98)" fill="#F37726" style="mix-blend-mode:normal;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="path" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path9 fill" style="mix-blend-mode:normal;" figma:type="vector">
|
||||||
|
<use xlink:href="#path9_fill" transform="translate(1639.73 2097.48)" fill="#F37726" style="mix-blend-mode:normal;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="path" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path10 fill" style="mix-blend-mode:normal;" figma:type="vector">
|
||||||
|
<use xlink:href="#path10_fill" transform="translate(1639.8 2135.81)" fill="#989798" style="mix-blend-mode:normal;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="path" style="mix-blend-mode:normal;" figma:type="group">
|
||||||
|
<g id="path11 fill" style="mix-blend-mode:normal;" figma:type="vector">
|
||||||
|
<use xlink:href="#path11_fill" transform="translate(1638.36 2098.06)" fill="#6F7070" style="mix-blend-mode:normal;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<path id="path0_fill" d="M 5.62592 17.9276C 5.62592 23.0737 5.23342 24.7539 4.18673 25.9942C 3.04416 27.0501 1.54971 27.6341 0 27.6304L 0.392506 30.6916C 2.79452 30.7249 5.12302 29.8564 6.92556 28.255C 8.80086 26.3021 9.45504 23.6015 9.45504 19.4583L 9.45504 0L 5.6172 0L 5.6172 17.954L 5.62592 17.9276Z"/>
|
||||||
|
<path id="path1_fill" d="M 17.7413 15.6229C 17.7413 17.8397 17.7413 19.7925 17.9157 21.4727L 14.5576 21.4727L 14.3396 17.954L 14.2523 17.954C 13.5454 19.1838 12.5262 20.2013 11.2997 20.9017C 10.0732 21.6022 8.68377 21.9602 7.27445 21.9389C 3.95995 21.9389 0 20.074 0 12.5441L 0 0L 3.83784 0L 3.83784 11.9019C 3.83784 15.9836 5.05897 18.7281 8.53919 18.7281C 9.63092 18.708 10.6925 18.3634 11.5908 17.7374C 12.4892 17.1115 13.1844 16.2321 13.5894 15.2095C 13.8222 14.57 13.9404 13.8938 13.9383 13.2126L 13.9383 0.0175934L 17.7762 0.0175934L 17.7762 15.6229L 17.7413 15.6229Z"/>
|
||||||
|
<path id="path2_fill" d="M 0.174447 7.53632C 0.174447 4.79175 0.0872236 2.57499 0 0.498968L 3.44533 0.498968L 3.61978 4.17598L 3.707 4.17598C 4.46074 2.85853 5.55705 1.77379 6.87754 1.03893C 8.19802 0.304077 9.69248 -0.0529711 11.1995 0.0063534C 16.2934 0.0063534 20.1312 4.4047 20.1312 10.9142C 20.1312 18.6289 15.5171 22.4379 10.5366 22.4379C 9.25812 22.492 7.98766 22.2098 6.84994 21.6192C 5.71222 21.0285 4.74636 20.1496 4.04718 19.0688L 3.95995 19.0688L 3.95995 30.7244L 0.165725 30.7244L 0.165725 7.50113L 0.174447 7.53632ZM 3.96868 13.2542C 3.97869 13.7891 4.03708 14.3221 4.14312 14.8464C 4.45574 16.1467 5.19222 17.3035 6.23449 18.1313C 7.27677 18.9592 8.56446 19.4101 9.89116 19.4118C 13.9471 19.4118 16.2934 16.0427 16.2934 11.1254C 16.2934 6.82378 14.0692 3.14677 10.022 3.14677C 8.66089 3.18518 7.35158 3.68134 6.30219 4.55638C 5.25279 5.43143 4.52354 6.63513 4.23035 7.97615C 4.07662 8.49357 3.98869 9.02858 3.96868 9.56835L 3.96868 13.2454L 3.96868 13.2542Z"/>
|
||||||
|
<path id="path3_fill" d="M 4.16057 0L 8.7747 12.676C 9.25443 14.0923 9.77777 15.7813 10.1267 17.0744L 10.2139 17.0744C 10.6064 15.7901 11.0425 14.1451 11.5659 12.5969L 15.7526 0.00879669L 19.8085 0.00879669L 14.0604 15.3062C 11.3129 22.6603 9.44632 26.434 6.82961 28.7388C 5.50738 29.9791 3.88672 30.8494 2.12826 31.2634L 1.1688 27.9823C 2.39912 27.5689 3.53918 26.9208 4.52691 26.0734C 5.92259 24.8972 7.02752 23.4094 7.75418 21.7278C 7.90932 21.4374 8.01266 21.1218 8.05946 20.7954C 8.02501 20.4436 7.93674 20.0994 7.79779 19.7749L 0 0.00879669L 4.18673 0.00879669L 4.16057 0Z"/>
|
||||||
|
<path id="path4_fill" d="M 7.0215 0L 7.0215 6.15768L 12.5079 6.15768L 12.5079 9.13096L 7.0215 9.13096L 7.0215 20.6898C 7.0215 23.3288 7.7629 24.8594 9.89988 24.8594C 10.6496 24.8712 11.3975 24.7824 12.1241 24.5955L 12.2985 27.5248C 11.207 27.9125 10.0534 28.0915 8.89681 28.0526C 8.1298 28.1 7.36177 27.9782 6.64622 27.6956C 5.93068 27.413 5.28484 26.9765 4.75369 26.4164C 3.66339 25.2641 3.27089 23.3552 3.27089 20.8306L 3.27089 9.13096L 0 9.13096L 0 6.15768L 3.27089 6.15768L 3.27089 1.01162L 7.0215 0Z"/>
|
||||||
|
<path id="path5_fill" d="M 3.6285 11.9283C 3.71573 17.2063 7.03022 19.3791 10.8593 19.3791C 12.8612 19.4425 14.8527 19.0642 16.6946 18.2707L 17.3488 21.0593C 15.1419 21.994 12.7638 22.4467 10.3709 22.3876C 3.88145 22.3876 0 18.042 0 11.5676C 0 5.09328 3.75062 0 9.89116 0C 16.7731 0 18.6135 6.15768 18.6135 10.1074C 18.607 10.7165 18.5634 11.3246 18.4827 11.9283L 3.65467 11.9283L 3.6285 11.9283ZM 14.8716 9.13976C 14.9152 6.65909 13.8686 2.79735 9.55971 2.79735C 5.67826 2.79735 3.98612 6.43038 3.68084 9.13976L 14.8803 9.13976L 14.8716 9.13976Z"/>
|
||||||
|
<path id="path6_fill" d="M 0.174447 7.17854C 0.174447 4.65389 0.130835 2.48111 0 0.484261L 3.35811 0.484261L 3.48894 4.69787L 3.66339 4.69787C 4.62285 1.81256 6.93428 0.00044283 9.49865 0.00044283C 9.8663 -0.0049786 10.233 0.0394012 10.5889 0.132393L 10.5889 3.80941C 10.1593 3.71494 9.72029 3.67067 9.28059 3.67746C 6.57666 3.67746 4.66646 5.76227 4.14312 8.68277C 4.03516 9.28384 3.97681 9.89289 3.96867 10.5037L 3.96867 21.9394L 0.174447 21.9394L 0.174447 7.17854Z"/>
|
||||||
|
<path id="path7_fill" d="M 5.89353 2.844C 5.91889 3.43165 5.77085 4.01367 5.46815 4.51645C 5.16545 5.01922 4.72168 5.42015 4.19299 5.66851C 3.6643 5.91688 3.07444 6.00151 2.49805 5.91171C 1.92166 5.8219 1.38463 5.5617 0.954898 5.16401C 0.52517 4.76633 0.222056 4.24903 0.0839037 3.67757C -0.0542483 3.10611 -0.02123 2.50617 0.178781 1.95364C 0.378793 1.4011 0.736809 0.920817 1.20754 0.573538C 1.67826 0.226259 2.24055 0.0275919 2.82326 0.00267229C 3.60389 -0.0307115 4.36573 0.249789 4.94142 0.782551C 5.51711 1.31531 5.85956 2.05676 5.89353 2.844Z"/>
|
||||||
|
<path id="path8_fill" d="M 18.2646 7.13411C 10.4145 7.13411 3.55872 4.2576 0 0C 1.32539 3.8204 3.79556 7.13081 7.0686 9.47303C 10.3417 11.8152 14.2557 13.0734 18.269 13.0734C 22.2823 13.0734 26.1963 11.8152 29.4694 9.47303C 32.7424 7.13081 35.2126 3.8204 36.538 0C 32.9705 4.2576 26.1148 7.13411 18.2646 7.13411Z"/>
|
||||||
|
<path id="path9_fill" d="M 18.2733 5.93931C 26.1235 5.93931 32.9793 8.81583 36.538 13.0734C 35.2126 9.25303 32.7424 5.94262 29.4694 3.6004C 26.1963 1.25818 22.2823 0 18.269 0C 14.2557 0 10.3417 1.25818 7.0686 3.6004C 3.79556 5.94262 1.32539 9.25303 0 13.0734C 3.56745 8.82463 10.4232 5.93931 18.2733 5.93931Z"/>
|
||||||
|
<path id="path10_fill" d="M 7.42789 3.58338C 7.46008 4.3243 7.27355 5.05819 6.89193 5.69213C 6.51031 6.32607 5.95075 6.83156 5.28411 7.1446C 4.61747 7.45763 3.87371 7.56414 3.14702 7.45063C 2.42032 7.33712 1.74336 7.0087 1.20184 6.50695C 0.660328 6.0052 0.27861 5.35268 0.105017 4.63202C -0.0685757 3.91135 -0.0262361 3.15494 0.226675 2.45856C 0.479587 1.76217 0.931697 1.15713 1.52576 0.720033C 2.11983 0.282935 2.82914 0.0334395 3.56389 0.00313344C 4.54667 -0.0374033 5.50529 0.316706 6.22961 0.987835C 6.95393 1.65896 7.38484 2.59235 7.42789 3.58338L 7.42789 3.58338Z"/>
|
||||||
|
<path id="path11_fill" d="M 2.27471 4.39629C 1.84363 4.41508 1.41671 4.30445 1.04799 4.07843C 0.679268 3.8524 0.385328 3.52114 0.203371 3.12656C 0.0214136 2.73198 -0.0403798 2.29183 0.0258116 1.86181C 0.0920031 1.4318 0.283204 1.03126 0.575213 0.710883C 0.867222 0.39051 1.24691 0.164708 1.66622 0.0620592C 2.08553 -0.0405897 2.52561 -0.0154714 2.93076 0.134235C 3.33591 0.283941 3.68792 0.551505 3.94222 0.90306C 4.19652 1.25462 4.34169 1.67436 4.35935 2.10916C 4.38299 2.69107 4.17678 3.25869 3.78597 3.68746C 3.39516 4.11624 2.85166 4.37116 2.27471 4.39629L 2.27471 4.39629Z"/>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 9.8 KiB |
6
packages/ui-components/style/index.css
Normal file
6
packages/ui-components/style/index.css
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
| Copyright (c) Jupyter Development Team.
|
||||||
|
| Distributed under the terms of the Modified BSD License.
|
||||||
|
|----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
@import url('./base.css');
|
10
packages/ui-components/test/foo.spec.ts
Normal file
10
packages/ui-components/test/foo.spec.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright (c) Jupyter Development Team.
|
||||||
|
// Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
describe('foo', () => {
|
||||||
|
describe('bar', () => {
|
||||||
|
it('should pass', () => {
|
||||||
|
expect(true).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
8
packages/ui-components/tsconfig.json
Normal file
8
packages/ui-components/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfigbase",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"]
|
||||||
|
}
|
9
packages/ui-components/tsconfig.test.json
Normal file
9
packages/ui-components/tsconfig.test.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfigbase.test",
|
||||||
|
"include": ["src/**/*", "test/**/*"],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
3
pyproject.toml
Normal file
3
pyproject.toml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["jupyter_packaging~=0.7.0", "jupyterlab>=3.0.0rc10,==3.*", "setuptools>=40.8.0", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
59
setup.py
Normal file
59
setup.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
"""
|
||||||
|
jupyterlab-classic setup
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
|
from jupyter_packaging import get_version
|
||||||
|
import setuptools
|
||||||
|
|
||||||
|
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
# The name of the project
|
||||||
|
NAME = "jupyterlab-classic"
|
||||||
|
PACKAGE_NAME = NAME.replace("-", "_")
|
||||||
|
|
||||||
|
# Get our version
|
||||||
|
version = get_version(os.path.join(PACKAGE_NAME, "_version.py"))
|
||||||
|
|
||||||
|
with open("README.md", "r") as fh:
|
||||||
|
long_description = fh.read()
|
||||||
|
|
||||||
|
setup_args = dict(
|
||||||
|
name=NAME,
|
||||||
|
version=version,
|
||||||
|
url="https://github.com/jtpio/jupyterlab-classic",
|
||||||
|
author="Jeremy Tuloup",
|
||||||
|
description="The next gen old-school Notebook UI",
|
||||||
|
long_description=long_description,
|
||||||
|
long_description_content_type="text/markdown",
|
||||||
|
data_files=[
|
||||||
|
(
|
||||||
|
"etc/jupyter/jupyter_server_config.d",
|
||||||
|
["jupyter-config/jupyter_server_config.d/jupyterlab_classic.json"],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
packages=setuptools.find_packages(),
|
||||||
|
install_requires=[
|
||||||
|
"jupyterlab>=3.0.0rc10,==3.*",
|
||||||
|
],
|
||||||
|
zip_safe=False,
|
||||||
|
include_package_data=True,
|
||||||
|
python_requires=">=3.6",
|
||||||
|
license="BSD-3-Clause",
|
||||||
|
platforms="Linux, Mac OS X, Windows",
|
||||||
|
keywords=["Jupyter", "JupyterLab", "Notebook"],
|
||||||
|
classifiers=[
|
||||||
|
"License :: OSI Approved :: BSD License",
|
||||||
|
"Programming Language :: Python",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.6",
|
||||||
|
"Programming Language :: Python :: 3.7",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Framework :: Jupyter",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
setuptools.setup(**setup_args)
|
5
tsconfig.eslint.json
Normal file
5
tsconfig.eslint.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfigbase",
|
||||||
|
"include": ["packages/**/*", "builder/**/*"],
|
||||||
|
"types": ["jest"]
|
||||||
|
}
|
22
tsconfig.test.json
Normal file
22
tsconfig.test.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": true,
|
||||||
|
"noEmitOnError": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"target": "es2015",
|
||||||
|
"lib": [
|
||||||
|
"es2015",
|
||||||
|
"es2015.collection",
|
||||||
|
"dom",
|
||||||
|
"es2015.iterable",
|
||||||
|
"es2017.object"
|
||||||
|
],
|
||||||
|
"types": ["jest"],
|
||||||
|
"jsx": "react",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true
|
||||||
|
}
|
||||||
|
}
|
22
tsconfigbase.json
Normal file
22
tsconfigbase.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"composite": true,
|
||||||
|
"declaration": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"incremental": true,
|
||||||
|
"jsx": "react",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"noEmitOnError": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"preserveWatchOutput": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"target": "es2017",
|
||||||
|
"types": []
|
||||||
|
}
|
||||||
|
}
|
25
tsconfigbase.test.json
Normal file
25
tsconfigbase.test.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noEmitOnError": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"target": "es2015",
|
||||||
|
"outDir": "lib",
|
||||||
|
"lib": [
|
||||||
|
"es2015",
|
||||||
|
"es2015.collection",
|
||||||
|
"dom",
|
||||||
|
"es2015.iterable",
|
||||||
|
"es2017.object"
|
||||||
|
],
|
||||||
|
"types": ["jest", "node"],
|
||||||
|
"jsx": "react",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"skipLibCheck": true
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user