Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JupyterHub integration #6451

Merged
merged 46 commits into from Jun 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
a6e3896
Clarifies exporting, and adds clarification on reveal.js slides workf…
duarteocarmo Jun 5, 2019
254287b
Merge remote-tracking branch 'origin/master' into docs/exporting
duarteocarmo Jun 6, 2019
e80fbf7
wip hub integration
blink1073 Jun 1, 2019
09782b7
integrity
blink1073 Jun 1, 2019
2ed5f9a
integry
blink1073 Jun 3, 2019
2f0d850
integrity
blink1073 Jun 3, 2019
0f74dcb
clean up hub_prefix handling
blink1073 Jun 7, 2019
6de3310
Explicitly type dummy promise as void.
ian-r-rose Jun 6, 2019
610c1a1
Use JupyterFrontEnd.IPaths.
ian-r-rose Jun 6, 2019
570d6a9
Use the right pageConfig.
ian-r-rose Jun 7, 2019
ed42fa8
Fix LabHubApp.
ian-r-rose Jun 7, 2019
8f3c6e7
This is an extension.
ian-r-rose Jun 7, 2019
d99a4e3
Add commands to file menu, command palette.
ian-r-rose Jun 7, 2019
a33f18d
If running im JupyterHub, provide a dialog that prompts the user to
ian-r-rose Jun 7, 2019
65c7866
Disable chunksSort in HtmlWebpackPlugin
mlucool Jun 7, 2019
864aa69
Adds note about nbconvert options. Closes #5018
duarteocarmo Jun 7, 2019
e7cd812
Merge pull request #6500 from mlucool/fix-htmlwebpack-plugin
blink1073 Jun 7, 2019
726ce5e
Make kernel message typing follow the spec more closely.
jasongrout May 29, 2019
ca4a22e
Fix a promise typing.
jasongrout Jun 7, 2019
681d7da
Fix test compilation errors.
jasongrout Jun 7, 2019
7eba2ae
Fix services test errors.
jasongrout Jun 7, 2019
3d998b3
Only write to text if the text would change
jasongrout Jun 7, 2019
129b2b9
Make the DefaultSession own (create and dispose) its kernel connection.
jasongrout Jun 7, 2019
eafd1f9
Merge pull request #6472 from duarteocarmo/docs/exporting
blink1073 Jun 8, 2019
a276231
Merge pull request #6502 from jasongrout/safari
blink1073 Jun 8, 2019
244f6be
Merge pull request #6503 from jasongrout/duplicatekernel
blink1073 Jun 8, 2019
bd04328
Merge pull request #6433 from jasongrout/kerneltypings
blink1073 Jun 8, 2019
fbdaeff
Add docstring documenting the intended use of LabHubApp.
ian-r-rose Jun 8, 2019
a12b762
Don't append content in rendered output upon rerendering.
ian-r-rose Jun 8, 2019
d25118b
Add tests checking that a model can be re-rendered correctly.
ian-r-rose Jun 8, 2019
a918f2c
Clarify comment.
ian-r-rose Jun 8, 2019
8d36127
Merge pull request #6513 from ian-r-rose/no-append-on-rerender
blink1073 Jun 8, 2019
a9cc9d2
wip hub integration
blink1073 Jun 1, 2019
f034683
integrity
blink1073 Jun 1, 2019
b08ea7e
integry
blink1073 Jun 3, 2019
654a4f8
integrity
blink1073 Jun 3, 2019
a699f51
clean up hub_prefix handling
blink1073 Jun 7, 2019
43028a1
Explicitly type dummy promise as void.
ian-r-rose Jun 6, 2019
3da56c7
Use JupyterFrontEnd.IPaths.
ian-r-rose Jun 6, 2019
9f14551
Use the right pageConfig.
ian-r-rose Jun 7, 2019
908c2a5
Fix LabHubApp.
ian-r-rose Jun 7, 2019
83ac052
This is an extension.
ian-r-rose Jun 7, 2019
16f274a
Add commands to file menu, command palette.
ian-r-rose Jun 7, 2019
d5e1c61
If running im JupyterHub, provide a dialog that prompts the user to
ian-r-rose Jun 7, 2019
3293670
remove dependency on hub extension
blink1073 Jun 9, 2019
a2f9d2d
Merge branch 'jhub-integration' of https://github.com/blink1073/jupyt…
blink1073 Jun 9, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions dev_mode/package.json
Expand Up @@ -34,6 +34,7 @@
"@jupyterlab/fileeditor-extension": "^1.0.0-alpha.9",
"@jupyterlab/help-extension": "^1.0.0-alpha.9",
"@jupyterlab/htmlviewer-extension": "^1.0.0-alpha.10",
"@jupyterlab/hub-extension": "^1.0.0-alpha.8",
"@jupyterlab/imageviewer": "^1.0.0-alpha.9",
"@jupyterlab/imageviewer-extension": "^1.0.0-alpha.9",
"@jupyterlab/inspector-extension": "^1.0.0-alpha.9",
Expand Down Expand Up @@ -130,6 +131,7 @@
"@jupyterlab/fileeditor-extension": "",
"@jupyterlab/help-extension": "",
"@jupyterlab/htmlviewer-extension": "",
"@jupyterlab/hub-extension": "",
"@jupyterlab/imageviewer-extension": "",
"@jupyterlab/inspector-extension": "",
"@jupyterlab/launcher-extension": "",
Expand Down Expand Up @@ -225,6 +227,7 @@
"@jupyterlab/fileeditor-extension": "../packages/fileeditor-extension",
"@jupyterlab/help-extension": "../packages/help-extension",
"@jupyterlab/htmlviewer-extension": "../packages/htmlviewer-extension",
"@jupyterlab/hub-extension": "../packages/hub-extension",
"@jupyterlab/imageviewer-extension": "../packages/imageviewer-extension",
"@jupyterlab/inspector-extension": "../packages/inspector-extension",
"@jupyterlab/javascript-extension": "../packages/javascript-extension",
Expand Down
1 change: 1 addition & 0 deletions dev_mode/webpack.config.js
Expand Up @@ -122,6 +122,7 @@ const plugins = [
}
}),
new HtmlWebpackPlugin({
chunksSortMode: 'none',
template: path.join('templates', 'template.html'),
title: jlab.name || 'JupyterLab'
}),
Expand Down
1 change: 1 addition & 0 deletions docs/source/index.rst
Expand Up @@ -41,6 +41,7 @@ JupyterLab is the next-generation web-based user interface for Project Jupyter.
user/file_formats
user/extensions
user/jupyterhub
user/export


