Merge remote-tracking branch 'remotes/upstream/devel' into dev/folderSupport
Conflicts: src/octoprint/static/js/app/viewmodels/files.js
This commit is contained in:
commit
59cb448913
52 changed files with 2550 additions and 1195 deletions
15
CHANGELOG.md
15
CHANGELOG.md
|
|
@ -2,6 +2,19 @@
|
|||
|
||||
## 1.3.0 (unreleased)
|
||||
|
||||
### New Features
|
||||
|
||||
* A new wizard dialog for system setups that can also be extended by plugins. Replaces the first run dialog
|
||||
for setting up access control and can also be triggered in other cases than only the first run, e.g.
|
||||
if Plugins necessitate user input to function properly.
|
||||
* An About dialog including licenses, authors, the changelog and more, extendable by plugins if necessary.
|
||||
* New features within the plugin system (TODO):
|
||||
* New plugin mixin `UiPlugin` for plugins that want to provide an alternative web interface delivered by the
|
||||
server.
|
||||
* Extracted a Javascript client library for utilizing the server's API, can be reused by `UiPlugin`s. (TODO)
|
||||
|
||||
(TODO) = needs to be further described and documented
|
||||
|
||||
### Improvements
|
||||
|
||||
* Upgraded versioneer, generated version numbers are now PEP440 compatible (relevant
|
||||
|
|
@ -41,6 +54,8 @@
|
|||
but a target temperature is set - this way the graph should be more responsive
|
||||
while monitoring a manual heatup.
|
||||
* Documentation improvements
|
||||
* Test buttons for webcam snapshot & stream URL, ffmpeg path and some other settings
|
||||
(see also [#183](https://github.com/foosel/OctoPrint/issues/183)).
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
|
|
|
|||
|
|
@ -53,26 +53,22 @@ $(function() {
|
|||
};
|
||||
|
||||
self._sendData = function(data, callback) {
|
||||
$.ajax({
|
||||
url: BASEURL + "plugin/corewizard/acl",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: data,
|
||||
success: function() {
|
||||
OctoPrint.postJson("plugin/corewizard/acl", data)
|
||||
.done(function() {
|
||||
self.setup(true);
|
||||
self.decision(data.ac);
|
||||
if (data.ac) {
|
||||
// we now log the user in
|
||||
var user = data.user;
|
||||
var pass = data.pass1;
|
||||
self.loginStateViewModel.login(user, pass, true, function() {
|
||||
if (callback) callback();
|
||||
});
|
||||
self.loginStateViewModel.login(user, pass, true)
|
||||
.done(function() {
|
||||
if (callback) callback();
|
||||
});
|
||||
} else {
|
||||
if (callback) callback();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self.onWizardTabChange = function(current, next) {
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ $(function() {
|
|||
dataType: "json",
|
||||
maxNumberOfFiles: 1,
|
||||
autoUpload: false,
|
||||
headers: OctoPrint.getRequestHeaders(),
|
||||
add: function(e, data) {
|
||||
if (data.files.length == 0) {
|
||||
return false;
|
||||
|
|
@ -131,14 +132,11 @@ $(function() {
|
|||
return (item.key == data.key);
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: data.resource(),
|
||||
type: "DELETE",
|
||||
success: function() {
|
||||
OctoPrint.slicing.deleteProfileForSlicer("cura", data.key, {url: data.resource})
|
||||
.done(function() {
|
||||
self.requestData();
|
||||
self.slicingViewModel.requestData();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self.makeProfileDefault = function(data) {
|
||||
|
|
@ -156,16 +154,10 @@ $(function() {
|
|||
item.isdefault(true);
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: data.resource(),
|
||||
type: "PATCH",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({default: true}),
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
success: function() {
|
||||
OctoPrint.slicing.updateProfileForSlicer("cura", data.key, {default: true}, {url: data.resource()})
|
||||
.done(function() {
|
||||
self.requestData();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self.showImportProfileDialog = function(makeDefault) {
|
||||
|
|
@ -176,13 +168,9 @@ $(function() {
|
|||
$("#settings_plugin_cura_import").modal("show");
|
||||
};
|
||||
|
||||
self.testEnginePath = function(successCallback) {
|
||||
self.sendTestRequest(self.settings.plugins.cura.cura_engine());
|
||||
};
|
||||
|
||||
self.sendTestRequest = function(enginePath, successCallback) {
|
||||
if (successCallback == undefined) {
|
||||
successCallback = function(response) {
|
||||
self.testEnginePath = function() {
|
||||
OctoPrint.util.testExecutable(self.settings.plugins.cura.cura_engine())
|
||||
.done(function(response) {
|
||||
if (!response.result) {
|
||||
if (!response.exists) {
|
||||
self.pathText(gettext("The path doesn't exist"));
|
||||
|
|
@ -196,31 +184,12 @@ $(function() {
|
|||
}
|
||||
self.pathOk(response.result);
|
||||
self.pathBroken(!response.result);
|
||||
}
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "util/test",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({
|
||||
command: "path",
|
||||
path: enginePath,
|
||||
check_type: "file",
|
||||
check_access: "x"
|
||||
}),
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
success: successCallback
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
self.requestData = function() {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "slicing/cura/profiles",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: self.fromResponse
|
||||
});
|
||||
OctoPrint.slicing.listProfilesForSlicer("cura")
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.fromResponse = function(data) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,70 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var exports = {};
|
||||
|
||||
exports.get = function(refresh, opts) {
|
||||
return OctoPrint.get(OctoPrint.getSimpleApiUrl("pluginmanager") + ((refresh) ? "?refresh_repository=true" : ""), opts);
|
||||
};
|
||||
|
||||
exports.getWithRefresh = function(opts) {
|
||||
return exports.get(true, opts);
|
||||
};
|
||||
|
||||
exports.getWithoutRefresh = function(opts) {
|
||||
return exports.get(false, opts);
|
||||
};
|
||||
|
||||
exports.install = function(pluginUrl, dependencyLinks, opts) {
|
||||
var data = {
|
||||
url: pluginUrl,
|
||||
dependency_links: !!dependencyLinks
|
||||
};
|
||||
return OctoPrint.simpleApiCommand("pluginmanager", "install", data, opts);
|
||||
};
|
||||
|
||||
exports.reinstall = function(plugin, pluginUrl, dependencyLinks, opts) {
|
||||
var data = {
|
||||
url: pluginUrl,
|
||||
dependency_links: !!dependencyLinks,
|
||||
reinstall: plugin,
|
||||
force: true
|
||||
};
|
||||
return OctoPrint.simpleApiCommand("pluginmanager", "install", data, opts);
|
||||
};
|
||||
|
||||
exports.uninstall = function(plugin, opts) {
|
||||
var data = {
|
||||
plugin: plugin
|
||||
};
|
||||
return OctoPrint.simpleApiCommand("pluginmanager", "uninstall", data, opts);
|
||||
};
|
||||
|
||||
exports.enable = function(plugin, opts) {
|
||||
var data = {
|
||||
plugin: plugin
|
||||
};
|
||||
return OctoPrint.simpleApiCommand("pluginmanager", "enable", data, opts);
|
||||
};
|
||||
|
||||
exports.disable = function(plugin, opts) {
|
||||
var data = {
|
||||
plugin: plugin
|
||||
};
|
||||
return OctoPrint.simpleApiCommand("pluginmanager", "disable", data, opts);
|
||||
};
|
||||
|
||||
exports.upload = function(file) {
|
||||
return OctoPrint.upload(OctoPrint.getBlueprintUrl("pluginmanager") + "upload_archive", file);
|
||||
};
|
||||
|
||||
OctoPrint.plugins.pluginmanager = exports;
|
||||
});
|
||||
|
||||
$(function() {
|
||||
function PluginManagerViewModel(parameters) {
|
||||
var self = this;
|
||||
|
|
@ -5,6 +72,7 @@ $(function() {
|
|||
self.loginState = parameters[0];
|
||||
self.settingsViewModel = parameters[1];
|
||||
self.printerState = parameters[2];
|
||||
self.systemViewModel = parameters[3];
|
||||
|
||||
self.config_repositoryUrl = ko.observable();
|
||||
self.config_repositoryTtl = ko.observable();
|
||||
|
|
@ -104,6 +172,20 @@ $(function() {
|
|||
self.workingDialog = undefined;
|
||||
self.workingOutput = undefined;
|
||||
|
||||
self.restartCommandSpec = undefined;
|
||||
self.systemViewModel.systemActions.subscribe(function() {
|
||||
var lastResponse = self.systemViewModel.lastCommandResponse;
|
||||
if (!lastResponse || !lastResponse.core) {
|
||||
self.restartCommandSpec = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
var restartSpec = _.filter(lastResponse.core, function(spec) { return spec.action == "restart" });
|
||||
self.restartCommandSpec = restartSpec != undefined && restartSpec.length > 0 ? restartSpec[0] : undefined;
|
||||
});
|
||||
|
||||
self.notifications = [];
|
||||
|
||||
self.enableManagement = ko.computed(function() {
|
||||
return !self.printerState.isPrinting();
|
||||
});
|
||||
|
|
@ -247,12 +329,8 @@ $(function() {
|
|||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "plugin/pluginmanager" + ((includeRepo) ? "?refresh_repository=true" : ""),
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: self.fromResponse
|
||||
});
|
||||
OctoPrint.plugins.pluginmanager.get(includeRepo)
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.togglePlugin = function(data) {
|
||||
|
|
@ -266,19 +344,25 @@ $(function() {
|
|||
|
||||
if (data.key == "pluginmanager") return;
|
||||
|
||||
var command = self._getToggleCommand(data);
|
||||
var onSuccess = self.requestData,
|
||||
onError = function() {
|
||||
new PNotify({
|
||||
title: gettext("Something went wrong"),
|
||||
text: gettext("Please consult octoprint.log for details"),
|
||||
type: "error",
|
||||
hide: false
|
||||
})
|
||||
};
|
||||
|
||||
var payload = {plugin: data.key};
|
||||
self._postCommand(command, payload, function(response) {
|
||||
self.requestData();
|
||||
}, function() {
|
||||
new PNotify({
|
||||
title: gettext("Something went wrong"),
|
||||
text: gettext("Please consult octoprint.log for details"),
|
||||
type: "error",
|
||||
hide: false
|
||||
})
|
||||
});
|
||||
if (self._getToggleCommand(data) == "enable") {
|
||||
OctoPrint.plugins.pluginmanager.enable(data.key)
|
||||
.done(onSuccess)
|
||||
.fail(onError);
|
||||
} else {
|
||||
OctoPrint.plugins.pluginmanager.disable(data.key)
|
||||
.done(onSuccess)
|
||||
.fail(onError);
|
||||
}
|
||||
};
|
||||
|
||||
self.showRepository = function() {
|
||||
|
|
@ -298,11 +382,7 @@ $(function() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (self.installed(data)) {
|
||||
self.installPlugin(data.archive, data.title, data.id, data.follow_dependency_links || self.followDependencyLinks());
|
||||
} else {
|
||||
self.installPlugin(data.archive, data.title, undefined, data.follow_dependency_links || self.followDependencyLinks());
|
||||
}
|
||||
self.installPlugin(data.archive, data.title, (self.installed(data) ? data.id : undefined), data.follow_dependency_links || self.followDependencyLinks());
|
||||
};
|
||||
|
||||
self.installPlugin = function(url, name, reinstall, followDependencyLinks) {
|
||||
|
|
@ -337,26 +417,33 @@ $(function() {
|
|||
}
|
||||
self._markWorking(workTitle, workText);
|
||||
|
||||
var command = "install";
|
||||
var payload = {url: url, dependency_links: followDependencyLinks};
|
||||
if (reinstall) {
|
||||
payload["plugin"] = reinstall;
|
||||
payload["force"] = true;
|
||||
}
|
||||
var onSuccess = function() {
|
||||
self.requestData();
|
||||
self.installUrl("");
|
||||
},
|
||||
onError = function() {
|
||||
new PNotify({
|
||||
title: gettext("Something went wrong"),
|
||||
text: gettext("Please consult octoprint.log for details"),
|
||||
type: "error",
|
||||
hide: false
|
||||
});
|
||||
},
|
||||
onAlways = function() {
|
||||
self._markDone();
|
||||
};
|
||||
|
||||
self._postCommand(command, payload, function(response) {
|
||||
self.requestData();
|
||||
self._markDone();
|
||||
self.installUrl("");
|
||||
}, function() {
|
||||
new PNotify({
|
||||
title: gettext("Something went wrong"),
|
||||
text: gettext("Please consult octoprint.log for details"),
|
||||
type: "error",
|
||||
hide: false
|
||||
});
|
||||
self._markDone();
|
||||
});
|
||||
if (reinstall) {
|
||||
OctoPrint.plugins.pluginmanager.reinstall(reinstall, url, followDependencyLinks)
|
||||
.done(onSuccess)
|
||||
.fail(onError)
|
||||
.always(onAlways);
|
||||
} else {
|
||||
OctoPrint.plugins.pluginmanager.install(url, followDependencyLinks)
|
||||
.done(onSuccess)
|
||||
.fail(onError)
|
||||
.always(onAlways);
|
||||
}
|
||||
};
|
||||
|
||||
self.uninstallPlugin = function(data) {
|
||||
|
|
@ -373,20 +460,19 @@ $(function() {
|
|||
|
||||
self._markWorking(gettext("Uninstalling plugin..."), _.sprintf(gettext("Uninstalling plugin \"%(name)s\""), {name: data.name}));
|
||||
|
||||
var command = "uninstall";
|
||||
var payload = {plugin: data.key};
|
||||
self._postCommand(command, payload, function(response) {
|
||||
self.requestData();
|
||||
self._markDone();
|
||||
}, function() {
|
||||
new PNotify({
|
||||
title: gettext("Something went wrong"),
|
||||
text: gettext("Please consult octoprint.log for details"),
|
||||
type: "error",
|
||||
hide: false
|
||||
OctoPrint.plugins.pluginmanager.uninstall(data.key)
|
||||
.done(self.requestData)
|
||||
.fail(function() {
|
||||
new PNotify({
|
||||
title: gettext("Something went wrong"),
|
||||
text: gettext("Please consult octoprint.log for details"),
|
||||
type: "error",
|
||||
hide: false
|
||||
});
|
||||
})
|
||||
.always(function() {
|
||||
self._markDone();
|
||||
});
|
||||
self._markDone();
|
||||
});
|
||||
};
|
||||
|
||||
self.refreshRepository = function() {
|
||||
|
|
@ -464,15 +550,59 @@ $(function() {
|
|||
};
|
||||
|
||||
self._displayNotification = function(response, titleSuccess, textSuccess, textRestart, textReload, titleError, textError) {
|
||||
var notification;
|
||||
|
||||
var beforeClose = function(notification) {
|
||||
self.notifications = _.without(self.notifications, notification);
|
||||
};
|
||||
|
||||
if (response.result) {
|
||||
if (response.needs_restart) {
|
||||
new PNotify({
|
||||
var options = {
|
||||
title: titleSuccess,
|
||||
text: textRestart,
|
||||
buttons: {
|
||||
closer: false,
|
||||
sticker: false
|
||||
},
|
||||
callbacks: {
|
||||
before_close: beforeClose
|
||||
},
|
||||
hide: false
|
||||
});
|
||||
};
|
||||
|
||||
if (self.restartCommandSpec) {
|
||||
options.confirm = {
|
||||
confirm: true,
|
||||
buttons: [{
|
||||
text: gettext("Restart now"),
|
||||
click: function () {
|
||||
showConfirmationDialog({
|
||||
message: gettext("This will restart your OctoPrint server."),
|
||||
onproceed: function() {
|
||||
OctoPrint.system.executeCommand("core", "restart")
|
||||
.done(function() {
|
||||
new PNotify({
|
||||
title: gettext("Restart in progress"),
|
||||
text: gettext("The server is now being restarted in the background")
|
||||
})
|
||||
})
|
||||
.fail(function() {
|
||||
new PNotify({
|
||||
title: gettext("Something went wrong"),
|
||||
text: gettext("Trying to restart the server produced an error, please check octoprint.log for details. You'll have to restart manually.")
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
notification = PNotify.singleButtonNotify(options);
|
||||
} else if (response.needs_refresh) {
|
||||
new PNotify({
|
||||
notification = PNotify.singleButtonNotify({
|
||||
title: titleSuccess,
|
||||
text: textReload,
|
||||
confirm: {
|
||||
|
|
@ -488,51 +618,35 @@ $(function() {
|
|||
closer: false,
|
||||
sticker: false
|
||||
},
|
||||
callbacks: {
|
||||
before_close: beforeClose
|
||||
},
|
||||
hide: false
|
||||
})
|
||||
} else {
|
||||
new PNotify({
|
||||
notification = new PNotify({
|
||||
title: titleSuccess,
|
||||
text: textSuccess,
|
||||
type: "success",
|
||||
callbacks: {
|
||||
before_close: beforeClose
|
||||
},
|
||||
hide: false
|
||||
})
|
||||
}
|
||||
} else {
|
||||
new PNotify({
|
||||
notification = new PNotify({
|
||||
title: titleError,
|
||||
text: textError,
|
||||
type: "error",
|
||||
callbacks: {
|
||||
before_close: beforeClose
|
||||
},
|
||||
hide: false
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
self._postCommand = function (command, data, successCallback, failureCallback, alwaysCallback, timeout) {
|
||||
var payload = _.extend(data, {command: command});
|
||||
|
||||
var params = {
|
||||
url: API_BASEURL + "plugin/pluginmanager",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: JSON.stringify(payload),
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
success: function(response) {
|
||||
if (successCallback) successCallback(response);
|
||||
},
|
||||
error: function() {
|
||||
if (failureCallback) failureCallback();
|
||||
},
|
||||
complete: function() {
|
||||
if (alwaysCallback) alwaysCallback();
|
||||
}
|
||||
};
|
||||
|
||||
if (timeout != undefined) {
|
||||
params.timeout = timeout;
|
||||
}
|
||||
|
||||
$.ajax(params);
|
||||
self.notifications.push(notification);
|
||||
};
|
||||
|
||||
self._markWorking = function(title, line) {
|
||||
|
|
@ -577,6 +691,16 @@ $(function() {
|
|||
self.onUserLoggedIn = function(user) {
|
||||
if (user.admin) {
|
||||
self.requestData();
|
||||
} else {
|
||||
self.onUserLoggedOut();
|
||||
}
|
||||
};
|
||||
|
||||
self.onUserLoggedOut = function() {
|
||||
if (self.notifications) {
|
||||
_.each(self.notifications, function(notification) {
|
||||
notification.remove();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -730,5 +854,9 @@ $(function() {
|
|||
}
|
||||
|
||||
// view model class, parameters for constructor, container to bind to
|
||||
ADDITIONAL_VIEWMODELS.push([PluginManagerViewModel, ["loginStateViewModel", "settingsViewModel", "printerStateViewModel"], "#settings_plugin_pluginmanager"]);
|
||||
ADDITIONAL_VIEWMODELS.push([
|
||||
PluginManagerViewModel,
|
||||
["loginStateViewModel", "settingsViewModel", "printerStateViewModel", "systemViewModel"],
|
||||
"#settings_plugin_pluginmanager"
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,3 +1,43 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var exports = {};
|
||||
|
||||
var url = OctoPrint.getBlueprintUrl("softwareupdate");
|
||||
var checkUrl = url + "check";
|
||||
var updateUrl = url + "update";
|
||||
|
||||
exports.check = function(force, opts) {
|
||||
return OctoPrint.get(checkUrl + ((!!force) ? "?force=true" : ""), opts);
|
||||
};
|
||||
|
||||
exports.update = function(entries, force, opts) {
|
||||
entries = entries || [];
|
||||
if (typeof entries == "string") {
|
||||
entries = [entries];
|
||||
}
|
||||
|
||||
var data = {
|
||||
entries: entries,
|
||||
force: !!force
|
||||
};
|
||||
return OctoPrint.postJson(updateUrl, data, opts);
|
||||
};
|
||||
|
||||
exports.updateAll = function(force, opts) {
|
||||
var data = {
|
||||
force: !!force
|
||||
};
|
||||
return OctoPrint.postJson(updateUrl, data, opts);
|
||||
};
|
||||
|
||||
OctoPrint.plugins.softwareupdate = exports;
|
||||
});
|
||||
|
||||
$(function() {
|
||||
function SoftwareUpdateViewModel(parameters) {
|
||||
var self = this;
|
||||
|
|
@ -221,20 +261,10 @@ $(function() {
|
|||
|
||||
self.performCheck = function(showIfNothingNew, force, ignoreSeen) {
|
||||
if (!self.loginState.isUser()) return;
|
||||
|
||||
var url = PLUGIN_BASEURL + "softwareupdate/check";
|
||||
if (force) {
|
||||
url += "?force=true";
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
OctoPrint.plugins.softwareupdate.check(force)
|
||||
.done(function(data) {
|
||||
self.fromCheckResponse(data, ignoreSeen, showIfNothingNew);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self._markNotificationAsSeen = function(data) {
|
||||
|
|
@ -285,13 +315,12 @@ $(function() {
|
|||
};
|
||||
self._showPopup(options);
|
||||
|
||||
$.ajax({
|
||||
url: PLUGIN_BASEURL + "softwareupdate/update",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify({force: (force == true)}),
|
||||
error: function() {
|
||||
OctoPrint.plugins.softwareupdate.updateAll(force)
|
||||
.done(function(data) {
|
||||
self.currentlyBeingUpdated = data.checks;
|
||||
self._markWorking(gettext("Updating..."), gettext("Updating, please wait."));
|
||||
})
|
||||
.fail(function() {
|
||||
self.updateInProgress = false;
|
||||
self._showPopup({
|
||||
title: gettext("Update not started!"),
|
||||
|
|
@ -302,12 +331,7 @@ $(function() {
|
|||
sticker: false
|
||||
}
|
||||
});
|
||||
},
|
||||
success: function(data) {
|
||||
self.currentlyBeingUpdated = data.checks;
|
||||
self._markWorking(gettext("Updating..."), gettext("Updating, please wait."));
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self.update = function(force) {
|
||||
|
|
|
|||
|
|
@ -912,6 +912,26 @@ class Server(object):
|
|||
"js/lib/loglevel.min.js",
|
||||
"js/lib/sockjs-0.3.4.min.js"
|
||||
]
|
||||
js_client = [
|
||||
"js/app/client/base.js",
|
||||
"js/app/client/socket.js",
|
||||
"js/app/client/browser.js",
|
||||
"js/app/client/connection.js",
|
||||
"js/app/client/control.js",
|
||||
"js/app/client/files.js",
|
||||
"js/app/client/job.js",
|
||||
"js/app/client/languages.js",
|
||||
"js/app/client/logs.js",
|
||||
"js/app/client/printer.js",
|
||||
"js/app/client/printerprofiles.js",
|
||||
"js/app/client/settings.js",
|
||||
"js/app/client/slicing.js",
|
||||
"js/app/client/system.js",
|
||||
"js/app/client/timelapse.js",
|
||||
"js/app/client/users.js",
|
||||
"js/app/client/util.js",
|
||||
"js/app/client/wizard.js"
|
||||
]
|
||||
js_app = dynamic_assets["js"] + [
|
||||
"js/app/dataupdater.js",
|
||||
"js/app/helpers.js",
|
||||
|
|
@ -966,8 +986,10 @@ class Server(object):
|
|||
|
||||
js_libs_bundle = Bundle(*js_libs, output="webassets/packed_libs.js", filters="js_delimiter_bundler")
|
||||
if minify:
|
||||
js_client_bundle = Bundle(*js_client, output="webassets/packed_client.js", filters="rjsmin, js_delimiter_bundler")
|
||||
js_app_bundle = Bundle(*js_app, output="webassets/packed_app.js", filters="rjsmin, js_delimiter_bundler")
|
||||
else:
|
||||
js_client_bundle = Bundle(*js_client, output="webassets/packed_client.js", filters="js_delimiter_bundler")
|
||||
js_app_bundle = Bundle(*js_app, output="webassets/packed_app.js", filters="js_delimiter_bundler")
|
||||
|
||||
css_libs_bundle = Bundle(*css_libs, output="webassets/packed_libs.css")
|
||||
|
|
@ -976,6 +998,7 @@ class Server(object):
|
|||
all_less_bundle = Bundle(*less_app, output="webassets/packed_app.less", filters="cssrewrite, less_importrewrite")
|
||||
|
||||
assets.register("js_libs", js_libs_bundle)
|
||||
assets.register("js_client", js_client_bundle)
|
||||
assets.register("js_app", js_app_bundle)
|
||||
assets.register("css_libs", css_libs_bundle)
|
||||
assets.register("css_app", css_app_bundle)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ from . import log as api_logs
|
|||
from . import slicing as api_slicing
|
||||
from . import printer_profiles as api_printer_profiles
|
||||
from . import languages as api_languages
|
||||
from . import system as api_system
|
||||
|
||||
|
||||
VERSION = "0.1"
|
||||
|
|
@ -177,51 +178,21 @@ def apiVersion():
|
|||
"api": VERSION
|
||||
})
|
||||
|
||||
#~~ system control
|
||||
|
||||
|
||||
@api.route("/system", methods=["POST"])
|
||||
@restricted_access
|
||||
@admin_permission.require(403)
|
||||
def performSystemAction():
|
||||
logger = logging.getLogger(__name__)
|
||||
if "action" in request.values.keys():
|
||||
action = request.values["action"]
|
||||
available_actions = s().get(["system", "actions"])
|
||||
for availableAction in available_actions:
|
||||
if availableAction["action"] == action:
|
||||
async = availableAction["async"] if "async" in availableAction else False
|
||||
ignore = availableAction["ignore"] if "ignore" in availableAction else False
|
||||
logger.info("Performing command: %s" % availableAction["command"])
|
||||
try:
|
||||
# we run this with shell=True since we have to trust whatever
|
||||
# our admin configured as command and since we want to allow
|
||||
# shell-alike handling here...
|
||||
p = sarge.run(availableAction["command"], stderr=sarge.Capture(), shell=True, async=async)
|
||||
if not async:
|
||||
if not ignore and p.returncode != 0:
|
||||
returncode = p.returncode
|
||||
stderr_text = p.stderr.text
|
||||
logger.warn("Command failed with return code %i: %s" % (returncode, stderr_text))
|
||||
return make_response(("Command failed with return code %i: %s" % (returncode, stderr_text), 500, []))
|
||||
except Exception, e:
|
||||
if not ignore:
|
||||
logger.warn("Command failed: %s" % e)
|
||||
return make_response(("Command failed: %s" % e, 500, []))
|
||||
break
|
||||
return NO_CONTENT
|
||||
|
||||
|
||||
#~~ Login/user handling
|
||||
|
||||
|
||||
@api.route("/login", methods=["POST"])
|
||||
def login():
|
||||
if octoprint.server.userManager is not None and "user" in request.values.keys() and "pass" in request.values.keys():
|
||||
username = request.values["user"]
|
||||
password = request.values["pass"]
|
||||
data = request.values
|
||||
if hasattr(request, "json") and request.json:
|
||||
data = request.json
|
||||
|
||||
if "remember" in request.values.keys() and request.values["remember"] == "true":
|
||||
if octoprint.server.userManager is not None and "user" in data and "pass" in data:
|
||||
username = data["user"]
|
||||
password = data["pass"]
|
||||
|
||||
if "remember" in data and data["remember"] in valid_boolean_trues:
|
||||
remember = True
|
||||
else:
|
||||
remember = False
|
||||
|
|
@ -241,7 +212,7 @@ def login():
|
|||
return jsonify(user.asDict())
|
||||
return make_response(("User unknown or password incorrect", 401, []))
|
||||
|
||||
elif "passive" in request.values:
|
||||
elif "passive" in data:
|
||||
return passive_login()
|
||||
return NO_CONTENT
|
||||
|
||||
|
|
|
|||
176
src/octoprint/server/api/system.py
Normal file
176
src/octoprint/server/api/system.py
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
# coding=utf-8
|
||||
from __future__ import absolute_import
|
||||
|
||||
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
||||
__copyright__ = "Copyright (C) 2015 The OctoPrint Project - Released under terms of the AGPLv3 License"
|
||||
|
||||
import collections
|
||||
import logging
|
||||
import sarge
|
||||
|
||||
from flask import request, make_response, jsonify, url_for
|
||||
from flask.ext.babel import gettext
|
||||
|
||||
from octoprint.settings import settings as s
|
||||
|
||||
from octoprint.server import admin_permission, NO_CONTENT
|
||||
from octoprint.server.api import api
|
||||
from octoprint.server.util.flask import restricted_access, get_remote_address
|
||||
|
||||
|
||||
@api.route("/system", methods=["POST"])
|
||||
@restricted_access
|
||||
@admin_permission.require(403)
|
||||
def performSystemAction():
|
||||
logging.getLogger(__name__).warn("Deprecated API call to /api/system made by {}, should be migrated to use /system/commands/custom/<action>".format(get_remote_address(request)))
|
||||
|
||||
data = request.values
|
||||
if hasattr(request, "json") and request.json:
|
||||
data = request.json
|
||||
|
||||
if not "action" in data:
|
||||
return make_response("action for perform is not defined", 400)
|
||||
|
||||
return executeSystemCommand("custom", data["action"])
|
||||
|
||||
|
||||
@api.route("/system/commands", methods=["GET"])
|
||||
@restricted_access
|
||||
@admin_permission.require(403)
|
||||
def retrieveSystemCommands():
|
||||
return jsonify(core=_to_client_specs(_get_core_command_specs()),
|
||||
custom=_to_client_specs(_get_custom_command_specs()))
|
||||
|
||||
|
||||
@api.route("/system/commands/<string:source>", methods=["GET"])
|
||||
@restricted_access
|
||||
@admin_permission.require(403)
|
||||
def retrieveSystemCommandsForSource(source):
|
||||
if source == "core":
|
||||
specs = _get_core_command_specs()
|
||||
elif source == "custom":
|
||||
specs = _get_custom_command_specs()
|
||||
else:
|
||||
return make_response("Unknown system command source: {}".format(source), 400)
|
||||
|
||||
return jsonify(_to_client_specs(specs))
|
||||
|
||||
|
||||
@api.route("/system/commands/<string:source>/<string:command>", methods=["POST"])
|
||||
@restricted_access
|
||||
@admin_permission.require(403)
|
||||
def executeSystemCommand(source, command):
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
command_spec = _get_command_spec(source, command)
|
||||
if not command_spec:
|
||||
return make_response("Command {}:{} not found".format(source, command), 404)
|
||||
|
||||
if not "command" in command_spec:
|
||||
return make_response("Command {}:{} does not define a command to execute, can't proceed".format(source, command), 500)
|
||||
|
||||
async = command_spec["async"] if "async" in command_spec else False
|
||||
ignore = command_spec["ignore"] if "ignore" in command_spec else False
|
||||
logger.info("Performing command for {}:{}: {}".format(source, command, command_spec["command"]))
|
||||
try:
|
||||
# we run this with shell=True since we have to trust whatever
|
||||
# our admin configured as command and since we want to allow
|
||||
# shell-alike handling here...
|
||||
p = sarge.run(command_spec["command"],
|
||||
stdout=sarge.Capture(),
|
||||
stderr=sarge.Capture(),
|
||||
shell=True,
|
||||
async=async)
|
||||
if not async:
|
||||
if not ignore and p.returncode != 0:
|
||||
returncode = p.returncode
|
||||
stdout_text = p.stdout.text
|
||||
stderr_text = p.stderr.text
|
||||
|
||||
error = "Command failed with return code {}:\nSTDOUT: {}\nSTDERR: {}".format(returncode, stdout_text, stderr_text)
|
||||
logger.warn(error)
|
||||
return make_response(error, 500)
|
||||
except Exception, e:
|
||||
if not ignore:
|
||||
error = "Command failed: {}".format(str(e))
|
||||
logger.warn(error)
|
||||
return make_response(error, 500)
|
||||
|
||||
return NO_CONTENT
|
||||
|
||||
|
||||
def _to_client_specs(specs):
|
||||
result = list()
|
||||
for spec in specs.values():
|
||||
if not "action" in spec or not "source" in spec:
|
||||
continue
|
||||
copied = dict((k, v) for k, v in spec.items() if k in ("source", "action", "name", "confirm"))
|
||||
copied["resource"] = url_for(".executeSystemCommand",
|
||||
source=spec["source"],
|
||||
command=spec["action"],
|
||||
_external=True)
|
||||
result.append(copied)
|
||||
return result
|
||||
|
||||
|
||||
def _get_command_spec(source, action):
|
||||
if source == "core":
|
||||
return _get_core_command_spec(action)
|
||||
elif source == "custom":
|
||||
return _get_custom_command_spec(action)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def _get_core_command_specs():
|
||||
commands = collections.OrderedDict(
|
||||
shutdown=dict(
|
||||
command=s().get(["server", "commands", "systemShutdownCommand"]),
|
||||
name=gettext("Shutdown"),
|
||||
confirm=gettext("You are about to shutdown the system.")),
|
||||
reboot=dict(
|
||||
command=s().get(["server", "commands", "systemRestartCommand"]),
|
||||
name=gettext("Reboot"),
|
||||
confirm=gettext("You are about to reboot the system.")),
|
||||
restart=dict(
|
||||
command=s().get(["server", "commands", "serverRestartCommand"]),
|
||||
name="Restart OctoPrint",
|
||||
confirm="You are about to restart the OctoPrint server.")
|
||||
)
|
||||
|
||||
available_commands = dict()
|
||||
for action, spec in commands.items():
|
||||
if not spec["command"]:
|
||||
continue
|
||||
spec.update(dict(action=action, source="core", async=True, ignore=True))
|
||||
available_commands[action] = spec
|
||||
return available_commands
|
||||
|
||||
|
||||
def _get_core_command_spec(action):
|
||||
available_actions = _get_core_command_specs()
|
||||
if not action in available_actions:
|
||||
logging.getLogger(__name__).warn("Command for core action {} is not configured, you need to configure the command before it can be used".format(action))
|
||||
return None
|
||||
|
||||
return available_actions[action]
|
||||
|
||||
|
||||
def _get_custom_command_specs():
|
||||
specs = collections.OrderedDict()
|
||||
for spec in s().get(["system", "actions"]):
|
||||
if not "action" in spec:
|
||||
continue
|
||||
copied = dict(spec)
|
||||
copied["source"] = "custom"
|
||||
specs[spec["action"]] = copied
|
||||
return specs
|
||||
|
||||
|
||||
def _get_custom_command_spec(action):
|
||||
available_actions = _get_custom_command_specs()
|
||||
if not action in available_actions:
|
||||
return None
|
||||
|
||||
return available_actions[action]
|
||||
|
||||
|
|
@ -68,52 +68,56 @@ def deleteTimelapse(filename):
|
|||
@api.route("/timelapse", methods=["POST"])
|
||||
@restricted_access
|
||||
def setTimelapseConfig():
|
||||
if "type" in request.values:
|
||||
data = request.values
|
||||
if hasattr(request, "json") and request.json:
|
||||
data = request.json
|
||||
|
||||
if "type" in data:
|
||||
config = {
|
||||
"type": request.values["type"],
|
||||
"type": data["type"],
|
||||
"postRoll": 0,
|
||||
"fps": 25,
|
||||
"options": {}
|
||||
}
|
||||
|
||||
if "postRoll" in request.values:
|
||||
if "postRoll" in data:
|
||||
try:
|
||||
postRoll = int(request.values["postRoll"])
|
||||
postRoll = int(data["postRoll"])
|
||||
except ValueError:
|
||||
return make_response("Invalid value for postRoll: %r" % request.values["postRoll"], 400)
|
||||
return make_response("Invalid value for postRoll: %r" % data["postRoll"], 400)
|
||||
else:
|
||||
if postRoll >= 0:
|
||||
config["postRoll"] = postRoll
|
||||
else:
|
||||
return make_response("Invalid value for postRoll: %d" % postRoll, 400)
|
||||
|
||||
if "fps" in request.values:
|
||||
if "fps" in data:
|
||||
try:
|
||||
fps = int(request.values["fps"])
|
||||
fps = int(data["fps"])
|
||||
except ValueError:
|
||||
return make_response("Invalid value for fps: %r" % request.values["fps"], 400)
|
||||
return make_response("Invalid value for fps: %r" % data["fps"], 400)
|
||||
else:
|
||||
if fps > 0:
|
||||
config["fps"] = fps
|
||||
else:
|
||||
return make_response("Invalid value for fps: %d" % fps, 400)
|
||||
|
||||
if "interval" in request.values:
|
||||
if "interval" in data:
|
||||
config["options"] = {
|
||||
"interval": 10
|
||||
}
|
||||
|
||||
try:
|
||||
interval = int(request.values["interval"])
|
||||
interval = int(data["interval"])
|
||||
except ValueError:
|
||||
return make_response("Invalid value for interval: %r" % request.values["interval"])
|
||||
return make_response("Invalid value for interval: %r" % data["interval"])
|
||||
else:
|
||||
if interval > 0:
|
||||
config["options"]["interval"] = interval
|
||||
else:
|
||||
return make_response("Invalid value for interval: %d" % interval)
|
||||
|
||||
if admin_permission.can() and "save" in request.values and request.values["save"] in valid_boolean_trues:
|
||||
if admin_permission.can() and "save" in data and data["save"] in valid_boolean_trues:
|
||||
octoprint.timelapse.configureTimelapse(config, True)
|
||||
else:
|
||||
octoprint.timelapse.configureTimelapse(config)
|
||||
|
|
|
|||
|
|
@ -631,6 +631,7 @@ def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"):
|
|||
'js/app/viewmodels/printerprofiles.js',
|
||||
'js/app/viewmodels/settings.js',
|
||||
'js/app/viewmodels/slicing.js',
|
||||
'js/app/viewmodels/system.js',
|
||||
'js/app/viewmodels/temperature.js',
|
||||
'js/app/viewmodels/terminal.js',
|
||||
'js/app/viewmodels/timelapse.js',
|
||||
|
|
|
|||
|
|
@ -573,4 +573,3 @@ def localeJs(locale, domain):
|
|||
def plugin_assets(name, filename):
|
||||
return redirect(url_for("plugin." + name + ".static", filename=filename))
|
||||
|
||||
|
||||
|
|
|
|||
249
src/octoprint/static/js/app/client/base.js
Normal file
249
src/octoprint/static/js/app/client/base.js
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define("OctoPrint", ["jquery", "lodash"], factory);
|
||||
} else {
|
||||
global.OctoPrint = factory(window.$, window._);
|
||||
}
|
||||
})(window || this, function($, _) {
|
||||
var OctoPrint = {};
|
||||
|
||||
var noCache = function(opts) {
|
||||
opts = opts || {};
|
||||
|
||||
var params = $.extend({}, opts);
|
||||
params.headers = $.extend({}, params.headers || {});
|
||||
params.headers["Cache-Control"] = "no-cache";
|
||||
|
||||
return params;
|
||||
};
|
||||
|
||||
var contentTypeJson = function(opts) {
|
||||
opts = opts || {};
|
||||
|
||||
var params = $.extend({}, opts);
|
||||
params.contentType = "application/json; charset=UTF-8";
|
||||
|
||||
return params;
|
||||
};
|
||||
|
||||
OctoPrint.options = {
|
||||
"baseurl": undefined,
|
||||
"apikey": undefined
|
||||
};
|
||||
|
||||
OctoPrint.plugins = {};
|
||||
|
||||
OctoPrint.getBaseUrl = function() {
|
||||
var url = OctoPrint.options.baseurl;
|
||||
if (!_.endsWith(url, "/")) {
|
||||
url = url + "/";
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
OctoPrint.getRequestHeaders = function(additional) {
|
||||
additional = additional || {};
|
||||
|
||||
var headers = $.extend({}, additional);
|
||||
headers["X-Api-Key"] = OctoPrint.options.apikey;
|
||||
|
||||
return headers;
|
||||
};
|
||||
|
||||
OctoPrint.ajax = function(method, url, opts) {
|
||||
opts = opts || {};
|
||||
|
||||
method = opts.method || method || "GET";
|
||||
url = opts.url || url || "";
|
||||
|
||||
var urlToCall = url;
|
||||
if (!_.startsWith(url, "http://") && !_.startsWith(url, "https://")) {
|
||||
urlToCall = OctoPrint.getBaseUrl() + url;
|
||||
}
|
||||
|
||||
var headers = OctoPrint.getRequestHeaders(opts.headers);
|
||||
|
||||
var params = $.extend({}, opts);
|
||||
params.type = method;
|
||||
params.headers = headers;
|
||||
params.dataType = params.dataType || "json";
|
||||
|
||||
return $.ajax(urlToCall, params);
|
||||
};
|
||||
|
||||
OctoPrint.ajaxWithData = function(method, url, data, opts) {
|
||||
opts = opts || {};
|
||||
|
||||
var params = $.extend({}, opts);
|
||||
params.data = data;
|
||||
|
||||
return OctoPrint.ajax(method, url, params);
|
||||
};
|
||||
|
||||
OctoPrint.get = function(url, opts) {
|
||||
return OctoPrint.ajax("GET", url, opts);
|
||||
};
|
||||
|
||||
OctoPrint.post = function(url, data, opts) {
|
||||
return OctoPrint.ajaxWithData("POST", url, data, noCache(opts));
|
||||
};
|
||||
|
||||
OctoPrint.postJson = function(url, data, opts) {
|
||||
return OctoPrint.post(url, JSON.stringify(data), contentTypeJson(opts));
|
||||
};
|
||||
|
||||
OctoPrint.put = function(url, data, opts) {
|
||||
return OctoPrint.ajaxWithData("PUT", url, data, noCache(opts));
|
||||
};
|
||||
|
||||
OctoPrint.putJson = function(url, data, opts) {
|
||||
return OctoPrint.put(url, data, contentTypeJson(opts));
|
||||
};
|
||||
|
||||
OctoPrint.patch = function(url, data, opts) {
|
||||
return OctoPrint.ajaxWithData("PATCH", url, data, noCache(opts));
|
||||
};
|
||||
|
||||
OctoPrint.patchJson = function(url, data, opts) {
|
||||
return OctoPrint.patch(url, JSON.stringify(data), contentTypeJson(opts));
|
||||
};
|
||||
|
||||
OctoPrint.delete = function(url, opts) {
|
||||
return OctoPrint.ajax("DELETE", url, opts);
|
||||
};
|
||||
|
||||
OctoPrint.download = function(url, opts) {
|
||||
var params = $.extend({}, opts || {});
|
||||
params.dataType = "text";
|
||||
return OctoPrint.get(url, params);
|
||||
};
|
||||
|
||||
OctoPrint.upload = function(url, file, filename, additional) {
|
||||
additional = additional || {};
|
||||
|
||||
var fileData;
|
||||
if (file instanceof jQuery) {
|
||||
fileData = file[0].files[0];
|
||||
} else if (typeof file == "string") {
|
||||
fileData = $(file)[0].files[0];
|
||||
} else {
|
||||
fileData = file;
|
||||
}
|
||||
|
||||
filename = filename || fileData.name;
|
||||
|
||||
var form = new FormData();
|
||||
form.append("file", fileData, filename);
|
||||
|
||||
_.each(additional, function(value, key) {
|
||||
form.append(key, value);
|
||||
});
|
||||
|
||||
var deferred = $.Deferred();
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
request.onreadystatechange = function() {
|
||||
if (request.readyState == 4) {
|
||||
deferred.notify({loaded: filesize, total: filesize});
|
||||
|
||||
var success = request.status >= 200 && request.status < 300
|
||||
|| request.status === 304;
|
||||
var error, json, statusText;
|
||||
|
||||
try {
|
||||
json = JSON.parse(request.response);
|
||||
statusText = "success";
|
||||
} catch (e) {
|
||||
success = false;
|
||||
error = e;
|
||||
statusText = "parsererror";
|
||||
}
|
||||
|
||||
if (success) {
|
||||
deferred.resolve([json, statusText, request]);
|
||||
} else {
|
||||
if (!statusText) {
|
||||
statusText = request.statusText;
|
||||
}
|
||||
deferred.reject([request, statusText, error]);
|
||||
}
|
||||
}
|
||||
};
|
||||
request.ontimeout = function() {
|
||||
deferred.reject([request, "timeout", "Timeout"]);
|
||||
};
|
||||
request.upload.addEventListener("loadstart", function(e) {
|
||||
deferred.notify({loaded: e.loaded, total: e.total});
|
||||
});
|
||||
request.upload.addEventListener("progress", function(e) {
|
||||
deferred.notify({loaded: e.loaded, total: e.total});
|
||||
});
|
||||
request.upload.addEventListener("loadend", function(e) {
|
||||
deferred.notify({loaded: e.loaded, total: e.total});
|
||||
});
|
||||
|
||||
var headers = OctoPrint.getRequestHeaders();
|
||||
|
||||
request.open("POST", OctoPrint.getBaseUrl() + url);
|
||||
_.each(headers, function(value, key) {
|
||||
request.setRequestHeader(key, value);
|
||||
});
|
||||
request.send(form);
|
||||
|
||||
return deferred.promise();
|
||||
};
|
||||
|
||||
OctoPrint.issueCommand = function(url, command, payload, opts) {
|
||||
payload = payload || {};
|
||||
|
||||
var data = $.extend({}, payload);
|
||||
data.command = command;
|
||||
|
||||
return OctoPrint.postJson(url, data, opts);
|
||||
};
|
||||
|
||||
OctoPrint.getSimpleApiUrl = function(plugin) {
|
||||
return "api/plugin/" + plugin;
|
||||
};
|
||||
|
||||
OctoPrint.simpleApiGet = function(plugin, opts) {
|
||||
return OctoPrint.get(OctoPrint.getSimpleApiUrl(plugin), opts);
|
||||
};
|
||||
|
||||
OctoPrint.simpleApiCommand = function(plugin, command, payload, opts) {
|
||||
return OctoPrint.issueCommand(OctoPrint.getSimpleApiUrl(plugin), command, payload, opts);
|
||||
};
|
||||
|
||||
OctoPrint.getBlueprintUrl = function(plugin) {
|
||||
return "plugin/" + plugin + "/";
|
||||
};
|
||||
|
||||
OctoPrint.createRejectedDeferred = function() {
|
||||
var deferred = $.Deferred();
|
||||
deferred.reject(arguments);
|
||||
return deferred;
|
||||
};
|
||||
|
||||
OctoPrint.createCustomException = function(name) {
|
||||
var constructor;
|
||||
|
||||
if (_.isFunction(name)) {
|
||||
constructor = name;
|
||||
} else {
|
||||
constructor = function(message) {
|
||||
this.name = name;
|
||||
this.message = message;
|
||||
this.stack = (new Error()).stack;
|
||||
};
|
||||
}
|
||||
|
||||
constructor.prototype = Object.create(Error.prototype);
|
||||
constructor.prototype.constructor = constructor;
|
||||
|
||||
return constructor;
|
||||
};
|
||||
|
||||
OctoPrint.InvalidArgumentError = OctoPrint.createCustomException("InvalidArgumentError");
|
||||
|
||||
return OctoPrint;
|
||||
});
|
||||
29
src/octoprint/static/js/app/client/browser.js
Normal file
29
src/octoprint/static/js/app/client/browser.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var loginUrl = "api/login";
|
||||
var logoutUrl = "api/logout";
|
||||
|
||||
OctoPrint.browser = {
|
||||
login: function(username, password, remember, opts) {
|
||||
var data = {
|
||||
user: username,
|
||||
pass: password,
|
||||
remember: !!remember
|
||||
};
|
||||
return OctoPrint.postJson(loginUrl, data, opts);
|
||||
},
|
||||
|
||||
passiveLogin: function(opts) {
|
||||
return OctoPrint.postJson(loginUrl, {passive: true}, opts);
|
||||
},
|
||||
|
||||
logout: function(opts) {
|
||||
return OctoPrint.postJson(logoutUrl, {}, opts);
|
||||
}
|
||||
};
|
||||
});
|
||||
27
src/octoprint/static/js/app/client/connection.js
Normal file
27
src/octoprint/static/js/app/client/connection.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var url = "api/connection";
|
||||
|
||||
OctoPrint.connection = {
|
||||
getSettings: function(opts) {
|
||||
return OctoPrint.get(url, opts);
|
||||
},
|
||||
|
||||
connect: function(data, opts) {
|
||||
return OctoPrint.issueCommand(url, "connect", data || {}, opts);
|
||||
},
|
||||
|
||||
disconnect: function(opts) {
|
||||
return OctoPrint.issueCommand(url, "disconnect", {}, opts);
|
||||
},
|
||||
|
||||
fakeAck: function(opts) {
|
||||
return OctoPrint.issueCommand(url, "fake_ack", {}, opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
46
src/octoprint/static/js/app/client/control.js
Normal file
46
src/octoprint/static/js/app/client/control.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var customUrl = "api/printer/command/custom";
|
||||
var commandUrl = "api/printer/command";
|
||||
|
||||
var sendGcodeWithParameters = function(commands, parameters, opts) {
|
||||
commands = commands || [];
|
||||
parameters = parameters || {};
|
||||
|
||||
if (typeof commands === "string") {
|
||||
commands = [commands];
|
||||
}
|
||||
|
||||
return OctoPrint.postJson(commandUrl, {
|
||||
commands: commands,
|
||||
parameters: parameters
|
||||
}, opts);
|
||||
};
|
||||
|
||||
OctoPrint.control = {
|
||||
sendGcodeWithParameters: sendGcodeWithParameters,
|
||||
|
||||
getCustomControls: function (opts) {
|
||||
return OctoPrint.get(customUrl, opts);
|
||||
},
|
||||
|
||||
sendGcode: function (commands, opts) {
|
||||
return sendGcodeWithParameters(commands, undefined, opts);
|
||||
},
|
||||
|
||||
sendGcodeScript: function (script, context, opts) {
|
||||
script = script || "";
|
||||
context = context || {};
|
||||
|
||||
return OctoPrint.postJson(commandUrl, {
|
||||
script: script,
|
||||
context: context
|
||||
}, opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
85
src/octoprint/static/js/app/client/files.js
Normal file
85
src/octoprint/static/js/app/client/files.js
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
(function (factory) {
|
||||
'use strict';
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// Register as an anonymous AMD module:
|
||||
define(["OctoPrint", "jquery"], factory);
|
||||
} else {
|
||||
// Browser globals:
|
||||
factory(window.OctoPrint, window.jQuery);
|
||||
}
|
||||
})(function(OctoPrint, $) {
|
||||
var url = "api/files";
|
||||
|
||||
var resourceForLocation = function(location) {
|
||||
return url + "/" + location;
|
||||
};
|
||||
|
||||
var resourceForFile = function(location, filename) {
|
||||
return resourceForLocation(location) + "/" + filename;
|
||||
};
|
||||
|
||||
var issueFileCommand = function(location, filename, command, data, opts) {
|
||||
var url = resourceForFile(location, filename);
|
||||
return OctoPrint.issueCommand(url, command, data, opts);
|
||||
};
|
||||
|
||||
var getFile = function(location, filename, opts) {
|
||||
return OctoPrint.get(resourceForFile(location, filename), opts);
|
||||
};
|
||||
|
||||
OctoPrint.files = {
|
||||
get: getFile,
|
||||
|
||||
list: function (opts) {
|
||||
return OctoPrint.get(url, opts);
|
||||
},
|
||||
|
||||
listForLocation: function (location, opts) {
|
||||
return OctoPrint.get(resourceForLocation(location), opts);
|
||||
},
|
||||
|
||||
select: function (location, filename, print, opts) {
|
||||
print = print || false;
|
||||
|
||||
var data = {
|
||||
print: print
|
||||
};
|
||||
|
||||
return issueFileCommand(location, filename, "select", data, opts);
|
||||
},
|
||||
|
||||
slice: function (location, filename, parameters, opts) {
|
||||
return issueFileCommand(location, filename, "slice",
|
||||
parameters || {}, opts);
|
||||
},
|
||||
|
||||
delete: function (location, filename, opts) {
|
||||
return OctoPrint.delete(resourceForFile(location, filename), opts);
|
||||
},
|
||||
|
||||
upload: function (location, file, data) {
|
||||
data = data || {};
|
||||
|
||||
var filename = data.filename || undefined;
|
||||
return OctoPrint.upload(resourceForLocation(location), file, filename, data);
|
||||
},
|
||||
|
||||
download: function (location, filename, opts) {
|
||||
var deferred = $.Deferred();
|
||||
getFile(location, filename, opts)
|
||||
.done(function (response) {
|
||||
OctoPrint.download(response.refs.download, opts)
|
||||
.done(function () {
|
||||
deferred.resolve.apply(null, arguments);
|
||||
})
|
||||
.fail(function () {
|
||||
deferred.reject.apply(null, arguments);
|
||||
});
|
||||
})
|
||||
.fail(function () {
|
||||
deferred.reject.apply(null, arguments);
|
||||
});
|
||||
return deferred.promise();
|
||||
}
|
||||
}
|
||||
});
|
||||
31
src/octoprint/static/js/app/client/job.js
Normal file
31
src/octoprint/static/js/app/client/job.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var url = "api/job";
|
||||
|
||||
var issueCommand = function(command, opts) {
|
||||
return OctoPrint.issueCommand(url, command, {}, opts);
|
||||
};
|
||||
|
||||
OctoPrint.job = {
|
||||
get: function(opts) {
|
||||
return OctoPrint.get(url, opts);
|
||||
},
|
||||
start: function(opts) {
|
||||
return issueCommand("start", opts);
|
||||
},
|
||||
restart: function(opts) {
|
||||
return issueCommand("restart", opts);
|
||||
},
|
||||
pause: function(opts) {
|
||||
return issueCommand("pause", opts);
|
||||
},
|
||||
cancel: function(opts) {
|
||||
return issueCommand("cancel", opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
22
src/octoprint/static/js/app/client/languages.js
Normal file
22
src/octoprint/static/js/app/client/languages.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var url = "api/languages";
|
||||
|
||||
OctoPrint.languages = {
|
||||
list: function(opts) {
|
||||
return OctoPrint.get(url, opts);
|
||||
},
|
||||
upload: function(file) {
|
||||
return OctoPrint.upload(url, file);
|
||||
},
|
||||
delete: function(locale, pack, opts) {
|
||||
var packUrl = url + "/" + locale + "/" + pack;
|
||||
return OctoPrint.delete(packUrl, opts);
|
||||
}
|
||||
};
|
||||
});
|
||||
25
src/octoprint/static/js/app/client/logs.js
Normal file
25
src/octoprint/static/js/app/client/logs.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var url = "api/logs";
|
||||
|
||||
OctoPrint.logs = {
|
||||
list: function(opts) {
|
||||
return OctoPrint.get(url, opts);
|
||||
},
|
||||
|
||||
delete: function(file, opts) {
|
||||
var fileUrl = url + "/" + file;
|
||||
return OctoPrint.delete(fileUrl, opts);
|
||||
},
|
||||
|
||||
download: function(file, opts) {
|
||||
var fileUrl = url + "/" + file;
|
||||
return OctoPrint.download(fileUrl, opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
207
src/octoprint/static/js/app/client/printer.js
Normal file
207
src/octoprint/static/js/app/client/printer.js
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var url = "api/printer";
|
||||
var printheadUrl = url + "/printhead";
|
||||
var toolUrl = url + "/tool";
|
||||
var bedUrl = url + "/bed";
|
||||
var sdUrl = url + "/sd";
|
||||
|
||||
var issuePrintheadCommand = function (command, payload, opts) {
|
||||
return OctoPrint.issueCommand(printheadUrl, command, payload, opts);
|
||||
};
|
||||
|
||||
var issueToolCommand = function (command, payload, opts) {
|
||||
return OctoPrint.issueCommand(toolUrl, command, payload, opts);
|
||||
};
|
||||
|
||||
var issueBedCommand = function (command, payload, opts) {
|
||||
return OctoPrint.issueCommand(bedUrl, command, payload, opts);
|
||||
};
|
||||
|
||||
var issueSdCommand = function (command, payload, opts) {
|
||||
return OctoPrint.issueCommand(sdUrl, command, payload, opts);
|
||||
};
|
||||
|
||||
OctoPrint.printer = {
|
||||
getFullState: function (data, opts) {
|
||||
data = data || {};
|
||||
|
||||
var history = data.history || undefined;
|
||||
var limit = data.limit || undefined;
|
||||
var exclude = data.exclude || undefined;
|
||||
|
||||
var getUrl = url;
|
||||
if (history || exclude) {
|
||||
getUrl += "?";
|
||||
if (history) {
|
||||
getUrl += "history=true&";
|
||||
if (limit) {
|
||||
getUrl += "limit=" + limit + "&";
|
||||
}
|
||||
}
|
||||
|
||||
if (exclude) {
|
||||
getUrl += "exclude=" + exclude.join(",") + "&";
|
||||
}
|
||||
}
|
||||
|
||||
return OctoPrint.get(getUrl, opts);
|
||||
},
|
||||
|
||||
getToolState: function (data, opts) {
|
||||
data = data || {};
|
||||
|
||||
var history = data.history || undefined;
|
||||
var limit = data.limit || undefined;
|
||||
|
||||
var getUrl = toolUrl;
|
||||
if (history) {
|
||||
getUrl += "?history=true";
|
||||
if (limit) {
|
||||
getUrl += "&limit=" + limit;
|
||||
}
|
||||
}
|
||||
|
||||
return OctoPrint.get(getUrl, opts);
|
||||
},
|
||||
|
||||
getBedState: function (data, opts) {
|
||||
data = data || {};
|
||||
|
||||
var history = data.history || undefined;
|
||||
var limit = data.limit || undefined;
|
||||
|
||||
var getUrl = bedUrl;
|
||||
if (history) {
|
||||
getUrl += "?history=true";
|
||||
if (limit) {
|
||||
getUrl += "&limit=" + limit;
|
||||
}
|
||||
}
|
||||
|
||||
return OctoPrint.get(getUrl, opts);
|
||||
},
|
||||
|
||||
getSdState: function (opts) {
|
||||
return OctoPrint.get(sdUrl, opts);
|
||||
},
|
||||
|
||||
jog: function (data, opts) {
|
||||
data = data || {};
|
||||
|
||||
var payload = {};
|
||||
if (data.x) payload.x = data.x;
|
||||
if (data.y) payload.y = data.y;
|
||||
if (data.z) payload.z = data.z;
|
||||
|
||||
return issuePrintheadCommand("jog", payload, opts);
|
||||
},
|
||||
|
||||
home: function (axes, opts) {
|
||||
axes = axes || [];
|
||||
|
||||
var payload = {
|
||||
axes: axes
|
||||
};
|
||||
|
||||
return issuePrintheadCommand("home", payload, opts);
|
||||
},
|
||||
|
||||
setFeedrate: function (factor, opts) {
|
||||
factor = factor || 100;
|
||||
|
||||
var payload = {
|
||||
factor: factor
|
||||
};
|
||||
|
||||
return issuePrintheadCommand("feedrate", payload, opts);
|
||||
},
|
||||
|
||||
setToolTargetTemperatures: function (targets, opts) {
|
||||
targets = targets || {};
|
||||
|
||||
var payload = {
|
||||
targets: targets
|
||||
};
|
||||
|
||||
return issueToolCommand("target", payload, opts);
|
||||
},
|
||||
|
||||
setToolTemperatureOffsets: function (offsets, opts) {
|
||||
offsets = offsets || {};
|
||||
|
||||
var payload = {
|
||||
offsets: offsets
|
||||
};
|
||||
|
||||
return issueToolCommand("offset", payload, opts);
|
||||
},
|
||||
|
||||
selectTool: function (tool, opts) {
|
||||
tool = tool || undefined;
|
||||
|
||||
var payload = {
|
||||
tool: tool
|
||||
};
|
||||
|
||||
return issueToolCommand("select", payload, opts);
|
||||
},
|
||||
|
||||
extrude: function (amount, opts) {
|
||||
amount = amount || undefined;
|
||||
|
||||
var payload = {
|
||||
amount: amount
|
||||
};
|
||||
|
||||
return issueToolCommand("extrude", payload, opts);
|
||||
},
|
||||
|
||||
setFlowrate: function (factor, opts) {
|
||||
factor = factor || 100;
|
||||
|
||||
var payload = {
|
||||
factor: factor
|
||||
};
|
||||
|
||||
return issueToolCommand("flowrate", payload, opts);
|
||||
},
|
||||
|
||||
setBedTargetTemperature: function (temperature, opts) {
|
||||
temperature = temperature || 0;
|
||||
|
||||
var payload = {
|
||||
target: temperature
|
||||
};
|
||||
|
||||
return issueBedCommand("target", payload, opts);
|
||||
},
|
||||
|
||||
setBedTemperatureOffset: function (offset, opts) {
|
||||
offset = offset || 0;
|
||||
|
||||
var payload = {
|
||||
offset: offset
|
||||
};
|
||||
|
||||
return issueBedCommand("offset", payload, opts);
|
||||
},
|
||||
|
||||
initSd: function (opts) {
|
||||
return issueSdCommand("init", {}, opts);
|
||||
},
|
||||
|
||||
refreshSd: function (opts) {
|
||||
return issueSdCommand("refresh", {}, opts);
|
||||
},
|
||||
|
||||
releaseSd: function (opts) {
|
||||
return issueSdCommand("release", {}, opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
43
src/octoprint/static/js/app/client/printerprofiles.js
Normal file
43
src/octoprint/static/js/app/client/printerprofiles.js
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint", "jquery"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint, window.$);
|
||||
}
|
||||
})(window || this, function(OctoPrint, $) {
|
||||
var url = "api/printerprofiles";
|
||||
|
||||
var profileUrl = function(profile) {
|
||||
return url + "/" + profile;
|
||||
};
|
||||
|
||||
OctoPrint.printerprofiles = {
|
||||
get: function (opts) {
|
||||
return OctoPrint.get(url, opts);
|
||||
},
|
||||
|
||||
add: function (profile, additional, opts) {
|
||||
profile = profile || {};
|
||||
additional = additional || {};
|
||||
|
||||
var data = $.extend({}, additional);
|
||||
data.profile = profile;
|
||||
|
||||
return OctoPrint.postJson(url, data, opts);
|
||||
},
|
||||
|
||||
update: function (id, profile, additional, opts) {
|
||||
profile = profile || {};
|
||||
additional = addtional || {};
|
||||
|
||||
var data = $.extend({}, additional);
|
||||
data.profile = profile;
|
||||
|
||||
return OctoPrint.patchJson(profileUrl(id), data, opts);
|
||||
},
|
||||
|
||||
delete: function (id, opts) {
|
||||
return OctoPrint.delete(profileUrl(id), opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
43
src/octoprint/static/js/app/client/settings.js
Normal file
43
src/octoprint/static/js/app/client/settings.js
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint", "jquery"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint, window.$);
|
||||
}
|
||||
})(window || this, function(OctoPrint, $) {
|
||||
var url = "api/settings";
|
||||
|
||||
var get = function(opts) {
|
||||
return OctoPrint.get(url, opts);
|
||||
};
|
||||
|
||||
var save = function(settings, opts) {
|
||||
settings = settings || {};
|
||||
return OctoPrint.postJson(url, settings, opts);
|
||||
};
|
||||
|
||||
OctoPrint.settings = {
|
||||
get: get,
|
||||
save: save,
|
||||
|
||||
getPluginSettings: function (plugin, opts) {
|
||||
return get(opts)
|
||||
.then(function (settings, statusText, request) {
|
||||
if (!settings.plugins || !settings.plugins[plugin]) {
|
||||
return $.Deferred()
|
||||
.reject(request, "dataerror", "No settings for plugin " + plugin)
|
||||
.promise();
|
||||
} else {
|
||||
return settings.plugins[plugin];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
savePluginSettings: function (plugin, settings, opts) {
|
||||
var data = {};
|
||||
data["plugins"] = {};
|
||||
data["plugins"][plugin] = settings;
|
||||
return save(data, opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
45
src/octoprint/static/js/app/client/slicing.js
Normal file
45
src/octoprint/static/js/app/client/slicing.js
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var url = "api/slicing";
|
||||
|
||||
var slicerUrl = function(slicer) {
|
||||
return url + "/" + slicer;
|
||||
};
|
||||
|
||||
var profileUrl = function(slicer, profileId) {
|
||||
return slicerUrl(slicer) + "/profiles/" + profileId;
|
||||
};
|
||||
|
||||
OctoPrint.slicing = {
|
||||
listAllSlicersAndProfiles: function(opts) {
|
||||
return OctoPrint.get(url, opts);
|
||||
},
|
||||
|
||||
listProfilesForSlicer: function(slicer, opts) {
|
||||
return OctoPrint.get(slicerUrl(slicer) + "/profiles", opts);
|
||||
},
|
||||
|
||||
getProfileForSlicer: function(slicer, profileId, opts) {
|
||||
return OctoPrint.get(profileUrl(slicer, profileId), opts);
|
||||
},
|
||||
|
||||
addProfileForSlicer: function(slicer, profileId, profile, opts) {
|
||||
profile = profile || {};
|
||||
return OctoPrint.putJson(profileUrl(slicer, profileId), profile, opts);
|
||||
},
|
||||
|
||||
updateProfileForSlicer: function(slicer, profileId, profile, opts) {
|
||||
profile = profile || {};
|
||||
return OctoPrint.patchJson(profileUrl(slicer, profileId), profile, opts);
|
||||
},
|
||||
|
||||
deleteProfileForSlicer: function(slicer, profileId, opts) {
|
||||
return OctoPrint.delete(profileUrl(slicer, profileId), opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
112
src/octoprint/static/js/app/client/socket.js
Normal file
112
src/octoprint/static/js/app/client/socket.js
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint", "jquery", "lodash", "sockjs"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint, window.$, window._, window.SockJS);
|
||||
}
|
||||
})(window || this, function(OctoPrint, $, _, SockJS) {
|
||||
var exports = {};
|
||||
|
||||
exports.options = {
|
||||
timeouts: [0, 1, 1, 2, 3, 5, 8, 13, 20, 40, 100]
|
||||
};
|
||||
|
||||
var normalClose = 1000;
|
||||
|
||||
var socket = undefined;
|
||||
var reconnecting = false;
|
||||
var reconnectTrial = 0;
|
||||
var registeredHandlers = {};
|
||||
|
||||
var onOpen = function() {
|
||||
reconnecting = false;
|
||||
reconnectTrial = 0;
|
||||
};
|
||||
|
||||
var onClose = function(e) {
|
||||
if (e.code == normalClose) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (exports.onReconnectAttempt(reconnectTrial)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reconnectTrial < exports.options.timeouts.length) {
|
||||
var timeout = exports.options.timeouts[reconnectTrial];
|
||||
setTimeout(exports.reconnect, timeout * 1000);
|
||||
reconnectTrial++;
|
||||
} else {
|
||||
exports.onReconnectFailed();
|
||||
}
|
||||
};
|
||||
|
||||
var onMessage = function(msg) {
|
||||
_.each(msg.data, function(data, key) {
|
||||
propagateMessage(key, data);
|
||||
});
|
||||
};
|
||||
|
||||
var propagateMessage = function(event, data) {
|
||||
if (!registeredHandlers.hasOwnProperty(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var eventObj = {event: event, data: data};
|
||||
|
||||
var catchAllHandlers = registeredHandlers["*"];
|
||||
if (catchAllHandlers && catchAllHandlers.length) {
|
||||
_.each(catchAllHandlers, function(handler) {
|
||||
handler({event: eventObj})
|
||||
});
|
||||
}
|
||||
|
||||
var handlers = registeredHandlers[event];
|
||||
if (handlers && handlers.length) {
|
||||
_.each(handlers, function(handler) {
|
||||
handler(eventObj);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.connect = function(opts) {
|
||||
opts = opts || {};
|
||||
|
||||
exports.disconnect();
|
||||
|
||||
var url = OctoPrint.options.baseurl;
|
||||
if (!_.endsWith(url, "/")) {
|
||||
url += "/";
|
||||
}
|
||||
|
||||
socket = new SockJS(url + "sockjs", undefined, opts);
|
||||
socket.onopen = onOpen;
|
||||
socket.onclose = onClose;
|
||||
socket.onmessage = onMessage;
|
||||
};
|
||||
|
||||
exports.reconnect = function() {
|
||||
exports.disconnect();
|
||||
socket = undefined;
|
||||
exports.connect();
|
||||
};
|
||||
|
||||
exports.disconnect = function() {
|
||||
if (socket != undefined) {
|
||||
socket.close();
|
||||
}
|
||||
};
|
||||
|
||||
exports.onMessage = function(message, handler) {
|
||||
if (!registeredHandlers.hasOwnProperty(message)) {
|
||||
registeredHandlers[message] = [];
|
||||
}
|
||||
registeredHandlers[message].push(handler);
|
||||
return exports;
|
||||
};
|
||||
|
||||
exports.onReconnectAttempt = function(trial) {};
|
||||
exports.onReconnectFailed = function() {};
|
||||
|
||||
OctoPrint.socket = exports;
|
||||
});
|
||||
24
src/octoprint/static/js/app/client/system.js
Normal file
24
src/octoprint/static/js/app/client/system.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var url = "api/system";
|
||||
var commandUrl = "api/system/commands";
|
||||
|
||||
OctoPrint.system = {
|
||||
getCommands: function (opts) {
|
||||
return OctoPrint.get(commandUrl, opts);
|
||||
},
|
||||
|
||||
getCommandsForSource: function (source, opts) {
|
||||
return OctoPrint.get(commandUrl + "/" + source, opts);
|
||||
},
|
||||
|
||||
executeCommand: function (source, action, opts) {
|
||||
return OctoPrint.postJson(commandUrl + "/" + source + "/" + action, {}, opts);
|
||||
}
|
||||
};
|
||||
});
|
||||
60
src/octoprint/static/js/app/client/timelapse.js
Normal file
60
src/octoprint/static/js/app/client/timelapse.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint", "jquery"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint, window.$);
|
||||
}
|
||||
})(window || this, function(OctoPrint, $) {
|
||||
var url = "api/timelapse";
|
||||
|
||||
var timelapseUrl = function(filename) {
|
||||
return url + "/" + filename;
|
||||
};
|
||||
|
||||
var getTimelapseData = function (opts) {
|
||||
return OctoPrint.get(url, opts);
|
||||
};
|
||||
|
||||
OctoPrint.timelapse = {
|
||||
get: getTimelapseData,
|
||||
|
||||
list: function (opts) {
|
||||
var deferred = $.Deferred();
|
||||
|
||||
getTimelapseData(opts)
|
||||
.done(function (response, status, request) {
|
||||
deferred.resolve(response.files, status, request);
|
||||
})
|
||||
.fail(function () {
|
||||
deferred.reject.apply(null, arguments);
|
||||
});
|
||||
|
||||
return deferred.promise();
|
||||
},
|
||||
|
||||
download: function (filename, opts) {
|
||||
return OctoPrint.download(timelapseUrl(filename), opts);
|
||||
},
|
||||
|
||||
delete: function (filename, opts) {
|
||||
return OctoPrint.delete(timelapseUrl(filename), opts);
|
||||
},
|
||||
|
||||
getConfig: function (opts) {
|
||||
var deferred = $.Deferred();
|
||||
getTimelapseData(opts)
|
||||
.done(function (response, status, request) {
|
||||
deferred.resolve(response.config, status, request);
|
||||
})
|
||||
.fail(function () {
|
||||
deferred.reject.apply(null, arguments);
|
||||
});
|
||||
return deferred.promise();
|
||||
},
|
||||
|
||||
saveConfig: function (config, opts) {
|
||||
config = config || {};
|
||||
return OctoPrint.postJson(url, config, opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
110
src/octoprint/static/js/app/client/users.js
Normal file
110
src/octoprint/static/js/app/client/users.js
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var baseUrl = "api/users";
|
||||
|
||||
var url = function() {
|
||||
if (arguments.length) {
|
||||
return baseUrl + "/" + Array.prototype.join.call(arguments, "/");
|
||||
} else {
|
||||
return baseUrl;
|
||||
}
|
||||
};
|
||||
|
||||
OctoPrint.users = {
|
||||
list: function (opts) {
|
||||
return OctoPrint.get(url(), opts);
|
||||
},
|
||||
|
||||
add: function (user, opts) {
|
||||
if (!user.name || !user.password) {
|
||||
throw new OctoPrint.InvalidArgumentError("Both user's name and password need to be set");
|
||||
}
|
||||
|
||||
var data = {
|
||||
name: user.name,
|
||||
password: user.password,
|
||||
active: user.hasOwnProperty("active") ? !!user.active : true,
|
||||
admin: user.hasOwnProperty("admin") ? !!user.admin : false
|
||||
};
|
||||
|
||||
return OctoPrint.postJson(url(), data, opts);
|
||||
},
|
||||
|
||||
get: function (name, opts) {
|
||||
if (!name) {
|
||||
throw new OctoPrint.InvalidArgumentError("user name must be set");
|
||||
}
|
||||
|
||||
return OctoPrint.get(url(name), opts);
|
||||
},
|
||||
|
||||
update: function (name, active, admin, opts) {
|
||||
if (!name) {
|
||||
throw new OctoPrint.InvalidArgumentError("user name must be set");
|
||||
}
|
||||
|
||||
var data = {
|
||||
active: !!active,
|
||||
admin: !!admin
|
||||
};
|
||||
return OctoPrint.putJson(url(name), data, opts);
|
||||
},
|
||||
|
||||
delete: function (name, opts) {
|
||||
if (!name) {
|
||||
throw new OctoPrint.InvalidArgumentError("user name must be set");
|
||||
}
|
||||
|
||||
return OctoPrint.delete(url(name), opts);
|
||||
},
|
||||
|
||||
changePassword: function (name, password, opts) {
|
||||
if (!name || !password) {
|
||||
throw new OctoPrint.InvalidArgumentError("user name and password must be set");
|
||||
}
|
||||
|
||||
var data = {
|
||||
password: password
|
||||
};
|
||||
return OctoPrint.putJson(url(name, "password"), data, opts);
|
||||
},
|
||||
|
||||
generateApiKey: function (name, opts) {
|
||||
if (!name) {
|
||||
throw new OctoPrint.InvalidArgumentError("user name must be set");
|
||||
}
|
||||
|
||||
return OctoPrint.postJson(url(name, "apikey"), opts);
|
||||
},
|
||||
|
||||
resetApiKey: function (name, opts) {
|
||||
if (!name) {
|
||||
throw new OctoPrint.InvalidArgumentError("user name must be set");
|
||||
}
|
||||
|
||||
return OctoPrint.delete(url(name, "apikey"), opts);
|
||||
},
|
||||
|
||||
getSettings: function (name, opts) {
|
||||
if (!name) {
|
||||
throw new OctoPrint.InvalidArgumentError("user name must be set");
|
||||
}
|
||||
|
||||
return OctoPrint.get(url(name, "settings"), opts);
|
||||
},
|
||||
|
||||
saveSettings: function (name, settings, opts) {
|
||||
if (!name) {
|
||||
throw new OctoPrint.InvalidArgumentError("user name must be set");
|
||||
}
|
||||
|
||||
settings = settings || {};
|
||||
return OctoPrint.patchJson(url(name, "settings"), settings, opts);
|
||||
}
|
||||
};
|
||||
});
|
||||
47
src/octoprint/static/js/app/client/util.js
Normal file
47
src/octoprint/static/js/app/client/util.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint", "jquery"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint, window.$);
|
||||
}
|
||||
})(window || this, function(OctoPrint, $) {
|
||||
var url = "api/util";
|
||||
var testUrl = url + "/test";
|
||||
|
||||
var test = function(command, data, opts) {
|
||||
return OctoPrint.issueCommand(testUrl, command, data, opts);
|
||||
};
|
||||
|
||||
OctoPrint.util = {
|
||||
test: test,
|
||||
|
||||
testPath: function(path, additional, opts) {
|
||||
additional = additional || {};
|
||||
|
||||
var data = $.extend({}, additional);
|
||||
data.path = path;
|
||||
|
||||
return test("path", data, opts);
|
||||
},
|
||||
|
||||
testExecutable: function(path, additional, opts) {
|
||||
additional = additional || {};
|
||||
|
||||
var data = $.extend({}, additional);
|
||||
data.path = path;
|
||||
data.check_type = "file";
|
||||
data.check_access = "x";
|
||||
|
||||
return test("path", data, opts);
|
||||
},
|
||||
|
||||
testUrl: function(url, additional, opts) {
|
||||
additional = additional || {};
|
||||
|
||||
var data = $.extend({}, additional);
|
||||
data.url = url;
|
||||
|
||||
return test("url", data, opts);
|
||||
}
|
||||
};
|
||||
});
|
||||
18
src/octoprint/static/js/app/client/wizard.js
Normal file
18
src/octoprint/static/js/app/client/wizard.js
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrint"], factory);
|
||||
} else {
|
||||
factory(window.OctoPrint);
|
||||
}
|
||||
})(window || this, function(OctoPrint) {
|
||||
var url = "api/setup/wizard";
|
||||
|
||||
OctoPrint.wizard = {
|
||||
get: function(opts) {
|
||||
return OctoPrint.get(url, opts);
|
||||
},
|
||||
finish: function(handled, opts) {
|
||||
return OctoPrint.postJson(url, {handled: handled || []}, opts);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
@ -3,12 +3,6 @@ function DataUpdater(allViewModels) {
|
|||
|
||||
self.allViewModels = allViewModels;
|
||||
|
||||
self._socket = undefined;
|
||||
self._autoReconnecting = false;
|
||||
self._autoReconnectTrial = 0;
|
||||
self._autoReconnectTimeouts = [0, 1, 1, 2, 3, 5, 8, 13, 20, 40, 100];
|
||||
self._autoReconnectDialogIndex = 1;
|
||||
|
||||
self._pluginHash = undefined;
|
||||
self._configHash = undefined;
|
||||
|
||||
|
|
@ -16,65 +10,39 @@ function DataUpdater(allViewModels) {
|
|||
$("#reloadui_overlay_reload").click(function() { location.reload(true); });
|
||||
|
||||
self.connect = function() {
|
||||
var options = {};
|
||||
if (SOCKJS_DEBUG) {
|
||||
options["debug"] = true;
|
||||
}
|
||||
|
||||
self._socket = new SockJS(SOCKJS_URI, undefined, options);
|
||||
self._socket.onopen = self._onconnect;
|
||||
self._socket.onclose = self._onclose;
|
||||
self._socket.onmessage = self._onmessage;
|
||||
OctoPrint.socket.connect({debug: !!SOCKJS_DEBUG});
|
||||
};
|
||||
|
||||
self.reconnect = function() {
|
||||
self._socket.close();
|
||||
delete self._socket;
|
||||
self.connect();
|
||||
OctoPrint.socket.reconnect();
|
||||
};
|
||||
|
||||
self._onconnect = function() {
|
||||
self._autoReconnecting = false;
|
||||
self._autoReconnectTrial = 0;
|
||||
};
|
||||
|
||||
self._onclose = function(e) {
|
||||
if (e.code == SOCKJS_CLOSE_NORMAL) {
|
||||
self._onReconnectAttempt = function(trial) {
|
||||
if (trial <= 0) {
|
||||
// Only consider it a real disconnect if the trial number has exceeded our threshold.
|
||||
return;
|
||||
}
|
||||
if (self._autoReconnectTrial >= self._autoReconnectDialogIndex) {
|
||||
// Only consider it a real disconnect if the trial number has exceeded our threshold.
|
||||
|
||||
var handled = false;
|
||||
callViewModelsIf(
|
||||
self.allViewModels,
|
||||
"onServerDisconnect",
|
||||
function() { return !handled; },
|
||||
function(method) { handled = !method() || handled; }
|
||||
);
|
||||
var handled = false;
|
||||
callViewModelsIf(
|
||||
self.allViewModels,
|
||||
"onServerDisconnect",
|
||||
function() { return !handled; },
|
||||
function(method) { handled = !method() || handled; }
|
||||
);
|
||||
|
||||
if (handled) {
|
||||
return;
|
||||
}
|
||||
|
||||
showOfflineOverlay(
|
||||
gettext("Server is offline"),
|
||||
gettext("The server appears to be offline, at least I'm not getting any response from it. I'll try to reconnect automatically <strong>over the next couple of minutes</strong>, however you are welcome to try a manual reconnect anytime using the button below."),
|
||||
self.reconnect
|
||||
);
|
||||
if (handled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (self._autoReconnectTrial < self._autoReconnectTimeouts.length) {
|
||||
var timeout = self._autoReconnectTimeouts[self._autoReconnectTrial];
|
||||
log.info("Reconnect trial #" + self._autoReconnectTrial + ", waiting " + timeout + "s");
|
||||
setTimeout(self.reconnect, timeout * 1000);
|
||||
self._autoReconnectTrial++;
|
||||
} else {
|
||||
self._onreconnectfailed();
|
||||
}
|
||||
showOfflineOverlay(
|
||||
gettext("Server is offline"),
|
||||
gettext("The server appears to be offline, at least I'm not getting any response from it. I'll try to reconnect automatically <strong>over the next couple of minutes</strong>, however you are welcome to try a manual reconnect anytime using the button below."),
|
||||
self.reconnect
|
||||
);
|
||||
};
|
||||
|
||||
self._onreconnectfailed = function() {
|
||||
self._onReconnectFailed = function() {
|
||||
var handled = false;
|
||||
callViewModelsIf(
|
||||
self.allViewModels,
|
||||
|
|
@ -91,182 +59,189 @@ function DataUpdater(allViewModels) {
|
|||
$("#offline_overlay_message").html(gettext("The server appears to be offline, at least I'm not getting any response from it. I <strong>could not reconnect automatically</strong>, but you may try a manual reconnect using the button below."));
|
||||
};
|
||||
|
||||
self._onmessage = function(e) {
|
||||
for (var prop in e.data) {
|
||||
if (!e.data.hasOwnProperty(prop)) {
|
||||
continue;
|
||||
self._onConnected = function(event) {
|
||||
var data = event.data;
|
||||
|
||||
// update version information
|
||||
var oldVersion = VERSION;
|
||||
VERSION = data["version"];
|
||||
DISPLAY_VERSION = data["display_version"];
|
||||
BRANCH = data["branch"];
|
||||
$("span.version").text(DISPLAY_VERSION);
|
||||
|
||||
// update plugin hash
|
||||
var oldPluginHash = self._pluginHash;
|
||||
self._pluginHash = data["plugin_hash"];
|
||||
|
||||
// update config hash
|
||||
var oldConfigHash = self._configHash;
|
||||
self._configHash = data["config_hash"];
|
||||
|
||||
// if the offline overlay is still showing, now's a good time to
|
||||
// hide it, plus reload the camera feed if it's currently displayed
|
||||
if ($("#offline_overlay").is(":visible")) {
|
||||
hideOfflineOverlay();
|
||||
callViewModels(self.allViewModels, "onDataUpdaterReconnect");
|
||||
|
||||
if ($('#tabs li[class="active"] a').attr("href") == "#control") {
|
||||
$("#webcam_image").attr("src", CONFIG_WEBCAM_STREAM + "?" + new Date().getTime());
|
||||
}
|
||||
}
|
||||
|
||||
var data = e.data[prop];
|
||||
|
||||
var gcodeUploadProgress = $("#gcode_upload_progress");
|
||||
var gcodeUploadProgressBar = $(".bar", gcodeUploadProgress);
|
||||
|
||||
switch (prop) {
|
||||
case "connected": {
|
||||
// update the current UI API key and send it with any request
|
||||
UI_API_KEY = data["apikey"];
|
||||
$.ajaxSetup({
|
||||
headers: {"X-Api-Key": UI_API_KEY}
|
||||
});
|
||||
|
||||
var oldVersion = VERSION;
|
||||
VERSION = data["version"];
|
||||
DISPLAY_VERSION = data["display_version"];
|
||||
BRANCH = data["branch"];
|
||||
$("span.version").text(DISPLAY_VERSION);
|
||||
|
||||
var oldPluginHash = self._pluginHash;
|
||||
self._pluginHash = data["plugin_hash"];
|
||||
|
||||
var oldConfigHash = self._configHash;
|
||||
self._configHash = data["config_hash"];
|
||||
|
||||
if ($("#offline_overlay").is(":visible")) {
|
||||
hideOfflineOverlay();
|
||||
callViewModels(self.allViewModels, "onDataUpdaterReconnect");
|
||||
|
||||
if ($('#tabs li[class="active"] a').attr("href") == "#control") {
|
||||
$("#webcam_image").attr("src", CONFIG_WEBCAM_STREAM + "?" + new Date().getTime());
|
||||
}
|
||||
}
|
||||
|
||||
var versionChanged = oldVersion != VERSION;
|
||||
var pluginsChanged = oldPluginHash != undefined && oldPluginHash != self._pluginHash;
|
||||
var configChanged = oldConfigHash != undefined && oldConfigHash != self._configHash;
|
||||
if (versionChanged || pluginsChanged || configChanged) {
|
||||
self.reloadOverlay.show();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "history": {
|
||||
callViewModels(self.allViewModels, "fromHistoryData", [data]);
|
||||
break;
|
||||
}
|
||||
case "current": {
|
||||
callViewModels(self.allViewModels, "fromCurrentData", [data]);
|
||||
break;
|
||||
}
|
||||
case "slicingProgress": {
|
||||
gcodeUploadProgressBar.text(_.sprintf(gettext("Slicing ... (%(percentage)d%%)"), {percentage: Math.round(data["progress"])}));
|
||||
|
||||
callViewModels(self.allViewModels, "onSlicingProgress", [
|
||||
data["slicer"],
|
||||
data["model_path"],
|
||||
data["machinecode_path"],
|
||||
data["progress"]
|
||||
]);
|
||||
break;
|
||||
}
|
||||
case "event": {
|
||||
var type = data["type"];
|
||||
var payload = data["payload"];
|
||||
var html = "";
|
||||
var format = {};
|
||||
|
||||
log.debug("Got event " + type + " with payload: " + JSON.stringify(payload));
|
||||
|
||||
if (type == "SettingsUpdated") {
|
||||
if (payload && payload.hasOwnProperty("config_hash")) {
|
||||
self._configHash = payload.config_hash;
|
||||
}
|
||||
} else if (type == "MovieRendering") {
|
||||
new PNotify({title: gettext("Rendering timelapse"), text: _.sprintf(gettext("Now rendering timelapse %(movie_basename)s"), payload)});
|
||||
} else if (type == "MovieDone") {
|
||||
new PNotify({title: gettext("Timelapse ready"), text: _.sprintf(gettext("New timelapse %(movie_basename)s is done rendering."), payload)});
|
||||
} else if (type == "MovieFailed") {
|
||||
html = "<p>" + _.sprintf(gettext("Rendering of timelapse %(movie_basename)s failed with return code %(returncode)s"), payload) + "</p>";
|
||||
html += pnotifyAdditionalInfo('<pre style="overflow: auto">' + payload.error + '</pre>');
|
||||
new PNotify({
|
||||
title: gettext("Rendering failed"),
|
||||
text: html,
|
||||
type: "error",
|
||||
hide: false
|
||||
});
|
||||
} else if (type == "PostRollStart") {
|
||||
if (payload.postroll_duration > 60) {
|
||||
format = {duration: _.sprintf(gettext("%(minutes)d min"), {minutes: payload.postroll_duration / 60})};
|
||||
} else {
|
||||
format = {duration: _.sprintf(gettext("%(seconds)d sec"), {seconds: payload.postroll_duration})};
|
||||
}
|
||||
|
||||
new PNotify({
|
||||
title: gettext("Capturing timelapse postroll"),
|
||||
text: _.sprintf(gettext("Now capturing timelapse post roll, this will take approximately %(duration)s..."), format)
|
||||
});
|
||||
} else if (type == "SlicingStarted") {
|
||||
gcodeUploadProgress.addClass("progress-striped").addClass("active");
|
||||
gcodeUploadProgressBar.css("width", "100%");
|
||||
if (payload.progressAvailable) {
|
||||
gcodeUploadProgressBar.text(_.sprintf(gettext("Slicing ... (%(percentage)d%%)"), {percentage: 0}));
|
||||
} else {
|
||||
gcodeUploadProgressBar.text(gettext("Slicing ..."));
|
||||
}
|
||||
} else if (type == "SlicingDone") {
|
||||
gcodeUploadProgress.removeClass("progress-striped").removeClass("active");
|
||||
gcodeUploadProgressBar.css("width", "0%");
|
||||
gcodeUploadProgressBar.text("");
|
||||
new PNotify({title: gettext("Slicing done"), text: _.sprintf(gettext("Sliced %(stl)s to %(gcode)s, took %(time).2f seconds"), payload), type: "success"});
|
||||
} else if (type == "SlicingCancelled") {
|
||||
gcodeUploadProgress.removeClass("progress-striped").removeClass("active");
|
||||
gcodeUploadProgressBar.css("width", "0%");
|
||||
gcodeUploadProgressBar.text("");
|
||||
} else if (type == "SlicingFailed") {
|
||||
gcodeUploadProgress.removeClass("progress-striped").removeClass("active");
|
||||
gcodeUploadProgressBar.css("width", "0%");
|
||||
gcodeUploadProgressBar.text("");
|
||||
|
||||
html = _.sprintf(gettext("Could not slice %(stl)s to %(gcode)s: %(reason)s"), payload);
|
||||
new PNotify({title: gettext("Slicing failed"), text: html, type: "error", hide: false});
|
||||
} else if (type == "TransferStarted") {
|
||||
gcodeUploadProgress.addClass("progress-striped").addClass("active");
|
||||
gcodeUploadProgressBar.css("width", "100%");
|
||||
gcodeUploadProgressBar.text(gettext("Streaming ..."));
|
||||
} else if (type == "TransferDone") {
|
||||
gcodeUploadProgress.removeClass("progress-striped").removeClass("active");
|
||||
gcodeUploadProgressBar.css("width", "0%");
|
||||
gcodeUploadProgressBar.text("");
|
||||
new PNotify({
|
||||
title: gettext("Streaming done"),
|
||||
text: _.sprintf(gettext("Streamed %(local)s to %(remote)s on SD, took %(time).2f seconds"), payload),
|
||||
type: "success"
|
||||
});
|
||||
gcodeFilesViewModel.requestData(payload.remote, "sdcard");
|
||||
}
|
||||
|
||||
var legacyEventHandlers = {
|
||||
"UpdatedFiles": "onUpdatedFiles",
|
||||
"MetadataStatisticsUpdated": "onMetadataStatisticsUpdated",
|
||||
"MetadataAnalysisFinished": "onMetadataAnalysisFinished",
|
||||
"SlicingDone": "onSlicingDone",
|
||||
"SlicingCancelled": "onSlicingCancelled",
|
||||
"SlicingFailed": "onSlicingFailed"
|
||||
};
|
||||
_.each(self.allViewModels, function(viewModel) {
|
||||
if (viewModel.hasOwnProperty("onEvent" + type)) {
|
||||
viewModel["onEvent" + type](payload);
|
||||
} else if (legacyEventHandlers.hasOwnProperty(type) && viewModel.hasOwnProperty(legacyEventHandlers[type])) {
|
||||
// there might still be code that uses the old callbacks, make sure those still get called
|
||||
// but log a warning
|
||||
log.warn("View model " + viewModel.name + " is using legacy event handler " + legacyEventHandlers[type] + ", new handler is called " + legacyEventHandlers[type]);
|
||||
viewModel[legacyEventHandlers[type]](payload);
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
case "timelapse": {
|
||||
callViewModels(self.allViewModels, "fromTimelapseData", [data]);
|
||||
break;
|
||||
}
|
||||
case "plugin": {
|
||||
callViewModels(self.allViewModels, "onDataUpdaterPluginMessage", [data.plugin, data.data]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if the version, the plugin hash or the config hash changed, we
|
||||
// want the user to reload the UI since it might be stale now
|
||||
var versionChanged = oldVersion != VERSION;
|
||||
var pluginsChanged = oldPluginHash != undefined && oldPluginHash != self._pluginHash;
|
||||
var configChanged = oldConfigHash != undefined && oldConfigHash != self._configHash;
|
||||
if (versionChanged || pluginsChanged || configChanged) {
|
||||
self.reloadOverlay.show();
|
||||
}
|
||||
};
|
||||
|
||||
self._onHistoryData = function(event) {
|
||||
callViewModels(self.allViewModels, "fromHistoryData", [event.data]);
|
||||
};
|
||||
|
||||
self._onCurrentData = function(event) {
|
||||
callViewModels(self.allViewModels, "fromCurrentData", [event.data]);
|
||||
};
|
||||
|
||||
self._onSlicingProgress = function(event) {
|
||||
$("#gcode_upload_progress").find(".bar").text(_.sprintf(gettext("Slicing ... (%(percentage)d%%)"), {percentage: Math.round(event.data["progress"])}));
|
||||
|
||||
callViewModels(self.allViewModels, "onSlicingProgress", [
|
||||
data["slicer"],
|
||||
data["model_path"],
|
||||
data["machinecode_path"],
|
||||
data["progress"]
|
||||
]);
|
||||
};
|
||||
|
||||
self._onEvent = function(event) {
|
||||
var gcodeUploadProgress = $("#gcode_upload_progress");
|
||||
var gcodeUploadProgressBar = $(".bar", gcodeUploadProgress);
|
||||
|
||||
var type = event.data["type"];
|
||||
var payload = event.data["payload"];
|
||||
var html = "";
|
||||
var format = {};
|
||||
|
||||
log.debug("Got event " + type + " with payload: " + JSON.stringify(payload));
|
||||
|
||||
if (type == "SettingsUpdated") {
|
||||
if (payload && payload.hasOwnProperty("config_hash")) {
|
||||
self._configHash = payload.config_hash;
|
||||
}
|
||||
} else if (type == "MovieRendering") {
|
||||
new PNotify({title: gettext("Rendering timelapse"), text: _.sprintf(gettext("Now rendering timelapse %(movie_basename)s"), payload)});
|
||||
} else if (type == "MovieDone") {
|
||||
new PNotify({title: gettext("Timelapse ready"), text: _.sprintf(gettext("New timelapse %(movie_basename)s is done rendering."), payload)});
|
||||
} else if (type == "MovieFailed") {
|
||||
html = "<p>" + _.sprintf(gettext("Rendering of timelapse %(movie_basename)s failed with return code %(returncode)s"), payload) + "</p>";
|
||||
html += pnotifyAdditionalInfo('<pre style="overflow: auto">' + payload.error + '</pre>');
|
||||
new PNotify({
|
||||
title: gettext("Rendering failed"),
|
||||
text: html,
|
||||
type: "error",
|
||||
hide: false
|
||||
});
|
||||
} else if (type == "PostRollStart") {
|
||||
var title = gettext("Capturing timelapse postroll");
|
||||
|
||||
var text;
|
||||
if (!payload.postroll_duration) {
|
||||
text = _.sprintf(gettext("Now capturing timelapse post roll, this will take only a moment..."), format);
|
||||
} else {
|
||||
if (payload.postroll_duration > 60) {
|
||||
format = {duration: _.sprintf(gettext("%(minutes)d min"), {minutes: payload.postroll_duration / 60})};
|
||||
} else {
|
||||
format = {duration: _.sprintf(gettext("%(seconds)d sec"), {seconds: payload.postroll_duration})};
|
||||
}
|
||||
text = _.sprintf(gettext("Now capturing timelapse post roll, this will take approximately %(duration)s..."), format);
|
||||
}
|
||||
|
||||
new PNotify({
|
||||
title: title,
|
||||
text: text
|
||||
});
|
||||
} else if (type == "SlicingStarted") {
|
||||
gcodeUploadProgress.addClass("progress-striped").addClass("active");
|
||||
gcodeUploadProgressBar.css("width", "100%");
|
||||
if (payload.progressAvailable) {
|
||||
gcodeUploadProgressBar.text(_.sprintf(gettext("Slicing ... (%(percentage)d%%)"), {percentage: 0}));
|
||||
} else {
|
||||
gcodeUploadProgressBar.text(gettext("Slicing ..."));
|
||||
}
|
||||
} else if (type == "SlicingDone") {
|
||||
gcodeUploadProgress.removeClass("progress-striped").removeClass("active");
|
||||
gcodeUploadProgressBar.css("width", "0%");
|
||||
gcodeUploadProgressBar.text("");
|
||||
new PNotify({title: gettext("Slicing done"), text: _.sprintf(gettext("Sliced %(stl)s to %(gcode)s, took %(time).2f seconds"), payload), type: "success"});
|
||||
} else if (type == "SlicingCancelled") {
|
||||
gcodeUploadProgress.removeClass("progress-striped").removeClass("active");
|
||||
gcodeUploadProgressBar.css("width", "0%");
|
||||
gcodeUploadProgressBar.text("");
|
||||
} else if (type == "SlicingFailed") {
|
||||
gcodeUploadProgress.removeClass("progress-striped").removeClass("active");
|
||||
gcodeUploadProgressBar.css("width", "0%");
|
||||
gcodeUploadProgressBar.text("");
|
||||
|
||||
html = _.sprintf(gettext("Could not slice %(stl)s to %(gcode)s: %(reason)s"), payload);
|
||||
new PNotify({title: gettext("Slicing failed"), text: html, type: "error", hide: false});
|
||||
} else if (type == "TransferStarted") {
|
||||
gcodeUploadProgress.addClass("progress-striped").addClass("active");
|
||||
gcodeUploadProgressBar.css("width", "100%");
|
||||
gcodeUploadProgressBar.text(gettext("Streaming ..."));
|
||||
} else if (type == "TransferDone") {
|
||||
gcodeUploadProgress.removeClass("progress-striped").removeClass("active");
|
||||
gcodeUploadProgressBar.css("width", "0%");
|
||||
gcodeUploadProgressBar.text("");
|
||||
new PNotify({
|
||||
title: gettext("Streaming done"),
|
||||
text: _.sprintf(gettext("Streamed %(local)s to %(remote)s on SD, took %(time).2f seconds"), payload),
|
||||
type: "success"
|
||||
});
|
||||
gcodeFilesViewModel.requestData(payload.remote, "sdcard");
|
||||
}
|
||||
|
||||
var legacyEventHandlers = {
|
||||
"UpdatedFiles": "onUpdatedFiles",
|
||||
"MetadataStatisticsUpdated": "onMetadataStatisticsUpdated",
|
||||
"MetadataAnalysisFinished": "onMetadataAnalysisFinished",
|
||||
"SlicingDone": "onSlicingDone",
|
||||
"SlicingCancelled": "onSlicingCancelled",
|
||||
"SlicingFailed": "onSlicingFailed"
|
||||
};
|
||||
_.each(self.allViewModels, function(viewModel) {
|
||||
if (viewModel.hasOwnProperty("onEvent" + type)) {
|
||||
viewModel["onEvent" + type](payload);
|
||||
} else if (legacyEventHandlers.hasOwnProperty(type) && viewModel.hasOwnProperty(legacyEventHandlers[type])) {
|
||||
// there might still be code that uses the old callbacks, make sure those still get called
|
||||
// but log a warning
|
||||
log.warn("View model " + viewModel.name + " is using legacy event handler " + legacyEventHandlers[type] + ", new handler is called " + legacyEventHandlers[type]);
|
||||
viewModel[legacyEventHandlers[type]](payload);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self._onTimelapse = function(event) {
|
||||
callViewModels(self.allViewModels, "fromTimelapseData", [event.data]);
|
||||
};
|
||||
|
||||
self._onPluginMessage = function(event) {
|
||||
callViewModels(self.allViewModels, "onDataUpdaterPluginMessage", [event.data.plugin, event.data.data]);
|
||||
};
|
||||
|
||||
OctoPrint.socket.onReconnectAttempt = self._onReconnectAttempt;
|
||||
OctoPrint.socket.onReconnectFailed = self._onReconnectFailed;
|
||||
OctoPrint.socket
|
||||
.onMessage("connected", self._onConnected)
|
||||
.onMessage("history", self._onHistoryData)
|
||||
.onMessage("current", self._onCurrentData)
|
||||
.onMessage("slicingProgress", self._onSlicingProgress)
|
||||
.onMessage("event", self._onEvent)
|
||||
.onMessage("timelapse", self._onTimelapse)
|
||||
.onMessage("plugin", self._onPluginMessage);
|
||||
|
||||
self.connect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
$(function() {
|
||||
OctoPrint = window.OctoPrint;
|
||||
|
||||
//~~ Lodash setup
|
||||
|
||||
_.mixin({"sprintf": sprintf, "vsprintf": vsprintf});
|
||||
|
|
@ -7,6 +9,23 @@ $(function() {
|
|||
|
||||
log.setLevel(CONFIG_DEBUG ? "debug" : "info");
|
||||
|
||||
//~~ OctoPrint client setup
|
||||
OctoPrint.options.baseurl = BASEURL;
|
||||
OctoPrint.options.apikey = UI_API_KEY;
|
||||
|
||||
OctoPrint.socket.onMessage("connected", function(data) {
|
||||
var payload = data.data;
|
||||
OctoPrint.options.apikey = payload.apikey;
|
||||
|
||||
// update the API key directly in jquery's ajax options too,
|
||||
// to ensure the fileupload plugin and any plugins still using
|
||||
// $.ajax directly still work fine too
|
||||
UI_API_KEY = payload["apikey"];
|
||||
$.ajaxSetup({
|
||||
headers: {"X-Api-Key": UI_API_KEY}
|
||||
});
|
||||
});
|
||||
|
||||
//~~ AJAX setup
|
||||
|
||||
// work around a stupid iOS6 bug where ajax requests get cached and only work once, as described at
|
||||
|
|
@ -62,6 +81,26 @@ $(function() {
|
|||
PNotify.prototype.options.styling = "bootstrap2";
|
||||
PNotify.prototype.options.mouse_reset = false;
|
||||
|
||||
PNotify.singleButtonNotify = function(options) {
|
||||
if (!options.confirm || !options.confirm.buttons || !options.confirm.buttons.length) {
|
||||
return new PNotify(options);
|
||||
}
|
||||
|
||||
var autoDisplay = options.auto_display != false;
|
||||
|
||||
var params = $.extend(true, {}, options);
|
||||
params.auto_display = false;
|
||||
|
||||
var notify = new PNotify(params);
|
||||
notify.options.confirm.buttons = [notify.options.confirm.buttons[0]];
|
||||
notify.modules.confirm.makeDialog(notify, notify.options.confirm);
|
||||
|
||||
if (autoDisplay) {
|
||||
notify.open();
|
||||
}
|
||||
return notify;
|
||||
};
|
||||
|
||||
//~~ Initialize view models
|
||||
|
||||
// the view model map is our basic look up table for dependencies that may be injected into other view models
|
||||
|
|
@ -487,7 +526,8 @@ $(function() {
|
|||
if (!_.has(viewModelMap, "settingsViewModel")) {
|
||||
throw new Error("settingsViewModel is missing, can't run UI")
|
||||
}
|
||||
viewModelMap["settingsViewModel"].requestData(bindViewModels);
|
||||
viewModelMap["settingsViewModel"].requestData()
|
||||
.done(bindViewModels);
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -47,14 +47,8 @@ $(function() {
|
|||
self.previousIsOperational = undefined;
|
||||
|
||||
self.requestData = function() {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "connection",
|
||||
method: "GET",
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
self.fromResponse(response);
|
||||
}
|
||||
})
|
||||
OctoPrint.connection.getSettings()
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.fromResponse = function(response) {
|
||||
|
|
@ -93,7 +87,7 @@ $(function() {
|
|||
} else if (!self.isOperational() && !connectionTab.hasClass("in")) {
|
||||
connectionTab.collapse("show");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self._processStateData = function(data) {
|
||||
self.previousIsOperational = self.isOperational();
|
||||
|
|
@ -116,7 +110,6 @@ $(function() {
|
|||
self.connect = function() {
|
||||
if (self.isErrorOrClosed()) {
|
||||
var data = {
|
||||
"command": "connect",
|
||||
"port": self.selectedPort() || "AUTO",
|
||||
"baudrate": self.selectedBaudrate() || 0,
|
||||
"printerProfile": self.selectedPrinter(),
|
||||
|
|
@ -126,26 +119,14 @@ $(function() {
|
|||
if (self.saveSettings())
|
||||
data["save"] = true;
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "connection",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify(data),
|
||||
success: function(response) {
|
||||
OctoPrint.connection.connect(data)
|
||||
.done(function() {
|
||||
self.settings.requestData();
|
||||
self.settings.printerProfiles.requestData();
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
self.requestData();
|
||||
$.ajax({
|
||||
url: API_BASEURL + "connection",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify({"command": "disconnect"})
|
||||
})
|
||||
OctoPrint.connection.disconnect();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -108,14 +108,10 @@ $(function() {
|
|||
};
|
||||
|
||||
self.requestData = function () {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "printer/command/custom",
|
||||
method: "GET",
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
OctoPrint.control.getCustomControls()
|
||||
.done(function(response) {
|
||||
self._fromResponse(response);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self._fromResponse = function (response) {
|
||||
|
|
@ -254,26 +250,17 @@ $(function() {
|
|||
multiplier *= -1;
|
||||
}
|
||||
|
||||
var data = {
|
||||
"command": "jog"
|
||||
};
|
||||
var data = {};
|
||||
data[axis] = distance * multiplier;
|
||||
|
||||
self.sendPrintHeadCommand(data);
|
||||
OctoPrint.printer.jog(data);
|
||||
};
|
||||
|
||||
self.sendHomeCommand = function (axis) {
|
||||
self.sendPrintHeadCommand({
|
||||
"command": "home",
|
||||
"axes": axis
|
||||
});
|
||||
OctoPrint.printer.home(axis);
|
||||
};
|
||||
|
||||
self.sendFeedRateCommand = function () {
|
||||
self.sendPrintHeadCommand({
|
||||
"command": "feedrate",
|
||||
"factor": self.feedRate()
|
||||
});
|
||||
OctoPrint.printer.setFeedrate(self.feedRate());
|
||||
};
|
||||
|
||||
self.sendExtrudeCommand = function () {
|
||||
|
|
@ -285,90 +272,46 @@ $(function() {
|
|||
};
|
||||
|
||||
self.sendFlowRateCommand = function () {
|
||||
self.sendToolCommand({
|
||||
"command": "flowrate",
|
||||
"factor": self.flowRate()
|
||||
});
|
||||
OctoPrint.printer.setFlowrate(self.flowRate());
|
||||
};
|
||||
|
||||
self._sendECommand = function (dir) {
|
||||
var length = self.extrusionAmount();
|
||||
if (!length) length = self.settings.printer_defaultExtrusionLength();
|
||||
|
||||
self.sendToolCommand({
|
||||
command: "extrude",
|
||||
amount: length * dir
|
||||
});
|
||||
var length = self.extrusionAmount() || self.settings.printer_defaultExtrusionLength();
|
||||
OctoPrint.printer.extrude(length * dir);
|
||||
};
|
||||
|
||||
self.sendSelectToolCommand = function (data) {
|
||||
if (!data || !data.key()) return;
|
||||
|
||||
self.sendToolCommand({
|
||||
command: "select",
|
||||
tool: data.key()
|
||||
});
|
||||
};
|
||||
|
||||
self.sendPrintHeadCommand = function (data) {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "printer/printhead",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify(data)
|
||||
});
|
||||
};
|
||||
|
||||
self.sendToolCommand = function (data) {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "printer/tool",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify(data)
|
||||
});
|
||||
OctoPrint.printer.selectTool(data.key());
|
||||
};
|
||||
|
||||
self.sendCustomCommand = function (command) {
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
var data = undefined;
|
||||
if (command.hasOwnProperty("command")) {
|
||||
// single command
|
||||
data = {"command": command.command};
|
||||
} else if (command.hasOwnProperty("commands")) {
|
||||
// multi command
|
||||
data = {"commands": command.commands};
|
||||
} else if (command.hasOwnProperty("script")) {
|
||||
data = {"script": command.script};
|
||||
if (command.hasOwnProperty("context")) {
|
||||
data["context"] = command.context;
|
||||
if (command.hasOwnProperty("command") || command.hasOwnProperty("commands")) {
|
||||
var commands = command.commands || [command.command];
|
||||
|
||||
if (commands.hasOwnProperty("input")) {
|
||||
var parameters = {};
|
||||
_.each(command.input, function(input) {
|
||||
if (!input.hasOwnProperty("parameter") || !input.hasOwnProperty("value")) {
|
||||
return;
|
||||
}
|
||||
|
||||
parameters[input.parameter] = input.value();
|
||||
});
|
||||
OctoPrint.control.sendGcodeWithParameters(commands, parameters);
|
||||
} else {
|
||||
OctoPrint.control.sendGcode(commands);
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
} else if (command.hasOwnProperty("script")) {
|
||||
var script = command.script;
|
||||
var context = command.context || {};
|
||||
|
||||
OctoPrint.control.sendGcodeScript(script, context);
|
||||
}
|
||||
|
||||
if (command.hasOwnProperty("input")) {
|
||||
// parametric command(s)
|
||||
data["parameters"] = {};
|
||||
_.each(command.input, function(input) {
|
||||
if (!input.hasOwnProperty("parameter") || !input.hasOwnProperty("value")) {
|
||||
return;
|
||||
}
|
||||
|
||||
data["parameters"][input.parameter] = input.value();
|
||||
});
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "printer/command",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify(data)
|
||||
})
|
||||
};
|
||||
|
||||
self.displayMode = function (customControl) {
|
||||
|
|
@ -414,7 +357,7 @@ $(function() {
|
|||
} else {
|
||||
$("#webcam_rotator").css("height", "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.onSettingsBeforeSave = self.updateRotatorWidth;
|
||||
|
||||
|
|
|
|||
|
|
@ -165,19 +165,13 @@ $(function() {
|
|||
if (self._otherRequestInProgress) return;
|
||||
|
||||
self._otherRequestInProgress = true;
|
||||
$.ajax({
|
||||
url: API_BASEURL + "files",
|
||||
method: "GET",
|
||||
dataType: "json",
|
||||
data: {"recursive": true},
|
||||
success: function(response) {
|
||||
OctoPrint.files.list({ data: { recursive: true} })
|
||||
.done(function(response) {
|
||||
self.fromResponse(response, filenameToFocus, locationToFocus, switchToPath);
|
||||
})
|
||||
.always(function() {
|
||||
self._otherRequestInProgress = false;
|
||||
},
|
||||
error: function() {
|
||||
self._otherRequestInProgress = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self.fromResponse = function(response, filenameToFocus, locationToFocus, switchToPath) {
|
||||
|
|
@ -244,7 +238,7 @@ $(function() {
|
|||
self.currentPath("");
|
||||
self.listHelper.updateItems(self.allItems());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.pathByElement = function(element) {
|
||||
if (!element || element.parent == undefined)
|
||||
|
|
@ -277,20 +271,22 @@ $(function() {
|
|||
};
|
||||
|
||||
self.loadFile = function(file, printAfterLoad) {
|
||||
if (!file || !file.refs || !file.refs.hasOwnProperty("resource")) return;
|
||||
|
||||
$.ajax({
|
||||
url: file.refs.resource,
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify({command: "select", print: printAfterLoad})
|
||||
});
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
OctoPrint.files.select(file.origin, file.name)
|
||||
.done(function() {
|
||||
if (printAfterLoad) {
|
||||
OctoPrint.job.start();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.removeFile = function(file) {
|
||||
if (!file || !file.refs || !file.refs.hasOwnProperty("resource")) return;
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
var index = self.listHelper.paginatedItems().indexOf(file) + 1;
|
||||
if (index >= self.listHelper.paginatedItems().length)
|
||||
index = index - 2;
|
||||
|
|
@ -301,42 +297,31 @@ $(function() {
|
|||
var fileToFocus = self.listHelper.paginatedItems()[index];
|
||||
if (fileToFocus)
|
||||
filenameToFocus = fileToFocus.name;
|
||||
|
||||
$.ajax({
|
||||
url: file.refs.resource,
|
||||
type: "DELETE",
|
||||
success: function() {
|
||||
|
||||
OctoPrint.files.delete(file.origin, file.name)
|
||||
.done(function() {
|
||||
self.requestData(undefined, filenameToFocus, self.pathByElement(file.parent));
|
||||
}
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
self.sliceFile = function(file) {
|
||||
if (!file) return;
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.slicing.show(file.origin, file.name, true);
|
||||
};
|
||||
|
||||
self.initSdCard = function() {
|
||||
self._sendSdCommand("init");
|
||||
OctoPrint.printer.initSd();
|
||||
};
|
||||
|
||||
self.releaseSdCard = function() {
|
||||
self._sendSdCommand("release");
|
||||
OctoPrint.printer.releaseSd();
|
||||
};
|
||||
|
||||
self.refreshSdFiles = function() {
|
||||
self._sendSdCommand("refresh");
|
||||
};
|
||||
|
||||
self._sendSdCommand = function(command) {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "printer/sd",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify({command: command})
|
||||
});
|
||||
OctoPrint.printer.refreshSd();
|
||||
};
|
||||
|
||||
self.downloadLink = function(data) {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ $(function() {
|
|||
self.ui_modelInfo = ko.observable("");
|
||||
self.ui_layerInfo = ko.observable("");
|
||||
|
||||
self.tabActive = false;
|
||||
self.enableReload = ko.observable(false);
|
||||
|
||||
self.waitForApproval = ko.observable(false);
|
||||
|
|
@ -231,19 +232,20 @@ $(function() {
|
|||
self._configureLayerSlider(layerSliderElement);
|
||||
self._configureLayerCommandSlider(commandSliderElement);
|
||||
|
||||
self.settings.requestData(function() {
|
||||
GCODE.ui.init({
|
||||
container: "#gcode_canvas",
|
||||
onProgress: self._onProgress,
|
||||
onModelLoaded: self._onModelLoaded,
|
||||
onLayerSelected: self._onLayerSelected,
|
||||
bed: self._retrieveBedDimensions(),
|
||||
toolOffsets: self._retrieveToolOffsets(),
|
||||
invertAxes: self._retrieveAxesConfiguration()
|
||||
self.settings.requestData()
|
||||
.done(function() {
|
||||
GCODE.ui.init({
|
||||
container: "#gcode_canvas",
|
||||
onProgress: self._onProgress,
|
||||
onModelLoaded: self._onModelLoaded,
|
||||
onLayerSelected: self._onLayerSelected,
|
||||
bed: self._retrieveBedDimensions(),
|
||||
toolOffsets: self._retrieveToolOffsets(),
|
||||
invertAxes: self._retrieveAxesConfiguration()
|
||||
});
|
||||
self.synchronizeOptions();
|
||||
self.enabled = true;
|
||||
});
|
||||
self.synchronizeOptions();
|
||||
self.enabled = true;
|
||||
});
|
||||
};
|
||||
|
||||
self.reset = function() {
|
||||
|
|
@ -289,11 +291,8 @@ $(function() {
|
|||
self.enableReload(false);
|
||||
if (self.status == "idle" && self.errorCount < 3) {
|
||||
self.status = "request";
|
||||
$.ajax({
|
||||
url: BASEURL + "downloads/files/local/" + filename,
|
||||
data: { "ctime": date },
|
||||
type: "GET",
|
||||
success: function(response, rstatus) {
|
||||
OctoPrint.files.download("local", filename)
|
||||
.done(function(response, rstatus) {
|
||||
if(rstatus === 'success'){
|
||||
self.showGCodeViewer(response, rstatus);
|
||||
self.loadedFilename = filename;
|
||||
|
|
@ -301,12 +300,11 @@ $(function() {
|
|||
self.status = "idle";
|
||||
self.enableReload(true);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
})
|
||||
.fail(function() {
|
||||
self.status = "idle";
|
||||
self.errorCount++;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -358,7 +356,7 @@ $(function() {
|
|||
if(self.loadedFilename
|
||||
&& self.loadedFilename == data.job.file.name
|
||||
&& self.loadedFileDate == data.job.file.date) {
|
||||
if (self.currentlyPrinting && self.renderer_syncProgress() && !self.waitForApproval()) {
|
||||
if (self.tabActive && self.currentlyPrinting && self.renderer_syncProgress() && !self.waitForApproval()) {
|
||||
var cmdIndex = GCODE.gCodeReader.getCmdIndexForPercentage(data.progress.completion);
|
||||
if(cmdIndex){
|
||||
GCODE.renderer.render(cmdIndex.layer, 0, cmdIndex.cmd);
|
||||
|
|
@ -506,6 +504,10 @@ $(function() {
|
|||
self.initialize();
|
||||
}
|
||||
|
||||
self.onTabChange = function(current, previous) {
|
||||
self.tabActive = current == "#gcode";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
OCTOPRINT_VIEWMODELS.push([
|
||||
|
|
|
|||
|
|
@ -36,12 +36,8 @@ $(function() {
|
|||
);
|
||||
|
||||
self.requestData = function() {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "logs",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: self.fromResponse
|
||||
});
|
||||
OctoPrint.logs.list()
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.fromResponse = function(response) {
|
||||
|
|
@ -53,12 +49,8 @@ $(function() {
|
|||
};
|
||||
|
||||
self.removeFile = function(filename) {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "logs/" + filename,
|
||||
type: "DELETE",
|
||||
dataType: "json",
|
||||
success: self.requestData
|
||||
});
|
||||
OctoPrint.logs.delete(filename)
|
||||
.done(self.requestData);
|
||||
};
|
||||
|
||||
self.onUserLoggedIn = function(user) {
|
||||
|
|
@ -73,4 +65,4 @@ $(function() {
|
|||
["loginStateViewModel"],
|
||||
"#logs"
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -32,20 +32,13 @@ $(function() {
|
|||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "users/" + self.currentUser().name,
|
||||
type: "GET",
|
||||
success: self.fromResponse
|
||||
})
|
||||
OctoPrint.users.get(self.currentUser().name)
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.requestData = function() {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "login",
|
||||
type: "POST",
|
||||
data: {"passive": true},
|
||||
success: self.fromResponse
|
||||
})
|
||||
OctoPrint.browser.passiveLogin()
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.fromResponse = function(response) {
|
||||
|
|
@ -70,7 +63,7 @@ $(function() {
|
|||
}
|
||||
};
|
||||
|
||||
self.login = function(u, p, r, callback) {
|
||||
self.login = function(u, p, r) {
|
||||
var username = u || self.loginUser();
|
||||
var password = p || self.loginPass();
|
||||
var remember = (r != undefined ? r : self.loginRemember());
|
||||
|
|
@ -79,30 +72,22 @@ $(function() {
|
|||
self.loginPass("");
|
||||
self.loginRemember(false);
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "login",
|
||||
type: "POST",
|
||||
data: {"user": username, "pass": password, "remember": remember},
|
||||
success: function(response) {
|
||||
return OctoPrint.browser.login(username, password, remember)
|
||||
.done(function(response) {
|
||||
new PNotify({title: gettext("Login successful"), text: _.sprintf(gettext('You are now logged in as "%(username)s"'), {username: response.name}), type: "success"});
|
||||
self.fromResponse(response);
|
||||
if (callback) callback(response);
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
})
|
||||
.fail(function() {
|
||||
new PNotify({title: gettext("Login failed"), text: gettext("User unknown or wrong password"), type: "error"});
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
self.logout = function() {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "logout",
|
||||
type: "POST",
|
||||
success: function(response) {
|
||||
OctoPrint.browser.logout()
|
||||
.done(function(response) {
|
||||
new PNotify({title: gettext("Logout successful"), text: gettext("You are now logged out"), type: "success"});
|
||||
self.fromResponse(response);
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
self.onLoginUserKeyup = function(data, event) {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ $(function() {
|
|||
self.appearance = parameters[1];
|
||||
self.settings = parameters[2];
|
||||
self.usersettings = parameters[3];
|
||||
|
||||
self.systemActions = self.settings.system_actions;
|
||||
self.system = parameters[4];
|
||||
|
||||
self.appearanceClasses = ko.computed(function() {
|
||||
var classes = self.appearance.color();
|
||||
|
|
@ -17,41 +16,11 @@ $(function() {
|
|||
return classes;
|
||||
});
|
||||
|
||||
self.triggerAction = function(action) {
|
||||
var callback = function() {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "system",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: "action=" + action.action,
|
||||
success: function() {
|
||||
new PNotify({title: "Success", text: _.sprintf(gettext("The command \"%(command)s\" executed successfully"), {command: action.name}), type: "success"});
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
if (!action.hasOwnProperty("ignore") || !action.ignore) {
|
||||
var error = "<p>" + _.sprintf(gettext("The command \"%(command)s\" could not be executed."), {command: action.name}) + "</p>";
|
||||
error += pnotifyAdditionalInfo("<pre>" + jqXHR.responseText + "</pre>");
|
||||
new PNotify({title: gettext("Error"), text: error, type: "error", hide: false});
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
if (action.confirm) {
|
||||
showConfirmationDialog({
|
||||
message: action.confirm,
|
||||
onproceed: function(e) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OCTOPRINT_VIEWMODELS.push([
|
||||
NavigationViewModel,
|
||||
["loginStateViewModel", "appearanceViewModel", "settingsViewModel", "userSettingsViewModel"],
|
||||
["loginStateViewModel", "appearanceViewModel", "settingsViewModel", "userSettingsViewModel", "systemViewModel"],
|
||||
"#navbar"
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -194,12 +194,8 @@ $(function() {
|
|||
};
|
||||
|
||||
self.requestData = function() {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "printerprofiles",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: self.fromResponse
|
||||
})
|
||||
OctoPrint.printerprofiles.get()
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.fromResponse = function(data) {
|
||||
|
|
@ -228,43 +224,35 @@ $(function() {
|
|||
self.addProfile = function(callback) {
|
||||
var profile = self._editorData();
|
||||
self.requestInProgress(true);
|
||||
$.ajax({
|
||||
url: API_BASEURL + "printerprofiles",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify({profile: profile}),
|
||||
success: function() {
|
||||
self.requestInProgress(false);
|
||||
OctoPrint.printerprofiles.add(profile)
|
||||
.done(function() {
|
||||
if (callback !== undefined) {
|
||||
callback();
|
||||
}
|
||||
self.requestData();
|
||||
},
|
||||
error: function() {
|
||||
self.requestInProgress(false);
|
||||
})
|
||||
.fail(function() {
|
||||
var text = gettext("There was unexpected error while saving the printer profile, please consult the logs.");
|
||||
new PNotify({title: gettext("Saving failed"), text: text, type: "error", hide: false});
|
||||
}
|
||||
});
|
||||
})
|
||||
.always(function() {
|
||||
self.requestInProgress(false);
|
||||
});
|
||||
};
|
||||
|
||||
self.removeProfile = function(data) {
|
||||
self.requestInProgress(true);
|
||||
$.ajax({
|
||||
url: data.resource,
|
||||
type: "DELETE",
|
||||
dataType: "json",
|
||||
success: function() {
|
||||
self.requestInProgress(false);
|
||||
OctoPrint.printerprofiles.delete(data.id, {url: data.resource})
|
||||
.done(function() {
|
||||
self.requestData();
|
||||
},
|
||||
error: function() {
|
||||
self.requestInProgress(false);
|
||||
})
|
||||
.fail(function() {
|
||||
var text = gettext("There was unexpected error while removing the printer profile, please consult the logs.");
|
||||
new PNotify({title: gettext("Saving failed"), text: text, type: "error", hide: false});
|
||||
}
|
||||
})
|
||||
})
|
||||
.always(function() {
|
||||
self.requestInProgress(false);
|
||||
});
|
||||
};
|
||||
|
||||
self.updateProfile = function(profile, callback) {
|
||||
|
|
@ -273,26 +261,20 @@ $(function() {
|
|||
}
|
||||
|
||||
self.requestInProgress(true);
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "printerprofiles/" + profile.id,
|
||||
type: "PATCH",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify({profile: profile}),
|
||||
success: function() {
|
||||
self.requestInProgress(false);
|
||||
OctoPrint.printerprofiles.update(profile.key, profile)
|
||||
.done(function() {
|
||||
if (callback !== undefined) {
|
||||
callback();
|
||||
}
|
||||
self.requestData();
|
||||
},
|
||||
error: function() {
|
||||
self.requestInProgress(false);
|
||||
})
|
||||
.fail(function() {
|
||||
var text = gettext("There was unexpected error while updating the printer profile, please consult the logs.");
|
||||
new PNotify({title: gettext("Saving failed"), text: text, type: "error", hide: false});
|
||||
}
|
||||
});
|
||||
})
|
||||
.always(function() {
|
||||
self.requestInProgress(false);
|
||||
});
|
||||
};
|
||||
|
||||
self.showEditProfileDialog = function(data) {
|
||||
|
|
|
|||
|
|
@ -198,45 +198,25 @@ $(function() {
|
|||
};
|
||||
|
||||
self.print = function() {
|
||||
var restartCommand = function() {
|
||||
self._jobCommand("restart");
|
||||
};
|
||||
|
||||
if (self.isPaused()) {
|
||||
showConfirmationDialog({
|
||||
message: gettext("This will restart the print job from the beginning."),
|
||||
onproceed: function(e) {
|
||||
restartCommand();
|
||||
onproceed: function() {
|
||||
OctoPrint.job.restart();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self._jobCommand("start");
|
||||
OctoPrint.job.start();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
self.pause = function() {
|
||||
self._jobCommand("pause");
|
||||
OctoPrint.job.pause();
|
||||
};
|
||||
|
||||
self.cancel = function() {
|
||||
self._jobCommand("cancel");
|
||||
OctoPrint.job.cancel();
|
||||
};
|
||||
|
||||
self._jobCommand = function(command, callback) {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "job",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify({command: command}),
|
||||
success: function(response) {
|
||||
if (callback != undefined) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
OCTOPRINT_VIEWMODELS.push([
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ $(function() {
|
|||
|
||||
self.receiving = ko.observable(false);
|
||||
self.sending = ko.observable(false);
|
||||
self.callbacks = [];
|
||||
self.outstanding = [];
|
||||
|
||||
self.settingsDialog = undefined;
|
||||
self.settings_dialog_update_detected = undefined;
|
||||
|
|
@ -225,18 +225,9 @@ $(function() {
|
|||
|
||||
var errorText = gettext("Could not retrieve snapshot URL, please double check the URL");
|
||||
var errorTitle = gettext("Snapshot test failed");
|
||||
$.ajax({
|
||||
url: API_BASEURL + "util/test",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({
|
||||
command: "url",
|
||||
url: self.webcam_snapshotUrl(),
|
||||
method: "GET",
|
||||
response: true
|
||||
}),
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
success: function(response) {
|
||||
|
||||
OctoPrint.util.testUrl(self.webcam_snapshotUrl(), {method: "GET", response: true})
|
||||
.done(function(response) {
|
||||
$("i.icon-spinner", target).remove();
|
||||
|
||||
if (!response.result) {
|
||||
|
|
@ -260,15 +251,14 @@ $(function() {
|
|||
title: gettext("Snapshot test"),
|
||||
message: $('<p>' + text + '</p><p><img src="data:' + mimeType + ';base64,' + content + '" /></p>')
|
||||
});
|
||||
},
|
||||
error: function() {
|
||||
})
|
||||
.fail(function() {
|
||||
$("i.icon-spinner", target).remove();
|
||||
showMessageDialog({
|
||||
title: errorTitle,
|
||||
message: errorText
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self.testWebcamFfmpegPath = function() {
|
||||
|
|
@ -276,36 +266,22 @@ $(function() {
|
|||
return;
|
||||
}
|
||||
|
||||
var successCallback = function(response) {
|
||||
if (!response.result) {
|
||||
if (!response.exists) {
|
||||
self.webcam_ffmpegPathText(gettext("The path doesn't exist"));
|
||||
} else if (!response.typeok) {
|
||||
self.webcam_ffmpegPathText(gettext("The path is not a file"));
|
||||
} else if (!response.access) {
|
||||
self.webcam_ffmpegPathText(gettext("The path is not an executable"));
|
||||
OctoPrint.util.testExecutable(self.webcam_ffmpegPath())
|
||||
.done(function(response) {
|
||||
if (!response.result) {
|
||||
if (!response.exists) {
|
||||
self.webcam_ffmpegPathText(gettext("The path doesn't exist"));
|
||||
} else if (!response.typeok) {
|
||||
self.webcam_ffmpegPathText(gettext("The path is not a file"));
|
||||
} else if (!response.access) {
|
||||
self.webcam_ffmpegPathText(gettext("The path is not an executable"));
|
||||
}
|
||||
} else {
|
||||
self.webcam_ffmpegPathText(gettext("The path is valid"));
|
||||
}
|
||||
} else {
|
||||
self.webcam_ffmpegPathText(gettext("The path is valid"));
|
||||
}
|
||||
self.webcam_ffmpegPathOk(response.result);
|
||||
self.webcam_ffmpegPathBroken(!response.result);
|
||||
};
|
||||
|
||||
var path = self.webcam_ffmpegPath();
|
||||
$.ajax({
|
||||
url: API_BASEURL + "util/test",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({
|
||||
command: "path",
|
||||
path: path,
|
||||
check_type: "file",
|
||||
check_access: "x"
|
||||
}),
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
success: successCallback
|
||||
})
|
||||
self.webcam_ffmpegPathOk(response.result);
|
||||
self.webcam_ffmpegPathBroken(!response.result);
|
||||
});
|
||||
};
|
||||
|
||||
self.onSettingsShown = function() {
|
||||
|
|
@ -331,6 +307,7 @@ $(function() {
|
|||
dataType: "json",
|
||||
maxNumberOfFiles: 1,
|
||||
autoUpload: false,
|
||||
headers: OctoPrint.getRequestHeaders(),
|
||||
add: function(e, data) {
|
||||
if (data.files.length == 0) {
|
||||
return false;
|
||||
|
|
@ -409,57 +386,83 @@ $(function() {
|
|||
return false;
|
||||
};
|
||||
|
||||
self.requestData = function(callback, local) {
|
||||
if (self.receiving()) {
|
||||
if (callback) {
|
||||
self.callbacks.push(callback);
|
||||
self.requestData = function(local) {
|
||||
// handle old parameter format
|
||||
var callback = undefined;
|
||||
if (arguments.length == 2 || _.isFunction(local)) {
|
||||
var exc = new Error();
|
||||
log.warn("The callback parameter of SettingsViewModel.requestData is deprecated, the method now returns a promise, please use that instead. Stacktrace:", (exc.stack || exc.stacktrace || "<n/a>"));
|
||||
|
||||
if (arguments.length == 2) {
|
||||
callback = arguments[0];
|
||||
local = arguments[1];
|
||||
} else {
|
||||
callback = local;
|
||||
local = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
self.receiving(true);
|
||||
$.ajax({
|
||||
url: API_BASEURL + "settings",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
if (callback) {
|
||||
self.callbacks.push(callback);
|
||||
}
|
||||
|
||||
try {
|
||||
self.fromResponse(response, local);
|
||||
|
||||
var cb;
|
||||
while (self.callbacks.length) {
|
||||
cb = self.callbacks.shift();
|
||||
try {
|
||||
cb();
|
||||
} catch(exc) {
|
||||
log.error("Error calling settings callback", cb, ":", (exc.stack || exc));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
self.receiving(false);
|
||||
self.callbacks = [];
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
self.receiving(false);
|
||||
// handler for any explicitely provided callbacks
|
||||
var callbackHandler = function() {
|
||||
if (!callback) return;
|
||||
try {
|
||||
callback();
|
||||
} catch (exc) {
|
||||
log.error("Error calling settings callback", callback, ":", (exc.stack || exc.stacktrace || exc));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// if a request is already active, create a new deferred and return
|
||||
// its promise, it will be resolved in the response handler of the
|
||||
// current request
|
||||
if (self.receiving()) {
|
||||
var deferred = $.Deferred();
|
||||
self.outstanding.push(deferred);
|
||||
|
||||
if (callback) {
|
||||
// if we have a callback, we need to make sure it will
|
||||
// get called when the deferred is resolved
|
||||
deferred.done(callbackHandler);
|
||||
}
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
// perform the request
|
||||
self.receiving(true);
|
||||
return OctoPrint.settings.get()
|
||||
.done(function(response) {
|
||||
self.fromResponse(response, local);
|
||||
|
||||
if (callback) {
|
||||
var deferred = $.Deferred();
|
||||
deferred.done(callbackHandler);
|
||||
self.outstanding.push(deferred);
|
||||
}
|
||||
|
||||
// resolve all promises
|
||||
var args = arguments;
|
||||
_.each(self.outstanding, function(deferred) {
|
||||
deferred.resolve(args);
|
||||
});
|
||||
self.outstanding = [];
|
||||
})
|
||||
.fail(function() {
|
||||
// reject all promises
|
||||
var args = arguments;
|
||||
_.each(self.outstanding, function(deferred) {
|
||||
deferred.reject(args);
|
||||
});
|
||||
self.outstanding = [];
|
||||
})
|
||||
.always(function() {
|
||||
self.receiving(false);
|
||||
});
|
||||
};
|
||||
|
||||
self.requestTranslationData = function(callback) {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "languages",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
self.fromTranslationResponse(response);
|
||||
if (callback) callback();
|
||||
}
|
||||
})
|
||||
self.requestTranslationData = function() {
|
||||
return OctoPrint.languages.list()
|
||||
.done(self.fromTranslationResponse);
|
||||
};
|
||||
|
||||
self.fromTranslationResponse = function(response) {
|
||||
|
|
@ -509,14 +512,8 @@ $(function() {
|
|||
});
|
||||
|
||||
self.deleteLanguagePack = function(locale, pack) {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "languages/" + locale + "/" + pack,
|
||||
type: "DELETE",
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
self.fromTranslationResponse(response);
|
||||
}
|
||||
})
|
||||
OctoPrint.languages.delete(locale, pack)
|
||||
.done(self.fromTranslationResponse);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -652,7 +649,10 @@ $(function() {
|
|||
longRunningCommands: function(value) { self.serial_longRunningCommands(value.join(", "))},
|
||||
checksumRequiringCommands: function(value) { self.serial_checksumRequiringCommands(value.join(", "))}
|
||||
},
|
||||
terminalFilters: function(value) { self.terminalFilters.removeAll(); _.each(value, function(item) {self.terminalFilters.push(item)}); }
|
||||
terminalFilters: function(value) { self.terminalFilters($.extend(true, [], value)) },
|
||||
temperature: {
|
||||
profiles: function(value) { self.temperature_profiles($.extend(true, [], value)); }
|
||||
}
|
||||
};
|
||||
|
||||
var mapToObservables = function(data, mapping, local, keyPrefix) {
|
||||
|
|
@ -705,13 +705,8 @@ $(function() {
|
|||
data = getOnlyChangedData(self.getLocalData(), self.lastReceivedSettings);
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "settings",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify(data),
|
||||
success: function(data, status, xhr) {
|
||||
OctoPrint.settings.save(data)
|
||||
.done(function(data, status, xhr) {
|
||||
self.receiving(true);
|
||||
self.sending(false);
|
||||
try {
|
||||
|
|
@ -720,15 +715,14 @@ $(function() {
|
|||
} finally {
|
||||
self.receiving(false);
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
})
|
||||
.fail(function(xhr, status, error) {
|
||||
self.sending(false);
|
||||
if (options.error) options.error(xhr, status, error);
|
||||
},
|
||||
complete: function(xhr, status) {
|
||||
})
|
||||
.always(function(xhr, status) {
|
||||
if (options.complete) options.complete(xhr, status);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self.onEventSettingsUpdated = function() {
|
||||
|
|
|
|||
|
|
@ -64,18 +64,11 @@ $(function() {
|
|||
&& self.profile() != undefined;
|
||||
});
|
||||
|
||||
self.requestData = function(callback) {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "slicing",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(data) {
|
||||
self.requestData = function() {
|
||||
return OctoPrint.slicing.listAllSlicersAndProfiles()
|
||||
.done(function(data) {
|
||||
self.fromResponse(data);
|
||||
if (callback !== undefined) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self.fromResponse = function(data) {
|
||||
|
|
@ -150,7 +143,6 @@ $(function() {
|
|||
}
|
||||
|
||||
var data = {
|
||||
command: "slice",
|
||||
slicer: self.slicer(),
|
||||
profile: self.profile(),
|
||||
printerProfile: self.printerProfile(),
|
||||
|
|
@ -163,19 +155,14 @@ $(function() {
|
|||
data["select"] = true;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "files/" + self.target + "/" + self.file,
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify(data)
|
||||
});
|
||||
OctoPrint.files.slice(self.target, self.file, data)
|
||||
.done(function() {
|
||||
$("#slicing_configuration_dialog").modal("hide");
|
||||
|
||||
$("#slicing_configuration_dialog").modal("hide");
|
||||
|
||||
self.gcodeFilename(undefined);
|
||||
self.slicer(self.defaultSlicer);
|
||||
self.profile(self.defaultProfile);
|
||||
self.gcodeFilename(undefined);
|
||||
self.slicer(self.defaultSlicer);
|
||||
self.profile(self.defaultProfile);
|
||||
});
|
||||
};
|
||||
|
||||
self._sanitize = function(name) {
|
||||
|
|
@ -196,4 +183,4 @@ $(function() {
|
|||
["loginStateViewModel", "printerProfilesViewModel"],
|
||||
"#slicing_configuration_dialog"
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
100
src/octoprint/static/js/app/viewmodels/system.js
Normal file
100
src/octoprint/static/js/app/viewmodels/system.js
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
$(function() {
|
||||
function SystemViewModel(parameters) {
|
||||
var self = this;
|
||||
|
||||
self.loginState = parameters[0];
|
||||
|
||||
self.lastCommandResponse = undefined;
|
||||
self.systemActions = ko.observableArray([]);
|
||||
|
||||
self.requestData = function() {
|
||||
self.requestCommandData();
|
||||
};
|
||||
|
||||
self.requestCommandData = function() {
|
||||
if (!self.loginState.isAdmin()) {
|
||||
return $.Deferred().reject().promise();
|
||||
}
|
||||
|
||||
return OctoPrint.system.getCommands()
|
||||
.done(self.fromCommandResponse);
|
||||
};
|
||||
|
||||
self.fromCommandResponse = function(response) {
|
||||
var actions = [];
|
||||
if (response.core && response.core.length) {
|
||||
_.each(response.core, function(data) {
|
||||
var action = _.extend({}, data);
|
||||
action.actionSource = "core";
|
||||
actions.push(action);
|
||||
});
|
||||
actions.push({action: "divider"});
|
||||
}
|
||||
_.each(response.custom, function(data) {
|
||||
var action = _.extend({}, data);
|
||||
action.actionSource = "custom";
|
||||
actions.push(action);
|
||||
});
|
||||
self.lastCommandResponse = response;
|
||||
self.systemActions(actions);
|
||||
};
|
||||
|
||||
self.triggerCommand = function(commandSpec) {
|
||||
var deferred = $.Deferred();
|
||||
|
||||
var callback = function() {
|
||||
OctoPrint.system.executeCommand(commandSpec.actionSource, commandSpec.action)
|
||||
.done(function() {
|
||||
new PNotify({title: "Success", text: _.sprintf(gettext("The command \"%(command)s\" executed successfully"), {command: commandSpec.name}), type: "success"});
|
||||
deferred.resolve(["success", arguments]);
|
||||
})
|
||||
.fail(function(jqXHR, textStatus, errorThrown) {
|
||||
if (!commandSpec.hasOwnProperty("ignore") || !commandSpec.ignore) {
|
||||
var error = "<p>" + _.sprintf(gettext("The command \"%(command)s\" could not be executed."), {command: commandSpec.name}) + "</p>";
|
||||
error += pnotifyAdditionalInfo("<pre>" + jqXHR.responseText + "</pre>");
|
||||
new PNotify({title: gettext("Error"), text: error, type: "error", hide: false});
|
||||
deferred.reject(["error", arguments]);
|
||||
} else {
|
||||
deferred.resolve(["ignored", arguments]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (commandSpec.confirm) {
|
||||
showConfirmationDialog({
|
||||
message: commandSpec.confirm,
|
||||
onproceed: function() {
|
||||
callback();
|
||||
},
|
||||
oncancel: function() {
|
||||
deferred.reject("cancelled", arguments);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
|
||||
return deferred.promise();
|
||||
};
|
||||
|
||||
self.onUserLoggedIn = function(user) {
|
||||
if (user.admin) {
|
||||
self.requestData();
|
||||
} else {
|
||||
self.onUserLoggedOut();
|
||||
}
|
||||
};
|
||||
|
||||
self.onUserLoggedOut = function() {
|
||||
self.lastCommandResponse = undefined;
|
||||
self.systemActions([]);
|
||||
}
|
||||
}
|
||||
|
||||
// view model class, parameters for constructor, container to bind to
|
||||
ADDITIONAL_VIEWMODELS.push([
|
||||
SystemViewModel,
|
||||
["loginStateViewModel"],
|
||||
[]
|
||||
]);
|
||||
});
|
||||
|
|
@ -268,87 +268,84 @@ $(function() {
|
|||
var value = item.newTarget();
|
||||
if (!value) return;
|
||||
|
||||
self._sendToolCommand("target",
|
||||
item.key(),
|
||||
item.newTarget(),
|
||||
function() {item.newTarget("");}
|
||||
);
|
||||
var onSuccess = function() {
|
||||
item.newTarget("");
|
||||
};
|
||||
|
||||
if (item.key() == "bed") {
|
||||
self._setBedTemperature(value)
|
||||
.done(onSuccess);
|
||||
} else {
|
||||
self._setToolTemperature(item.key(), value)
|
||||
.done(onSuccess);
|
||||
}
|
||||
};
|
||||
|
||||
self.setTargetFromProfile = function(item, profile) {
|
||||
if (!profile) return;
|
||||
|
||||
var value = undefined;
|
||||
if (item.key() == "bed") {
|
||||
value = profile.bed;
|
||||
} else {
|
||||
value = profile.extruder;
|
||||
}
|
||||
var onSuccess = function() {
|
||||
item.newTarget("");
|
||||
};
|
||||
|
||||
self._sendToolCommand("target",
|
||||
item.key(),
|
||||
value,
|
||||
function() {item.newTarget("");}
|
||||
);
|
||||
if (item.key() == "bed") {
|
||||
self._setBedTemperature(profile.bed)
|
||||
.done(onSuccess);
|
||||
} else {
|
||||
self._setToolTemperature(item.key(), profile.extruder)
|
||||
.done(onSuccess);
|
||||
}
|
||||
};
|
||||
|
||||
self.setTargetToZero = function(item) {
|
||||
self._sendToolCommand("target",
|
||||
item.key(),
|
||||
0,
|
||||
function() {item.newTarget("");}
|
||||
);
|
||||
var onSuccess = function() {
|
||||
item.newTarget("");
|
||||
};
|
||||
|
||||
if (item.key() == "bed") {
|
||||
self._setBedTemperature(0)
|
||||
.done(onSuccess);
|
||||
} else {
|
||||
self._setToolTemperature(item.key(), 0)
|
||||
.done(onSuccess);
|
||||
}
|
||||
};
|
||||
|
||||
self.setOffset = function(item) {
|
||||
self._sendToolCommand("offset",
|
||||
item.key(),
|
||||
item.newOffset(),
|
||||
function() {item.newOffset("");}
|
||||
);
|
||||
};
|
||||
var value = item.newOffset();
|
||||
if (!value) return;
|
||||
|
||||
self._sendToolCommand = function(command, type, temp, successCb, errorCb) {
|
||||
var data = {
|
||||
command: command
|
||||
var onSuccess = function() {
|
||||
item.newOffset("");
|
||||
};
|
||||
|
||||
var endpoint;
|
||||
if (type == "bed") {
|
||||
if ("target" == command) {
|
||||
data["target"] = parseInt(temp);
|
||||
} else if ("offset" == command) {
|
||||
data["offset"] = parseInt(temp);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
endpoint = "bed";
|
||||
if (item.key() == "bed") {
|
||||
self._setBedOffset(value)
|
||||
.done(onSuccess);
|
||||
} else {
|
||||
var group;
|
||||
if ("target" == command) {
|
||||
group = "targets";
|
||||
} else if ("offset" == command) {
|
||||
group = "offsets";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
data[group] = {};
|
||||
data[group][type] = parseInt(temp);
|
||||
|
||||
endpoint = "tool";
|
||||
self._setToolOffset(item.key(), value)
|
||||
.done(onSuccess);
|
||||
}
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "printer/" + endpoint,
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify(data),
|
||||
success: function() { if (successCb !== undefined) successCb(); },
|
||||
error: function() { if (errorCb !== undefined) errorCb(); }
|
||||
});
|
||||
self._setToolTemperature = function(tool, temperature) {
|
||||
var data = {};
|
||||
data[tool] = parseInt(temperature);
|
||||
return OctoPrint.printer.setToolTargetTemperatures(data);
|
||||
};
|
||||
|
||||
self._setToolOffset = function(tool, offset) {
|
||||
var data = {};
|
||||
data[tool] = parseInt(offset);
|
||||
return OctoPrint.printer.setToolTemperatureOffsets(data);
|
||||
};
|
||||
|
||||
self._setBedTemperature = function(temperature) {
|
||||
return OctoPrint.printer.setBedTargetTemperature(parseInt(temperature));
|
||||
};
|
||||
|
||||
self._setBedOffset = function(offset) {
|
||||
return OctoPrint.printer.setBedTemperatureOffset(parseInt(offset));
|
||||
};
|
||||
|
||||
self.handleEnter = function(event, type, item) {
|
||||
|
|
@ -375,4 +372,4 @@ $(function() {
|
|||
["loginStateViewModel", "settingsViewModel"],
|
||||
"#temp"
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -158,29 +158,18 @@ $(function() {
|
|||
}
|
||||
|
||||
if (command) {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "printer/command",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify({"command": command})
|
||||
});
|
||||
|
||||
self.cmdHistory.push(command);
|
||||
self.cmdHistory.slice(-300); // just to set a sane limit to how many manually entered commands will be saved...
|
||||
self.cmdHistoryIdx = self.cmdHistory.length;
|
||||
self.command("");
|
||||
OctoPrint.control.sendGcode(command)
|
||||
.done(function() {
|
||||
self.cmdHistory.push(command);
|
||||
self.cmdHistory.slice(-300); // just to set a sane limit to how many manually entered commands will be saved...
|
||||
self.cmdHistoryIdx = self.cmdHistory.length;
|
||||
self.command("");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
self.fakeAck = function() {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "connection",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify({"command": "fake_ack"})
|
||||
});
|
||||
OctoPrint.printer.fakeAck();
|
||||
};
|
||||
|
||||
self.handleKeyDown = function(event) {
|
||||
|
|
@ -232,4 +221,4 @@ $(function() {
|
|||
["loginStateViewModel", "settingsViewModel"],
|
||||
"#term"
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -34,20 +34,20 @@ $(function() {
|
|||
return self.isDirty() && self.isOperational() && !self.isPrinting() && self.loginState.isUser();
|
||||
});
|
||||
|
||||
self.isOperational.subscribe(function(newValue) {
|
||||
self.isOperational.subscribe(function() {
|
||||
self.requestData();
|
||||
});
|
||||
|
||||
self.timelapseType.subscribe(function(newValue) {
|
||||
self.timelapseType.subscribe(function() {
|
||||
self.isDirty(true);
|
||||
});
|
||||
self.timelapseTimedInterval.subscribe(function(newValue) {
|
||||
self.timelapseTimedInterval.subscribe(function() {
|
||||
self.isDirty(true);
|
||||
});
|
||||
self.timelapsePostRoll.subscribe(function(newValue) {
|
||||
self.timelapsePostRoll.subscribe(function() {
|
||||
self.isDirty(true);
|
||||
});
|
||||
self.timelapseFps.subscribe(function(newValue) {
|
||||
self.timelapseFps.subscribe(function() {
|
||||
self.isDirty(true);
|
||||
});
|
||||
|
||||
|
|
@ -83,12 +83,8 @@ $(function() {
|
|||
);
|
||||
|
||||
self.requestData = function() {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "timelapse",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: self.fromResponse
|
||||
});
|
||||
OctoPrint.timelapse.get()
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.fromResponse = function(response) {
|
||||
|
|
@ -141,15 +137,11 @@ $(function() {
|
|||
};
|
||||
|
||||
self.removeFile = function(filename) {
|
||||
$.ajax({
|
||||
url: API_BASEURL + "timelapse/" + filename,
|
||||
type: "DELETE",
|
||||
dataType: "json",
|
||||
success: self.requestData
|
||||
});
|
||||
OctoPrint.timelapse.delete(filename)
|
||||
.done(self.requestData);
|
||||
};
|
||||
|
||||
self.save = function(data, event) {
|
||||
self.save = function() {
|
||||
var payload = {
|
||||
"type": self.timelapseType(),
|
||||
"postRoll": self.timelapsePostRoll(),
|
||||
|
|
@ -161,20 +153,15 @@ $(function() {
|
|||
payload["interval"] = self.timelapseTimedInterval();
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "timelapse",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: payload,
|
||||
success: self.fromResponse
|
||||
});
|
||||
OctoPrint.timelapse.saveConfig(payload)
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.onDataUpdaterReconnect = function() {
|
||||
self.requestData();
|
||||
};
|
||||
|
||||
self.onEventMovieDone = function(payload) {
|
||||
self.onEventMovieDone = function() {
|
||||
self.requestData();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -60,12 +60,8 @@ $(function() {
|
|||
self.requestData = function() {
|
||||
if (!CONFIG_ACCESS_CONTROL) return;
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "users",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: self.fromResponse
|
||||
});
|
||||
OctoPrint.users.list()
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.fromResponse = function(response) {
|
||||
|
|
@ -83,12 +79,19 @@ $(function() {
|
|||
self.confirmAddUser = function() {
|
||||
if (!CONFIG_ACCESS_CONTROL) return;
|
||||
|
||||
var user = {name: self.editorUsername(), password: self.editorPassword(), admin: self.editorAdmin(), active: self.editorActive()};
|
||||
self.addUser(user, function() {
|
||||
// close dialog
|
||||
self.currentUser(undefined);
|
||||
self.addUserDialog.modal("hide");
|
||||
});
|
||||
var user = {
|
||||
name: self.editorUsername(),
|
||||
password: self.editorPassword(),
|
||||
admin: self.editorAdmin(),
|
||||
active: self.editorActive()
|
||||
};
|
||||
|
||||
self.addUser(user)
|
||||
.done(function() {
|
||||
// close dialog
|
||||
self.currentUser(undefined);
|
||||
self.addUserDialog.modal("hide");
|
||||
});
|
||||
};
|
||||
|
||||
self.showEditUserDialog = function(user) {
|
||||
|
|
@ -105,12 +108,12 @@ $(function() {
|
|||
user.active = self.editorActive();
|
||||
user.admin = self.editorAdmin();
|
||||
|
||||
// make AJAX call
|
||||
self.updateUser(user, function() {
|
||||
// close dialog
|
||||
self.currentUser(undefined);
|
||||
self.editUserDialog.modal("hide");
|
||||
});
|
||||
self.updateUser(user)
|
||||
.done(function() {
|
||||
// close dialog
|
||||
self.currentUser(undefined);
|
||||
self.editUserDialog.modal("hide");
|
||||
});
|
||||
};
|
||||
|
||||
self.showChangePasswordDialog = function(user) {
|
||||
|
|
@ -123,27 +126,30 @@ $(function() {
|
|||
self.confirmChangePassword = function() {
|
||||
if (!CONFIG_ACCESS_CONTROL) return;
|
||||
|
||||
self.updatePassword(self.currentUser().name, self.editorPassword(), function() {
|
||||
// close dialog
|
||||
self.currentUser(undefined);
|
||||
self.changePasswordDialog.modal("hide");
|
||||
});
|
||||
self.updatePassword(self.currentUser().name, self.editorPassword())
|
||||
.done(function() {
|
||||
// close dialog
|
||||
self.currentUser(undefined);
|
||||
self.changePasswordDialog.modal("hide");
|
||||
});
|
||||
};
|
||||
|
||||
self.confirmGenerateApikey = function() {
|
||||
if (!CONFIG_ACCESS_CONTROL) return;
|
||||
|
||||
self.generateApikey(self.currentUser().name, function(response) {
|
||||
self._updateApikey(response.apikey);
|
||||
})
|
||||
self.generateApikey(self.currentUser().name)
|
||||
.done(function(response) {
|
||||
self._updateApikey(response.apikey);
|
||||
});
|
||||
};
|
||||
|
||||
self.confirmDeleteApikey = function() {
|
||||
if (!CONFIG_ACCESS_CONTROL) return;
|
||||
|
||||
self.deleteApikey(self.currentUser().name, function() {
|
||||
self._updateApikey(undefined);
|
||||
})
|
||||
self.deleteApikey(self.currentUser().name)
|
||||
.done(function() {
|
||||
self._updateApikey(undefined);
|
||||
});
|
||||
};
|
||||
|
||||
self._updateApikey = function(apikey) {
|
||||
|
|
@ -159,108 +165,55 @@ $(function() {
|
|||
self.changePasswordDialog = $("#settings-usersDialogChangePassword");
|
||||
};
|
||||
|
||||
//~~ AJAX calls
|
||||
//~~ API calls
|
||||
|
||||
self.addUser = function(user, callback) {
|
||||
if (!CONFIG_ACCESS_CONTROL) return;
|
||||
if (user === undefined) return;
|
||||
self.addUser = function(user) {
|
||||
if (!user) {
|
||||
throw OctoPrint.InvalidArgumentError("user must be set");
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "users",
|
||||
type: "POST",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify(user),
|
||||
success: function(response) {
|
||||
self.fromResponse(response);
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
return OctoPrint.users.add(user)
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.removeUser = function(user, callback) {
|
||||
if (!CONFIG_ACCESS_CONTROL) return;
|
||||
if (user === undefined) return;
|
||||
self.removeUser = function(user) {
|
||||
if (!user) {
|
||||
throw OctoPrint.InvalidArgumentError("user must be set");
|
||||
}
|
||||
|
||||
if (user.name == self.loginState.username()) {
|
||||
// we do not allow to delete ourselves
|
||||
new PNotify({title: "Not possible", text: "You may not delete your own account.", type: "error"});
|
||||
return;
|
||||
new PNotify({
|
||||
title: gettext("Not possible"),
|
||||
text: gettext("You may not delete your own account."),
|
||||
type: "error"
|
||||
});
|
||||
return $.Deferred().reject("You may not delete your own account").promise();
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "users/" + user.name,
|
||||
type: "DELETE",
|
||||
success: function(response) {
|
||||
self.fromResponse(response);
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
return OctoPrint.users.delete(user.name)
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.updateUser = function(user, callback) {
|
||||
if (!CONFIG_ACCESS_CONTROL) return;
|
||||
if (user === undefined) return;
|
||||
self.updateUser = function(user) {
|
||||
if (!user) {
|
||||
throw OctoPrint.InvalidArgumentError("user must be set");
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "users/" + user.name,
|
||||
type: "PUT",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify(user),
|
||||
success: function(response) {
|
||||
self.fromResponse(response);
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
return OctoPrint.users.update(user.name, user.active, user.admin)
|
||||
.done(self.fromResponse);
|
||||
};
|
||||
|
||||
self.updatePassword = function(username, password, callback) {
|
||||
if (!CONFIG_ACCESS_CONTROL) return;
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "users/" + username + "/password",
|
||||
type: "PUT",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify({password: password}),
|
||||
success: function(response) {
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
self.updatePassword = function(username, password) {
|
||||
return OctoPrint.users.changePassword(username, password);
|
||||
};
|
||||
|
||||
self.generateApikey = function(username, callback) {
|
||||
if (!CONFIG_ACCESS_CONTROL) return;
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "users/" + username + "/apikey",
|
||||
type: "POST",
|
||||
success: function(response) {
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
self.generateApikey = function(username) {
|
||||
return OctoPrint.users.generateApiKey(username);
|
||||
};
|
||||
|
||||
self.deleteApikey = function(username, callback) {
|
||||
if (!CONFIG_ACCESS_CONTROL) return;
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "users/" + username + "/apikey",
|
||||
type: "DELETE",
|
||||
success: function(response) {
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
self.deleteApikey = function(username) {
|
||||
return OctoPrint.users.resetApiKey(username);
|
||||
};
|
||||
|
||||
self.onUserLoggedIn = function(user) {
|
||||
|
|
@ -275,4 +228,4 @@ $(function() {
|
|||
["loginStateViewModel"],
|
||||
[]
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -60,24 +60,17 @@ $(function() {
|
|||
"language": self.interface_language()
|
||||
}
|
||||
};
|
||||
self.updateSettings(self.currentUser().name, settings, function() {
|
||||
// close dialog
|
||||
self.currentUser(undefined);
|
||||
self.userSettingsDialog.modal("hide");
|
||||
self.loginState.reloadUser();
|
||||
});
|
||||
self.updateSettings(self.currentUser().name, settings)
|
||||
.done(function() {
|
||||
// close dialog
|
||||
self.currentUser(undefined);
|
||||
self.userSettingsDialog.modal("hide");
|
||||
self.loginState.reloadUser();
|
||||
});
|
||||
};
|
||||
|
||||
self.updateSettings = function(username, settings, callback) {
|
||||
if (!CONFIG_ACCESS_CONTROL) return;
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "users/" + username + "/settings",
|
||||
type: "PATCH",
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
data: JSON.stringify(settings),
|
||||
success: callback
|
||||
});
|
||||
self.updateSettings = function(username, settings) {
|
||||
return OctoPrint.users.saveSettings(username, settings);
|
||||
};
|
||||
|
||||
self.saveEnabled = function() {
|
||||
|
|
|
|||
|
|
@ -19,18 +19,19 @@ $(function() {
|
|||
self.showDialog = function() {
|
||||
if (!CONFIG_WIZARD || !(CONFIG_FIRST_RUN || self.loginState.isAdmin())) return;
|
||||
|
||||
self.getWizardDetails(function(response) {
|
||||
callViewModels(self.allViewModels, "onWizardDetails", [response]);
|
||||
self.getWizardDetails()
|
||||
.done(function(response) {
|
||||
callViewModels(self.allViewModels, "onWizardDetails", [response]);
|
||||
|
||||
if (!self.isDialogActive()) {
|
||||
self.wizardDialog.modal({
|
||||
minHeight: function() { return Math.max($.fn.modal.defaults.maxHeight() - 80, 250); }
|
||||
}).css({
|
||||
width: 'auto',
|
||||
'margin-left': function() { return -($(this).width() /2); }
|
||||
});
|
||||
}
|
||||
});
|
||||
if (!self.isDialogActive()) {
|
||||
self.wizardDialog.modal({
|
||||
minHeight: function() { return Math.max($.fn.modal.defaults.maxHeight() - 80, 250); }
|
||||
}).css({
|
||||
width: 'auto',
|
||||
'margin-left': function() { return -($(this).width() /2); }
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.closeDialog = function() {
|
||||
|
|
@ -121,53 +122,34 @@ $(function() {
|
|||
// then
|
||||
reload = (method() == "reload") || reload;
|
||||
});
|
||||
self.finishWizard(function() {
|
||||
self.closeDialog();
|
||||
if (reload) {
|
||||
log.info("Wizard requested reloading");
|
||||
location.reload(true);
|
||||
}
|
||||
});
|
||||
self.finishWizard()
|
||||
.done(function() {
|
||||
self.closeDialog();
|
||||
if (reload) {
|
||||
log.info("Wizard requested reloading");
|
||||
location.reload(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
self.showDialog();
|
||||
};
|
||||
|
||||
self.getWizardDetails = function(callback) {
|
||||
if (!callback) return;
|
||||
|
||||
$.ajax({
|
||||
url: API_BASEURL + "setup/wizard",
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
self.getWizardDetails = function() {
|
||||
return OctoPrint.wizard.get()
|
||||
.done(function(response) {
|
||||
self.wizards = _.filter(_.keys(response), function(key) { return response[key] && response[key]["required"] && !response[key]["ignored"]; });
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self.finishWizard = function(callback) {
|
||||
self.finishWizard = function() {
|
||||
self.finishing = true;
|
||||
|
||||
self.settingsViewModel.saveData();
|
||||
$.ajax({
|
||||
url: API_BASEURL + "setup/wizard",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: JSON.stringify({handled: self.wizards}),
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
success: function() {
|
||||
return OctoPrint.wizard.finish(self.wizards)
|
||||
.always(function() {
|
||||
self.finishing = false;
|
||||
callback();
|
||||
},
|
||||
failure: function() {
|
||||
self.finishing = false;
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
self.onSettingsPreventRefresh = function() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %}
|
||||
|
||||
{% assets "js_client" %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %}
|
||||
|
||||
{% assets "js_app" %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
<i class="icon-off"></i> {{ _('System') }}
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu" data-bind="foreach: systemActions">
|
||||
<ul class="dropdown-menu" data-bind="foreach: system.systemActions">
|
||||
<!-- ko if: action == "divider" -->
|
||||
<li class="divider" />
|
||||
<!-- /ko -->
|
||||
<!-- ko if: action != "divider" -->
|
||||
<li><a href="#" data-bind="click: $root.triggerAction, text: name"></a></li>
|
||||
<li><a href="#" data-bind="click: $root.system.triggerCommand, text: name"></a></li>
|
||||
<!-- /ko -->
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ class Timelapse(object):
|
|||
return f
|
||||
|
||||
if self._post_roll > 0:
|
||||
eventManager().fire(Events.POSTROLL_START, dict(postroll_duration=self.post_roll * self.fps, postroll_length=self.post_roll, postroll_fps=self.fps))
|
||||
eventManager().fire(Events.POSTROLL_START, dict(postroll_duration=self.calculate_post_roll(), postroll_length=self.post_roll, postroll_fps=self.fps))
|
||||
self._post_roll_start = time.time()
|
||||
if doCreateMovie:
|
||||
self._on_post_roll_done = getWaitForCaptures(resetAndCreate)
|
||||
|
|
@ -247,6 +247,9 @@ class Timelapse(object):
|
|||
else:
|
||||
resetImageNumber()
|
||||
|
||||
def calculate_post_roll(self):
|
||||
return None
|
||||
|
||||
def process_post_roll(self):
|
||||
self.post_roll_finished()
|
||||
|
||||
|
|
@ -470,6 +473,9 @@ class TimedTimelapse(Timelapse):
|
|||
self._postroll_captures = self.post_roll * self.fps
|
||||
Timelapse.on_print_done(self, event, payload)
|
||||
|
||||
def calculate_post_roll(self):
|
||||
return self.post_roll * self.fps * self.interval
|
||||
|
||||
def process_post_roll(self):
|
||||
pass
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue