Merge branch 'master' into issues-3998/3971/3968

This commit is contained in:
Joshua Zeltser 2019-06-25 15:55:47 +01:00 committed by GitHub
commit e32d847ce0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 222 additions and 131 deletions

View File

@ -8,8 +8,6 @@ cache:
python:
- 3.6
sudo: required
env:
global:

View File

@ -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",

View File

@ -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

View File

@ -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",

View File

@ -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):

View File

@ -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)))

View File

@ -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)

View File

@ -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"

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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);
};

View File

@ -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')))

View File

@ -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');
}
});
};

View File

@ -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) {

View File

@ -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)

View File

@ -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/>")

View File

@ -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 &amp; 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 &amp; 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>

View File

@ -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">&nbsp;</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">&nbsp;</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>&nbsp;{% 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>&nbsp;{% 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>&nbsp;{% 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>&nbsp;{% 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>&nbsp;{% 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>&nbsp;{% 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>&nbsp;{% 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>&nbsp;{% 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>