.. toctree::
Expand Down
52 changes: 52 additions & 0 deletions docs/source/user/export.rst
@@ -0,0 +1,52 @@
.. _user_export:

Exporting Notebooks
-------------------

JupyterLab allows you to export your jupyter notebook files (``.ipynb``)
into other file formats such as:

- Asciidoc ``.asciidoc``
- HTML ``.html``
- Latex ``.tex``
- Markdown ``.md``
- PDF ``.pdf``
- ReStructured Text ``.rst``
- Executable Script ``.py``
- Reveal.js Slides ``.html``

To access these options, while a notebook is open, browse the File menu:

.. image:: images/exporting_menu.png
:align: center
:class: jp-screenshot

Note: The exporting options depend on your nbconvert configuration. For more
information visit the
`official nbconvert documentation <https://nbconvert.readthedocs.io/en/latest/>`__.

.. _user_export_revealjs:

Reveal.js Slides
~~~~~~~~~~~~~~~~
In order to export your notebooks as `Reveal.js <https://github.com/hakimel/reveal.js>`__
slides, follow these steps:

1. Open a notebook by double clicking it in the
:ref:`file browser <working-with-files>`.
2. Select Cell tools in the :ref:`left sidebar <left-sidebar>`.
3. Select the slide type (Slide, Subslide, Fragment, Skip, Notes).

