Merge branch 'maintenance' into fa-update
This commit is contained in:
commit
d8d9c7fe64
20 changed files with 131 additions and 54 deletions
15
.github/ISSUE_TEMPLATE.md
vendored
15
.github/ISSUE_TEMPLATE.md
vendored
|
|
@ -10,13 +10,14 @@ This is a bug and feature tracker, please only use it to report bugs
|
|||
or request features within OctoPrint (not OctoPi, not any OctoPrint
|
||||
plugins and not unofficial OctoPrint versions).
|
||||
|
||||
Do not seek support here ("I need help with ..."), that belongs on
|
||||
the mailing list or the G+ community (both linked in the "guidelines
|
||||
for contributing" linked above, read it!), NOT here.
|
||||
Do not seek support here ("I need help with ...", "I have a
|
||||
question ..."), that belongs on the mailing list or the G+ community
|
||||
(both linked in the "guidelines for contributing" linked above, read
|
||||
them!), NOT here.
|
||||
|
||||
Mark requests with a "[Request]" prefix in the title please. Fully fill
|
||||
out the bug reporting template for bug reports (if you don't know where
|
||||
to find some information - it's all described in the Contribution
|
||||
Mark requests with a "[Request]" prefix in the title please. For bug
|
||||
reports fully fill out the bug reporting template (if you don't know
|
||||
where to find some information - it's all described in the Contribution
|
||||
Guidelines linked up there in the big yellow box).
|
||||
|
||||
When reporting a bug do NOT delete ANY lines from the template but
|
||||
|
|
@ -91,7 +92,7 @@ reporting communication issues. Never truncate.
|
|||
serial.log is usually not written due to performance reasons and must be
|
||||
enabled explicitly. Provide at the very least the FULL contents of your
|
||||
terminal tab at the time of the bug occurrence, even if you do not have
|
||||
a serial.log.]
|
||||
a serial.log (which the Contribution Guidelines tell you where to find).]
|
||||
|
||||
#### Link to contents of Javascript console in the browser
|
||||
|
||||
|
|
|
|||
|
|
@ -16,11 +16,14 @@ prerelease
|
|||
HEAD
|
||||
\(detached.*
|
||||
|
||||
# maintenance is currently the branch for preparation of maintenance release 1.3.3
|
||||
# maintenance is currently the branch for preparation of maintenance release 1.3.4
|
||||
# so are any fix/... and improve/... branches
|
||||
maintenance 1.3.3 0a69dbeddb301d5a32827a3f0d561f875df24234 pep440-dev
|
||||
fix/.* 1.3.3 0a69dbeddb301d5a32827a3f0d561f875df24234 pep440-dev
|
||||
improve/.* 1.3.3 0a69dbeddb301d5a32827a3f0d561f875df24234 pep440-dev
|
||||
maintenance 1.3.4 3fbd477d15b5776ca929ea578c5437720aaf7f31 pep440-dev
|
||||
fix/.* 1.3.4 3fbd477d15b5776ca929ea578c5437720aaf7f31 pep440-dev
|
||||
improve/.* 1.3.4 3fbd477d15b5776ca929ea578c5437720aaf7f31 pep440-dev
|
||||
|
||||
# staging/maintenance is currently the branch for preparation of 1.3.3rc3 (if we'll need that)
|
||||
staging/maintenance 1.3.3rc2 3fbd477d15b5776ca929ea578c5437720aaf7f31 pep440-dev
|
||||
|
||||
# every other branch is a development branch and thus gets resolved to 1.4.0-dev for now
|
||||
.* 1.4.0 7f5d03d0549bcbd26f40e7e4a3297ea5204fb1cc pep440-dev
|
||||
|
|
|
|||
14
CHANGELOG.md
14
CHANGELOG.md
|
|
@ -1,11 +1,21 @@
|
|||
# OctoPrint Changelog
|
||||
|
||||
## 1.3.3rc2 (2017-05-17)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* [#1917](https://github.com/foosel/OctoPrint/issues/1917) (regression) - Fix job data resetting on print job completion.
|
||||
* [#1918](https://github.com/foosel/OctoPrint/issues/1918) (regression) - Fix "save as default" checkbox not being disabled when other controls are disabled.
|
||||
* [#1919](https://github.com/foosel/OctoPrint/issues/1919) (regression) - Fix call to no longer existing function in Plugin Manager UI.
|
||||
|
||||
([Commits](https://github.com/foosel/OctoPrint/compare/1.3.3rc1...1.3.3rc2))
|
||||
|
||||
## 1.3.3rc1 (2017-05-11)
|
||||
|
||||
### Improvements
|
||||
|
||||
* [#478](https://github.com/foosel/OctoPrint/issues/478) - Made webcam stream contained fixed height (with selectable aspect ratio) to prevent jumps of the controls beneath it on load.
|
||||
* [#748](https://github.com/foosel/OctoPrint/issues/748) - Added delete confirmation and bulk delete for timelapses. See also the discussion in brainstorming ticket [#1807].(https://github.com/foosel/OctoPrint/issues/1807).
|
||||
* [#478](https://github.com/foosel/OctoPrint/issues/478) - Made webcam stream container fixed height (with selectable aspect ratio) to prevent jumps of the controls beneath it on load.
|
||||
* [#748](https://github.com/foosel/OctoPrint/issues/748) - Added delete confirmation and bulk delete for timelapses. See also the discussion in brainstorming ticket [#1807](https://github.com/foosel/OctoPrint/issues/1807).
|
||||
* [#1092](https://github.com/foosel/OctoPrint/issues/1092) - Added new event to the file manager: `FileAdded`, `FileRemoved`, `FolderAdded`, `FolderRemoved`. Contrary to the `Upload` event, `FileAdded` will always fire when a file was added to storage through the file manager, not only when added through the web interface. Extended documentation accordingly.
|
||||
* [#1521](https://github.com/foosel/OctoPrint/issues/1521) - Software update plugin: Display timestamp of last version cache refresh in "Advanced options" area.
|
||||
* [#1734](https://github.com/foosel/OctoPrint/issues/1734) - Treat default/initial printer profile like all other printer profiles, persisting it to disk instead of `config.yaml` and allowing deletion. OctoPrint will migrate the existing default profile to the new location on first start.
|
||||
|
|
|
|||
|
|
@ -365,10 +365,16 @@ There are three main branches in OctoPrint:
|
|||
the `maintenance` branch and are now being pushed on the "Maintenance"
|
||||
pre release channel for further testing. Version number follows the scheme
|
||||
`<x>.<y>.<z>rc<n>` (e.g. `1.2.9rc1`).
|
||||
* `staging/maintenance`: Any preparation for potential follow-up RCs takes place here.
|
||||
Version number follows the scheme `<x>.<y>.<z>rc<n+1>.dev<commits since increase of n>` (e.g.
|
||||
`1.2.9rc1.dev3`) for a current Maintenance RC of `<x>.<y>.<z>rc<n>`.
|
||||
* `rc/devel`: This branch is reserved for future releases that have graduated from
|
||||
the `devel` branch and are now being pushed on the "Devel" pre release channel
|
||||
for further testing. Version number follows the scheme `<x>.<y+1>.0rc<n>` (e.g. `1.3.0rc1`)
|
||||
for a current stable OctoPrint version of `<x>.<y>.<z>`.
|
||||
* `staging/devel`: Any preparation for potential follow-up Devel RCs takes place
|
||||
here. Version number follows the scheme `<x>.<y>.0rc<n+1>.dev<commits since increase of n>` (e.g.
|
||||
`1.3.0rc1.dev12`) for a current Devel RC of `<x>.<y>.0rc<n>`.
|
||||
|
||||
Additionally, from time to time you might see other branches pop up in the repository.
|
||||
Those usually have one of the following prefixes:
|
||||
|
|
|
|||
|
|
@ -64,4 +64,4 @@ thanks to everyone who contributed!
|
|||
* Timeshell.ca
|
||||
* Trent Shumay
|
||||
|
||||
and 1076 more wonderful people pledging on the [Patreon campaign](https://patreon.com/foosel)!
|
||||
and 1084 more wonderful people pledging on the [Patreon campaign](https://patreon.com/foosel)!
|
||||
|
|
@ -258,22 +258,22 @@ $(function() {
|
|||
buttons: [{
|
||||
text: gettext("Later"),
|
||||
click: function(notice) {
|
||||
self.hiddenChannels.push(key);
|
||||
notice.remove();
|
||||
self.hiddenChannels.push(key);
|
||||
}
|
||||
}, {
|
||||
text: gettext("Mark read"),
|
||||
click: function(notice) {
|
||||
self.markRead(key, value.last);
|
||||
notice.remove();
|
||||
self.markRead(key, value.last);
|
||||
}
|
||||
}, {
|
||||
text: gettext("Read..."),
|
||||
addClass: "btn-primary",
|
||||
click: function(notice) {
|
||||
notice.remove();
|
||||
self.showAnnouncementDialog(key);
|
||||
self.markRead(key, value.last);
|
||||
notice.remove();
|
||||
}
|
||||
}]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -526,13 +526,11 @@ $(function() {
|
|||
if (reinstall) {
|
||||
OctoPrint.plugins.pluginmanager.reinstall(reinstall, url, followDependencyLinks)
|
||||
.done(onSuccess)
|
||||
.fail(onError)
|
||||
.always(onAlways);
|
||||
.fail(onError);
|
||||
} else {
|
||||
OctoPrint.plugins.pluginmanager.install(url, followDependencyLinks)
|
||||
.done(onSuccess)
|
||||
.fail(onError)
|
||||
.always(onAlways);
|
||||
.fail(onError);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -687,17 +685,21 @@ $(function() {
|
|||
hide: false
|
||||
};
|
||||
|
||||
var restartClicked = false;
|
||||
if (self.restartCommandSpec) {
|
||||
options.confirm = {
|
||||
confirm: true,
|
||||
buttons: [{
|
||||
text: gettext("Restart now"),
|
||||
click: function () {
|
||||
click: function (notice) {
|
||||
if (restartClicked) return;
|
||||
restartClicked = true;
|
||||
showConfirmationDialog({
|
||||
message: gettext("This will restart your OctoPrint server."),
|
||||
onproceed: function() {
|
||||
OctoPrint.system.executeCommand("core", "restart")
|
||||
.done(function() {
|
||||
notice.remove();
|
||||
new PNotify({
|
||||
title: gettext("Restart in progress"),
|
||||
text: gettext("The server is now being restarted in the background")
|
||||
|
|
@ -709,6 +711,9 @@ $(function() {
|
|||
text: gettext("Trying to restart the server produced an error, please check octoprint.log for details. You'll have to restart manually.")
|
||||
})
|
||||
});
|
||||
},
|
||||
onclose: function() {
|
||||
restartClicked = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -718,6 +723,7 @@ $(function() {
|
|||
|
||||
notification = PNotify.singleButtonNotify(options);
|
||||
} else if (response.needs_refresh) {
|
||||
var refreshClicked = false;
|
||||
notification = PNotify.singleButtonNotify({
|
||||
title: titleSuccess,
|
||||
text: textReload,
|
||||
|
|
@ -726,6 +732,8 @@ $(function() {
|
|||
buttons: [{
|
||||
text: gettext("Reload now"),
|
||||
click: function () {
|
||||
if (refreshClicked) return;
|
||||
refreshClicked = true;
|
||||
location.reload(true);
|
||||
}
|
||||
}]
|
||||
|
|
|
|||
|
|
@ -868,7 +868,7 @@ class SoftwareUpdatePlugin(octoprint.plugin.BlueprintPlugin,
|
|||
|
||||
self._logger.info("Restarting...")
|
||||
try:
|
||||
util.execute(restart_command)
|
||||
util.execute(restart_command, evaluate_returncode=False, async=True)
|
||||
except exceptions.ScriptError as e:
|
||||
self._logger.exception("Error while restarting via command {}".format(restart_command))
|
||||
self._logger.warn("Restart stdout:\n{}".format(e.stdout))
|
||||
|
|
|
|||
|
|
@ -123,8 +123,9 @@ $(function() {
|
|||
self.config_updateMethod = ko.observable();
|
||||
self.config_releaseChannel = ko.observable();
|
||||
|
||||
self.configurationDialog = $("#settings_plugin_softwareupdate_configurationdialog");
|
||||
self.confirmationDialog = $("#softwareupdate_confirmation_dialog");
|
||||
self.configurationDialog = undefined;
|
||||
self.confirmationDialog = undefined;
|
||||
self._updateClicked = false;
|
||||
|
||||
self.config_availableCheckTypes = ko.observableArray([]);
|
||||
self.config_availableReleaseChannels = ko.observableArray([]);
|
||||
|
|
@ -357,7 +358,11 @@ $(function() {
|
|||
}, {
|
||||
text: gettext("Update now"),
|
||||
addClass: "btn-primary",
|
||||
click: self.update
|
||||
click: function() {
|
||||
if (self._updateClicked) return;
|
||||
self._updateClicked = true;
|
||||
self.update();
|
||||
}
|
||||
}]
|
||||
};
|
||||
options["buttons"] = {
|
||||
|
|
@ -501,8 +506,14 @@ $(function() {
|
|||
};
|
||||
|
||||
self.update = function(force) {
|
||||
if (self.updateInProgress) return;
|
||||
if (!self.loginState.isAdmin()) return;
|
||||
if (self.updateInProgress) {
|
||||
self._updateClicked = false;
|
||||
return;
|
||||
}
|
||||
if (!self.loginState.isAdmin()) {
|
||||
self._updateClicked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.printerState.isPrinting()) {
|
||||
self._showPopup({
|
||||
|
|
@ -510,6 +521,7 @@ $(function() {
|
|||
text: gettext("A print job is currently in progress. Updating will be prevented until it is done."),
|
||||
type: "error"
|
||||
});
|
||||
self._updateClicked = false;
|
||||
} else {
|
||||
self.forceUpdate = (force == true);
|
||||
self.confirmationDialog.modal("show");
|
||||
|
|
@ -518,9 +530,13 @@ $(function() {
|
|||
};
|
||||
|
||||
self.confirmUpdate = function() {
|
||||
self.confirmationDialog.modal("hide");
|
||||
self.performUpdate(self.forceUpdate,
|
||||
_.map(self.availableAndPossible(), function(info) { return info.key }));
|
||||
self.confirmationDialog.modal("hide");
|
||||
};
|
||||
|
||||
self.confirmationHidden = function() {
|
||||
self._updateClicked = false;
|
||||
};
|
||||
|
||||
self._showWorkingDialog = function(title) {
|
||||
|
|
@ -578,6 +594,10 @@ $(function() {
|
|||
self.onStartup = function() {
|
||||
self.workingDialog = $("#settings_plugin_softwareupdate_workingdialog");
|
||||
self.workingOutput = $("#settings_plugin_softwareupdate_workingdialog_output");
|
||||
self.configurationDialog = $("#settings_plugin_softwareupdate_configurationdialog");
|
||||
self.confirmationDialog = $("#softwareupdate_confirmation_dialog");
|
||||
|
||||
self.confirmationDialog.on("hidden", self.confirmationHidden);
|
||||
};
|
||||
|
||||
self.onServerDisconnect = function() {
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ __copyright__ = "Copyright (C) 2014 The OctoPrint Project - Released under terms
|
|||
from .exceptions import ScriptError
|
||||
|
||||
|
||||
def execute(command, cwd=None, evaluate_returncode=True):
|
||||
def execute(command, cwd=None, evaluate_returncode=True, async=False):
|
||||
import sarge
|
||||
p = None
|
||||
|
||||
try:
|
||||
p = sarge.run(command, cwd=cwd, stdout=sarge.Capture(), stderr=sarge.Capture())
|
||||
p = sarge.run(command, cwd=cwd, stdout=sarge.Capture(), stderr=sarge.Capture(), async=async)
|
||||
except:
|
||||
returncode = p.returncode if p is not None else None
|
||||
stdout = p.stdout.text if p is not None and p.stdout is not None else ""
|
||||
|
|
|
|||
|
|
@ -299,6 +299,7 @@ class PrinterInterface(object):
|
|||
after the file is selected.
|
||||
|
||||
Raises:
|
||||
InvalidFileType: if the file is not a machinecode file and hence cannot be printed
|
||||
InvalidFileLocation: if an absolute path was provided and not contained within local storage or
|
||||
doesn't exist
|
||||
"""
|
||||
|
|
@ -593,3 +594,6 @@ class UnknownScript(Exception):
|
|||
|
||||
class InvalidFileLocation(Exception):
|
||||
pass
|
||||
|
||||
class InvalidFileType(Exception):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ import time
|
|||
|
||||
from octoprint import util as util
|
||||
from octoprint.events import eventManager, Events
|
||||
from octoprint.filemanager import FileDestinations, NoSuchStorage
|
||||
from octoprint.filemanager import FileDestinations, NoSuchStorage, valid_file_type
|
||||
from octoprint.plugin import plugin_manager, ProgressPlugin
|
||||
from octoprint.printer import PrinterInterface, PrinterCallback, UnknownScript, InvalidFileLocation
|
||||
from octoprint.printer import PrinterInterface, PrinterCallback, UnknownScript, InvalidFileLocation, InvalidFileType
|
||||
from octoprint.printer.estimation import TimeEstimationHelper
|
||||
from octoprint.settings import settings
|
||||
from octoprint.util import comm as comm
|
||||
|
|
@ -846,6 +846,9 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback):
|
|||
self._stateMonitor.add_temperature(data)
|
||||
|
||||
def _validateJob(self, filename, sd):
|
||||
if not valid_file_type(filename, type="machinecode"):
|
||||
raise InvalidFileType("{} is not a machinecode file, cannot print".format(filename))
|
||||
|
||||
if sd:
|
||||
return
|
||||
|
||||
|
|
@ -1070,13 +1073,17 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback):
|
|||
must_be_set=False)
|
||||
|
||||
def on_comm_print_job_done(self):
|
||||
self._updateProgressData()
|
||||
self._stateMonitor.set_state({"text": self.get_state_string(), "flags": self._getStateFlags()})
|
||||
self._fileManager.delete_recovery_data()
|
||||
|
||||
payload = self._payload_for_print_job_event()
|
||||
if payload:
|
||||
payload["time"] = self._comm.getPrintTime()
|
||||
self._updateProgressData(completion=1.0,
|
||||
filepos=payload["size"],
|
||||
printTime=payload["time"],
|
||||
printTimeLeft=0)
|
||||
self._stateMonitor.set_state({"text": self.get_state_string(), "flags": self._getStateFlags()})
|
||||
|
||||
eventManager().fire(Events.PRINT_DONE, payload)
|
||||
self.script("afterPrintDone",
|
||||
context=dict(event=payload),
|
||||
|
|
@ -1088,6 +1095,10 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback):
|
|||
payload["time"],
|
||||
True,
|
||||
self._printerProfileManager.get_current_or_default()["id"])
|
||||
else:
|
||||
self._updateProgressData()
|
||||
self._stateMonitor.set_state({"text": self.get_state_string(), "flags": self._getStateFlags()})
|
||||
|
||||
|
||||
def on_comm_print_job_failed(self):
|
||||
payload = self._payload_for_print_job_event()
|
||||
|
|
@ -1134,7 +1145,7 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback):
|
|||
self._sdStreaming = True
|
||||
|
||||
self._setJobData(filename, filesize, True)
|
||||
self._updateProgressData()
|
||||
self._updateProgressData(completion=0.0, filepos=0, printTime=0)
|
||||
self._stateMonitor.set_state({"text": self.get_state_string(), "flags": self._getStateFlags()})
|
||||
|
||||
def on_comm_file_transfer_done(self, filename):
|
||||
|
|
@ -1162,6 +1173,7 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback):
|
|||
self._logger.exception("Error while trying to persist print recovery data")
|
||||
|
||||
def _payload_for_print_job_event(self, location=None, print_job_file=None, position=None):
|
||||
print_job_size = None
|
||||
if print_job_file is None:
|
||||
with self._selectedFileMutex:
|
||||
selected_file = self._selectedFile
|
||||
|
|
@ -1169,9 +1181,10 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback):
|
|||
return dict()
|
||||
|
||||
print_job_file = selected_file.get("filename", None)
|
||||
print_job_size = selected_file.get("filesize", None)
|
||||
location = FileDestinations.SDCARD if selected_file.get("sd", False) else FileDestinations.LOCAL
|
||||
|
||||
if not print_job_file or not location:
|
||||
if not print_job_file or not print_job_size or not location:
|
||||
return dict()
|
||||
|
||||
if location == FileDestinations.SDCARD:
|
||||
|
|
@ -1190,6 +1203,7 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback):
|
|||
result= dict(name=name,
|
||||
path=path,
|
||||
origin=origin,
|
||||
size=print_job_size,
|
||||
|
||||
# TODO deprecated, remove in 1.4.0
|
||||
file=full_path,
|
||||
|
|
|
|||
|
|
@ -550,7 +550,7 @@ class Server(object):
|
|||
"on_shutdown",
|
||||
sorting_context="ShutdownPlugin.on_shutdown")
|
||||
|
||||
# wait for shutdown even to be processed, but maximally for 15s
|
||||
# wait for shutdown event to be processed, but maximally for 15s
|
||||
event_timeout = 15.0
|
||||
if eventManager.join(timeout=event_timeout):
|
||||
self._logger.warn("Event loop was still busy processing after {}s, shutting down anyhow".format(event_timeout))
|
||||
|
|
@ -565,13 +565,16 @@ class Server(object):
|
|||
def sigterm_handler(*args, **kwargs):
|
||||
# will stop tornado on SIGTERM, making the program exit cleanly
|
||||
def shutdown_tornado():
|
||||
self._logger.debug("Shutting down tornado's IOLoop...")
|
||||
ioloop.stop()
|
||||
self._logger.debug("SIGTERM received...")
|
||||
ioloop.add_callback_from_signal(shutdown_tornado)
|
||||
signal.signal(signal.SIGTERM, sigterm_handler)
|
||||
|
||||
try:
|
||||
# this is the main loop - as long as tornado is running, OctoPrint is running
|
||||
ioloop.start()
|
||||
self._logger.debug("Tornado's IOLoop stopped")
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
pass
|
||||
except:
|
||||
|
|
|
|||
|
|
@ -646,6 +646,7 @@ function showConfirmationDialog(msg, onacknowledge, options) {
|
|||
var proceed = options.proceed || gettext("Proceed");
|
||||
var proceedClass = options.proceedClass || "danger";
|
||||
var onproceed = options.onproceed || undefined;
|
||||
var onclose = options.onclose || undefined;
|
||||
var dialogClass = options.dialogClass || "";
|
||||
|
||||
var modalHeader = $('<a href="javascript:void(0)" class="close" data-dismiss="modal" aria-hidden="true">×</a><h3>' + title + '</h3>');
|
||||
|
|
@ -663,14 +664,19 @@ function showConfirmationDialog(msg, onacknowledge, options) {
|
|||
.append($('<div></div>').addClass('modal-header').append(modalHeader))
|
||||
.append($('<div></div>').addClass('modal-body').append(modalBody))
|
||||
.append($('<div></div>').addClass('modal-footer').append(cancelButton).append(proceedButton));
|
||||
modal.on('hidden', function(event) {
|
||||
if (onclose && _.isFunction(onclose)) {
|
||||
onclose(event);
|
||||
}
|
||||
});
|
||||
modal.modal("show");
|
||||
|
||||
proceedButton.click(function(e) {
|
||||
e.preventDefault();
|
||||
modal.modal("hide");
|
||||
if (onproceed && _.isFunction(onproceed)) {
|
||||
onproceed(e);
|
||||
}
|
||||
modal.modal("hide");
|
||||
});
|
||||
|
||||
return modal;
|
||||
|
|
|
|||
|
|
@ -442,6 +442,7 @@ $(function() {
|
|||
self.additionalControls = additionalControls;
|
||||
self.rerenderControls();
|
||||
}
|
||||
self._enableWebcam();
|
||||
};
|
||||
|
||||
self.onFocus = function (data, event) {
|
||||
|
|
|
|||
|
|
@ -841,13 +841,14 @@ $(function() {
|
|||
|
||||
function evaluateDropzones() {
|
||||
var enableLocal = self.loginState.isUser();
|
||||
var enableSd = enableLocal && CONFIG_SD_SUPPORT && self.printerState.isSdReady();
|
||||
var enableSd = enableLocal && CONFIG_SD_SUPPORT && self.printerState.isSdReady() && !self.isPrinting();
|
||||
|
||||
self._setDropzone("local", enableLocal);
|
||||
self._setDropzone("sdcard", enableSd);
|
||||
}
|
||||
self.loginState.isUser.subscribe(evaluateDropzones);
|
||||
self.printerState.isSdReady.subscribe(evaluateDropzones);
|
||||
self.isPrinting.subscribe(evaluateDropzones);
|
||||
evaluateDropzones();
|
||||
|
||||
self.requestData();
|
||||
|
|
@ -1106,7 +1107,7 @@ $(function() {
|
|||
if (foundLocal) {
|
||||
self.dropZoneLocalBackground.addClass("hover");
|
||||
self.dropZoneSdBackground.removeClass("hover");
|
||||
} else if (foundSd && self.printerState.isSdReady()) {
|
||||
} else if (foundSd && self.printerState.isSdReady() && !self.isPrinting()) {
|
||||
self.dropZoneSdBackground.addClass("hover");
|
||||
self.dropZoneLocalBackground.removeClass("hover");
|
||||
} else if (found) {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ $(function() {
|
|||
return ("timed" == self.timelapseType());
|
||||
});
|
||||
self.saveButtonEnabled = ko.pureComputed(function() {
|
||||
return self.isDirty() && self.isOperational() && !self.isPrinting() && self.loginState.isUser();
|
||||
return self.isDirty() && !self.isPrinting() && self.loginState.isUser();
|
||||
});
|
||||
|
||||
self.isOperational.subscribe(function() {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
{% if enableSdSupport %}
|
||||
<div class="dropzone" id="drop_locally"><span class="text"><i class="fa fa-upload"></i><br>{{ _('Upload locally') }}</span></div>
|
||||
<div class="dropzone_background" id="drop_locally_background"></div>
|
||||
<div class="dropzone" id="drop_sd"><span class="text"><i class="fa fa-upload"></i><br>{{ _('Upload to SD') }}<br><small data-bind="visible: !isSdReady()">({{ _('SD not initialized') }})</small></span></div>
|
||||
<div class="dropzone" id="drop_sd"><span class="text"><i class="fa fa-upload"></i><br>{{ _('Upload to SD') }}<br><small data-bind="visible: isSdReady() && isPrinting()">({{ _('Cannot upload to printer\'s SD while printing') }})</small><small data-bind="visible: !isSdReady()">({{ _('SD not initialized') }})</small></span></div>
|
||||
<div class="dropzone_background" id="drop_sd_background"></div>
|
||||
{% else %}
|
||||
<div class="dropzone" id="drop"><span class="text"><i class="fa fa-upload"></i><br>{{ _('Upload') }}</span></div>
|
||||
|
|
|
|||
|
|
@ -55,18 +55,18 @@
|
|||
</div>
|
||||
<div class="row-fluid upload-buttons">
|
||||
{% if enableSdSupport %}
|
||||
<span class="btn btn-primary fileinput-button span6" data-bind="css: {disabled: !$root.loginState.isUser()}" style="margin-bottom: 10px">
|
||||
<span class="btn btn-primary fileinput-button span6" data-bind="enable: $root.loginState.isUser(), css: {disabled: !$root.loginState.isUser()}" style="margin-bottom: 10px">
|
||||
<i class="fa fa-upload"></i>
|
||||
<span>{{ _('Upload') }}</span>
|
||||
<input id="gcode_upload" accept="{{ ",".join(supportedExtensions) }}" type="file" name="file" class="fileinput-button" data-bind="enable: loginState.isUser()">
|
||||
</span>
|
||||
<span class="btn btn-primary fileinput-button span6" data-bind="css: {disabled: !$root.loginState.isUser() || !$root.isSdReady()}" style="margin-bottom: 10px">
|
||||
<span class="btn btn-primary fileinput-button span6" data-bind="enable: $root.loginState.isUser() && $root.isSdReady() && !$root.isPrinting(), css: {disabled: !$root.loginState.isUser() || !$root.isSdReady() || $root.isPrinting()}" style="margin-bottom: 10px">
|
||||
<i class="fa fa-upload"></i>
|
||||
<span>{{ _('Upload to SD') }}</span>
|
||||
<input id="gcode_upload_sd" accept="{{ ",".join(supportedExtensions) }}" type="file" name="file" class="fileinput-button" data-bind="enable: loginState.isUser() && isSdReady()">
|
||||
<input id="gcode_upload_sd" accept="{{ ",".join(supportedExtensions) }}" type="file" name="file" class="fileinput-button" data-bind="enable: loginState.isUser() && isSdReady() && !isPrinting()">
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="btn btn-primary fileinput-button span12" data-bind="css: {disabled: !$root.loginState.isUser()}" style="margin-bottom: 10px">
|
||||
<span class="btn btn-primary fileinput-button span12" data-bind="enable: $root.loginState.isUser(), css: {disabled: !$root.loginState.isUser()}" style="margin-bottom: 10px">
|
||||
<i class="fa fa-upload"></i>
|
||||
<span>{{ _('Upload') }}</span>
|
||||
<input id="gcode_upload" accept="{{ ",".join(supportedExtensions) }}" type="file" name="file" class="fileinput-button" data-bind="enable: loginState.isUser()">
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<h1>{{ _('Timelapse Configuration') }}</h1>
|
||||
|
||||
<label for="webcam_timelapse_mode">{{ _('Timelapse Mode') }}</label>
|
||||
<select id="webcam_timelapse_mode" data-bind="value: timelapseType, enable: isOperational() && !isPrinting() && loginState.isUser()">
|
||||
<select id="webcam_timelapse_mode" data-bind="value: timelapseType, enable: !isPrinting() && loginState.isUser()">
|
||||
<option value="off">{{ _('Off') }}</option>
|
||||
<option value="timed">{{ _('Timed') }}</option>
|
||||
<option value="zchange">{{ _('On Z Change') }}</option>
|
||||
|
|
@ -16,25 +16,25 @@
|
|||
<div id="webcam_timelapse_timedsettings" data-bind="visible: intervalInputEnabled">
|
||||
<label for="webcam_timelapse_interval">{{ _('Interval between snapshots (in seconds)') }}</label>
|
||||
<div class="input-append">
|
||||
<input type="text" class="input-mini" id="webcam_timelapse_interval" data-bind="value: timelapseTimedInterval, valueUpdate: 'afterkeydown', enable: isOperational() && !isPrinting() && loginState.isUser()">
|
||||
<input type="text" class="input-mini" id="webcam_timelapse_interval" data-bind="value: timelapseTimedInterval, valueUpdate: 'afterkeydown', enable: !isPrinting() && loginState.isUser()">
|
||||
<span class="add-on">{{ _('sec') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label for="webcam_timelapse_fps">{{ _('Timelapse frame rate (in frames per second)') }}</label>
|
||||
<div class="input-append">
|
||||
<input type="text" class="input-mini" id="webcam_timelapse_fps" data-bind="value: timelapseFps, valueUpdate: 'afterkeydown', enable: isOperational() && !isPrinting() && loginState.isUser() && timelapseTypeSelected()">
|
||||
<input type="text" class="input-mini" id="webcam_timelapse_fps" data-bind="value: timelapseFps, valueUpdate: 'afterkeydown', enable: !isPrinting() && loginState.isUser() && timelapseTypeSelected()">
|
||||
<span class="add-on">{{ _('fps') }}</span>
|
||||
</div>
|
||||
|
||||
<label for="webcam_timelapse_postRoll">{{ _('Timelapse post roll (in rendered seconds)') }}</label>
|
||||
<div class="input-append">
|
||||
<input type="text" class="input-mini" id="webcam_timelapse_postRoll" data-bind="value: timelapsePostRoll, valueUpdate: 'afterkeydown', enable: isOperational() && !isPrinting() && loginState.isUser() && timelapseTypeSelected()">
|
||||
<input type="text" class="input-mini" id="webcam_timelapse_postRoll" data-bind="value: timelapsePostRoll, valueUpdate: 'afterkeydown', enable: !isPrinting() && loginState.isUser() && timelapseTypeSelected()">
|
||||
<span class="add-on">{{ _('sec') }}</span>
|
||||
</div>
|
||||
<div id="webcam_timelapse_capturePostRoll" data-bind="visible: timelapseType() == 'timed'">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: timelapseCapturePostRoll, valueUpdate: 'afterkeydown', enable: isOperational() && !isPrinting() && loginState.isUser()"> {{ _('Capture post roll images') }}
|
||||
<input type="checkbox" data-bind="checked: timelapseCapturePostRoll, valueUpdate: 'afterkeydown', enable: !isPrinting() && loginState.isUser()"> {{ _('Capture post roll images') }}
|
||||
<span class="help-block">{{ _('If this is unchecked, OctoPrint will simply repeat the last frame for the post roll instead of continuing to capture new frames.') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
<div id="webcam_timelapse_retractionsettings" data-bind="visible: timelapseType() == 'zchange'">
|
||||
<label for="webcam_timelapse_retractionZHop">{{ _('Retraction Z-Hop (in mm)') }}</label>
|
||||
<div class="input-append">
|
||||
<input type="text" class="input-mini" id="webcam_timelapse_retractionZHop" data-bind="value: timelapseRetractionZHop, valueUpdate: 'afterkeydown', enable: isOperational() && !isPrinting() && loginState.isUser()">
|
||||
<input type="text" class="input-mini" id="webcam_timelapse_retractionZHop" data-bind="value: timelapseRetractionZHop, valueUpdate: 'afterkeydown', enable: !isPrinting() && loginState.isUser()">
|
||||
<span class="add-on">{{ _('mm') }}</span>
|
||||
</div>
|
||||
<span class="help-block">{{ _('Enter the retraction z-hop used in the firmware or the gcode file to trigger snapshots for the timelapse only if a real layer change happens. For this to work properly your retraction z-hop has to be different from your layerheight!') }}</span>
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
|
||||
<div data-bind="visible: loginState.isAdmin">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: persist"> {{ _('Save as default') }}
|
||||
<input type="checkbox" data-bind="checked: persist, enable: isOperational() && !isPrinting() && loginState.isUser()"> {{ _('Save as default') }}
|
||||
<span class="help-block">{{ _('Check this to make your selected timelapse mode and options persist across restarts.') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue