diff --git a/src/octoprint/server/api/timelapse.py b/src/octoprint/server/api/timelapse.py
index 43f2aaee..340e4d45 100644
--- a/src/octoprint/server/api/timelapse.py
+++ b/src/octoprint/server/api/timelapse.py
@@ -7,6 +7,7 @@ __copyright__ = "Copyright (C) 2014 The OctoPrint Project - Released under terms
import os
import threading
+import logging
from flask import request, jsonify, url_for, make_response
from werkzeug.utils import secure_filename
@@ -128,7 +129,12 @@ def deleteTimelapse(filename):
timelapse_folder = settings().getBaseFolder("timelapse")
full_path = os.path.realpath(os.path.join(timelapse_folder, filename))
if full_path.startswith(timelapse_folder) and os.path.exists(full_path):
- os.remove(full_path)
+ try:
+ os.remove(full_path)
+ except Exception as ex:
+ logging.getLogger(__file__).exception("Error deleting timelapse file {}".format(full_path))
+ return make_response("Unexpected error: {}".format(ex), 500)
+
return getTimelapseData()
diff --git a/src/octoprint/static/js/app/helpers.js b/src/octoprint/static/js/app/helpers.js
index d7248db6..2d0d28d4 100644
--- a/src/octoprint/static/js/app/helpers.js
+++ b/src/octoprint/static/js/app/helpers.js
@@ -688,9 +688,14 @@ function showConfirmationDialog(msg, onacknowledge, options) {
* Will listen to the supplied promise, update the progress on .progress events and
* enabling the close button and (optionally) closing the dialog on promise resolve.
*
- * The calling code should call "notify" on the deferred backing the promise and supply
- * two parameters: the text to display on the progress bar and the optional output field and
- * a boolean value indicating whether the operation behind that update was successful or not.
+ * The calling code should call "notify" on the deferred backing the promise and supply:
+ *
+ * * the text to display on the progress bar and the optional output field and
+ * a boolean value indicating whether the operation behind that update was successful or not
+ * * a short text to display on the progress bar, a long text to display on the optional output
+ * field and a boolean value indicating whether the operation behind that update was
+ * successful or not
+ *
* Non-successful progress updates will remove the barClassSuccess class from the progress bar and
* apply the barClassFailure class and also apply the outputClassFailure to the produced line
* in the output.
@@ -784,7 +789,19 @@ function showProgressModal(options, promise) {
var counter = 0;
promise
- .progress(function(text, success) {
+ .progress(function() {
+ var short, long, success;
+ if (arguments.length === 2) {
+ short = long = arguments[0];
+ success = arguments[1];
+ } else if (arguments.length === 3) {
+ short = arguments[0];
+ long = arguments[1];
+ success = arguments[2];
+ } else {
+ throw Error("Invalid parameters for showProgressModal, expected either (text, success) or (short, long, success)");
+ }
+
var value;
if (max === undefined || max <= 0) {
@@ -796,8 +813,8 @@ function showProgressModal(options, promise) {
// update progress bar
progressBar.width(String(value) + "%");
- progressTextFront.text(text);
- progressTextBack.text(text);
+ progressTextFront.text(short);
+ progressTextBack.text(short);
progressTextFront.width(progress.width());
// if not successful, apply failure class
@@ -809,9 +826,9 @@ function showProgressModal(options, promise) {
if (output && pre) {
if (success) {
- pre.append($("" + text + "
"));
+ pre.append($("" + long + "
"));
} else {
- pre.append($("" + text + "
"));
+ pre.append($("" + long + "
"));
}
pre.scrollTop(pre[0].scrollHeight - pre.height());
}
diff --git a/src/octoprint/static/js/app/viewmodels/timelapse.js b/src/octoprint/static/js/app/viewmodels/timelapse.js
index d8dae375..88c19a03 100644
--- a/src/octoprint/static/js/app/viewmodels/timelapse.js
+++ b/src/octoprint/static/js/app/viewmodels/timelapse.js
@@ -229,6 +229,16 @@ $(function() {
.done(function() {
self.markedForFileDeletion.remove(filename);
self.requestData()
+ })
+ .fail(function(jqXHR) {
+ var html = "
" + _.sprintf(gettext("Failed to remove timelapse %(name)s.
Please consult octoprint.log for details.
"), {name: filename}); + html += pnotifyAdditionalInfo('' + jqXHR.responseText + ''); + new PNotify({ + title: gettext("Could not remove timelapse"), + text: html, + type: "error", + hide: false + }); }); }; @@ -288,7 +298,7 @@ $(function() { self._bulkRemove = function(files, type) { var title, message, handler; - if (type == "files") { + if (type === "files") { title = gettext("Deleting timelapse files"); message = _.sprintf(gettext("Deleting %(count)d timelapse files..."), {count: files.length}); handler = function(filename) { @@ -296,11 +306,13 @@ $(function() { .done(function() { deferred.notify(_.sprintf(gettext("Deleted %(filename)s..."), {filename: filename}), true); }) - .fail(function() { - deferred.notify(_.sprintf(gettext("Deletion of %(filename)s failed, continuing..."), {filename: filename}), false); + .fail(function(jqXHR) { + var short = _.sprintf(gettext("Deletion of %(filename)s failed, continuing..."), {filename: filename}); + var long = _.sprintf(gettext("Deletion of %(filename)s failed: %(error)s"), {filename: filename, error: jqXHR.responseText}); + deferred.notify(short, long, false); }); } - } else if (type == "unrendered") { + } else if (type === "unrendered") { title = gettext("Deleting unrendered timelapses"); message = _.sprintf(gettext("Deleting %(count)d unrendered timelapses..."), {count: files.length}); handler = function(filename) {