From f20185db3a9ed2473b13404c7b426409e72b767a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Tue, 27 Jun 2017 11:32:42 +0200 Subject: [PATCH] Better handling of timelapse deletion errors Closes #1975 --- src/octoprint/server/api/timelapse.py | 8 ++++- src/octoprint/static/js/app/helpers.js | 33 ++++++++++++++----- .../static/js/app/viewmodels/timelapse.js | 20 ++++++++--- 3 files changed, 48 insertions(+), 13 deletions(-) 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) {