Support for opening new terminals via the URL

This commit is contained in:
Jeremy Tuloup 2020-12-09 20:55:49 +01:00
parent ab0ee41a86
commit ffbaab1e23
12 changed files with 173 additions and 3 deletions

View File

@ -99,6 +99,8 @@ async function main() {
),
require('@jupyterlab/rendermime-extension'),
require('@jupyterlab/shortcuts-extension'),
// so new terminals can be create from the menu
require('@jupyterlab/terminal-extension'),
require('@jupyterlab/theme-light-extension'),
require('@jupyterlab/theme-dark-extension')
];
@ -113,7 +115,7 @@ async function main() {
].includes(id)
),
require('@jupyterlab/running-extension'),
require('@jupyterlab/terminal-extension')
require('@jupyterlab-classic/terminal-extension')
]);
} else if (page === 'notebooks') {
mods = mods.concat([
@ -139,6 +141,8 @@ async function main() {
['@jupyterlab-classic/tree-extension:factory'].includes(id)
)
]);
} else if (page === 'terminals') {
mods = mods.concat([require('@jupyterlab-classic/terminal-extension')]);
}
const extension_data = JSON.parse(

View File

@ -14,6 +14,7 @@
"@jupyterlab-classic/application-extension": "^0.1.0",
"@jupyterlab-classic/docmanager-extension": "^0.1.0",
"@jupyterlab-classic/notebook-extension": "^0.1.0",
"@jupyterlab-classic/terminal-extension": "^0.1.0",
"@jupyterlab-classic/tree-extension": "^0.1.0",
"@jupyterlab-classic/ui-components": "^0.1.0",
"@jupyterlab/apputils-extension": "^3.0.0-rc.12",

View File

@ -88,6 +88,21 @@ class ClassicTreeHandler(ClassicPageConfigMixin, ExtensionHandlerJinjaMixin, Ext
)
class ClassicTerminalHandler(ClassicPageConfigMixin, ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler):
@web.authenticated
def get(self, path=None):
page_config = self.get_page_config()
page_config['terminalsAvailable'] = self.settings['terminals_available']
return self.write(
self.render_template(
"terminals.html",
base_url=self.base_url,
token=self.settings["token"],
page_config=page_config,
)
)
class ClassicFileHandler(ClassicPageConfigMixin, ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler):
@web.authenticated
def get(self, path=None):
@ -101,6 +116,7 @@ class ClassicFileHandler(ClassicPageConfigMixin, ExtensionHandlerJinjaMixin, Ext
)
)
class ClassicNotebookHandler(ClassicPageConfigMixin, ExtensionHandlerJinjaMixin, ExtensionHandlerMixin, JupyterHandler):
@web.authenticated
def get(self, path=None):
@ -133,6 +149,7 @@ class ClassicApp(NBClassicConfigShimMixin, LabServerApp):
self.handlers.append(("/classic/tree(.*)", ClassicTreeHandler))
self.handlers.append(("/classic/notebooks(.*)", ClassicNotebookHandler))
self.handlers.append(("/classic/edit(.*)", ClassicFileHandler))
self.handlers.append(("/classic/terminals/(.*)", ClassicTerminalHandler))
def initialize_templates(self):
super().initialize_templates()

View File

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

View File

@ -13,3 +13,7 @@
.jp-Document {
height: 100%;
}
.jp-MainAreaWidget {
height: 100%;
}

View File

@ -102,7 +102,7 @@ export class ClassicShell extends Widget implements JupyterFrontEnd.IShell {
if (area === 'menu') {
return this._menuHandler.addWidget(widget, rank);
}
if (area === 'main') {
if (area === 'main' || area === undefined) {
if (this._main.widgets.length > 0) {
// do not add the widget if there is already one
// TODO: should the widget be closed?

View File

@ -0,0 +1,52 @@
{
"name": "@jupyterlab-classic/terminal-extension",
"version": "0.1.0",
"description": "JupyterLab Classic - Terminal 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/application": "^3.0.0-rc.12",
"@jupyterlab/terminal": "^3.0.0-rc.12"
},
"devDependencies": {
"rimraf": "~3.0.0",
"typescript": "~4.0.2"
},
"publishConfig": {
"access": "public"
},
"jupyterlab": {
"extension": true
}
}

View File

@ -0,0 +1,47 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
import {
IRouter,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '@jupyterlab/application';
/**
* A plugin to terminals in a new tab
*/
const opener: JupyterFrontEndPlugin<void> = {
id: '@jupyterlab-classic/terminal-extension:opener',
requires: [IRouter],
autoStart: true,
activate: (app: JupyterFrontEnd, router: IRouter) => {
const { commands } = app;
const terminalPattern = new RegExp('/terminals/(.*)');
const command = 'router:terminal';
commands.addCommand(command, {
execute: (args: any) => {
const parsed = args as IRouter.ILocation;
const matches = parsed.path.match(terminalPattern);
if (!matches) {
return;
}
const [, name] = matches;
if (!name) {
return;
}
commands.execute('terminal:open', { name });
}
});
router.register({ command, pattern: terminalPattern });
}
};
/**
* Export the plugins as default.
*/
const plugins: JupyterFrontEndPlugin<any>[] = [opener];
export default plugins;

View File

@ -0,0 +1 @@
@import url('./base.css');

View File

@ -0,0 +1,8 @@
{
"extends": "../../tsconfigbase",
"compilerOptions": {
"outDir": "lib",
"rootDir": "src"
},
"include": ["src/**/*"]
}

View File

@ -2357,7 +2357,7 @@
"@lumino/algorithm" "^1.3.3"
"@lumino/widgets" "^1.16.1"
"@jupyterlab/terminal@^3.0.0-rc.13":
"@jupyterlab/terminal@^3.0.0-rc.12", "@jupyterlab/terminal@^3.0.0-rc.13":
version "3.0.0-rc.13"
resolved "https://registry.yarnpkg.com/@jupyterlab/terminal/-/terminal-3.0.0-rc.13.tgz#3651a03b96691bae22a0562f6a6a22f2f718ff25"
integrity sha512-n1Wl9HAeGvkpuHJIJpd5JUsrTJtrbzDP7XAdWn+SuITdTPxz5cleT5lAxk5jRukN69r9S9nicLig+WHJgQL8AA==