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

Dashboard improvement (necessary merge of #1658 and #1676 + fix #1492) #1739

Merged
merged 22 commits into from May 31, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 IPython/frontend/html/notebook/handlers.py
Expand Up @@ -590,7 +590,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
Expand Down
23 changes: 23 additions & 0 deletions IPython/frontend/html/notebook/static/css/alternateuploadform.css
@@ -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;
}
3 changes: 2 additions & 1 deletion IPython/frontend/html/notebook/static/css/boilerplate.css
Expand Up @@ -70,4 +70,5 @@ select, input, textarea, button { font:99% sans-serif; }
en.wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome */
pre, code, kbd, samp { font-family: monospace, sans-serif; }


em,i { font-style: italic; }
b,strong { font-weight: bold; }
4 changes: 4 additions & 0 deletions IPython/frontend/html/notebook/static/js/menubar.js
Expand Up @@ -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();
Expand Down
104 changes: 78 additions & 26 deletions IPython/frontend/html/notebook/static/js/notebooklist.js
Expand Up @@ -43,41 +43,51 @@ 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();
}


NotebookList.prototype.load_list = function () {
this.clear_list();
var settings = {
processData : false,
cache : false,
Expand All @@ -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);
}
}
};
};
Expand Down Expand Up @@ -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().
Expand Down Expand Up @@ -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');
Expand Down
47 changes: 45 additions & 2 deletions IPython/frontend/html/notebook/static/js/projectdashboardmain.js
Expand Up @@ -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');
});

});

2 changes: 1 addition & 1 deletion IPython/frontend/html/notebook/templates/login.html
Expand Up @@ -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 %}
Expand Down
2 changes: 2 additions & 0 deletions IPython/frontend/html/notebook/templates/notebook.html
Expand Up @@ -65,6 +65,8 @@
</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>
Expand Down
10 changes: 7 additions & 3 deletions IPython/frontend/html/notebook/templates/projectdashboard.html
Expand Up @@ -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 %}


Expand All @@ -30,9 +31,12 @@
<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>
Expand Down