.. image:: images/exporting_slide_type.png
:align: center
:class: jp-screenshot

4. Activate another cell.
5. Repeat 3 and 4 until you selected the slide type for all of your cells.

After completing these steps, browse the file menu and export as described in
the :ref:`exporting notebooks <user_export>` section. A ``.html`` file that
you will be prompted to download.

If you don't know how to navigate and interact with a Reveal.js presentation,
visit the project's `website <https://github.com/hakimel/reveal.js>`__.
Binary file added docs/source/user/images/exporting_menu.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/user/images/exporting_slide_type.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions jupyterlab/extension.py
Expand Up @@ -204,6 +204,14 @@ def load_jupyter_server_extension(nbapp):
# Must add before the root server handlers to avoid shadowing.
web_app.add_handlers('.*$', handlers)

# If running under JupyterHub, add more metadata.
if hasattr(nbapp, 'hub_prefix'):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check doesn't appear to be working, at least not in my testing. At the time the server extension is loaded, it doesn't seem like the hub_prefix traitlet has been set.

labhubapp.py seems to be working correctly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned that we won't actually be able to deprecate LabHubApp. Without it, I'm not sure that JupyterHub spawners can easily configure the LabApp specific traitlets (which is a problem I'm having while testing this).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why you saw this state. I'm seeing it working fine locally...

page_config['hubPrefix'] = nbapp.hub_prefix
page_config['hubHost'] = nbapp.hub_host
page_config['hubUser'] = nbapp.user
api_token = os.getenv('JUPYTERHUB_API_TOKEN', '')
page_config['token'] = api_token

# Add the root handlers if we have not errored.
if not errored:
add_handlers(web_app, config)
34 changes: 18 additions & 16 deletions jupyterlab/labhubapp.py
@@ -1,4 +1,5 @@
import os
import warnings

from traitlets import default

Expand All @@ -11,29 +12,30 @@
raise ImportError('You must have jupyterhub installed for this to work.')
else:
class SingleUserLabApp(SingleUserNotebookApp, LabApp):

"""
A sublcass of JupyterHub's SingleUserNotebookApp which includes LabApp
as a mixin. This makes the LabApp configurables available to the spawned
jupyter server.

If you don't need to change any of the configurables from their default
values, then this class is not necessary, and you can deploy JupyterLab
by ensuring that its server extension is enabled and setting the
`Spawner.default_url` to '/lab'.

If you do need to configure JupyterLab, then use this application by
setting `Spawner.cmd = ['jupyter-labhub']`.
"""
@default("default_url")
def _default_url(self):
"""when using jupyter-labhub, jupyterlab is default ui"""
return "/lab"

def init_webapp(self, *args, **kwargs):
warnings.warn(
"SingleUserLabApp is deprecated, use SingleUserNotebookApp and set " + \
"c.Spawner.default_url = '/lab' in jupyterhub_config.py", DeprecationWarning
)
super().init_webapp(*args, **kwargs)
settings = self.web_app.settings
if 'page_config_data' not in settings:
settings['page_config_data'] = {}
settings['page_config_data']['hub_prefix'] = self.hub_prefix
settings['page_config_data']['hub_host'] = self.hub_host
settings['page_config_data']['hub_user'] = self.user
api_token = os.getenv('JUPYTERHUB_API_TOKEN')
if not api_token:
api_token = ''
if not self.token:
ian-r-rose marked this conversation as resolved.
Show resolved Hide resolved
try:
self.token = api_token
except AttributeError:
self.log.error("Can't set self.token")
settings['page_config_data']['token'] = api_token


def main(argv=None):
Expand Down
1 change: 1 addition & 0 deletions jupyterlab/staging/webpack.config.js
Expand Up @@ -122,6 +122,7 @@ const plugins = [
}
}),
new HtmlWebpackPlugin({
chunksSortMode: 'none',
template: path.join('templates', 'template.html'),
title: jlab.name || 'JupyterLab'
}),
Expand Down
28 changes: 8 additions & 20 deletions packages/application-extension/src/index.tsx
Expand Up @@ -2,12 +2,12 @@
// Distributed under the terms of the Modified BSD License.

