mirror of
https://github.com/jupyter/notebook.git
synced 2025-01-12 11:45:38 +08:00
Merge branch 'master' into issues-3998/3971/3968
This commit is contained in:
commit
e32d847ce0
@ -8,8 +8,6 @@ cache:
|
||||
python:
|
||||
- 3.6
|
||||
|
||||
sudo: required
|
||||
|
||||
|
||||
env:
|
||||
global:
|
||||
|
@ -16,9 +16,9 @@
|
||||
"marked": "~0.5",
|
||||
"MathJax": "^2.7.4",
|
||||
"moment": "~2.19.3",
|
||||
"preact": "https://unpkg.com/preact@^7.2.0/dist/preact.min.js",
|
||||
"preact-compat": "https://unpkg.com/preact-compat@^3.14.3/dist/preact-compat.min.js",
|
||||
"proptypes": "https://unpkg.com/proptypes@^0.14.4/index.js",
|
||||
"preact": "https://unpkg.com/preact@~7.2.0/dist/preact.min.js",
|
||||
"preact-compat": "https://unpkg.com/preact-compat@~3.14.3/dist/preact-compat.min.js",
|
||||
"proptypes": "https://unpkg.com/proptypes@~0.14.4/index.js",
|
||||
"requirejs": "~2.2",
|
||||
"requirejs-text": "~2.0.15",
|
||||
"requirejs-plugins": "~1.0.3",
|
||||
|
@ -21,6 +21,16 @@ We strongly recommend that you upgrade pip to version 9+ of pip before upgrading
|
||||
Use ``pip install pip --upgrade`` to upgrade pip. Check pip version with
|
||||
``pip --version``.
|
||||
|
||||
.. _release-6.0.0:
|
||||
|
||||
6.0.0
|
||||
-----
|
||||
|
||||
- add ``?no_track_activity=1`` argument to allow API requests
|
||||
to not be registered as activity (e.g. API calls by external activity monitors).
|
||||
- Kernels shutting down due to an idle timeout is no longer considered
|
||||
an activity-updating event.
|
||||
|
||||
.. _release-5.7.8:
|
||||
|
||||
5.7.8
|
||||
|
@ -226,7 +226,7 @@
|
||||
},
|
||||
"source": [
|
||||
"### Defining the server extension and nbextension\n",
|
||||
"This example again shows that the server extension and its `load_jupyter_server_extension` function are defined in the `__init__.py` file. This time, there is also a function `_jupyter_nbextension_path` for the nbextension.\n",
|
||||
"This example again shows that the server extension and its `load_jupyter_server_extension` function are defined in the `__init__.py` file. This time, there is also a function `_jupyter_nbextension_paths` for the nbextension.\n",
|
||||
"\n",
|
||||
"#### `my_fancy_module/__init__.py`\n",
|
||||
"\n",
|
||||
|
@ -650,7 +650,11 @@ class APIHandler(IPythonHandler):
|
||||
def update_api_activity(self):
|
||||
"""Update last_activity of API requests"""
|
||||
# record activity of authenticated requests
|
||||
if self._track_activity and getattr(self, '_user_cache', None):
|
||||
if (
|
||||
self._track_activity
|
||||
and getattr(self, '_user_cache', None)
|
||||
and self.get_argument('no_track_activity', None) is None
|
||||
):
|
||||
self.settings['api_last_activity'] = utcnow()
|
||||
|
||||
def finish(self, *args, **kwargs):
|
||||
|
@ -10,7 +10,7 @@ from ..utils import url_path_join
|
||||
|
||||
from tornado import gen, web
|
||||
from tornado.concurrent import Future
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado.ioloop import IOLoop, PeriodicCallback
|
||||
from tornado.websocket import WebSocketHandler, websocket_connect
|
||||
from tornado.httpclient import HTTPRequest
|
||||
from tornado.escape import url_escape, json_decode, utf8
|
||||
@ -21,12 +21,16 @@ from traitlets.config.configurable import LoggingConfigurable
|
||||
|
||||
from .managers import GatewayClient
|
||||
|
||||
# Keepalive ping interval (default: 30 seconds)
|
||||
GATEWAY_WS_PING_INTERVAL_SECS = int(os.getenv('GATEWAY_WS_PING_INTERVAL_SECS', 30))
|
||||
|
||||
|
||||
class WebSocketChannelsHandler(WebSocketHandler, IPythonHandler):
|
||||
|
||||
session = None
|
||||
gateway = None
|
||||
kernel_id = None
|
||||
ping_callback = None
|
||||
|
||||
def set_default_headers(self):
|
||||
"""Undo the set_default_headers in IPythonHandler which doesn't make sense for websockets"""
|
||||
@ -63,8 +67,18 @@ class WebSocketChannelsHandler(WebSocketHandler, IPythonHandler):
|
||||
self.kernel_id = cast_unicode(kernel_id, 'ascii')
|
||||
super(WebSocketChannelsHandler, self).get(kernel_id=kernel_id, *args, **kwargs)
|
||||
|
||||
def send_ping(self):
|
||||
if self.ws_connection is None and self.ping_callback is not None:
|
||||
self.ping_callback.stop()
|
||||
return
|
||||
|
||||
self.ping(b'')
|
||||
|
||||
def open(self, kernel_id, *args, **kwargs):
|
||||
"""Handle web socket connection open to notebook server and delegate to gateway web socket handler """
|
||||
self.ping_callback = PeriodicCallback(self.send_ping, GATEWAY_WS_PING_INTERVAL_SECS * 1000)
|
||||
self.ping_callback.start()
|
||||
|
||||
self.gateway.on_open(
|
||||
kernel_id=kernel_id,
|
||||
message_callback=self.write_message,
|
||||
@ -80,6 +94,8 @@ class WebSocketChannelsHandler(WebSocketHandler, IPythonHandler):
|
||||
"""Send message back to notebook client. This is called via callback from self.gateway._read_messages."""
|
||||
self.log.debug("Receiving message from gateway: {}".format(message))
|
||||
if self.ws_connection: # prevent WebSocketClosedError
|
||||
if isinstance(message, bytes):
|
||||
binary = True
|
||||
super(WebSocketChannelsHandler, self).write_message(message, binary=binary)
|
||||
elif self.log.isEnabledFor(logging.DEBUG):
|
||||
msg_summary = WebSocketChannelsHandler._get_message_summary(json_decode(utf8(message)))
|
||||
|
@ -35,6 +35,7 @@ class GatewayClient(SingletonConfigurable):
|
||||
)
|
||||
|
||||
url_env = 'JUPYTER_GATEWAY_URL'
|
||||
|
||||
@default('url')
|
||||
def _url_default(self):
|
||||
return os.environ.get(self.url_env)
|
||||
@ -55,6 +56,7 @@ class GatewayClient(SingletonConfigurable):
|
||||
)
|
||||
|
||||
ws_url_env = 'JUPYTER_GATEWAY_WS_URL'
|
||||
|
||||
@default('ws_url')
|
||||
def _ws_url_default(self):
|
||||
default_value = os.environ.get(self.ws_url_env)
|
||||
@ -100,7 +102,7 @@ class GatewayClient(SingletonConfigurable):
|
||||
def _kernelspecs_resource_endpoint_default(self):
|
||||
return os.environ.get(self.kernelspecs_resource_endpoint_env, self.kernelspecs_resource_endpoint_default_value)
|
||||
|
||||
connect_timeout_default_value = 20.0
|
||||
connect_timeout_default_value = 60.0
|
||||
connect_timeout_env = 'JUPYTER_GATEWAY_CONNECT_TIMEOUT'
|
||||
connect_timeout = Float(default_value=connect_timeout_default_value, config=True,
|
||||
help="""The time allowed for HTTP connection establishment with the Gateway server.
|
||||
@ -110,7 +112,7 @@ class GatewayClient(SingletonConfigurable):
|
||||
def connect_timeout_default(self):
|
||||
return float(os.environ.get('JUPYTER_GATEWAY_CONNECT_TIMEOUT', self.connect_timeout_default_value))
|
||||
|
||||
request_timeout_default_value = 20.0
|
||||
request_timeout_default_value = 60.0
|
||||
request_timeout_env = 'JUPYTER_GATEWAY_REQUEST_TIMEOUT'
|
||||
request_timeout = Float(default_value=request_timeout_default_value, config=True,
|
||||
help="""The time allowed for HTTP request completion. (JUPYTER_GATEWAY_REQUEST_TIMEOUT env var)""")
|
||||
@ -171,7 +173,7 @@ class GatewayClient(SingletonConfigurable):
|
||||
|
||||
headers_default_value = '{}'
|
||||
headers_env = 'JUPYTER_GATEWAY_HEADERS'
|
||||
headers = Unicode(default_value=headers_default_value, allow_none=True,config=True,
|
||||
headers = Unicode(default_value=headers_default_value, allow_none=True, config=True,
|
||||
help="""Additional HTTP headers to pass on the request. This value will be converted to a dict.
|
||||
(JUPYTER_GATEWAY_HEADERS env var)
|
||||
"""
|
||||
@ -189,7 +191,7 @@ class GatewayClient(SingletonConfigurable):
|
||||
|
||||
@default('auth_token')
|
||||
def _auth_token_default(self):
|
||||
return os.environ.get(self.auth_token_env)
|
||||
return os.environ.get(self.auth_token_env, '')
|
||||
|
||||
validate_cert_default_value = True
|
||||
validate_cert_env = 'JUPYTER_GATEWAY_VALIDATE_CERT'
|
||||
@ -222,13 +224,26 @@ class GatewayClient(SingletonConfigurable):
|
||||
def gateway_enabled(self):
|
||||
return bool(self.url is not None and len(self.url) > 0)
|
||||
|
||||
# Ensure KERNEL_LAUNCH_TIMEOUT has a default value.
|
||||
KERNEL_LAUNCH_TIMEOUT = int(os.environ.get('KERNEL_LAUNCH_TIMEOUT', 40))
|
||||
os.environ['KERNEL_LAUNCH_TIMEOUT'] = str(KERNEL_LAUNCH_TIMEOUT)
|
||||
|
||||
LAUNCH_TIMEOUT_PAD = int(os.environ.get('LAUNCH_TIMEOUT_PAD', 2))
|
||||
|
||||
def init_static_args(self):
|
||||
"""Initialize arguments used on every request. Since these are static values, we'll
|
||||
perform this operation once.
|
||||
|
||||
"""
|
||||
# Ensure that request timeout is at least "pad" greater than launch timeout.
|
||||
if self.request_timeout < float(GatewayClient.KERNEL_LAUNCH_TIMEOUT + GatewayClient.LAUNCH_TIMEOUT_PAD):
|
||||
self.request_timeout = float(GatewayClient.KERNEL_LAUNCH_TIMEOUT + GatewayClient.LAUNCH_TIMEOUT_PAD)
|
||||
|
||||
self._static_args['headers'] = json.loads(self.headers)
|
||||
self._static_args['headers'].update({'Authorization': 'token {}'.format(self.auth_token)})
|
||||
if 'Authorization' not in self._static_args['headers'].keys():
|
||||
self._static_args['headers'].update({
|
||||
'Authorization': 'token {}'.format(self.auth_token)
|
||||
})
|
||||
self._static_args['connect_timeout'] = self.connect_timeout
|
||||
self._static_args['request_timeout'] = self.request_timeout
|
||||
self._static_args['validate_cert'] = self.validate_cert
|
||||
@ -270,13 +285,13 @@ def gateway_request(endpoint, **kwargs):
|
||||
"Check to be sure the Gateway instance is running.".format(GatewayClient.instance().url))
|
||||
except HTTPError:
|
||||
# This can occur if the host is valid (e.g., foo.com) but there's nothing there.
|
||||
raise web.HTTPError(504, "Error attempting to connect to Gateway server url '{}'. " \
|
||||
"Ensure gateway url is valid and the Gateway instance is running.".format(
|
||||
GatewayClient.instance().url))
|
||||
raise web.HTTPError(504, "Error attempting to connect to Gateway server url '{}'. "
|
||||
"Ensure gateway url is valid and the Gateway instance is running.".
|
||||
format(GatewayClient.instance().url))
|
||||
except gaierror as e:
|
||||
raise web.HTTPError(404, "The Gateway server specified in the gateway_url '{}' doesn't appear to be valid. "
|
||||
"Ensure gateway url is valid and the Gateway instance is running.".format(
|
||||
GatewayClient.instance().url))
|
||||
"Ensure gateway url is valid and the Gateway instance is running.".
|
||||
format(GatewayClient.instance().url))
|
||||
|
||||
raise gen.Return(response)
|
||||
|
||||
@ -409,7 +424,7 @@ class GatewayKernelManager(MappingKernelManager):
|
||||
self.log.debug("Request list kernels: %s", kernel_url)
|
||||
response = yield gateway_request(kernel_url, method='GET')
|
||||
kernels = json_decode(response.body)
|
||||
self._kernels = {x['id']:x for x in kernels}
|
||||
self._kernels = {x['id']: x for x in kernels}
|
||||
raise gen.Return(kernels)
|
||||
|
||||
@gen.coroutine
|
||||
@ -420,6 +435,10 @@ class GatewayKernelManager(MappingKernelManager):
|
||||
==========
|
||||
kernel_id : uuid
|
||||
The id of the kernel to shutdown.
|
||||
now : bool
|
||||
Shutdown the kernel immediately (True) or gracefully (False)
|
||||
restart : bool
|
||||
The purpose of this shutdown is to restart the kernel (True)
|
||||
"""
|
||||
kernel_url = self._get_kernel_endpoint_url(kernel_id)
|
||||
self.log.debug("Request shutdown kernel at: %s", kernel_url)
|
||||
|
@ -1187,7 +1187,7 @@ msgstr ""
|
||||
|
||||
#: notebook/static/notebook/js/notificationarea.js:166
|
||||
msgid "Connection failed"
|
||||
msgstr "Échec de la connection"
|
||||
msgstr "Échec de la connexion"
|
||||
|
||||
#: notebook/static/notebook/js/notificationarea.js:179
|
||||
msgid "No kernel"
|
||||
|
@ -421,7 +421,7 @@ def shutdown_server(server_info, timeout=5, log=None):
|
||||
|
||||
# Poll to see if it shut down.
|
||||
for _ in range(timeout*10):
|
||||
if check_pid(pid):
|
||||
if not check_pid(pid):
|
||||
if log: log.debug("Server PID %s is gone", pid)
|
||||
return True
|
||||
time.sleep(0.1)
|
||||
@ -434,7 +434,7 @@ def shutdown_server(server_info, timeout=5, log=None):
|
||||
|
||||
# Poll to see if it shut down.
|
||||
for _ in range(timeout * 10):
|
||||
if check_pid(pid):
|
||||
if not check_pid(pid):
|
||||
if log: log.debug("Server PID %s is gone", pid)
|
||||
return True
|
||||
time.sleep(0.1)
|
||||
|
@ -1,27 +1,27 @@
|
||||
"""Test the basic /api endpoints"""
|
||||
|
||||
import requests
|
||||
from datetime import timedelta
|
||||
|
||||
from notebook._tz import isoformat
|
||||
from notebook._tz import isoformat, utcnow
|
||||
from notebook.utils import url_path_join
|
||||
from notebook.tests.launchnotebook import NotebookTestBase
|
||||
|
||||
|
||||
class KernelAPITest(NotebookTestBase):
|
||||
class APITest(NotebookTestBase):
|
||||
"""Test the kernels web service API"""
|
||||
|
||||
|
||||
def _req(self, verb, path, **kwargs):
|
||||
r = self.request(verb, url_path_join('api', path))
|
||||
r.raise_for_status()
|
||||
return r
|
||||
|
||||
|
||||
def get(self, path, **kwargs):
|
||||
return self._req('GET', path)
|
||||
|
||||
|
||||
def test_get_spec(self):
|
||||
r = self.get('spec.yaml')
|
||||
assert r.text
|
||||
|
||||
|
||||
def test_get_status(self):
|
||||
r = self.get('status')
|
||||
data = r.json()
|
||||
@ -30,3 +30,18 @@ class KernelAPITest(NotebookTestBase):
|
||||
assert data['last_activity'].endswith('Z')
|
||||
assert data['started'].endswith('Z')
|
||||
assert data['started'] == isoformat(self.notebook.web_app.settings['started'])
|
||||
|
||||
def test_no_track_activity(self):
|
||||
# initialize with old last api activity
|
||||
old = utcnow() - timedelta(days=1)
|
||||
settings = self.notebook.web_app.settings
|
||||
settings['api_last_activity'] = old
|
||||
# accessing status doesn't update activity
|
||||
self.get('status')
|
||||
assert settings['api_last_activity'] == old
|
||||
# accessing with ?no_track_activity doesn't update activity
|
||||
self.get('contents?no_track_activity=1')
|
||||
assert settings['api_last_activity'] == old
|
||||
# accessing without ?no_track_activity does update activity
|
||||
self.get('contents')
|
||||
assert settings['api_last_activity'] > old
|
||||
|
@ -292,7 +292,6 @@ class MappingKernelManager(MultiKernelManager):
|
||||
kernel._activity_stream = None
|
||||
self.stop_buffering(kernel_id)
|
||||
self._kernel_connections.pop(kernel_id, None)
|
||||
self.last_kernel_activity = utcnow()
|
||||
|
||||
# Decrease the metric of number of kernels
|
||||
# running for the relevant kernel type by 1
|
||||
|
@ -60,6 +60,7 @@ define(['jquery',
|
||||
})
|
||||
.append($("<button>")
|
||||
.attr("type", "button")
|
||||
.attr("aria-label", i18n.msg._("close"))
|
||||
.addClass("close")
|
||||
.attr("data-dismiss", "modal")
|
||||
.attr("aria-hidden", "true")
|
||||
@ -234,6 +235,8 @@ define(['jquery',
|
||||
});
|
||||
|
||||
modal_obj.on('shown.bs.modal', function(){ editor.refresh(); });
|
||||
modal_obj.on('hide.bs.modal', function(){
|
||||
options.edit_metadata_button ? options.edit_metadata_button.focus() : "";});
|
||||
};
|
||||
|
||||
var edit_attachments = function (options) {
|
||||
|
@ -10,7 +10,7 @@ define([
|
||||
|
||||
var CellToolbar = celltoolbar.CellToolbar;
|
||||
|
||||
var raw_edit = function (cell) {
|
||||
var raw_edit = function (cell , edit_metadata_button) {
|
||||
dialog.edit_metadata({
|
||||
md: cell.metadata,
|
||||
callback: function (md) {
|
||||
@ -18,7 +18,8 @@ define([
|
||||
},
|
||||
name: i18n.msg._('Cell'),
|
||||
notebook: this.notebook,
|
||||
keyboard_manager: this.keyboard_manager
|
||||
keyboard_manager: this.keyboard_manager,
|
||||
edit_metadata_button: edit_metadata_button
|
||||
});
|
||||
};
|
||||
|
||||
@ -28,9 +29,10 @@ define([
|
||||
.addClass("btn btn-default btn-xs")
|
||||
.text(i18n.msg._("Edit Metadata"))
|
||||
.click( function () {
|
||||
raw_edit(cell);
|
||||
raw_edit(cell, this);
|
||||
return false;
|
||||
});
|
||||
|
||||
button_container.append(button);
|
||||
};
|
||||
|
||||
|
@ -58,7 +58,9 @@ define([
|
||||
],
|
||||
'run_int'],
|
||||
['<add_celltype_list>'],
|
||||
[['jupyter-notebook:show-command-palette']]
|
||||
[
|
||||
['jupyter-notebook:show-command-palette'],
|
||||
'cmd_palette']
|
||||
];
|
||||
this.construct(grps);
|
||||
};
|
||||
@ -73,6 +75,8 @@ define([
|
||||
var multiselect = $('<option/>').attr('value','multiselect').attr('disabled','').text('-');
|
||||
var sel = $('<select/>')
|
||||
.attr('id','cell_type')
|
||||
.attr('aria-label', i18n.msg._('combobox, select cell type'))
|
||||
.attr('role', 'combobox')
|
||||
.addClass('form-control select-xs')
|
||||
.append($('<option/>').attr('value','code').text(i18n.msg._('Code')))
|
||||
.append($('<option/>').attr('value','markdown').text(i18n.msg._('Markdown')))
|
||||
|
@ -398,13 +398,14 @@ define([
|
||||
return false;
|
||||
}, {'title':'Javascript enabled for notebook display'});
|
||||
// don't allow 'Trusted' button to be clicked
|
||||
$(tnw.selector).attr('disabled', true)
|
||||
$(tnw.selector).attr('disabled', true);
|
||||
$(tnw.selector).css('cursor', 'help');
|
||||
} else {
|
||||
tnw.set_message(i18n.msg._("Not Trusted"), undefined, function() {
|
||||
that.notebook.trust_notebook();
|
||||
return false;
|
||||
}, {'title':'Javascript disabled for notebook display'});
|
||||
$(tnw.selector).attr('role', 'button');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -190,6 +190,15 @@ requirejs([
|
||||
$("#alternate_upload").change(function (event){
|
||||
notebook_list.handleFilesUpload(event,'form');
|
||||
});
|
||||
|
||||
// bound the the span around the input file upload to enable keyboard click
|
||||
$("#upload_span").keydown(function (event) {
|
||||
var key = event.which;
|
||||
if ((key === 13) || (key === 32)) {
|
||||
event.preventDefault();
|
||||
$("#upload_span_input").click();
|
||||
}
|
||||
})
|
||||
|
||||
// set hash on tab click
|
||||
$("#tabs").find("a").click(function(e) {
|
||||
|
@ -63,6 +63,8 @@ define([
|
||||
.attr("id", "kernel-" +ks.name)
|
||||
.data('kernelspec', ks).append(
|
||||
$('<a>')
|
||||
.attr("aria-label", ks.name)
|
||||
.attr("role", "menuitem")
|
||||
.attr('href', '#')
|
||||
.click($.proxy(this.new_notebook, this, ks.name))
|
||||
.text(ks.spec.display_name)
|
||||
|
@ -955,7 +955,11 @@ define([
|
||||
var item_path = this.selected[0].path;
|
||||
var item_name = this.selected[0].name;
|
||||
var item_type = this.selected[0].type;
|
||||
var input = $('<input/>').attr('type','text').attr('size','25').addClass('form-control')
|
||||
var input = $('<input/>')
|
||||
.attr('type','text')
|
||||
.attr('size','25')
|
||||
.attr('aria-labelledby','rename-message')
|
||||
.addClass('form-control')
|
||||
.val(item_name);
|
||||
var rename_msg = function (type) {
|
||||
switch(type) {
|
||||
@ -975,6 +979,7 @@ define([
|
||||
};
|
||||
var dialog_body = $('<div/>').append(
|
||||
$("<p/>").addClass("rename-message")
|
||||
.attr('id', 'rename-message')
|
||||
.text(rename_msg(item_type))
|
||||
).append(
|
||||
$("<br/>")
|
||||
|
@ -83,19 +83,19 @@ data-notebook-path="{{notebook_path | urlencode}}"
|
||||
<a href="#">{% trans %}New Notebook{% endtrans %}<span class="sr-only">{% trans %}Toggle Dropdown{% endtrans %}</span></a>
|
||||
<ul class="dropdown-menu" id="menu-new-notebook-submenu"></ul>
|
||||
</li>
|
||||
<li id="open_notebook"
|
||||
<li id="open_notebook" role="none"
|
||||
title="{% trans %}Opens a new window with the Dashboard view{% endtrans %}">
|
||||
<a href="#">{% trans %}Open...{% endtrans %}</a></li>
|
||||
<a href="#" role="menuitem">{% trans %}Open...{% endtrans %}</a></li>
|
||||
<!-- <hr/> -->
|
||||
<li class="divider"></li>
|
||||
<li id="copy_notebook"
|
||||
<li class="divider" role="none"></li>
|
||||
<li id="copy_notebook" role="none"
|
||||
title="{% trans %}Open a copy of this notebook's contents and start a new kernel{% endtrans %}">
|
||||
<a href="#">{% trans %}Make a Copy...{% endtrans %}</a></li>
|
||||
<li id="save_notebook_as"
|
||||
<a href="#" role="menuitem">{% trans %}Make a Copy...{% endtrans %}</a></li>
|
||||
<li id="save_notebook_as" role="none"
|
||||
title="{% trans %}Save a copy of the notebook's contents and start a new kernel{% endtrans %}">
|
||||
<a href="#">{% trans %}Save as...{% endtrans %}</a></li>
|
||||
<li id="rename_notebook"><a href="#">{% trans %}Rename...{% endtrans %}</a></li>
|
||||
<li id="save_checkpoint"><a href="#">{% trans %}Save and Checkpoint{% endtrans %}</a></li>
|
||||
<a href="#" role="menuitem">{% trans %}Save as...{% endtrans %}</a></li>
|
||||
<li id="rename_notebook" role="none"><a href="#" role="menuitem">{% trans %}Rename...{% endtrans %}</a></li>
|
||||
<li id="save_checkpoint" role="none"><a href="#" role="menuitem">{% trans %}Save and Checkpoint{% endtrans %}</a></li>
|
||||
<!-- <hr/> -->
|
||||
<li class="divider"></li>
|
||||
<li id="restore_checkpoint" class="dropdown-submenu"><a href="#">{% trans %}Revert to Checkpoint{% endtrans %}<span class="sr-only">{% trans %}Toggle Dropdown{% endtrans %}</span></a>
|
||||
@ -118,75 +118,76 @@ data-notebook-path="{{notebook_path | urlencode}}"
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown-submenu hidden"><a href="#">{% trans %}Deploy as{% endtrans %}</a>
|
||||
<li class="dropdown-submenu hidden" role="none"><a href="#" role="menuitem">{% trans %}Deploy as{% endtrans %}</a>
|
||||
<ul id="deploy_menu" class="dropdown-menu"></ul>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li id="trust_notebook"
|
||||
<li class="divider" role="none"></li>
|
||||
<li id="trust_notebook" role="none"
|
||||
title="{% trans %}Trust the output of this notebook{% endtrans %}">
|
||||
<a href="#" >{% trans %}Trust Notebook{% endtrans %}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="close_and_halt"
|
||||
<a href="#" role="menuitem">{% trans %}Trust Notebook{% endtrans %}</a></li>
|
||||
<li class="divider" role="none"></li>
|
||||
<li id="close_and_halt" role="none"
|
||||
title="{% trans %}Shutdown this notebook's kernel, and close this window{% endtrans %}">
|
||||
<a href="#" >{% trans %}Close and Halt{% endtrans %}</a></li>
|
||||
<a href="#" role="menuitem">{% trans %}Close and Halt{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">{% trans %}Edit{% endtrans %}</a>
|
||||
<ul id="edit_menu" class="dropdown-menu">
|
||||
<li id="cut_cell"><a href="#">{% trans %}Cut Cells{% endtrans %}</a></li>
|
||||
<li id="copy_cell"><a href="#">{% trans %}Copy Cells{% endtrans %}</a></li>
|
||||
<li id="paste_cell_above" class="disabled"><a href="#">{% trans %}Paste Cells Above{% endtrans %}</a></li>
|
||||
<li id="paste_cell_below" class="disabled"><a href="#">{% trans %}Paste Cells Below{% endtrans %}</a></li>
|
||||
<li id="paste_cell_replace" class="disabled"><a href="#">{% trans %}Paste Cells & Replace{% endtrans %}</a></li>
|
||||
<li id="delete_cell"><a href="#">{% trans %}Delete Cells{% endtrans %}</a></li>
|
||||
<li id="undelete_cell" class="disabled"><a href="#">{% trans %}Undo Delete Cells{% endtrans %}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="split_cell"><a href="#">{% trans %}Split Cell{% endtrans %}</a></li>
|
||||
<li id="merge_cell_above"><a href="#">{% trans %}Merge Cell Above{% endtrans %}</a></li>
|
||||
<li id="merge_cell_below"><a href="#">{% trans %}Merge Cell Below{% endtrans %}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="move_cell_up"><a href="#">{% trans %}Move Cell Up{% endtrans %}</a></li>
|
||||
<li id="move_cell_down"><a href="#">{% trans %}Move Cell Down{% endtrans %}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="edit_nb_metadata"><a href="#">{% trans %}Edit Notebook Metadata{% endtrans %}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="find_and_replace"><a href="#"> {% trans %}Find and Replace{% endtrans %} </a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="cut_cell_attachments"><a href="#">{% trans %}Cut Cell Attachments{% endtrans %}</a></li>
|
||||
<li id="copy_cell_attachments"><a href="#">{% trans %}Copy Cell Attachments{% endtrans %}</a></li>
|
||||
<li id="paste_cell_attachments" class="disabled"><a href="#">{% trans %}Paste Cell Attachments{% endtrans %}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li id="insert_image" class="disabled"><a href="#"> {% trans %}Insert Image{% endtrans %} </a></li>
|
||||
|
||||
<li class="dropdown"><a href="#" class="dropdown-toggle" id="editlink" data-toggle="dropdown" aria-haspopup="true" aria-controls="edit_menu">{% trans %}Edit{% endtrans %}</a>
|
||||
<ul id="edit_menu" class="dropdown-menu" role="menu" aria-labelledby="editlink">
|
||||
<li id="cut_cell" role="none"><a href="#" role="menuitem">{% trans %}Cut Cells{% endtrans %}</a></li>
|
||||
<li id="copy_cell" role="none"><a href="#" role="menuitem">{% trans %}Copy Cells{% endtrans %}</a></li>
|
||||
<li id="paste_cell_above" class="disabled role="none"><a href="#" role="menuitem">{% trans %}Paste Cells Above{% endtrans %}</a></li>
|
||||
<li id="paste_cell_below" class="disabled" role="none"><a href="#" role="menuitem">{% trans %}Paste Cells Below{% endtrans %}</a></li>
|
||||
<li id="paste_cell_replace" class="disabled" role="none"><a href="#" role="menuitem">{% trans %}Paste Cells & Replace{% endtrans %}</a></li>
|
||||
<li id="delete_cell" role="none"><a href="#" role="menuitem">{% trans %}Delete Cells{% endtrans %}</a></li>
|
||||
<li id="undelete_cell" class="disabled" role="none"><a href="#" role="menuitem">{% trans %}Undo Delete Cells{% endtrans %}</a></li>
|
||||
<li class="divider" role="none"></li>
|
||||
<li id="split_cell" role="none"><a href="#" role="menuitem">{% trans %}Split Cell{% endtrans %}</a></li>
|
||||
<li id="merge_cell_above" role="none"><a href="#" role="menuitem">{% trans %}Merge Cell Above{% endtrans %}</a></li>
|
||||
<li id="merge_cell_below" role="none"><a href="#" role="menuitem">{% trans %}Merge Cell Below{% endtrans %}</a></li>
|
||||
<li class="divider" role="none"></li>
|
||||
<li id="move_cell_up" role="none"><a href="#" role="menuitem">{% trans %}Move Cell Up{% endtrans %}</a></li>
|
||||
<li id="move_cell_down" role="none"><a href="#" role="menuitem">{% trans %}Move Cell Down{% endtrans %}</a></li>
|
||||
<li class="divider" role="none"></li>
|
||||
<li id="edit_nb_metadata" role="none"><a href="#" role="menuitem">{% trans %}Edit Notebook Metadata{% endtrans %}</a></li>
|
||||
<li class="divider" role="none"></li>
|
||||
<li id="find_and_replace" role="none"><a href="#" role="menuitem"> {% trans %}Find and Replace{% endtrans %} </a></li>
|
||||
<li class="divider" role="none"></li>
|
||||
<li id="cut_cell_attachments" role="none"><a href="#" role="menuitem">{% trans %}Cut Cell Attachments{% endtrans %}</a></li>
|
||||
<li id="copy_cell_attachments" role="none"><a href="#" role="menuitem">{% trans %}Copy Cell Attachments{% endtrans %}</a></li>
|
||||
<li id="paste_cell_attachments" class="disabled" role="none"><a href="#" role="menuitem">{% trans %}Paste Cell Attachments{% endtrans %}</a></li>
|
||||
<li class="divider" role="none"></li>
|
||||
<li id="insert_image" class="disabled" role="none"><a href="#" role="menuitem"> {% trans %}Insert Image{% endtrans %} </a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">{% trans %}View{% endtrans %}</a>
|
||||
<ul id="view_menu" class="dropdown-menu">
|
||||
<li id="toggle_header"
|
||||
<li class="dropdown"><a href="#" class="dropdown-toggle" id="viewlink" data-toggle="dropdown" aria-haspopup="true" aria-controls="view_menu">{% trans %}View{% endtrans %}</a>
|
||||
<ul id="view_menu" class="dropdown-menu" role="menu" aria-labelledby="viewlink">
|
||||
<li id="toggle_header" role="none"
|
||||
title="{% trans %}Show/Hide the logo and notebook title (above menu bar){% endtrans %}">
|
||||
<a href="#">{% trans %}Toggle Header{% endtrans %}</a>
|
||||
<a href="#" role="menuitem">{% trans %}Toggle Header{% endtrans %}</a>
|
||||
</li>
|
||||
<li id="toggle_toolbar"
|
||||
<li id="toggle_toolbar" role="none"
|
||||
title="{% trans %}Show/Hide the action icons (below menu bar){% endtrans %}">
|
||||
<a href="#">{% trans %}Toggle Toolbar{% endtrans %}</a>
|
||||
<a href="#" role="menuitem">{% trans %}Toggle Toolbar{% endtrans %}</a>
|
||||
</li>
|
||||
<li id="toggle_line_numbers"
|
||||
<li id="toggle_line_numbers" role="none"
|
||||
title="{% trans %}Show/Hide line numbers in cells{% endtrans %}">
|
||||
<a href="#">{% trans %}Toggle Line Numbers{% endtrans %}</a>
|
||||
<a href="#" role="menuitem">{% trans %}Toggle Line Numbers{% endtrans %}</a>
|
||||
</li>
|
||||
<li id="menu-cell-toolbar" class="dropdown-submenu">
|
||||
<a href="#">{% trans %}Cell Toolbar{% endtrans %}</a>
|
||||
<li id="menu-cell-toolbar" class="dropdown-submenu" role="none">
|
||||
<a href="#" role="menuitem">{% trans %}Cell Toolbar{% endtrans %}</a>
|
||||
<ul class="dropdown-menu" id="menu-cell-toolbar-submenu"></ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">{% trans %}Insert{% endtrans %}</a>
|
||||
<ul id="insert_menu" class="dropdown-menu">
|
||||
<li id="insert_cell_above"
|
||||
<li class="dropdown"><a href="#" class="dropdown-toggle" id="insertlink" data-toggle="dropdown" aria-haspopup="true" aria-controls="insert_menu">{% trans %}Insert{% endtrans %}</a>
|
||||
<ul id="insert_menu" class="dropdown-menu" role="menu" aria-labelledby="insertlink">
|
||||
<li id="insert_cell_above" role="none"
|
||||
title="{% trans %}Insert an empty Code cell above the currently active cell{% endtrans %}">
|
||||
<a href="#">{% trans %}Insert Cell Above{% endtrans %}</a></li>
|
||||
<li id="insert_cell_below"
|
||||
<a href="#" role="menuitem">{% trans %}Insert Cell Above{% endtrans %}</a></li>
|
||||
<li id="insert_cell_below" role="none"
|
||||
title="{% trans %}Insert an empty Code cell below the currently active cell{% endtrans %}">
|
||||
<a href="#">{% trans %}Insert Cell Below{% endtrans %}</a></li>
|
||||
<a href="#" role="menuitem">{% trans %}Insert Cell Below{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">{% trans %}Cell{% endtrans %}</a>
|
||||
|
@ -55,9 +55,9 @@ data-server-root="{{server_root}}"
|
||||
<div class="pull-right">
|
||||
<form id='alternate_upload' class='alternate_upload'>
|
||||
<span id="notebook_list_info">
|
||||
<span class="btn btn-xs btn-default btn-upload">
|
||||
<input title="{% trans %}Click to browse for a file to upload.{% endtrans %}" type="file" name="datafile" class="fileinput" multiple='multiple'>
|
||||
{% trans %}Upload{% endtrans %}
|
||||
<span id="upload_span" class="btn btn-xs btn-default btn-upload" role="button" tabindex="0">
|
||||
<input id="upload_span_input" title="{% trans %}Click to browse for a file to upload.{% endtrans %}" type="file" name="datafile" class="fileinput" multiple='multiple' tabindex="-1">
|
||||
{% trans %}Upload{% endtrans %}
|
||||
</span>
|
||||
</span>
|
||||
</form>
|
||||
@ -65,24 +65,25 @@ data-server-root="{{server_root}}"
|
||||
<button class="dropdown-toggle btn btn-default btn-xs" id="new-dropdown-button" data-toggle="dropdown">
|
||||
<span>{% trans %}New{% endtrans %}</span>
|
||||
<span class="caret"></span>
|
||||
<span class="sr-only">{% trans %}Toggle Dropdown{% endtrans %}</span>
|
||||
</button>
|
||||
<ul id="new-menu" class="dropdown-menu">
|
||||
<li role="presentation" class="dropdown-header" id="notebook-kernels">Notebook:</li>
|
||||
<ul id="new-menu" class="dropdown-menu" role="menu">
|
||||
<li role="menuitem" class="dropdown-header" id="notebook-kernels">Notebook:</li>
|
||||
<li role="presentation" class="divider"></li>
|
||||
<li role="presentation" class="dropdown-header" >Other:</li>
|
||||
<li role="presentation" id="new-file">
|
||||
<a role="menuitem" tabindex="-1" href="#">{% trans %}Text File{% endtrans %}</a>
|
||||
<li role="menuitem" class="dropdown-header" >Other:</li>
|
||||
<li role="none" id="new-file">
|
||||
<a role="menuitem" tabindex="-1" href="#">{% trans %}Text File{% endtrans %}</a>
|
||||
</li>
|
||||
<li role="presentation" id="new-folder">
|
||||
<a role="menuitem" tabindex="-1" href="#">{% trans %}Folder{% endtrans %}</a>
|
||||
<li role="none" id="new-folder">
|
||||
<a role="menuitem" tabindex="-1" href="#">{% trans %}Folder{% endtrans %}</a>
|
||||
</li>
|
||||
{% if terminals_available %}
|
||||
<li role="presentation" id="new-terminal">
|
||||
<a role="menuitem" tabindex="-1" href="#">{% trans %}Terminal{% endtrans %}</a>
|
||||
<li role="none" id="new-terminal">
|
||||
<a role="menuitem" tabindex="-1" href="#">{% trans %}Terminal{% endtrans %}</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li role="presentation" id="new-terminal-disabled" class="disabled">
|
||||
<a role="menuitem" tabindex="-1" href="#">{% trans %}Terminals Unavailable{% endtrans %}</a>
|
||||
<li role="none" id="new-terminal-disabled" class="disabled">
|
||||
<a role="menuitem" tabindex="-1" href="#">{% trans %}Terminals Unavailable{% endtrans %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
@ -96,8 +97,8 @@ data-server-root="{{server_root}}"
|
||||
<div id="notebook_list">
|
||||
<div id="notebook_list_header" class="row list_header">
|
||||
<div class="btn-group dropdown" id="tree-selector">
|
||||
<button title="{% trans %}Select All / None{% endtrans %}" aria-label="{% trans %}Select All / None{% endtrans %}" type="button" class="btn btn-default btn-xs" id="button-select-all">
|
||||
<input type="checkbox" class="pull-left tree-selector" id="select-all"><span id="counter-select-all"> </span></input>
|
||||
<button title="{% trans %}Select All / None{% endtrans %}" aria-label="{% trans %}Select All / None{% endtrans %}" type="button" class="btn btn-default btn-xs" id="button-select-all" role="checkbox">
|
||||
<input type="checkbox" class="pull-left tree-selector" id="select-all" tabindex="-1"><span id="counter-select-all"> </span></input>
|
||||
</button>
|
||||
<button title="{% trans %}Select Folders/All Notebooks/Running/Files {% endtrans %}" class="btn btn-default btn-xs dropdown-toggle" type="button" id="tree-selector-btn" data-toggle="dropdown" aria-expanded="true">
|
||||
<span class="sr-only">checkbox</span>
|
||||
@ -105,10 +106,10 @@ data-server-root="{{server_root}}"
|
||||
<span class="sr-only">Toggle Dropdown</span>
|
||||
</button>
|
||||
<ul id='selector-menu' class="dropdown-menu" role="menu" aria-labelledby="tree-selector-btn">
|
||||
<li role="presentation"><a id="select-folders" role="menuitem" tabindex="-1" href="#" title="{% trans %}Select All Folders{% endtrans %}"><i class="menu_icon folder_icon icon-fixed-width"></i> {% trans %}Folders{% endtrans %}</a></li>
|
||||
<li role="presentation"><a id="select-notebooks" role="menuitem" tabindex="-1" href="#" title="{% trans %}Select All Notebooks{% endtrans %}"><i class="menu_icon notebook_icon icon-fixed-width"></i> {% trans %}All Notebooks{% endtrans %}</a></li>
|
||||
<li role="presentation"><a id="select-running-notebooks" role="menuitem" tabindex="-1" href="#" title="{% trans %}Select Running Notebooks{% endtrans %}"><i class="menu_icon running_notebook_icon icon-fixed-width"></i> {% trans %}Running{% endtrans %}</a></li>
|
||||
<li role="presentation"><a id="select-files" role="menuitem" tabindex="-1" href="#" title="{% trans %}Select All Files{% endtrans %}"><i class="menu_icon file_icon icon-fixed-width"></i> {% trans %}Files{% endtrans %}</a></li>
|
||||
<li role="none"><a id="select-folders" role="menuitem" tabindex="-1" href="#" title="{% trans %}Select All Folders{% endtrans %}"><i class="menu_icon folder_icon icon-fixed-width"></i> {% trans %}Folders{% endtrans %}</a></li>
|
||||
<li role="none"><a id="select-notebooks" role="menuitem" tabindex="-1" href="#" title="{% trans %}Select All Notebooks{% endtrans %}"><i class="menu_icon notebook_icon icon-fixed-width"></i> {% trans %}All Notebooks{% endtrans %}</a></li>
|
||||
<li role="none"><a id="select-running-notebooks" role="menuitem" tabindex="-1" href="#" title="{% trans %}Select Running Notebooks{% endtrans %}"><i class="menu_icon running_notebook_icon icon-fixed-width"></i> {% trans %}Running{% endtrans %}</a></li>
|
||||
<li role="none"><a id="select-files" role="menuitem" tabindex="-1" href="#" title="{% trans %}Select All Files{% endtrans %}"><i class="menu_icon file_icon icon-fixed-width"></i> {% trans %}Files{% endtrans %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="project_name">
|
||||
@ -119,23 +120,25 @@ data-server-root="{{server_root}}"
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div id="file_size" class="pull-right sort_button">
|
||||
<span class="btn btn-xs btn-default sort-action" id="file-size">
|
||||
{% trans %}File size{% endtrans %}
|
||||
<i class="fa"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div id="last_modified" class="pull-right sort_button">
|
||||
<span class="btn btn-xs btn-default sort-action" id="last-modified">
|
||||
{% trans %}Last Modified{% endtrans %}
|
||||
<i class="fa"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div id="sort_name" class="pull-right sort_button">
|
||||
<span class="btn btn-xs btn-default sort-action" id="sort-name">
|
||||
{% trans %}Name{% endtrans %}
|
||||
<i class="fa fa-arrow-down"></i>
|
||||
</span>
|
||||
<div id="sort_buttons" class="pull-right">
|
||||
<div id="sort_name" class="sort_button">
|
||||
<button type="button" class="btn btn-xs btn-default sort-action" id="sort-name" aria-label="{% trans %}Sort by name{% endtrans %}">
|
||||
{% trans %}Name{% endtrans %}
|
||||
<i class="fa fa-arrow-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="last_modified" class="sort_button">
|
||||
<button type="button" class="btn btn-xs btn-default sort-action" id="last-modified" aria-label="{% trans %}Sort by last modified{% endtrans %}">
|
||||
{% trans %}Last Modified{% endtrans %}
|
||||
<i class="fa"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="file_size" class="sort_button">
|
||||
<button type="button" class="btn btn-xs btn-default sort-action" id="file-size" aria-label="{% trans %}Sort by file size{% endtrans %}">
|
||||
{% trans %}File size{% endtrans %}
|
||||
<i class="fa"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user