🦄 refactor: Restart command
-change restart command setting to work with new editor -add migrate settings docstrings -refactor statement for check_parse in cfgUtils.py>save_cfg -change knockout binding for ace editor -change calculating for height of editor modal-body -moved editorbuttons to modal_footer -set focus to editor after modal shown -load printer.cfg on start for the editor -show Confirmation on dirty editor closing
This commit is contained in:
parent
ef6c846f56
commit
c835795fe9
|
@ -139,6 +139,7 @@ class KlipperPlugin(
|
|||
old_config="",
|
||||
logpath="/tmp/klippy.log",
|
||||
reload_command="RESTART",
|
||||
restart_onsave=False,
|
||||
shortStatus_navbar=True,
|
||||
shortStatus_sidebar=True,
|
||||
parse_check=False,
|
||||
|
@ -146,40 +147,7 @@ class KlipperPlugin(
|
|||
)
|
||||
)
|
||||
|
||||
def on_settings_load(self):
|
||||
data = octoprint.plugin.SettingsPlugin.on_settings_load(self)
|
||||
|
||||
configpath = os.path.expanduser(
|
||||
self._settings.get(["configuration", "configpath"])
|
||||
)
|
||||
standardconfigfile = os.path.join(configpath, "printer.cfg")
|
||||
data["config"] = cfgUtils.get_cfg(self, standardconfigfile)
|
||||
util.send_message(self, "reload", "config", "", data["config"])
|
||||
# send the configdata to frontend to update ace editor
|
||||
return data
|
||||
|
||||
def on_settings_save(self, data):
|
||||
if "config" in data:
|
||||
if cfgUtils.save_cfg(self, data["config"], "printer.cfg"):
|
||||
#load the reload command from changed data if it is not existing load the saved setting
|
||||
if util.key_exist(data, "configuration", "reload_command"):
|
||||
reload_command = os.path.expanduser(
|
||||
data["configuration"]["reload_command"]
|
||||
)
|
||||
else:
|
||||
reload_command = self._settings.get(["configuration", "reload_command"])
|
||||
|
||||
if reload_command != "manually":
|
||||
# Restart klippy to reload config
|
||||
self._printer.commands(reload_command)
|
||||
logger.log_info(self, "Restarting Klipper.")
|
||||
# we dont want to write the klipper conf to the octoprint settings
|
||||
else:
|
||||
# save not sure. saving to the octoprintconfig:
|
||||
self._settings.set(["configuration", "temp_config"], data)
|
||||
data.pop("config", None)
|
||||
|
||||
# save the rest of changed settings into config.yaml of octoprint
|
||||
old_debug_logging = self._settings.get_boolean(["configuration", "debug_logging"])
|
||||
|
||||
octoprint.plugin.SettingsPlugin.on_settings_save(self, data)
|
||||
|
@ -205,6 +173,10 @@ class KlipperPlugin(
|
|||
)
|
||||
|
||||
def get_settings_version(self):
|
||||
# Settings_Versionhistory:
|
||||
# 3 = add shortstatus on navbar. migrate the navbar setting for this
|
||||
# 4 = -change of configpath to only path without filename
|
||||
# -add setting for restart checkbox on editor save
|
||||
return 4
|
||||
|
||||
|
||||
|
@ -213,35 +185,43 @@ class KlipperPlugin(
|
|||
settings = self._settings
|
||||
if current is None:
|
||||
self.migrate_old_settings(settings)
|
||||
|
||||
if current is not None and current < 3:
|
||||
self.migrate_configuration(
|
||||
self.migrate_settings_configuration(
|
||||
settings,
|
||||
"shortStatus_navbar",
|
||||
"navbar",
|
||||
)
|
||||
|
||||
if current is not None and current < 4:
|
||||
self.migrate_configuration(
|
||||
self.migrate_settings_configuration(
|
||||
settings,
|
||||
"old_config",
|
||||
"temp_config",
|
||||
)
|
||||
|
||||
setting_path = settings.get(["configuration", "configpath"])
|
||||
if setting_path.find("printer.cfg")!=-1:
|
||||
new_setting_path = setting_path.replace("printer.cfg","")
|
||||
logger.log_info(self, "migrate setting for 'configuration/configpath': " + setting_path + " -> " + new_setting_path)
|
||||
settings.set(["configuration", "configpath"], new_setting_path)
|
||||
cfg_path = settings.get(["configuration", "configpath"])
|
||||
if cfg_path.find("printer.cfg") != -1:
|
||||
new_cfg_path = cfg_path.replace("printer.cfg","")
|
||||
logger.log_info(self, "migrate setting for 'configuration/configpath': " + cfg_path + " -> " + new_cfg_path)
|
||||
settings.set(["configuration", "configpath"], new_cfg_path)
|
||||
|
||||
if settings.get(["configuration", "reload_command"]) != "manually" :
|
||||
logger.log_info(self, "migrate setting for 'configuration/restart_onsave': False -> True")
|
||||
settings.set(["configuration", "restart_onsave"], True)
|
||||
|
||||
|
||||
def migrate_old_settings(self, settings):
|
||||
|
||||
'''
|
||||
For Old settings
|
||||
'''
|
||||
self.migrate_settings(settings, "serialport", "connection", "port")
|
||||
self.migrate_settings(settings, "replace_connection_panel", "connection", "replace_connection_panel")
|
||||
self.migrate_settings(settings, "probeHeight", "probe", "height")
|
||||
self.migrate_settings(settings, "probeLift", "probe", "lift")
|
||||
self.migrate_settings(settings, "probeSpeedXy", "probe", "speed_xy")
|
||||
self.migrate_settings(settings, "probeSpeedZ", "probe", "speed_z")
|
||||
self.migrate_settings(settings, "configPath", "configpath")
|
||||
self.migrate_settings(settings, "configPath", "configuration", "configpath")
|
||||
|
||||
if settings.has(["probePoints"]):
|
||||
points = settings.get(["probePoints"])
|
||||
|
@ -250,6 +230,14 @@ class KlipperPlugin(
|
|||
settings.remove(["probePoints"])
|
||||
|
||||
def migrate_settings(self, settings, old, new, new2="") -> None:
|
||||
"""migrate setting to setting with additional group
|
||||
|
||||
Args:
|
||||
settings (any): instance of self._settings
|
||||
old (str): the old setting to migrate
|
||||
new (str): group or only new setting if there is no new2
|
||||
new2 (str, optional): the new setting to migrate to. Defaults to "".
|
||||
""" ''''''
|
||||
if settings.has([old]):
|
||||
if new2 != "":
|
||||
logger.log_info(self, "migrate setting for '" + old + "' -> '" + new + "/" + new2 + "'")
|
||||
|
@ -574,6 +562,20 @@ class KlipperPlugin(
|
|||
if saved == True:
|
||||
util.send_message(self, "reload", "configlist", "", "")
|
||||
return flask.jsonify(saved = saved)
|
||||
|
||||
# restart klipper
|
||||
@octoprint.plugin.BlueprintPlugin.route("/restart", methods=["POST"])
|
||||
@restricted_access
|
||||
@Permissions.PLUGIN_KLIPPER_CONFIG.require(403)
|
||||
def restart_klipper(self):
|
||||
reload_command = self._settings.get(["configuration", "reload_command"])
|
||||
|
||||
if reload_command != "manually":
|
||||
|
||||
# Restart klippy to reload config
|
||||
self._printer.commands(reload_command)
|
||||
logger.log_info(self, "Restarting Klipper.")
|
||||
return NO_CONTENT
|
||||
# APIs end
|
||||
|
||||
|
||||
|
|
|
@ -113,34 +113,35 @@ def save_cfg(self, content, filename="printer.cfg"):
|
|||
|
||||
if sys.version_info[0] < 3:
|
||||
content = content.encode('utf-8')
|
||||
check_parse = self._settings.get(["configuration", "parse_check"])
|
||||
logger.log_debug(self, "check_parse on filesave: {}".format(check_parse))
|
||||
|
||||
configpath = os.path.expanduser(self._settings.get(["configuration", "configpath"]))
|
||||
if filename[-4:] != ".cfg":
|
||||
filename += ".cfg"
|
||||
filepath = os.path.join(configpath, filename)
|
||||
|
||||
logger.log_debug(self, "save filepath: {}".format(filepath))
|
||||
|
||||
self._settings.set(["configuration", "temp_config"], content)
|
||||
check = True
|
||||
if check_parse:
|
||||
check=check_cfg(self, content)
|
||||
if check == True:
|
||||
try:
|
||||
logger.log_debug(self, "Writing Klipper config to {}".format(filepath))
|
||||
with open(filepath, "w") as f:
|
||||
f.write(content)
|
||||
except IOError:
|
||||
logger.log_error(self, "Error: Couldn't open Klipper config file: {}".format(filepath))
|
||||
return False
|
||||
else:
|
||||
logger.log_debug(self, "Writen Klipper config to {}".format(filepath))
|
||||
return True
|
||||
finally:
|
||||
f.close()
|
||||
copy_cfg_to_backup(self, filepath)
|
||||
else:
|
||||
|
||||
check_parse = self._settings.get(["configuration", "parse_check"])
|
||||
logger.log_debug(self, "check_parse on filesave: {}".format(check_parse))
|
||||
if check_parse and not check_cfg(self, content):
|
||||
return False
|
||||
|
||||
try:
|
||||
logger.log_debug(self, "Writing Klipper config to {}".format(filepath))
|
||||
with open(filepath, "w") as f:
|
||||
f.write(content)
|
||||
except IOError:
|
||||
logger.log_error(self, "Error: Couldn't open Klipper config file: {}".format(filepath))
|
||||
return False
|
||||
else:
|
||||
logger.log_debug(self, "Writen Klipper config to {}".format(filepath))
|
||||
return True
|
||||
finally:
|
||||
f.close()
|
||||
copy_cfg_to_backup(self, filepath)
|
||||
|
||||
def check_cfg(self, data):
|
||||
"""Checks the given data on parsing errors.
|
||||
|
||||
|
@ -158,37 +159,46 @@ def check_cfg(self, data):
|
|||
dataToValidated.readfp(buf)
|
||||
else:
|
||||
dataToValidated.read_string(data)
|
||||
is_float_ok(self, dataToValidated)
|
||||
except configparser.Error as error:
|
||||
error.message = error.message.replace("\\n","")
|
||||
if sys.version_info[0] < 3:
|
||||
error.message = error.message.replace("file: u","Klipper Configuration", 1)
|
||||
error.message = error.message.replace("'","", 2)
|
||||
error.message = error.message.replace("u'","'", 1)
|
||||
|
||||
else:
|
||||
error.message = error.message.replace("file:","Klipper Configuration", 1)
|
||||
error.message = error.message.replace("'","", 2)
|
||||
logger.log_error(
|
||||
self,
|
||||
"Error: Invalid Klipper config file:\n"
|
||||
+ "{}".format(str(error))
|
||||
)
|
||||
util.send_message(self, "PopUp", "warning", "Invalid Config data\n",
|
||||
"\n"
|
||||
+ str(error))
|
||||
|
||||
show_error_message(self, error)
|
||||
logger.log_debug(self, 'check_cfg: NOK!')
|
||||
return False
|
||||
else:
|
||||
if not is_float_ok(self, dataToValidated):
|
||||
logger.log_debug(self, "check_cfg: NOK!")
|
||||
return False
|
||||
logger.log_debug(self, "check_cfg: OK")
|
||||
return True
|
||||
|
||||
def show_error_message(self, error):
|
||||
error.message = error.message.replace('\\n', '')
|
||||
if sys.version_info[0] < 3:
|
||||
error.message = error.message.replace('file: u', 'Klipper Configuration', 1)
|
||||
error.message = error.message.replace("'", '', 2)
|
||||
error.message = error.message.replace("u'", "'", 1)
|
||||
else:
|
||||
error.message = error.message.replace('file:', 'Klipper Configuration', 1)
|
||||
error.message = error.message.replace("'", '', 2)
|
||||
logger.log_error(
|
||||
self,
|
||||
('Error: Invalid Klipper config file:\n' + '{}'.format(str(error))),
|
||||
)
|
||||
|
||||
util.send_message(
|
||||
self, 'PopUp', 'warning', 'Invalid Config data\n', ('\n' + str(error))
|
||||
)
|
||||
|
||||
def is_float_ok(self, dataToValidated):
|
||||
|
||||
sections_search_list = ["bltouch",
|
||||
"probe"]
|
||||
value_search_list = ["x_offset",
|
||||
"y_offset",
|
||||
"z_offset"]
|
||||
sections_search_list = [
|
||||
"bltouch",
|
||||
"probe"
|
||||
]
|
||||
value_search_list = [
|
||||
"x_offset",
|
||||
"y_offset",
|
||||
"z_offset"
|
||||
]
|
||||
try:
|
||||
# cycle through sections and then values
|
||||
for y in sections_search_list:
|
||||
|
|
|
@ -1,72 +1,76 @@
|
|||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrintClient"], factory);
|
||||
} else {
|
||||
factory(global.OctoPrintClient);
|
||||
}
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["OctoPrintClient"], factory);
|
||||
} else {
|
||||
factory(global.OctoPrintClient);
|
||||
}
|
||||
})(this, function (OctoPrintClient) {
|
||||
var OctoKlipperClient = function (base) {
|
||||
this.base = base;
|
||||
this.url = this.base.getBlueprintUrl("klipper");
|
||||
};
|
||||
var OctoKlipperClient = function (base) {
|
||||
this.base = base;
|
||||
this.url = this.base.getBlueprintUrl("klipper");
|
||||
};
|
||||
|
||||
OctoKlipperClient.prototype.getCfg = function (config, opts) {
|
||||
return this.base.get(this.url + "config/" + config, opts);
|
||||
};
|
||||
OctoKlipperClient.prototype.restartKlipper = function (opts) {
|
||||
return this.base.post(this.url + "restart", opts);
|
||||
};
|
||||
|
||||
OctoKlipperClient.prototype.getCfgBak = function (backup, opts) {
|
||||
return this.base.get(this.url + "backup/" + backup, opts);
|
||||
};
|
||||
OctoKlipperClient.prototype.getCfg = function (config, opts) {
|
||||
return this.base.get(this.url + "config/" + config, opts);
|
||||
};
|
||||
|
||||
OctoKlipperClient.prototype.listCfg = function (opts) {
|
||||
return this.base.get(this.url + "config/list", opts);
|
||||
};
|
||||
OctoKlipperClient.prototype.getCfgBak = function (backup, opts) {
|
||||
return this.base.get(this.url + "backup/" + backup, opts);
|
||||
};
|
||||
|
||||
OctoKlipperClient.prototype.listCfgBak = function (opts) {
|
||||
return this.base.get(this.url + "backup/list", opts);
|
||||
};
|
||||
OctoKlipperClient.prototype.listCfg = function (opts) {
|
||||
return this.base.get(this.url + "config/list", opts);
|
||||
};
|
||||
|
||||
OctoKlipperClient.prototype.checkCfg = function (content, opts) {
|
||||
content = content || [];
|
||||
OctoKlipperClient.prototype.listCfgBak = function (opts) {
|
||||
return this.base.get(this.url + "backup/list", opts);
|
||||
};
|
||||
|
||||
var data = {
|
||||
DataToCheck: content,
|
||||
};
|
||||
OctoKlipperClient.prototype.checkCfg = function (content, opts) {
|
||||
content = content || [];
|
||||
|
||||
return this.base.postJson(this.url + "config/check", data, opts);
|
||||
};
|
||||
var data = {
|
||||
DataToCheck: content,
|
||||
};
|
||||
|
||||
OctoKlipperClient.prototype.saveCfg = function (content, filename, opts) {
|
||||
content = content || [];
|
||||
filename = filename || [];
|
||||
return this.base.postJson(this.url + "config/check", data, opts);
|
||||
};
|
||||
|
||||
var data = {
|
||||
DataToSave: content,
|
||||
filename: filename,
|
||||
};
|
||||
OctoKlipperClient.prototype.saveCfg = function (content, filename, opts) {
|
||||
content = content || [];
|
||||
filename = filename || [];
|
||||
|
||||
return this.base.postJson(this.url + "config/save", data, opts);
|
||||
};
|
||||
var data = {
|
||||
DataToSave: content,
|
||||
filename: filename,
|
||||
};
|
||||
|
||||
OctoKlipperClient.prototype.deleteCfg = function (config, opts) {
|
||||
return this.base.delete(this.url + "config/" + config, opts);
|
||||
};
|
||||
return this.base.postJson(this.url + "config/save", data, opts);
|
||||
};
|
||||
|
||||
OctoKlipperClient.prototype.deleteBackup = function (backup, opts) {
|
||||
return this.base.delete(this.url + "backup/" + backup, opts);
|
||||
};
|
||||
OctoKlipperClient.prototype.deleteCfg = function (config, opts) {
|
||||
return this.base.delete(this.url + "config/" + config, opts);
|
||||
};
|
||||
|
||||
OctoKlipperClient.prototype.restoreBackup = function (backup, opts) {
|
||||
return this.base.get(this.url + "backup/restore/" + backup, opts);
|
||||
};
|
||||
OctoKlipperClient.prototype.deleteBackup = function (backup, opts) {
|
||||
return this.base.delete(this.url + "backup/" + backup, opts);
|
||||
};
|
||||
|
||||
OctoKlipperClient.prototype.restoreBackupFromUpload = function (file, data) {
|
||||
data = data || {};
|
||||
OctoKlipperClient.prototype.restoreBackup = function (backup, opts) {
|
||||
return this.base.get(this.url + "backup/restore/" + backup, opts);
|
||||
};
|
||||
|
||||
var filename = data.filename || undefined;
|
||||
return this.base.upload(this.url + "restore", file, filename, data);
|
||||
};
|
||||
OctoKlipperClient.prototype.restoreBackupFromUpload = function (file, data) {
|
||||
data = data || {};
|
||||
|
||||
OctoPrintClient.registerPluginComponent("klipper", OctoKlipperClient);
|
||||
return OctoKlipperClient;
|
||||
var filename = data.filename || undefined;
|
||||
return this.base.upload(this.url + "restore", file, filename, data);
|
||||
};
|
||||
|
||||
OctoPrintClient.registerPluginComponent("klipper", OctoKlipperClient);
|
||||
return OctoKlipperClient;
|
||||
});
|
||||
|
|
|
@ -256,47 +256,40 @@ div#settings_plugin_klipper div.tab-content div#conf.tab-pane div.control-group
|
|||
|
||||
@media (max-width: 979px) {
|
||||
|
||||
div#klipper_editor.modal {
|
||||
/* div#klipper_editor.modal {
|
||||
height: unset !important;
|
||||
} */
|
||||
|
||||
div#klipper_editor .modal-footer .btn {
|
||||
margin-bottom: 1px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#klipper_editor {
|
||||
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
|
||||
.octoprint-container.UICMainCont.container-fluid {
|
||||
margin-top:0px !important;
|
||||
}
|
||||
|
||||
div#klipper_editor .modal-header div button.btn + button.btn {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
div#klipper_editor .modal-body {
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
|
||||
.klipper-btn-group {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
div#klipper_editor .modal-body label.checkbox {
|
||||
display: unset;
|
||||
}
|
||||
|
||||
div#klipper_editor .modal-body input[type="text"] {
|
||||
div#klipper_editor .modal-footer input[type="text"] {
|
||||
margin-bottom: 0px !important;
|
||||
}
|
||||
|
||||
div#klipper_editor .modal-body input[type="checkbox"] {
|
||||
float: unset;
|
||||
margin-left: unset;
|
||||
vertical-align: unset;
|
||||
}
|
||||
|
||||
div#klipper_editor .modal-body .editor-controls {
|
||||
div#klipper_editor .modal-footer .editor-controls {
|
||||
flex: 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -308,29 +301,17 @@ div#klipper_editor div.conf-editor {
|
|||
width: calc(100% - 4px);
|
||||
margin-top: 5px;
|
||||
overflow: auto;
|
||||
flex-grow : 1;
|
||||
}
|
||||
|
||||
div#klipper_editor div.conf-editor div#plugin-klipper-config {
|
||||
font-family: monospace;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.ace_editor {
|
||||
margin: auto;
|
||||
height: 200px;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
/* div#settings_plugin_klipper.tab-pane.active form.form-horizontal div.tab-content div#conf.tab-pane.active button.btn.btn-small ,div#klipper_editor button.btn.btn-small{
|
||||
width: 30%;
|
||||
display: inline-block;
|
||||
margin: 0px 2px 2px 2px;
|
||||
} */
|
||||
|
||||
/*checkboxes*/
|
||||
div#settings_plugin_klipper.tab-pane.active form.form-horizontal div.tab-content div.tab-pane.active input.inline-checkbox,
|
||||
div#klipper_editor input.inline-checkbox {
|
||||
div#settings_plugin_klipper.tab-pane.active form.form-horizontal div.tab-content div.tab-pane.active input.inline-checkbox {
|
||||
vertical-align: -0.2em;
|
||||
}
|
||||
|
||||
|
@ -343,10 +324,6 @@ div#settings_plugin_klipper.tab-pane.active form.form-horizontal div.tab-content
|
|||
margin-top: 8px;
|
||||
}
|
||||
|
||||
div#settings_plugin_klipper div#basic label.checkbox {
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
/*macros*/
|
||||
div#settings_plugin_klipper div#macros label.control-label {
|
||||
width: 80px;
|
||||
|
|
|
@ -51,27 +51,12 @@ $(function () {
|
|||
});
|
||||
};
|
||||
|
||||
self.onStartupComplete = function () {
|
||||
var klipper_editor = $('#klipper_editor')
|
||||
var modalOverflow = $(window).height() - 10 < klipper_editor.height();
|
||||
|
||||
klipper_editor.css('display', 'none');
|
||||
if (modalOverflow) {
|
||||
klipper_editor
|
||||
.css('margin-top', 0)
|
||||
.addClass('modal-overflow');
|
||||
} else {
|
||||
klipper_editor
|
||||
.css('margin-top', 0 - klipper_editor.height() / 2)
|
||||
.removeClass('modal-overflow');
|
||||
}
|
||||
};
|
||||
|
||||
self.showEditorDialog = function () {
|
||||
if (!self.hasRight("CONFIG")) return;
|
||||
var editorDialog = $("#klipper_editor");
|
||||
editorDialog.modal({
|
||||
show: "true",
|
||||
width: "90%",
|
||||
backdrop: "static",
|
||||
});
|
||||
}
|
||||
|
@ -162,6 +147,8 @@ $(function () {
|
|||
case "PopUp":
|
||||
self.showPopUp(data.subtype, data.title, data.payload);
|
||||
break;
|
||||
case "start":
|
||||
break;
|
||||
case "reload":
|
||||
break;
|
||||
case "console":
|
||||
|
@ -245,6 +232,25 @@ $(function () {
|
|||
}
|
||||
};
|
||||
|
||||
self.requestRestart = function () {
|
||||
if (!self.loginState.hasPermission(self.access.permissions.PLUGIN_KLIPPER_CONFIG)) return;
|
||||
|
||||
var request = function () {
|
||||
OctoPrint.plugins.klipper.restartKlipper().done(function () {
|
||||
self.consoleMessage("debug", "requestRestart");
|
||||
});
|
||||
};
|
||||
|
||||
var html = "<h4>" + gettext("All ongoing Prints will be stopped!") + "</h4>";
|
||||
|
||||
showConfirmationDialog({
|
||||
title: gettext("Klipper restart?"),
|
||||
html: html,
|
||||
proceed: gettext("Proceed"),
|
||||
onproceed: request,
|
||||
});
|
||||
};
|
||||
|
||||
// OctoKlipper settings link
|
||||
self.openOctoKlipperSettings = function (profile_type) {
|
||||
if (!self.hasRight("CONFIG")) return;
|
||||
|
@ -256,6 +262,10 @@ $(function () {
|
|||
$(query).click();
|
||||
}
|
||||
};
|
||||
|
||||
self.sleep = function (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
};
|
||||
}
|
||||
|
||||
OCTOPRINT_VIEWMODELS.push({
|
||||
|
|
|
@ -79,11 +79,10 @@ $(function () {
|
|||
);
|
||||
|
||||
self.listBakFiles = function () {
|
||||
self.klipperViewModel.consoleMessage("debug", "listBakFiles:");
|
||||
self.klipperViewModel.consoleMessage("debug", "listBakFiles");
|
||||
|
||||
OctoPrint.plugins.klipper.listCfgBak()
|
||||
.done(function (response) {
|
||||
self.klipperViewModel.consoleMessage("debug", "listBakFilesdone: " + response);
|
||||
self.backups.updateItems(response.files);
|
||||
self.backups.resetPage();
|
||||
});
|
||||
|
@ -132,7 +131,7 @@ $(function () {
|
|||
|
||||
var restore = function () {
|
||||
OctoPrint.plugins.klipper.restoreBackup(backup).done(function (response) {
|
||||
self.klipperViewModel.consoleMessage("debug", "restoreCfg: " + response.text);
|
||||
self.klipperViewModel.consoleMessage("debug", "restoreCfg: " + backup + " / " + response.restored);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -142,7 +141,7 @@ $(function () {
|
|||
title: gettext("Are you sure you want to restore now?"),
|
||||
html: html,
|
||||
proceed: gettext("Proceed"),
|
||||
onproceed: restore(),
|
||||
onproceed: restore,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -207,7 +206,7 @@ $(function () {
|
|||
}),
|
||||
true
|
||||
);
|
||||
self.klipperViewModel.consoleMessage("debug", "restoreCfg: " + response.text);
|
||||
self.klipperViewModel.consoleMessage("debug", "restoreCfg: " + filename + " / " + response);
|
||||
self.markedForFileRestore.remove(function (item) {
|
||||
return item.name == filename;
|
||||
});
|
||||
|
|
|
@ -18,6 +18,7 @@ $(function () {
|
|||
var self = this;
|
||||
var obKlipperConfig = null;
|
||||
var editor = null;
|
||||
var editor_dirty = false;
|
||||
|
||||
self.settings = parameters[0];
|
||||
self.klipperViewModel = parameters[1];
|
||||
|
@ -31,56 +32,122 @@ $(function () {
|
|||
"cache-control": "no-cache",
|
||||
});
|
||||
|
||||
self.process = function (config) {
|
||||
self.config = config;
|
||||
self.CfgFilename(config.file);
|
||||
self.CfgContent(config.content);
|
||||
$('#klipper_editor').on('shown.bs.modal', function () {
|
||||
editor.focus();
|
||||
self.setEditorDivSize();
|
||||
$(window).on('resize', function(){
|
||||
self.klipperViewModel.sleep(500).then(
|
||||
function () {
|
||||
self.setEditorDivSize();
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
self.closeEditor = function () {
|
||||
if (editor_dirty===true) {
|
||||
showConfirmationDialog({
|
||||
message: gettext(
|
||||
"Your file seems to have changed."
|
||||
),
|
||||
question: gettext("Do you really want to close it?"),
|
||||
cancel: gettext("No"),
|
||||
proceed: gettext("Yes"),
|
||||
onproceed: function () {
|
||||
var dialog = $("#klipper_editor");
|
||||
dialog.modal('hide');
|
||||
},
|
||||
nofade: true
|
||||
});
|
||||
} else {
|
||||
var dialog = $("#klipper_editor");
|
||||
dialog.modal('hide');
|
||||
}
|
||||
}
|
||||
|
||||
self.addStyleAttribute = function ($element, styleAttribute) {
|
||||
$element.attr('style', $element.attr('style') + '; ' + styleAttribute);
|
||||
}
|
||||
|
||||
self.setEditorDivSize = function () {
|
||||
var klipper_modal_body= $('#klipper_editor .modal-body');
|
||||
var klipper_config= $('#plugin-klipper-config');
|
||||
|
||||
var height = $(window).height() - $('#klipper_editor .modal-header').outerHeight() - $('#klipper_editor .modal-footer').outerHeight() - 118;
|
||||
self.addStyleAttribute(klipper_modal_body, 'height: ' + height + 'px !important;');
|
||||
//self.addStyleAttribute(klipper_config, 'height: ' + height + 'px !important;');
|
||||
klipper_config.css('height', height);
|
||||
if (editor) {
|
||||
editor.session.setValue(config.content);
|
||||
self.settings.settings.plugins.klipper.configuration.old_config(config.content);
|
||||
editor.clearSelection();
|
||||
editor.resize();
|
||||
}
|
||||
};
|
||||
|
||||
self.process = function (config) {
|
||||
return new Promise(function (resolve) {
|
||||
self.config = config;
|
||||
self.CfgFilename(config.file);
|
||||
self.CfgContent(config.content);
|
||||
|
||||
if (editor) {
|
||||
editor.session.setValue(self.CfgContent());
|
||||
editor_dirty=false;
|
||||
editor.setFontSize(self.settings.settings.plugins.klipper.configuration.fontsize());
|
||||
self.settings.settings.plugins.klipper.configuration.old_config(config.content);
|
||||
editor.clearSelection();
|
||||
self.klipperViewModel.sleep(500).then(
|
||||
function() {
|
||||
self.setEditorDivSize();
|
||||
resolve("done");
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
self.checkSyntax = function () {
|
||||
if (editor.session) {
|
||||
self.klipperViewModel.consoleMessage("debug", "checkSyntax:");
|
||||
self.klipperViewModel.consoleMessage("debug", "checkSyntax started");
|
||||
|
||||
OctoPrint.plugins.klipper.checkCfg(editor.session.getValue())
|
||||
.done(function (response) {
|
||||
var msg = ""
|
||||
if (response.is_syntax_ok == true) {
|
||||
self.klipperViewModel.showPopUp("success", gettext("SyntaxCheck"), gettext("SyntaxCheck OK"));
|
||||
self.editorFocusDelay(1000);
|
||||
} else {
|
||||
msg = gettext('Syntax NOK')
|
||||
showMessageDialog(
|
||||
msg,
|
||||
{
|
||||
title: gettext("SyntaxCheck")
|
||||
title: gettext("SyntaxCheck"),
|
||||
onclose: function () { self.editorFocusDelay(1000); }
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
self.saveCfg = function () {
|
||||
if (editor.session) {
|
||||
self.klipperViewModel.consoleMessage("debug", "Save:");
|
||||
self.klipperViewModel.consoleMessage("debug", "SaveCfg start");
|
||||
|
||||
OctoPrint.plugins.klipper.saveCfg(editor.session.getValue(), self.CfgFilename())
|
||||
.done(function (response) {
|
||||
var msg = ""
|
||||
if (response.saved === true) {
|
||||
self.klipperViewModel.showPopUp("success", gettext("Save Config"), gettext("File saved."));
|
||||
editor_dirty = false;
|
||||
if (self.settings.settings.plugins.klipper.configuration.restart_onsave()==true) {
|
||||
self.klipperViewModel.requestRestart();
|
||||
}
|
||||
} else {
|
||||
msg = gettext('File not saved!')
|
||||
showMessageDialog(
|
||||
msg,
|
||||
{
|
||||
title: gettext("Save Config")
|
||||
title: gettext("Save Config"),
|
||||
onclose: function () { self.editorFocusDelay(1000); }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -138,7 +205,7 @@ $(function () {
|
|||
|
||||
OctoPrint.plugins.klipper.getCfg(self.CfgFilename())
|
||||
.done(function (response) {
|
||||
self.klipperViewModel.consoleMessage("debug", "reloadFromFile: " + response);
|
||||
self.klipperViewModel.consoleMessage("debug", "reloadFromFile done");
|
||||
if (response.response.text != "") {
|
||||
var msg = response.response.text
|
||||
showMessageDialog(
|
||||
|
@ -152,6 +219,7 @@ $(function () {
|
|||
if (editor) {
|
||||
editor.session.setValue(response.response.config);
|
||||
editor.clearSelection();
|
||||
editor.focus();
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -166,32 +234,6 @@ $(function () {
|
|||
});
|
||||
};
|
||||
|
||||
self.configBound = function (config) {
|
||||
config.withSilence = function () {
|
||||
this.notifySubscribers = function () {
|
||||
if (!this.isSilent) {
|
||||
ko.subscribable.fn.notifySubscribers.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
this.silentUpdate = function (newValue) {
|
||||
this.isSilent = true;
|
||||
this(newValue);
|
||||
this.isSilent = false;
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
obKlipperConfig = config.withSilence();
|
||||
if (editor) {
|
||||
editor.setValue(obKlipperConfig());
|
||||
editor.setFontSize(self.settings.settings.plugins.klipper.configuration.fontsize());
|
||||
editor.resize();
|
||||
editor.clearSelection();
|
||||
}
|
||||
return obKlipperConfig;
|
||||
};
|
||||
|
||||
self.onStartup = function () {
|
||||
ace.config.set("basePath", "plugin/klipper/static/js/lib/ace/");
|
||||
|
@ -205,18 +247,23 @@ $(function () {
|
|||
vScrollBarAlwaysVisible: false,
|
||||
autoScrollEditorIntoView: true,
|
||||
showPrintMargin: false,
|
||||
maxLines: "Infinity",
|
||||
minLines: 100
|
||||
//maxLines: "Infinity"
|
||||
});
|
||||
|
||||
editor.session.on('change', function (delta) {
|
||||
if (obKlipperConfig) {
|
||||
obKlipperConfig.silentUpdate(editor.getValue());
|
||||
editor.resize();
|
||||
}
|
||||
self.CfgContent(editor.getValue());
|
||||
editor_dirty = true;
|
||||
editor.resize();
|
||||
});
|
||||
};
|
||||
|
||||
self.editorFocusDelay = function (delay) {
|
||||
self.klipperViewModel.sleep(delay).then(
|
||||
function () {
|
||||
editor.focus();
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
OCTOPRINT_VIEWMODELS.push({
|
||||
|
|
|
@ -38,6 +38,7 @@ $(function () {
|
|||
self.settings.settings.plugins.klipper.configuration.fontsize(9)
|
||||
}
|
||||
}
|
||||
|
||||
// initialize list helper
|
||||
self.configs = new ItemListHelper(
|
||||
"klipperCfgFiles",
|
||||
|
@ -70,18 +71,31 @@ $(function () {
|
|||
|
||||
self.onStartupComplete = function () {
|
||||
self.listCfgFiles();
|
||||
self.loadBaseConfig();
|
||||
};
|
||||
|
||||
self.listCfgFiles = function () {
|
||||
self.klipperViewModel.consoleMessage("debug", "listCfgFiles:");
|
||||
self.klipperViewModel.consoleMessage("debug", "listCfgFiles started");
|
||||
|
||||
OctoPrint.plugins.klipper.listCfg().done(function (response) {
|
||||
self.klipperViewModel.consoleMessage("debug", "listCfgFiles: " + response);
|
||||
self.klipperViewModel.consoleMessage("debug", "listCfgFiles done");
|
||||
self.configs.updateItems(response.files);
|
||||
self.configs.resetPage();
|
||||
});
|
||||
};
|
||||
|
||||
self.loadBaseConfig = function () {
|
||||
if (!self.klipperViewModel.hasRight("CONFIG")) return;
|
||||
|
||||
OctoPrint.plugins.klipper.getCfg("printer.cfg").done(function (response) {
|
||||
var config = {
|
||||
content: response.response.config,
|
||||
file: "printer.cfg",
|
||||
};
|
||||
self.klipperEditorViewModel.process(config).then();
|
||||
});
|
||||
};
|
||||
|
||||
self.removeCfg = function (config) {
|
||||
if (!self.klipperViewModel.hasRight("CONFIG")) return;
|
||||
|
||||
|
@ -190,7 +204,7 @@ $(function () {
|
|||
};
|
||||
|
||||
self.showBackupsDialog = function () {
|
||||
self.klipperViewModel.consoleMessage("debug", "showBackupsDialog:");
|
||||
self.klipperViewModel.consoleMessage("debug", "showBackupsDialog");
|
||||
self.klipperBackupViewModel.listBakFiles();
|
||||
var dialog = $("#klipper_backups_dialog");
|
||||
dialog.modal({
|
||||
|
@ -198,21 +212,29 @@ $(function () {
|
|||
});
|
||||
};
|
||||
|
||||
self.showEditor = function () {
|
||||
if (!self.klipperViewModel.hasRight("CONFIG")) return;
|
||||
|
||||
var editorDialog = $("#klipper_editor");
|
||||
editorDialog.modal({
|
||||
show: "true",
|
||||
width: "90%",
|
||||
backdrop: "static",
|
||||
});
|
||||
}
|
||||
|
||||
self.newFile = function () {
|
||||
if (!self.klipperViewModel.hasRight("CONFIG")) return;
|
||||
var config = {
|
||||
content: "",
|
||||
file: "Change Filename",
|
||||
};
|
||||
self.klipperEditorViewModel.process(config);
|
||||
var editorDialog = $("#klipper_editor");
|
||||
editorDialog.modal({
|
||||
show: "true",
|
||||
backdrop: "static",
|
||||
});
|
||||
self.klipperEditorViewModel.process(config).then(
|
||||
function() { self.showEditor(); }
|
||||
);
|
||||
};
|
||||
|
||||
self.showEditUserDialog = function (file) {
|
||||
self.openConfig = function (file) {
|
||||
if (!self.klipperViewModel.hasRight("CONFIG")) return;
|
||||
|
||||
OctoPrint.plugins.klipper.getCfg(file).done(function (response) {
|
||||
|
@ -220,23 +242,11 @@ $(function () {
|
|||
content: response.response.config,
|
||||
file: file,
|
||||
};
|
||||
self.klipperEditorViewModel.process(config);
|
||||
self.klipperEditorViewModel.process(config).then(
|
||||
function() { self.showEditor(); }
|
||||
);
|
||||
|
||||
var editorDialog = $("#klipper_editor");
|
||||
editorDialog.modal({
|
||||
show: "true",
|
||||
backdrop: "static",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
self.showEditor = function () {
|
||||
if (!self.klipperViewModel.hasRight("CONFIG")) return;
|
||||
|
||||
var editorDialog = $("#klipper_editor");
|
||||
editorDialog.modal({
|
||||
show: "true",
|
||||
backdrop: "static",
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -302,8 +312,21 @@ $(function () {
|
|||
if (plugin == "klipper" && data.type == "reload" && data.subtype == "configlist") {
|
||||
self.klipperViewModel.consoleMessage("debug", "onDataUpdaterPluginMessage klipper reload configlist");
|
||||
self.listCfgFiles();
|
||||
} else if (plugin == "klipper" && data.type == "start" && data.subtype == "config") {
|
||||
self.klipperViewModel.consoleMessage("debug", "onDataUpdaterPluginMessage klipper start config");
|
||||
self.startConfig(data.title, data.payload);
|
||||
}
|
||||
};
|
||||
|
||||
self.startConfig = function (file, content) {
|
||||
if (!self.klipperViewModel.hasRight("CONFIG")) return;
|
||||
filename = file || "";
|
||||
var config = {
|
||||
content: content,
|
||||
file: filename,
|
||||
};
|
||||
self.klipperEditorViewModel.process(config).then();
|
||||
};
|
||||
}
|
||||
|
||||
OCTOPRINT_VIEWMODELS.push({
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
<a href="javascript:void(0)" class="fas fa-download" title="{{ _('Download') }}"
|
||||
data-bind="css: {disabled: !$root.klipperViewModel.hasRightKo('CONFIG')()}, attr: { href: ($root.klipperViewModel.hasRightKo('CONFIG')()) ? $data.url : 'javascript:void(0)'}"></a>
|
||||
|
|
||||
<a href="javascript:void(0)" class="fas fa-camera" title="{{ _('Preview') }}"
|
||||
<a href="javascript:void(0)" class="fas fa-eye" title="{{ _('Preview') }}"
|
||||
data-bind="css: {disabled: !$root.klipperViewModel.hasRightKo('CONFIG')()}, click: function() { $parent.showCfg($data.name); }"></a>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -104,7 +104,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="textarea">
|
||||
<textarea readonly data-bind="value: CfgContent" id="klipper_bak_text"></textarea>
|
||||
<textarea rows="21" readonly data-bind="value: CfgContent" id="klipper_bak_text"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,41 +1,46 @@
|
|||
<div id="klipper_editor" class="modal hide fade large" tabindex="-1" role="dialog" aria-labelledby="klipper_editor_label" aria-hidden="true">
|
||||
<div id="klipper_editor" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="klipper_editor_label" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h3 id="klipper_dialog_label">{{ _('Editor') }}</h3>
|
||||
<button type="button" class="close" data-bind="click: closeEditor">×</button>
|
||||
<h3 id="klipper_dialog_label">Editor
|
||||
<div class="pull-right">
|
||||
<button data-bind="click: minusFontsize" title="{{ _('Decrease Fontsize') }}" class="btn">
|
||||
<i class="fas fa-search-minus"></i>
|
||||
</button>
|
||||
<button data-bind="click: plusFontsize" title="{{ _('Increase Fontsize') }}" class="btn">
|
||||
<i class="fas fa-search-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<script src="plugin/klipper/static/js/lib/ace/ace.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="plugin/klipper/static/js/lib/ace/theme-monokai.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="plugin/klipper/static/js/lib/ace/mode-klipper_config.js" type="text/javascript"></script>
|
||||
<div class="full-sized-box">
|
||||
<div class="conf-editor" id="conf_editor">
|
||||
<input id="hdnLoadKlipperConfig" type="hidden" data-bind="value: CfgContent">
|
||||
<div id="plugin-klipper-config"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="editor-controls">
|
||||
<span class="control-label">{{ _('Filename') }}:</span>
|
||||
<input type="text" data-bind="value: CfgFilename">
|
||||
<div class="klipper-btn-group klipper-fluid-item-2">
|
||||
<button class="btn btn-small" data-bind="click: saveCfg" title="{{ _('Save Config') }}">
|
||||
<i class="fas fa-save"></i> {{ _('Save Config') }}
|
||||
<button class="btn btn-small" data-bind="click: reloadFromFile" title="{{ _('Reload from file') }}">
|
||||
<i class="fas fa-upload"></i> {{ _('Reload from file') }}
|
||||
</button>
|
||||
<button class="btn btn-small" data-bind="click: loadLastSession" title="{{ _('Reload last version') }}">
|
||||
<i class="fas fa-redo"></i> {{ _('Reload last version') }}
|
||||
</button>
|
||||
<button class="btn btn-small" data-bind="click: reloadFromFile" title="{{ _('Reload from file') }}">
|
||||
<i class="fas fa-upload"></i> {{ _('Reload from file') }}
|
||||
</button>
|
||||
<button class="btn btn-small" data-bind="click: checkSyntax" title="{{ _('Check Syntax') }}">
|
||||
<i class="fas fa-spell-check"></i> {{ _('Check Syntax') }}
|
||||
</button>
|
||||
<button class="btn btn-small btn-primary" data-bind="click: saveCfg" title="{{ _('Save Config') }}">
|
||||
<i class="fas fa-save"></i> {{ _('Save Config') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<a href='#' style="text-decoration: none;" data-bind="click: minusFontsize" title="{{ _('Decrease Fontsize') }}">
|
||||
<i class="fas fa-search-minus"></i>
|
||||
</a>
|
||||
<a href='#' style="text-decoration: none;" data-bind="click: plusFontsize" title="{{ _('Increase Fontsize') }}">
|
||||
<i class="fas fa-search-plus"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="conf-editor" id="conf_editor">
|
||||
<input id="hdnLoadKlipperConfig" type="hidden" data-bind="value: configBound(CfgContent)">
|
||||
<div id="plugin-klipper-config"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -67,12 +67,13 @@
|
|||
<select data-bind="value: settings.settings.plugins.klipper.configuration.reload_command">
|
||||
<option value="RESTART">RESTART</option>
|
||||
<option value="FIRMWARE_RESTART">FIRMWARE_RESTART</option>
|
||||
<option value="manually">Manually</option>
|
||||
</select>
|
||||
<span class="help-block">
|
||||
{{ _('The command that is executed when the Klipper configuration changed and needs to be reloaded.<br />
|
||||
Set this to "Manually" if you don\'t want to immediately restart klipper.') }}
|
||||
<span class="help-block" style="margin-top:5px;">
|
||||
{{ _('The command that is executed if you want to restart klipper.') }}
|
||||
</span>
|
||||
<label class="checkbox" title="{{ _('Reload klipper on editor save?') }}"><input type="checkbox"
|
||||
data-bind="checked: settings.settings.plugins.klipper.configuration.restart_onsave" /> {{ _('Reload klipper on editor save?') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
|
@ -246,7 +247,7 @@
|
|||
<i class="far fa-file"></i> {{ _('New File') }}
|
||||
</button>
|
||||
<button class="btn btn-small" data-bind="click: showEditor" title="{{ _('Open last config') }}">
|
||||
<i class="fas fa-file-code"></i> {{ _('Show Editor') }}
|
||||
<i class="fas fa-file-code"></i> {{ _('Open last Editor') }}
|
||||
</button>
|
||||
<button class="btn btn-small" data-bind="click: listCfgFiles" title="{{ _('Refresh file list') }}">
|
||||
<i class="icon-refresh"></i> {{ _('Refresh Files') }}
|
||||
|
@ -297,7 +298,7 @@
|
|||
data-bind="css: {disabled: !$root.klipperViewModel.hasRightKo('CONFIG')()}, attr: { href: ($root.klipperViewModel.hasRightKo('CONFIG')()) ? $data.url : 'javascript:void(0)'}"></a>
|
||||
|
|
||||
<a href="javascript:void(0)" class="fas fa-pencil-alt" title="{{ _('Edit') }}"
|
||||
data-bind="css: {disabled: !$root.klipperViewModel.hasRightKo('CONFIG')()}, click: function() { $parent.showEditUserDialog($data.name);}"></a>
|
||||
data-bind="css: {disabled: !$root.klipperViewModel.hasRightKo('CONFIG')()}, click: function() { $parent.openConfig($data.name);}"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
Loading…
Reference in New Issue