-refactoring js files,

-implementing 3 decimal observer
-reusing load steps and save steps event
-adding settings for xyzSteps
-subsection macro default spacing = true
This commit is contained in:
sergiuToporjinschi
2022-02-05 13:44:49 +02:00
parent 30ce20a60f
commit d294fa5724
13 changed files with 971 additions and 27 deletions
+17 -2
View File
@@ -16,7 +16,7 @@ class API(octoprint.plugin.SimpleApiPlugin):
@staticmethod
def apiCommands():
return {
CMD_ESTEPS_SAVE: ['newESteps'],
CMD_ESTEPS_SAVE: [],
CMD_ESTEPS_LOAD_STEPS: [],
CMD_ESTEPS_START_EXTRUSION: ['extrudeLength','extrudeSpeed','extrudeTemp']
}
@@ -56,11 +56,26 @@ class API(octoprint.plugin.SimpleApiPlugin):
self._printer.commands("M104 S%(extrudeTemp)s" % data)
if command == CMD_ESTEPS_SAVE:
if "newESteps" not in data and ("newXSteps" not in data and "newYSteps" not in data and "newZSteps" not in data):
return flask.abort(400, {
"msg": "Invalid arguments. No value provided for X,Y, Z or E steps"
})
stopHeater = []
if "newESteps" in data:
eStepsSettings = self._settings.get(['eSteps'])
userControlsTemp = eStepsSettings.get("userControlsTemp")
turnOffHotend = eStepsSettings.get("turnOffHotend")
stopHeater = ["M104 S0"] if turnOffHotend and not userControlsTemp else []
steps = ("M92 " +
("E%(newESteps)s " % data if "newESteps" in data else "") +
("X%(newXSteps)s " % data if "newXSteps" in data else "") +
("Y%(newYSteps)s " % data if "newYSteps" in data else "") +
("Z%(newYSteps)s " % data if "newZSteps" in data else ""))
#save data to EEPROM and cool-down
self._printer.commands(["M92 E%(newESteps)s" % data, "M500"] + ["M104 S0"] if turnOffHotend and not userControlsTemp else [])
self._printer.commands([steps, "M500"] + stopHeater)
return
+15 -2
View File
@@ -14,13 +14,21 @@ defaultSettings = {
"extrudeSpeed": 50,
"markLength": 120
},
"XYZSteps": {
"gCodeCubeSize": {
"X":20,
"Y":20,
"Z":20
}
},
"pid": {
"hotEnd":{
"fanSpeed": 255,
"noCycles": 8,
"hotEndIndex": 0,
"targetTemp": 200,
},"bed":{
},
"bed":{
"fanSpeed": 255,
"noCycles": 8,
"hotEndIndex": -1,
@@ -55,7 +63,12 @@ class CalibrationtoolsPlugin(
# Define your plugin's asset files to automatically include in the
# core UI here.
return {
"js": ["js/ESteps.js","js/PIDTuneViewModel.js"],
"js": [
"js/GeneralViewModel.js",
"js/EStepsViewModel.js",
"js/PIDTuneViewModel.js",
"js/XYZStepsViewModel.js"
],
"css": ["css/style.css"]
}
@@ -1,7 +1,6 @@
$(function () {
function CalibrationToolsViewModel(parameters) {
function CalibrationToolsEStepsModelView(parameters) {
var self = this;
console.log(gettext("test"));
self.loginStateViewModel = parameters[0];
self.settingsViewModel = parameters[1];
self.controlViewModel = parameters[2];
@@ -97,7 +96,6 @@ $(function () {
self.onAllBound = self.onEventConnected = function () {
OctoPrint.simpleApiGet("CalibrationTools").done(function (response) {
console.log("CalibrationTools");
self.from_json(response);
});
}
@@ -107,7 +105,7 @@ $(function () {
// information to the global variable OCTOPRINT_VIEWMODELS
OCTOPRINT_VIEWMODELS.push({
// This is the constructor to call for instantiating the plugin
construct: CalibrationToolsViewModel,
construct: CalibrationToolsEStepsModelView,
// This is a list of dependencies to inject into the plugin, the order which you request
// here is the order in which the dependencies will be injected into your view model upon
// instantiation via the parameters argument
@@ -0,0 +1,37 @@
$(function () {
function CalibrationToolsGeneralViewModel(parameters) {
this.loginState = parameters[0];
this.decimal3 = function (defaultVal) {
return {
numeric: {
decimals: 3,
default: defaultVal
}
}
}
ko.extenders.numeric = function (target, options) {
var returnObs = ko.pureComputed({
read: target,
write: function (value) {
var newVal = options.decimals ? parseFloat(value).toFixed(options.decimals) : parseInt(value);
target(isNaN(newVal) ? options.default : newVal);
}
}).extend({
notify: 'always'
});
returnObs(target());
return returnObs;
};
}
// OCTOPRINT_VIEWMODELS.push([GeneralViewModel, ["loginStateViewModel"], []]);
OCTOPRINT_VIEWMODELS.push({
// This is the constructor to call for instantiating the plugin
construct: CalibrationToolsGeneralViewModel,
name: "calibrationToolsGeneralViewModel",
// This is a list of dependencies to inject into the plugin, the order which you request
// here is the order in which the dependencies will be injected into your view model upon
// instantiation via the parameters argument
dependencies: ["loginStateViewModel"]
// Finally, this is the list of selectors for all elements we want this view model to be bound to.
});
});
@@ -0,0 +1,94 @@
$(function () {
function CalibrationToolsXYZStepsModelView(parameters) {
var self = this;
self.loginStateViewModel = parameters[0];
self.settingsViewModel = parameters[1];
self.controlViewModel = parameters[2];
generalVM = parameters[5];
self.eStepsXYZ = {
currentSteps: {
X: ko.observable(0).extend(generalVM.decimal3(0.000)),
Y: ko.observable(0).extend(generalVM.decimal3(0.000)),
Z: ko.observable(0).extend(generalVM.decimal3(0.000))
},
gCodeCubeSize: {
X: ko.observable().extend(generalVM.decimal3(22.000)),
Y: ko.observable().extend(generalVM.decimal3(22.000)),
Z: ko.observable().extend(generalVM.decimal3(22.000))
},
printedCubeSize: {
X: ko.observable().extend(generalVM.decimal3(25.000)),
Y: ko.observable().extend(generalVM.decimal3(25.000)),
Z: ko.observable().extend(generalVM.decimal3(25.000))
},
newSteps: {
X: ko.observable().extend(generalVM.decimal3(0.000)),
Y: ko.observable().extend(generalVM.decimal3(0.000)),
Z: ko.observable().extend(generalVM.decimal3(0.000))
}
};
self.eStepsXYZ.newSteps.X = ko.computed(function () {
return parseFloat(self.eStepsXYZ.currentSteps.X() * self.eStepsXYZ.gCodeCubeSize.X() / self.eStepsXYZ.printedCubeSize.X()).toFixed(3);
}, self);
self.eStepsXYZ.newSteps.Y = ko.computed(function () {
return parseFloat(self.eStepsXYZ.currentSteps.Y() * self.eStepsXYZ.gCodeCubeSize.Y() / self.eStepsXYZ.printedCubeSize.Y()).toFixed(3);
}, self);
self.eStepsXYZ.newSteps.Z = ko.computed(function () {
return parseFloat(self.eStepsXYZ.currentSteps.Z() * self.eStepsXYZ.gCodeCubeSize.Z() / self.eStepsXYZ.printedCubeSize.Z()).toFixed(3);
}, self);
self.loadEStepsActive = ko.observable(true);
self.loadESteps = function () {
self.loadEStepsActive(false);
OctoPrint.simpleApiCommand("CalibrationTools", "eSteps_load").done(function (response) {
self.eStepsXYZ.currentSteps.X(response.data.X);
self.eStepsXYZ.currentSteps.Y(response.data.Y);
self.eStepsXYZ.currentSteps.Z(response.data.Z);
}).always(function (response) {
self.loadEStepsActive(true);
})
};
self.saveEStepsXYZActive = ko.observable(true)
self.saveEStepsXYZ = function () {
self.saveEStepsXYZActive(false);
OctoPrint.simpleApiCommand("CalibrationTools", "eSteps_save", {
"newXSteps": self.eStepsXYZ.newSteps.X(),
"newYSteps": self.eStepsXYZ.newSteps.Y(),
"newZSteps": self.eStepsXYZ.newSteps.Z()
}).done(function (response) {
}).always(function (response) {
self.saveEStepsXYZActive(true);
})
};
self.isAdmin = ko.observable(false);
self.onBeforeBinding = self.onUserLoggedIn = self.onUserLoggedOut = function () {
self.eStepsXYZ.gCodeCubeSize.X(self.settingsViewModel.settings.plugins.CalibrationTools.XYZSteps.gCodeCubeSize.X());
self.eStepsXYZ.gCodeCubeSize.Y(self.settingsViewModel.settings.plugins.CalibrationTools.XYZSteps.gCodeCubeSize.Y());
self.eStepsXYZ.gCodeCubeSize.Z(self.settingsViewModel.settings.plugins.CalibrationTools.XYZSteps.gCodeCubeSize.Z());
self.eStepsXYZ.printedCubeSize.X(self.settingsViewModel.settings.plugins.CalibrationTools.XYZSteps.gCodeCubeSize.X());
self.eStepsXYZ.printedCubeSize.Y(self.settingsViewModel.settings.plugins.CalibrationTools.XYZSteps.gCodeCubeSize.Y());
self.eStepsXYZ.printedCubeSize.Z(self.settingsViewModel.settings.plugins.CalibrationTools.XYZSteps.gCodeCubeSize.Z());
self.isAdmin(self.loginStateViewModel.isAdmin());
}
}
OCTOPRINT_VIEWMODELS.push({
// This is the constructor to call for instantiating the plugin
construct: CalibrationToolsXYZStepsModelView,
// This is a list of dependencies to inject into the plugin, the order which you request
// here is the order in which the dependencies will be injected into your view model upon
// instantiation via the parameters argument
dependencies: ["loginStateViewModel", "settingsViewModel", "controlViewModel", "terminalViewModel", "accessViewModel", "calibrationToolsGeneralViewModel"],
// Finally, this is the list of selectors for all elements we want this view model to be bound to.
elements: ["#calibration_x-y-z"]
});
});
@@ -0,0 +1,694 @@
$(function () {
function AccessViewModel(parameters) {
var access = this;
access.loginState = parameters[0];
var GROUP_ADMINS = "admins";
var GROUP_GUESTS = "guests";
access.users = (function () {
var self = {};
self.listHelper = new ItemListHelper("users", {
name: function (a, b) {
if (a["name"].toLocaleLowerCase() < b["name"].toLocaleLowerCase())
return -1;
if (a["name"].toLocaleLowerCase() > b["name"].toLocaleLowerCase())
return 1;
return 0;
}
}, {}, "name", [], [], CONFIG_USERSPERPAGE);
self.emptyUser = {
name: "",
active: false
};
self.currentUser = ko.observable(self.emptyUser).extend({
notify: "always"
});
self.editor = {
name: ko.observable(undefined),
groups: ko.observableArray([]),
permissions: ko.observableArray([]),
password: ko.observable(undefined),
repeatedPassword: ko.observable(undefined),
passwordMismatch: ko.pureComputed(function () {
return self.editor.password() !== self.editor.repeatedPassword();
}),
apikey: ko.observable(undefined),
active: ko.observable(undefined),
permissionSelectable: function (permission) {
return true;
},
permissionSelected: function (permission) {
var index = self.editor.permissions().indexOf(permission);
return index >= 0;
},
togglePermission: function (permission) {
var permissions = self.editor.permissions();
var index = permissions.indexOf(permission);
if (index < 0) {
permissions.push(permission);
} else {
permissions.splice(index, 1);
}
self.editor.permissions(permissions);
},
groupSelected: function (group) {
var index = self.editor.groups().indexOf(group);
return index >= 0;
},
toggleGroup: function (group) {
var groups = self.editor.groups();
var index = groups.indexOf(group);
if (index < 0) {
groups.push(group);
} else {
groups.splice(index, 1);
}
self.editor.groups(groups);
},
joinedGroupPermissions: function (group) {
return access.permissionList(group);
},
header: ko.observable(undefined),
new: ko.observable(true),
confirm: undefined,
valid: ko.pureComputed(function () {
return (self.editor.name() && self.editor.name().trim() && (!self.editor.new() || (self.editor.password() && self.editor.password().trim() && !self.editor.passwordMismatch())));
}),
dangerRestricted: function () {
return false;
},
dangerRestrictedText: gettext("This user may not have dangerous permissions.")
};
self.userEditorDialog = undefined;
self.changePasswordDialog = undefined;
self.currentUser.subscribe(function (newValue) {
if (newValue === undefined) {
self.editor.name(undefined);
self.editor.groups(access.groups.defaults.slice(0));
self.editor.permissions([]);
self.editor.active(true);
self.editor.apikey(undefined);
self.editor.header(gettext("Add user"));
self.editor.new(true);
self.editor.confirm = self.confirmAddUser;
} else {
self.editor.name(newValue.name);
self.editor.groups(newValue.groups.slice(0));
self.editor.permissions(newValue.permissions.slice(0));
self.editor.active(newValue.active);
self.editor.apikey(newValue.apikey);
self.editor.header(_.sprintf(gettext('Edit user "%(name)s"'), {
name: newValue.name
}));
self.editor.new(false);
self.editor.confirm = self.confirmEditUser;
}
self.editor.password(undefined);
self.editor.repeatedPassword(undefined);
});
self.requestData = function () {
if (!CONFIG_ACCESS_CONTROL)
return;
if (!access.loginState.hasPermissionKo(access.permissions.ADMIN))
return;
return OctoPrint.access.users.list().done(self.fromResponse);
}
;
self.fromResponse = function (response) {
self.listHelper.updateItems(response.users);
}
;
self.showAddUserDialog = function () {
if (!CONFIG_ACCESS_CONTROL)
return;
self.currentUser(undefined);
$('ul.nav-pills a[data-toggle="tab"]:first', self.userEditorDialog).tab("show");
self.userEditorDialog.modal({
minHeight: function () {
return Math.max($.fn.modal.defaults.maxHeight() - 80, 250);
}
}).css({
"margin-left": function () {
return -($(this).width() / 2);
}
});
}
;
self.confirmAddUser = function () {
if (!CONFIG_ACCESS_CONTROL)
return;
var user = {
name: self.editor.name(),
password: self.editor.password(),
groups: self.editor.groups(),
permissions: self.editor.permissions(),
active: self.editor.active()
};
self.addUser(user).done(function () {
self.currentUser(undefined);
self.userEditorDialog.modal("hide");
});
}
;
self.showEditUserDialog = function (user) {
if (!CONFIG_ACCESS_CONTROL)
return;
var process = function (user) {
self.currentUser(user);
$('ul.nav-pills a[data-toggle="tab"]:first', self.userEditorDialog).tab("show");
self.userEditorDialog.modal({
minHeight: function () {
return Math.max($.fn.modal.defaults.maxHeight() - 80, 250);
}
}).css({
"margin-left": function () {
return -($(this).width() / 2);
}
});
};
OctoPrint.users.get(user.name).done(function (data) {
process(data);
}).fail(function () {
log.warn("Could not fetch current user data, proceeding with client side data copy");
process(user);
});
}
;
self.confirmEditUser = function () {
if (!CONFIG_ACCESS_CONTROL)
return;
var user = self.currentUser();
user.active = self.editor.active();
user.groups = self.editor.groups();
user.permissions = self.editor.permissions();
self.updateUser(user).done(function () {
self.currentUser(undefined);
self.userEditorDialog.modal("hide");
});
}
;
self.showChangePasswordDialog = function (user) {
if (!CONFIG_ACCESS_CONTROL)
return;
self.currentUser(user);
self.changePasswordDialog.modal("show");
}
;
self.confirmChangePassword = function () {
if (!CONFIG_ACCESS_CONTROL)
return;
self.updatePassword(self.currentUser().name, self.editor.password()).done(function () {
self.currentUser(undefined);
self.changePasswordDialog.modal("hide");
});
}
;
self.confirmGenerateApikey = function () {
if (!CONFIG_ACCESS_CONTROL)
return;
self.generateApikey(self.currentUser().name).done(function (response) {
self._updateApikey(response.apikey);
});
}
;
self.copyApikey = function () {
copyToClipboard(self.editor.apikey());
}
;
self._updateApikey = function (apikey) {
self.editor.apikey(apikey);
self.requestData();
}
;
self.confirmDeleteApikey = function () {
if (!CONFIG_ACCESS_CONTROL)
return;
self.deleteApikey(self.currentUser().name).done(function () {
self._updateApikey(undefined);
});
}
;
self.onStartup = function () {
self.userEditorDialog = $("#settings-usersEditorDialog");
self.changePasswordDialog = $("#settings-usersDialogChangePassword");
}
;
self.addUser = function (user) {
if (!user) {
throw OctoPrint.InvalidArgumentError("user must be set");
}
if (!access.loginState.hasPermissionKo(access.permissions.ADMIN))
return $.Deferred().reject("You are not authorized to perform this action").promise();
return OctoPrint.access.users.add(user).done(self.fromResponse);
}
;
self.removeUser = function (user) {
if (!user) {
throw OctoPrint.InvalidArgumentError("user must be set");
}
if (!access.loginState.hasPermissionKo(access.permissions.ADMIN))
return $.Deferred().reject("You are not authorized to perform this action").promise();
if (user.name === access.loginState.username()) {
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();
}
showConfirmationDialog({
title: gettext("Are you sure?"),
message: _.sprintf(gettext('You are about to delete the user "%(name)s".'), {
name: user.name
}),
proceed: gettext("Delete"),
onproceed: function () {
OctoPrint.access.users.delete(user.name).done(self.fromResponse);
}
});
}
;
self.updateUser = function (user) {
if (!user) {
throw OctoPrint.InvalidArgumentError("user must be set");
}
return OctoPrint.access.users.update(user.name, user.active, user.admin, user.permissions, user.groups).done(self.fromResponse);
}
;
self.updatePassword = function (username, password) {
return OctoPrint.access.users.changePassword(username, password);
}
;
self.generateApikey = function (username) {
return OctoPrint.access.users.generateApiKey(username).done(function () {
self.requestData();
});
}
;
self.deleteApikey = function (username) {
return OctoPrint.access.users.resetApiKey(username);
}
;
return self;
}
)();
access.groups = (function () {
var self = {};
self.listHelper = new ItemListHelper("groups", {
name: function (a, b) {
if (a["name"].toLocaleLowerCase() < b["name"].toLocaleLowerCase())
return -1;
if (a["name"].toLocaleLowerCase() > b["name"].toLocaleLowerCase())
return 1;
return 0;
}
}, {}, "name", [], [], CONFIG_GROUPSPERPAGE);
self.groupsList = self.listHelper.items;
self.lookup = {};
self.defaults = [];
self.emptyGroup = {
name: ""
};
self.currentGroup = ko.observable(self.emptyGroup);
self.editor = {
key: ko.observable(undefined),
name: ko.observable(undefined),
description: ko.observable(undefined),
permissions: ko.observableArray([]),
subgroups: ko.observableArray([]),
default: ko.observable(false),
permissionSelectable: function (permission) {
return self.editor.key() !== GROUP_GUESTS || !permission.dangerous;
},
permissionSelected: function (permission) {
var index = self.editor.permissions().indexOf(permission);
return index >= 0;
},
togglePermission: function (permission) {
var permissions = self.editor.permissions();
var index = permissions.indexOf(permission);
if (index < 0) {
permissions.push(permission);
} else {
permissions.splice(index, 1);
}
self.editor.permissions(permissions);
},
subgroupSelectable: function (subgroup) {
return (self.editor.key() !== subgroup.key && (self.editor.key() !== GROUP_GUESTS || !subgroup.dangerous));
},
subgroupSelected: function (subgroup) {
var index = self.editor.subgroups().indexOf(subgroup);
return index >= 0;
},
toggleSubgroup: function (subgroup) {
var subgroups = self.editor.subgroups();
var index = subgroups.indexOf(subgroup);
if (index < 0) {
subgroups.push(subgroup);
} else {
subgroups.splice(index, 1);
}
self.editor.subgroups(subgroups);
},
joinedGroupPermissions: function (group) {
return access.permissionList(group);
},
header: ko.observable(undefined),
new: ko.observable(true),
confirm: undefined,
valid: ko.pureComputed(function () {
return self.editor.name() && self.editor.name().trim();
}),
dangerRestricted: function () {
return self.editor.key() === GROUP_GUESTS;
},
dangerRestrictedText: gettext("This group may not have dangerous permissions or subgroups.")
};
self.groupEditorDialog = undefined;
self.groupsList.subscribe(function (oldValue) {
if (oldValue === undefined || oldValue.length === 0)
return;
oldValue.forEach(function (p) {
delete self[p.key.toUpperCase()];
});
}, null, "beforeChange");
self.groupsList.subscribe(function (newValue) {
if (newValue === undefined)
return;
newValue.forEach(function (g) {
var needs = [];
g.permissions.forEach(function (p) {
for (var key in p.needs) {
p.needs[key].forEach(function (value) {
needs.push(access.permissions.need(key, value));
});
}
});
if (needs.length > 0) {
self.registerGroup(g.key.toUpperCase(), needs);
}
});
});
self.registerGroup = function (name, group) {
Object.defineProperty(self, name, {
value: group,
enumerable: true,
configurable: true
});
}
;
self.currentGroup.subscribe(function (newValue) {
if (newValue === undefined) {
self.editor.key(undefined);
self.editor.name(undefined);
self.editor.description(undefined);
self.editor.permissions([]);
self.editor.subgroups([]);
self.editor.default(false);
self.editor.header(gettext("Add group"));
self.editor.new(true);
self.editor.confirm = self.confirmAddGroup;
} else {
self.editor.key(newValue.key);
self.editor.name(newValue.name);
self.editor.description(newValue.description);
self.editor.permissions(newValue.permissions.slice(0));
self.editor.subgroups(newValue.subgroups.slice(0));
self.editor.default(newValue.default);
self.editor.header(_.sprintf(gettext('Edit group "%(name)s"'), {
name: newValue.name
}));
self.editor.new(false);
self.editor.confirm = self.confirmEditGroup;
}
});
self.requestData = function () {
return OctoPrint.access.groups.list().done(self.fromResponse);
}
;
self.fromResponse = function (response) {
var lookup = {};
var defaults = [];
_.each(response.groups, function (group) {
lookup[group.key] = group;
if (group.default) {
defaults.push(group.key);
}
});
self.lookup = lookup;
self.defaults = defaults;
self.listHelper.updateItems(response.groups);
}
;
self.showAddGroupDialog = function () {
self.currentGroup(undefined);
$('ul.nav-pills a[data-toggle="tab"]:first', self.groupEditorDialog).tab("show");
self.groupEditorDialog.modal({
minHeight: function () {
return Math.max($.fn.modal.defaults.maxHeight() - 80, 250);
}
}).css({
"margin-left": function () {
return -($(this).width() / 2);
}
});
}
;
self.confirmAddGroup = function () {
var group = {
key: self.editor.name().toLowerCase().replace(/[^a-z0-9_ ]/g, "").replace(/ /g, "_"),
name: self.editor.name(),
description: self.editor.description(),
permissions: self.editor.permissions(),
subgroups: self.editor.subgroups(),
default: self.editor.default()
};
self.addGroup(group).done(function () {
self.currentGroup(undefined);
self.groupEditorDialog.modal("hide");
});
}
;
self.showEditGroupDialog = function (group) {
if (!group.changeable)
return;
self.currentGroup(group);
$('ul.nav-pills a[data-toggle="tab"]:first', self.groupEditorDialog).tab("show");
self.groupEditorDialog.modal({
minHeight: function () {
return Math.max($.fn.modal.defaults.maxHeight() - 80, 250);
}
}).css({
"margin-left": function () {
return -($(this).width() / 2);
}
});
}
;
self.confirmEditGroup = function () {
var group = self.currentGroup();
var data = {
key: group.key,
name: group.name,
description: self.editor.description(),
permissions: self.editor.permissions(),
subgroups: self.editor.subgroups(),
default: self.editor.default()
};
self.updateGroup(data).done(function () {
self.currentGroup(undefined);
self.groupEditorDialog.modal("hide");
});
}
;
self.onStartup = function () {
self.groupEditorDialog = $("#settings-groupsEditorDialog");
}
;
self.addGroup = function (group) {
if (!group) {
throw OctoPrint.InvalidArgumentError("group must be set");
}
return OctoPrint.access.groups.add(group).done(self.fromResponse);
}
;
self.removeGroup = function (group) {
if (!group) {
throw OctoPrint.InvalidArgumentError("group must be set");
}
if (!group.removable)
return;
showConfirmationDialog({
title: gettext("Are you sure?"),
message: _.sprintf(gettext('You are about to delete the group "%(name)s".'), {
name: group.name
}),
proceed: gettext("Delete"),
onproceed: function () {
OctoPrint.access.groups.delete(group.key).done(function (response) {
self.fromResponse(response);
access.users.requestData();
});
}
});
}
;
self.updateGroup = function (group) {
if (!group) {
throw OctoPrint.InvalidArgumentError("group must be set");
}
return OctoPrint.access.groups.update(group).done(self.fromResponse);
}
;
return self;
}
)();
access.permissions = (function () {
var self = {};
self.need = function (method, value) {
return {
method: method,
value: value
};
}
;
self.roleNeed = function (value) {
return self.need("role", value);
}
;
self.permissionList = ko.observableArray([]);
self.lookup = {};
var registeredPermissions = [];
var registerPermission = function (key, permission) {
Object.defineProperty(self, key, {
value: permission,
enumerable: true,
configurable: true
});
registeredPermissions.push(key);
};
var clearAllRegisteredPermissions = function () {
_.each(registeredPermissions, function (key) {
delete self[key];
});
registeredPermissions = [];
};
self.initialize = function () {
clearAllRegisteredPermissions();
var permissionList = [];
var lookup = {};
_.each(PERMISSIONS, function (permission) {
var needs = [];
_.each(permission.needs, function (value, key) {
needs.push(self.need(key, value));
});
if (needs.length > 0) {
registerPermission(permission.key, needs);
}
if (!permission.combined) {
permissionList.push(permission);
}
lookup[permission.key] = permission;
});
permissionList.sort(access.permissionComparator);
self.permissionList(permissionList);
self.lookup = lookup;
}
;
return self;
}
)();
access.groupComparator = function (a, b) {
var nameA = a.name ? a.name.toUpperCase() : "";
var nameB = b.name ? b.name.toUpperCase() : "";
if (nameA < nameB) {
return -1;
} else if (nameA > nameB) {
return 1;
} else {
return 0;
}
}
;
access.permissionComparator = function (a, b) {
var nameA = a.name ? a.name.toUpperCase() : "";
var nameB = b.name ? b.name.toUpperCase() : "";
var pluginA = a.plugin || "";
var pluginB = b.plugin || "";
var compA = pluginA + ":" + nameA;
var compB = pluginB + ":" + nameB;
if (compA < compB) {
return -1;
} else if (compA > compB) {
return 1;
} else {
return 0;
}
}
;
access.groupList = function (data) {
if (data.groups === undefined)
return "";
var mappedGroups = _.filter(_.map(data.groups, function (g) {
return access.groups.lookup[g];
}), function (g) {
return g !== undefined;
});
mappedGroups.sort(access.groupComparator);
return _.map(mappedGroups, function (g) {
return g.name;
}).join(", ");
}
;
access.subgroupList = function (data) {
if (data.subgroups === undefined)
return "";
var mappedGroups = _.filter(_.map(data.subgroups, function (g) {
return access.groups.lookup[g];
}), function (g) {
return g !== undefined;
});
mappedGroups.sort(access.groupComparator);
return _.map(mappedGroups, function (g) {
return g.name;
}).join(", ");
}
;
access.permissionList = function (data) {
if (!data || data.permissions === undefined)
return "";
var mappedPermissions = _.filter(_.map(data.permissions, function (p) {
return access.permissions.lookup[p];
}), function (p) {
return p !== undefined;
});
mappedPermissions.sort(access.permissionComparator);
return _.map(mappedPermissions, function (p) {
return p.name;
}).join(", ");
}
;
access.onStartup = function () {
access.groups.onStartup();
access.users.onStartup();
}
;
access.onServerConnect = function () {
access.permissions.initialize();
}
;
access.onServerReconnect = function () {
access.permissions.initialize();
}
;
access.onUserPermissionsChanged = access.onUserLoggedIn = access.onUserLoggedOut = function (user) {
if (access.loginState.hasPermission(access.permissions.SETTINGS)) {
access.groups.requestData().done(function () {
access.users.requestData();
});
}
}
;
}
OCTOPRINT_VIEWMODELS.push([AccessViewModel, ["loginStateViewModel"], []]);
});
@@ -1,5 +1,5 @@
{% import "macros.jinja2" as snipped %}
{{ snipped.subSection("E-Steps default settings", true) }}
{{ snipped.subSection("E-Steps default values",true) }}
<div class="row-fluid">
<div class="span6"><label for="userControlsTemp" class="checkbox pull-right" style="margin-top: 5px;">Let me to control temperature</label></div>
<div class="span6"><input id="userControlsTemp" type="checkbox" data-bind="checked: settings.plugins.CalibrationTools.eSteps.userControlsTemp"></div>
@@ -23,14 +23,18 @@
{{ snipped.field("Filament mark length", "The length marked on filament",
"number", "settings.plugins.CalibrationTools.eSteps.markLength", "true", "mm", 50) }}
{{ snipped.subSection("X-Y-Z-Steps", true) }}
{{ snipped.subSection("X-Y-Z-Steps default values") }}
{{ snipped.field("gCode cube size of X", "", "number", "settings.plugins.CalibrationTools.XYZSteps.gCodeCubeSize.X", "true", "mm", 0.01, 10.00, "") }}
{{ snipped.field("gCode cube size of Y", "", "number", "settings.plugins.CalibrationTools.XYZSteps.gCodeCubeSize.Y", "true", "mm", 0.01, 10.00, "") }}
{{ snipped.field("gCode cube size of Z", "", "number", "settings.plugins.CalibrationTools.XYZSteps.gCodeCubeSize.Z", "true", "mm", 0.01, 10.00, "") }}
{{ snipped.subSection("Hot-end PID", true) }}
{{ snipped.subSection("Hot-end PID default values") }}
{{ snipped.field("Fan speed", "Default value for fan speed while tuning", "number", "settings.plugins.CalibrationTools.pid.hotEnd.fanSpeed", "true", "", 1, 0, 255) }}
{{ snipped.field("Number of cycles", "Default number of cycles to sample while tuning", "number", "settings.plugins.CalibrationTools.pid.hotEnd.noCycles", "true", "", 1, 3, 200) }}
{{ snipped.field("HotEnd index", "Default number of cycles to sample while tuning", "number", "settings.plugins.CalibrationTools.pid.hotEnd.hotEndIndex", "true", "", 1, 0) }}
{{ snipped.field("Target temperature", "Default target temperature for tuning", "number", "settings.plugins.CalibrationTools.pid.hotEnd.targetTemp", "true", "&ordmC", 1, 3, 200) }}
{{ snipped.subSection("Bed PID", true) }}
{{ snipped.subSection("Bed PID default values") }}
{{ snipped.field("Fan speed", "Default value for fan speed while tuning", "number", "settings.plugins.CalibrationTools.pid.bed.fanSpeed", "true", "", 1, 0, 255) }}
{{ snipped.field("Number of cycles", "Default number of cycles to sample while tuning", "number", "settings.plugins.CalibrationTools.pid.bed.noCycles", "true", "", 1, 3, 200) }}
{{ snipped.field("Target temperature", "Default target temperature for tuning", "number", "settings.plugins.CalibrationTools.pid.bed.targetTemp", "true", "&ordmC", 1, 3, 200) }}
@@ -26,13 +26,13 @@
<div class="main row-fluid">
<div class="span3">
<ul class="nav nav-list">
<li class="active">
<li>
<a data-toggle="tab" href="#calibration_documentation">Documentation</a>
</li>
<li>
<a data-toggle="tab" href="#calibration_eSteps">E-Steps</a>
</li>
<li>
<li class="active">
<a data-toggle="tab" href="#calibration_x-y-z">X-Y-Z-Steps</a>
</li>
<li>
@@ -1,5 +1,5 @@
{% macro subSection(title, spaceBefore) %}
{% if (spaceBefore) %} <br><br> {% endif %}
{% macro subSection(title, spaceBefore = false) %}
{% if (not spaceBefore) %} <br><br> {% endif %}
<strong>{{ _(title) }}</strong>
<hr>
{% endmacro %}
@@ -1,8 +1,8 @@
<div class="tab-content">
<div id="calibration_documentation" class="tab-pane active">
<div id="calibration_documentation" class="tab-pane ">
{% include "tabs/tab-doc.jinja2" %}
</div>
<div id="calibration_x-y-z" visible="false" class="tab-pane">
<div id="calibration_x-y-z" visible="false" class="tab-pane active">
{% include "tabs/tab-xyz.jinja2" %}
</div>
<div id="calibration_eSteps" visible="false" class="tab-pane">
@@ -51,7 +51,7 @@
</div>
</div>
{{ snipped.subSection("Test results", true) }}
{{ snipped.subSection("Test results") }}
<div class="row-fluid">
<div class="span6">
@@ -102,7 +102,7 @@
</div>
{{ snipped.subSection("Process description", true) }}
{{ snipped.subSection("Process description") }}
{{ snipped.quote("
This calibration is best done with the extruder detached from the hot end, so no restriction is present on the movement. If it is convenient, you can partially disassemble the printer so the output of the extruder is
open and the filament exits in free air. If this is inconvenient, the process below aims to minimize restrictions by extruding very slowly and with a slightly higher temperature. The results from this should still be
@@ -48,7 +48,7 @@
</div>
</div>
{{ snipped.subSection("Hot-end tuning", true) }}
{{ snipped.subSection("Hot-end tuning") }}
<div class="row-fluid">
<div class="span5">
<label for="fanSpeed" class="pull-right" style="margin-top: 5px;" title="Fan speed">
@@ -95,7 +95,7 @@
</div>
</div>
{{ snipped.subSection("Heated bed tuning", true) }}
{{ snipped.subSection("Heated bed tuning") }}
<div class="row-fluid">
<div class="span5">
<label for="fanSpeed" class="pull-right" style="margin-top: 5px;" title="Fan speed">
@@ -142,7 +142,7 @@
</div>
</div>
{{ snipped.subSection("Note", true) }}
{{ snipped.subSection("Note") }}
{{ snipped.quote("It is recommended to run the tuning with conditions as close to printing as possible. This means filament loaded and the part cooling fan set to your normal speed. It is not essential, but you may
prefer to start this process with the hot end at room temperature.",
"<a href='https://teachingtechyt.github.io/calibration.html#pid' target='_blank'>teachingtechyt.github.io</a>", "text-warning") }}
@@ -1 +1,90 @@
Something in xyz tab...
{% import "macros.jinja2" as snipped %}
{{ snipped.subSection("Current PID values", true) }}
<div class="row-fluid">
<div class="span3">
<label for="tunningPIDNoCycles" class="pull-right" style="margin-top: 5px;" title="x">
Current values
</label>
</div>
<div class="span9">
<div class="input-prepend input-append">
{{ snipped.linkToMarlin("M092", "Marlin website") }}
<span class="add-on" title="">M92&nbsp;&nbsp;&nbsp;X</span>
<input type="number" id="" class="input-small" step="0.001" min="0" max="100" title="" data-bind="value: $root.eStepsXYZ.currentSteps.X, enable: false">
<span class="add-on" title="">&nbsp;&nbsp;&nbsp;Y</span>
<input type="number" id="" class="input-small" step="0.001" min="0" max="100" title="" data-bind="value: $root.eStepsXYZ.currentSteps.Y, enable: false">
<span class="add-on" title="">&nbsp;&nbsp;&nbsp;Z</span>
<input type="number" id="" class="input-small" step="0.001" min="0" max="100" title="" data-bind="value: $root.eStepsXYZ.currentSteps.Z, enable: false">
<button class="btn" data-bind="click: $root.loadESteps, enable: $root.loadEStepsActive() && $root.controlViewModel.isOperational() && (!$root.controlViewModel.isPrinting())"
title="Loads current value from EEPROM by calling M92">
<i class="fas fa-sync-alt" style="color:false" data-color="false"></i>
</button>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span3">
<label for="tunningPIDNoCycles" class="pull-right" style="margin-top: 5px;" title="x">
GCode cube size
</label>
</div>
<div class="span9">
<div class="input-prepend input-append">
<span class="add-on" title="">X</span>
<input type="number" id="" class="input-small" step="0.001" min="0" max="100" title="" data-bind="value: $root.eStepsXYZ.gCodeCubeSize.X">
<span class="add-on" title="">&nbsp;&nbsp;&nbsp;Y</span>
<input type="number" id="" class="input-small" step="0.001" min="0" max="100" title="" data-bind="value: $root.eStepsXYZ.gCodeCubeSize.Y">
<span class="add-on" title="">&nbsp;&nbsp;&nbsp;Z</span>
<input type="number" id="" class="input-small" step="0.001" min="0" max="100" title="" data-bind="value: $root.eStepsXYZ.gCodeCubeSize.Z">
<span class="add-on" title="">&nbsp;&nbsp;&nbsp;mm</span>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span3">
<label for="tunningPIDNoCycles" class="pull-right" style="margin-top: 5px;" title="x">
Printed cube size
</label>
</div>
<div class="span9">
<div class="input-prepend input-append">
<span class="add-on" title="">X</span>
<input type="number" id="" class="input-small" step="0.001" min="0" max="100" title="" data-bind="value: $root.eStepsXYZ.printedCubeSize.X">
<span class="add-on" title="">&nbsp;&nbsp;&nbsp;Y</span>
<input type="number" id="" class="input-small" step="0.001" min="0" max="100" title="" data-bind="value: $root.eStepsXYZ.printedCubeSize.Y">
<span class="add-on" title="">&nbsp;&nbsp;&nbsp;Z</span>
<input type="number" id="" class="input-small" step="0.001" min="0" max="100" title="" data-bind="value: $root.eStepsXYZ.printedCubeSize.Z">
<span class="add-on" title="">&nbsp;&nbsp;&nbsp;mm</span>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span3">
<label for="tunningPIDNoCycles" class="pull-right" style="margin-top: 5px;" title="x">
New values
</label>
</div>
<div class="span9">
<div class="input-prepend input-append">
{{ snipped.linkToMarlin("M092", "Marlin website") }}
<span class="add-on" title="">M92&nbsp;&nbsp;&nbsp;X</span>
<input type="number" id="" class="input-small" step="0.001" min="0" max="100" title="" data-bind="value: $root.eStepsXYZ.newSteps.X">
<span class="add-on" title="">&nbsp;&nbsp;&nbsp;Y</span>
<input type="number" id="" class="input-small" step="0.001" min="0" max="100" title="" data-bind="value: $root.eStepsXYZ.newSteps.Y">
<span class="add-on" title="">&nbsp;&nbsp;&nbsp;Z</span>
<input type="number" id="" class="input-small" step="0.001" min="0" max="100" title="" data-bind="value: $root.eStepsXYZ.newSteps.Z">
{{ snipped.m500Icon() }}
</div>
</div>
</div>
<div class="row-fluid" style="margin-bottom: 5px;">
<div class="span3"></div>
<div class="span9">
<button class="btn btn-success" data-bind="click: $root.saveEStepsXYZ, enable: $root.saveEStepsXYZActive() && $root.controlViewModel.isOperational() && (!$root.controlViewModel.isPrinting())"
title="This will save new values to EEPROM (M92 Xx Yx Zx; M500)">
<i class="fas fa-save" style="color:false" data-color="false"></i>&nbsp&nbsp
Save to EEPROM
</button>
</div>
</div>