add dialogs for failed save/load

- failed validation doesn't prevent save/load,
  but the user is now warned about it.
- there is now a warning dialog if fromJSON fails,
  rather than the usual silent failure.
This commit is contained in:
MinRK 2014-09-10 17:09:42 -07:00
parent 1a4b795870
commit ddd3aa2a5a
3 changed files with 97 additions and 1 deletions

View File

@ -176,6 +176,7 @@ class FileContentsManager(ContentsManager):
model['created'] = created
model['content'] = None
model['format'] = None
model['message'] = None
return model
def _dir_model(self, name, path='', content=True):
@ -258,6 +259,7 @@ class FileContentsManager(ContentsManager):
self.mark_trusted_cells(nb, name, path)
model['content'] = nb
model['format'] = 'json'
self.validate_notebook_model(model)
return model
def get_model(self, name, path='', content=True):
@ -366,7 +368,14 @@ class FileContentsManager(ContentsManager):
except Exception as e:
raise web.HTTPError(400, u'Unexpected error while saving file: %s %s' % (os_path, e))
validation_message = None
if model['type'] == 'notebook':
self.validate_notebook_model(model)
validation_message = model.get('message', None)
model = self.get_model(new_name, new_path, content=False)
if validation_message:
model['message'] = validation_message
return model
def update(self, model, name, path=''):

View File

@ -5,6 +5,7 @@
from fnmatch import fnmatch
import itertools
import json
import os
from tornado.web import HTTPError
@ -216,6 +217,16 @@ class ContentsManager(LoggingConfigurable):
break
return name
def validate_notebook_model(self, model):
"""Add failed-validation message to model"""
try:
current.validate(model['content'])
except current.ValidationError as e:
model['message'] = 'Notebook Validation failed: {}:\n{}'.format(
e.message, json.dumps(e.instance, indent=1, default=lambda obj: '<UNKNOWN>'),
)
return model
def create_file(self, model=None, path='', ext='.ipynb'):
"""Create a new file or directory and return its model with no content."""
path = path.strip('/')

View File

@ -1826,6 +1826,7 @@ define([
* @param {Object} data JSON representation of a notebook
*/
Notebook.prototype.fromJSON = function (data) {
var content = data.content;
var ncells = this.ncells();
var i;
@ -1975,6 +1976,7 @@ define([
type : "PUT",
data : JSON.stringify(model),
headers : {'Content-Type': 'application/json'},
dataType : "json",
success : $.proxy(this.save_notebook_success, this, start),
error : $.proxy(this.save_notebook_error, this)
};
@ -2004,6 +2006,30 @@ define([
*/
Notebook.prototype.save_notebook_success = function (start, data, status, xhr) {
this.set_dirty(false);
if (data.message) {
// save succeeded, but validation failed.
var body = $("<div>");
var title = "Notebook validation failed";
body.append($("<p>").text(
"The save operation succeeded," +
" but the notebook does not appear to be valid." +
" The validation error was:"
)).append($("<div>").addClass("validation-error").append(
$("<pre>").text(data.message)
));
dialog.modal({
notebook: this,
keyboard_manager: this.keyboard_manager,
title: title,
body: body,
buttons : {
OK : {
"class" : "btn-primary"
}
}
});
}
this.events.trigger('notebook_saved.Notebook');
this._update_autosave_interval(start);
if (this._checkpoint_after_save) {
@ -2278,7 +2304,57 @@ define([
* @param {jqXHR} xhr jQuery Ajax object
*/
Notebook.prototype.load_notebook_success = function (data, status, xhr) {
this.fromJSON(data);
var failed;
try {
this.fromJSON(data);
} catch (e) {
failed = e;
console.log("Notebook failed to load from JSON:", e);
}
if (failed || data.message) {
// *either* fromJSON failed or validation failed
var body = $("<div>");
var title;
if (failed) {
title = "Notebook failed to load";
body.append($("<p>").text(
"The error was: "
)).append($("<div>").addClass("js-error").text(
failed.toString()
)).append($("<p>").text(
"See the error console for details."
));
} else {
title = "Notebook validation failed";
}
if (data.message) {
var msg;
if (failed) {
msg = "The notebook also failed validation:"
} else {
msg = "An invalid notebook may not function properly." +
" The validation error was:"
}
body.append($("<p>").text(
msg
)).append($("<div>").addClass("validation-error").append(
$("<pre>").text(data.message)
));
}
dialog.modal({
notebook: this,
keyboard_manager: this.keyboard_manager,
title: title,
body: body,
buttons : {
OK : {
"class" : "btn-primary"
}
}
});
}
if (this.ncells() === 0) {
this.insert_cell_below('code');
this.edit_mode(0);