Merge pull request #1739 from Carreau/dashboardImprovement

Dashboard improvement

see #1658 #1676

Allow to shutdown the kernels from the dashboard, 
autorefresh dashboard,
add a native upload method, especially for https/chrome/linux that prevent drag and drop
This commit is contained in:
Bussonnier Matthias 2012-05-31 00:24:14 -07:00
commit 711c2ef6cc
8 changed files with 163 additions and 32 deletions

View File

@ -591,7 +591,10 @@ class NotebookRootHandler(AuthenticatedHandler):
@authenticate_unless_readonly
def get(self):
nbm = self.application.notebook_manager
km = self.application.kernel_manager
files = nbm.list_notebooks()
for f in files :
f['kernel_id'] = km.kernel_for_notebook(f['notebook_id'])
self.finish(jsonapi.dumps(files))
@web.authenticated

View File

@ -0,0 +1,23 @@
/* We need an invisible input field on top of the sentense*/
/* "Drag file onto the list ..." */
.alternate_upload
{
background-color:none;
display: inline;
}
.alternate_upload.form
{
padding: 0;
margin:0;
}
.alternate_upload input.fileinput
{
background-color:red;
position:relative;
opacity: 0;
z-index: 2;
width: 447px;
}

View File

@ -68,6 +68,10 @@ var IPython = (function (IPython) {
this.element.find('button#print_notebook').click(function () {
IPython.print_widget.print_notebook();
});
this.element.find('#kill_and_exit').click(function () {
IPython.notebook.kernel.kill();
setTimeout(function(){window.close();}, 200);
});
// Edit
this.element.find('#cut_cell').click(function () {
IPython.notebook.cut_cell();

View File

@ -43,33 +43,44 @@ var IPython = (function (IPython) {
this.element.bind('dragover', function () {
return false;
});
this.element.bind('drop', function (event) {
var files = event.originalEvent.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
var reader = new FileReader();
reader.readAsText(f);
var fname = f.name.split('.');
var nbname = fname.slice(0,-1).join('.');
var nbformat = fname.slice(-1)[0];
if (nbformat === 'ipynb') {nbformat = 'json';};
if (nbformat === 'py' || nbformat === 'json') {
var item = that.new_notebook_item(0);
that.add_name_input(nbname, item);
item.data('nbformat', nbformat);
// Store the notebook item in the reader so we can use it later
// to know which item it belongs to.
$(reader).data('item', item);
reader.onload = function (event) {
var nbitem = $(event.target).data('item');
that.add_notebook_data(event.target.result, nbitem);
that.add_upload_button(nbitem);
};
};
}
this.element.bind('drop', function(event){
that.handelFilesUpload(event,'drop');
return false;
});
};
NotebookList.prototype.handelFilesUpload = function(event, dropOrForm) {
var that = this;
var files;
if(dropOrForm =='drop'){
files = event.originalEvent.dataTransfer.files;
} else
{
files = event.originalEvent.target.files
}
for (var i = 0, f; f = files[i]; i++) {
var reader = new FileReader();
reader.readAsText(f);
var fname = f.name.split('.');
var nbname = fname.slice(0,-1).join('.');
var nbformat = fname.slice(-1)[0];
if (nbformat === 'ipynb') {nbformat = 'json';};
if (nbformat === 'py' || nbformat === 'json') {
var item = that.new_notebook_item(0);
that.add_name_input(nbname, item);
item.data('nbformat', nbformat);
// Store the notebook item in the reader so we can use it later
// to know which item it belongs to.
$(reader).data('item', item);
reader.onload = function (event) {
var nbitem = $(event.target).data('item');
that.add_notebook_data(event.target.result, nbitem);
that.add_upload_button(nbitem);
};
};
}
return false;
};
NotebookList.prototype.clear_list = function () {
this.element.children('.list_item').remove();
@ -77,7 +88,6 @@ var IPython = (function (IPython) {
NotebookList.prototype.load_list = function () {
this.clear_list();
var settings = {
processData : false,
cache : false,
@ -92,15 +102,30 @@ var IPython = (function (IPython) {
NotebookList.prototype.list_loaded = function (data, status, xhr) {
var len = data.length;
// Todo: remove old children
this.clear_list();
if(len == 0)
{
$(this.new_notebook_item(0))
.append(
$('<div style="margin:auto;text-align:center;color:grey"/>')
.text('Notebook list empty.')
)
}
for (var i=0; i<len; i++) {
var notebook_id = data[i].notebook_id;
var nbname = data[i].name;
var kernel = data[i].kernel_id;
var item = this.new_notebook_item(i);
this.add_link(notebook_id, nbname, item);
if (!IPython.read_only){
// hide delete buttons when readonly
this.add_delete_button(item);
if(kernel == null){
this.add_delete_button(item);
} else {
this.add_shutdown_button(item,kernel);
}
}
};
};
@ -164,6 +189,32 @@ var IPython = (function (IPython) {
};
NotebookList.prototype.add_shutdown_button = function (item,kernel) {
var new_buttons = $('<span/>').addClass('item_buttons');
var that = this;
var shutdown_button = $('<button>Shutdown</button>').button().
click(function (e) {
var settings = {
processData : false,
cache : false,
type : "DELETE",
dataType : "json",
success : function (data, status, xhr) {
that.load_list();
}
};
var url = $('body').data('baseProjectUrl') + 'kernels/'+kernel;
$.ajax(url, settings);
});
new_buttons.append(shutdown_button);
var e = item.find('.item_buttons');
if (e.length === 0) {
item.append(new_buttons);
} else {
e.replaceWith(new_buttons);
};
};
NotebookList.prototype.add_delete_button = function (item) {
var new_buttons = $('<span/>').addClass('item_buttons');
var delete_button = $('<button>Delete</button>').button().
@ -217,6 +268,7 @@ var IPython = (function (IPython) {
var that = this;
var new_buttons = $('<span/>').addClass('item_buttons');
var upload_button = $('<button>Upload</button>').button().
addClass('upload-button').
click(function (e) {
var nbname = item.find('.item_name > input').attr('value');
var nbformat = item.data('nbformat');

View File

@ -30,10 +30,53 @@ $(document).ready(function () {
IPython.cluster_list = new IPython.ClusterList('div#cluster_list');
IPython.login_widget = new IPython.LoginWidget('span#login_widget');
IPython.notebook_list.load_list();
IPython.cluster_list.load_list();
var interval_id=0;
// auto refresh every xx secondes, no need to be fast,
// update is done at least when page get focus
var time_refresh = 60; // in sec
var enable_autorefresh = function(){
//refresh immediately , then start interval
if($('.upload_button').length == 0)
{
IPython.notebook_list.load_list();
IPython.cluster_list.load_list();
}
if (!interval_id){
interval_id = setInterval(function(){
if($('.upload_button').length == 0)
{
IPython.notebook_list.load_list();
IPython.cluster_list.load_list();
}
}, time_refresh*1000);
}
}
var disable_autorefresh = function(){
clearInterval(interval_id);
interval_id = 0;
}
// stop autorefresh when page lose focus
$(window).blur(function() {
disable_autorefresh();
})
//re-enable when page get focus back
$(window).focus(function() {
enable_autorefresh();
});
// finally start it, it will refresh immediately
enable_autorefresh();
IPython.page.show();
// bound the upload method to the on change of the file select list
$("#alternate_upload").change(function (event){
IPython.notebook_list.handelFilesUpload(event,'form');
});
});

View File

@ -17,7 +17,7 @@
{% if login_available %}
<form action="/login?next={{url_escape(next)}}" method="post">
Password: <input type="password" name="password" id="password_input">
Password: <input type="password" class='ui-widget ui-widget-content' name="password" id="password_input">
<input type="submit" value="Log in" id="login_submit">
</form>
{% end %}

View File

@ -65,6 +65,8 @@ data-notebook-id={{notebook_id}}
</li>
<hr/>
<li id="print_notebook"><a href="/{{notebook_id}}/print" target="_blank">Print View</a></li>
<hr/>
<li id="kill_and_exit"><a href="#" >Close and halt</a></li>
</ul>
</li>
<li><a href="#">Edit</a>

View File

@ -4,6 +4,7 @@
{% block stylesheet %}
<link rel="stylesheet" href="{{static_url("css/projectdashboard.css") }}" type="text/css" />
<link rel="stylesheet" href="{{static_url("css/alternateuploadform.css") }}" type="text/css" />
{% end %}
@ -30,9 +31,12 @@ data-read-only={{read_only}}
<div id="tab1">
{% if logged_in or not read_only %}
<div id="notebook_toolbar">
<span id="drag_info">Drag files onto the list to import
notebooks.</span>
<form id='alternate_upload' class='alternate_upload' >
<span id="drag_info" style="position:absolute" >
To import a notebook, drag the file onto the listing below or <strong>click here</strong>.
</span>
<input type="file" name="datafile" class="fileinput" multiple='multiple'>
</form>
<span id="notebook_buttons">
<button id="refresh_notebook_list" title="Refresh notebook list">Refresh</button>
<button id="new_notebook" title="Create new notebook">New Notebook</button>