import {
ConnectionLost,
IConnectionLost,
ILabShell,
ILabStatus,
ILayoutRestorer,
IRouter,
ConnectionLost,
JupyterFrontEnd,
JupyterFrontEndPlugin,
JupyterLab,
Expand Down Expand Up @@ -75,13 +75,14 @@ namespace CommandIDs {
*/
const main: JupyterFrontEndPlugin<void> = {
id: '@jupyterlab/application-extension:main',
requires: [ICommandPalette, IConnectionLost, IRouter, IWindowResolver],
requires: [ICommandPalette, IRouter, IWindowResolver],
optional: [IConnectionLost],
activate: (
app: JupyterFrontEnd,
palette: ICommandPalette,
connectionLost: IConnectionLost,
router: IRouter,
resolver: IWindowResolver
resolver: IWindowResolver,
connectionLost: IConnectionLost | undefined
) => {
if (!(app instanceof JupyterLab)) {
throw new Error(`${main.id} must be activated in JupyterLab.`);
Expand Down Expand Up @@ -112,7 +113,8 @@ const main: JupyterFrontEndPlugin<void> = {
});

// If the connection to the server is lost, handle it with the
// connection lost token.
// connection lost handler.
connectionLost = connectionLost || ConnectionLost;
app.serviceManager.connectionFailure.connect(connectionLost);

const builder = app.serviceManager.builder;
Expand Down Expand Up @@ -746,19 +748,6 @@ const paths: JupyterFrontEndPlugin<JupyterFrontEnd.IPaths> = {
provides: JupyterFrontEnd.IPaths
};

/**
* The default JupyterLab connection lost provider. This may be overridden
* to provide custom behavior when a connection to the server is lost.
*/
const connectionlost: JupyterFrontEndPlugin<IConnectionLost> = {
id: '@jupyterlab/apputils-extension:connectionlost',
activate: (app: JupyterFrontEnd): IConnectionLost => {
return ConnectionLost;
},
autoStart: true,
provides: IConnectionLost
};

/**
* Export the plugins as default.
*/
Expand All @@ -773,8 +762,7 @@ const plugins: JupyterFrontEndPlugin<any>[] = [
shell,
status,
info,
paths,
connectionlost
paths
];

export default plugins;
4 changes: 3 additions & 1 deletion packages/application/src/frontend.ts
Expand Up @@ -41,7 +41,7 @@ export abstract class JupyterFrontEnd<
super(options);

// The default restored promise if one does not exist in the options.
const restored = new Promise(resolve => {
const restored = new Promise<void>(resolve => {
requestAnimationFrame(() => {
resolve();
});
Expand Down Expand Up @@ -272,6 +272,8 @@ export namespace JupyterFrontEnd {
readonly themes: string;
readonly tree: string;
readonly workspaces: string;
readonly hubPrefix?: string;
readonly hubHost?: string;
};

/**
Expand Down
4 changes: 3 additions & 1 deletion packages/application/src/lab.ts
Expand Up @@ -244,7 +244,9 @@ export namespace JupyterLab {
settings: PageConfig.getOption('settingsUrl'),
themes: PageConfig.getOption('themesUrl'),
tree: PageConfig.getOption('treeUrl'),
workspaces: PageConfig.getOption('workspacesUrl')
workspaces: PageConfig.getOption('workspacesUrl'),
hubHost: PageConfig.getOption('hubHost') || undefined,
hubPrefix: PageConfig.getOption('hubPrefix') || undefined
},
directories: {
appSettings: PageConfig.getOption('appSettingsDir'),
Expand Down
2 changes: 1 addition & 1 deletion packages/completer/src/kernelconnector.ts
Expand Up @@ -41,7 +41,7 @@ export class KernelConnector extends DataConnector<
return Promise.reject(new Error('No kernel for completion request.'));
}

const contents: KernelMessage.ICompleteRequest = {
const contents: KernelMessage.ICompleteRequestMsg['content'] = {
code: request.text,
cursor_pos: request.offset
};
Expand Down
12 changes: 7 additions & 5 deletions packages/console/src/history.ts
Expand Up @@ -224,10 +224,12 @@ export class ConsoleHistory implements IConsoleHistory {
this._history.length = 0;
let last = '';
let current = '';
for (let i = 0; i < value.content.history.length; i++) {
current = (value.content.history[i] as string[])[2];
if (current !== last) {
this._history.push((last = current));
if (value.content.status === 'ok') {
for (let i = 0; i < value.content.history.length; i++) {
current = (value.content.history[i] as string[])[2];
if (current !== last) {
this._history.push((last = current));
}
}
}
// Reset the history navigation cursor back to the bottom.
Expand Down Expand Up @@ -360,7 +362,7 @@ export namespace ConsoleHistory {
* A namespace for private data.
*/
namespace Private {
export const initialRequest: KernelMessage.IHistoryRequest = {
export const initialRequest: KernelMessage.IHistoryRequestMsg['content'] = {
output: false,
raw: true,
hist_access_type: 'tail',
Expand Down
8 changes: 6 additions & 2 deletions packages/console/src/widget.ts
Expand Up @@ -646,7 +646,7 @@ export class CodeConsole extends Widget {
return;
}
if (value && value.content.status === 'ok') {
let content = value.content as KernelMessage.IExecuteOkReply;
let content = value.content;
// Use deprecated payloads for backwards compatibility.
if (content.payload && content.payload.length) {
let setNextInput = content.payload.filter(i => {
Expand Down Expand Up @@ -682,7 +682,11 @@ export class CodeConsole extends Widget {
/**
* Update the console based on the kernel info.
*/
private _handleInfo(info: KernelMessage.IInfoReply): void {
private _handleInfo(info: KernelMessage.IInfoReplyMsg['content']): void {
if (info.status !== 'ok') {
this._banner.model.value.text = 'Error in getting kernel banner';
return;
}
this._banner.model.value.text = info.banner;
let lang = info.language_info as nbformat.ILanguageInfoMetadata;
this._mimetype = this._mimeTypeService.getMimeTypeByLanguage(lang);
Expand Down
2 changes: 1 addition & 1 deletion packages/filebrowser/src/listing.ts
Expand Up @@ -1763,7 +1763,7 @@ export namespace DirListing {

node.title = model.name;
// If an item is being edited currently, its text node is unavailable.
if (text) {
if (text && text.textContent !== model.name) {
text.textContent = model.name;
}

Expand Down
5 changes: 4 additions & 1 deletion packages/help-extension/src/index.tsx
Expand Up @@ -164,7 +164,10 @@ function activate(
helpMenu.addGroup(resourcesGroup, 10);

// Generate a cache of the kernel help links.
const kernelInfoCache = new Map<string, KernelMessage.IInfoReply>();
const kernelInfoCache = new Map<
string,
KernelMessage.IInfoReplyMsg['content']
>();
serviceManager.sessions.runningChanged.connect((m, sessions) => {
// If a new session has been added, it is at the back
// of the session list. If one has changed or stopped,
Expand Down
7 changes: 7 additions & 0 deletions packages/hub-extension/README.md
@@ -0,0 +1,7 @@
# @jupyterlab/hub-extension

JupyterLab](https://github.com/jupyterlab/jupyterlab) integration for
[JupyterHub](https://github.com/jupyterhub/jupyterhub).

This adds a "Hub" menu to JupyterLab that allows a user to log out of JupyterHub
or access their JupyterHub control panel.