zaxis setting, settings not a popup anymore

This commit is contained in:
Teja 2015-01-04 18:24:52 +01:00
parent 6f6c07c3dc
commit de58b08e90
14 changed files with 580 additions and 50 deletions

View file

@ -36,8 +36,9 @@ function WorkingAreaViewModel(loginStateViewModel, settingsViewModel, printerSta
};
self._fromData = function(data) {
workPosition = data.workPosition;
self._processPos(workPosition);
if(data.workPosition){
self._processPos(data.workPosition);
}
};
self.fromCurrentData = function(data) {

View file

@ -79,7 +79,7 @@
<li class="active"><a href="#workingarea" data-toggle="tab">working area</a></li>
<li><a href="#designlib" data-toggle="tab">design library</a></li>
<li><a href="#focus" data-toggle="tab">focus</a></li>
<li style="display: none;" data-bind="visible: loginState.isAdmin">
<li xstyle="display: none;" xdata-bind="visible: loginState.isAdmin">
<a id="navbar_show_settings" class="pull-right" href="#settings" data-toggle="tab">{{ _('settings') }}</a>
</li>
</ul>
@ -127,11 +127,19 @@
<div class="container-fluid">
<div class="row-fluid">
<div class="span4 accordion">
<div class="accordion-group" data-bind="visible: loginState.isUser" id="connection_accordion">
<!-- <div class="accordion-group" data-bind="visible: loginState.isUser" id="connection_accordion">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" href="#connection"><i class="icon-signal"></i> {{ _('Connection') }}</a>
</div>
<div class="accordion-body collapse in" id="connection">
</div>-->
<div class="accordion-group" id="state_accordion">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" href="#state"><i class="icon-info-sign"></i> {{ _('State') }}</a>
</div>
<div class="accordion-body collapse in" id="connection" data-bind="visible: isErrorOrClosed() && loginState.isUser()">
<div class="accordion-inner">
<label for="connection_ports" data-bind="css: {disabled: !isErrorOrClosed()}, enable: isErrorOrClosed() && loginState.isUser()">{{ _('Serial Port') }}</label>
<select id="connection_ports" data-bind="options: portOptions, optionsCaption: 'AUTO', value: selectedPort, css: {disabled: !isErrorOrClosed()}, enable: isErrorOrClosed() && loginState.isUser()"></select>
@ -146,12 +154,7 @@
<button class="btn btn-block" id="printer_connect" data-bind="click: connect, text: buttonText(), enable: loginState.isUser()">{{ _('Connect') }}</button>
</div>
</div>
</div>
<div class="accordion-group" id="state_accordion">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" href="#state"><i class="icon-info-sign"></i> {{ _('State') }}</a>
</div>
<div class="accordion-body collapse in" id="state">
<div class="accordion-body collapse in" id="state" data-bind="visible: !isErrorOrClosed() && loginState.isUser()">
<div class="accordion-inner">
{{ _('Machine State') }}: <strong data-bind="text: stateString"></strong><br>
{{ _('File') }}: <strong data-bind="text: filename"></strong>&nbsp;<strong data-bind="visible: sd">(SD)</strong><br>
@ -269,12 +272,9 @@
</div>
<div class="span8">
<div id="area_preview" class="workingarea" data-bind="click: move_laser">
<div id="crosshair"></div>
<div class="laserpos" data-bind="text: laserPos">x,y</div>
<div class="row-fluid print-control" style="display: none;" data-bind="visible: loginState.isUser">
<button class="btn btn-primary span4" data-bind="click: print, enable: isOperational() && isReady() && !isPrinting() && loginState.isUser(), css: {'btn-danger': isPaused()}, attr: {title: titlePrintButton}" id="job_print"><i class="icon-white" data-bind="css: {'icon-fire': !isPaused(), 'icon-undo': isPaused()}"></i> <span data-bind="text: (isPaused() ? '{{ _('Restart') }}' : '{{ _('Laser') }}')">{{ _('Laser') }}</span></button>
<button class="btn span4" id="job_pause" data-bind="click: pause, enable: isOperational() && (isPrinting() || isPaused()) && loginState.isUser(), css: {active: isPaused()}, attr: {title: titlePauseButton}"><i data-bind="css: {'icon-pause': !isPaused(), 'icon-play': isPaused()}"></i> <span data-bind="visible: !isPaused()">{{ _('Pause') }}</span><span data-bind="visible: isPaused()">{{ _('Resume') }}</span></button>
<button class="btn span4" id="job_cancel" data-bind="click: cancel, enable: isOperational() && (isPrinting() || isPaused()) && loginState.isUser()" title="{{ _('Cancels the job') }}"><i class="icon-stop"></i> {{ _('Cancel') }}</button>
</div>
<div class="" id="control">
<div class="jog-panel" style="display: none;" data-bind="visible: loginState.isUser">
@ -293,6 +293,8 @@
<button class="btn box" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendJogCommand('y',-1) }"><i class="icon-arrow-down"></i></button>
</div>
</div>
{% if hasZAxis %}
<!-- Z jogging control panel -->
<div class="jog-panel" id="control_zaxis">
<div>
@ -305,6 +307,8 @@
<button class="btn box" data-bind="enable: isOperational() && !isPrinting() && loginState.isUser(), click: function() { $root.sendJogCommand('z',-1) }"><i class="icon-arrow-down"></i></button>
</div>
</div>
{% endif %}
<!-- Jog distance -->
<div class="distance">
<div class="btn-group" data-toggle="buttons-radio" id="jog_distance">
@ -376,12 +380,11 @@
<div class="tab-pane" id="settings">
<div class="container-fluid">
<div class="row-fluid">
<div class="span2">
setting menu
</div>
<div class="span10">
<div class="settings" > settings </div>
</div>
<div class="settings" >
{% include 'settings_mrbeam.jinja2' %}
</div>
</div>
</div>
</div>
@ -393,7 +396,7 @@
<!------>
<div class="container octoprint-container">
<div class="footer">
<footer class="footer">
<ul class="pull-left muted">
<li><small>{{ _('Version') }}: <span class="version">{{ display_version }}</span></small></li>
</ul>
@ -403,10 +406,10 @@
<li><a href="https://wiki.mr-beam.org"><i class="icon-book"></i> {{ _('Documentation') }}</a></li>
<li><a href="https://github.com/mrbeam/OctoPrint/issues"><i class="icon-flag"></i> {{ _('Bugs and Requests') }}</a></li>
</ul>
</div>
</footer>
</div>
{% include 'settings.jinja2' %}
{% include 'dialogs.jinja2' %}
<!-- Plugin template files -->

View file

@ -760,6 +760,7 @@ class StateMonitor(object):
self._changeEvent.set()
def setState(self, state):
print("state", state)
with self._stateMutex:
self._state = state
self._changeEvent.set()

View file

@ -120,6 +120,7 @@ def index():
return render_template(
root_template,
webcamStream=settings().get(["webcam", "stream"]),
hasZAxis=settings().get(["feature", "zaxis"]),
enableTimelapse=(settings().get(["webcam", "snapshot"]) is not None and settings().get(["webcam", "ffmpeg"]) is not None),
enableGCodeVisualizer=settings().get(["gcodeViewer", "enabled"]),
enableTemperatureGraph=settings().get(["feature", "temperatureGraph"]),

View file

@ -70,7 +70,8 @@ def getSettings():
"sdAlwaysAvailable": s.getBoolean(["feature", "sdAlwaysAvailable"]),
"swallowOkAfterResend": s.getBoolean(["feature", "swallowOkAfterResend"]),
"repetierTargetTemp": s.getBoolean(["feature", "repetierTargetTemp"]),
"grbl": s.getBoolean(["feature", "grbl"])
"grbl": s.getBoolean(["feature", "grbl"]),
"zaxis": s.getBoolean(["feature", "zaxis"])
},
"serial": {
"port": connectionOptions["portPreference"],
@ -169,6 +170,7 @@ def setSettings():
if "swallowOkAfterResend" in data["feature"].keys(): s.setBoolean(["feature", "swallowOkAfterResend"], data["feature"]["swallowOkAfterResend"])
if "repetierTargetTemp" in data["feature"].keys(): s.setBoolean(["feature", "repetierTargetTemp"], data["feature"]["repetierTargetTemp"])
if "grbl" in data["feature"].keys(): s.setBoolean(["feature", "grbl"], data["feature"]["grbl"])
if "zaxis" in data["feature"].keys(): s.setBoolean(["feature", "zaxis"], data["feature"]["zaxis"])
if "serial" in data.keys():
if "autoconnect" in data["serial"].keys(): s.setBoolean(["serial", "autoconnect"], data["serial"]["autoconnect"])

View file

@ -70,7 +70,6 @@ class PrinterStateConnection(sockjs.tornado.SockJSConnection):
pass
def sendCurrentData(self, data):
print("send_current_data", data)
# add current temperature, log and message backlogs to sent data
with self._temperatureBacklogMutex:
temperatures = self._temperatureBacklog
@ -132,5 +131,4 @@ class PrinterStateConnection(sockjs.tornado.SockJSConnection):
self.sendEvent(event, payload)
def _emit(self, type, payload):
print("emit", type, payload)
self.send({type: payload})

View file

@ -85,7 +85,8 @@ default_settings = {
"sdAlwaysAvailable": False,
"swallowOkAfterResend": True,
"repetierTargetTemp": False,
"grbl": True
"grbl": True,
"zaxis": False
},
"folder": {
"uploads": None,

View file

@ -1504,7 +1504,6 @@ ul.dropdown-menu li a {
#control #btn_motors_off,
#tab_temp,
#temp,
#control_zaxis,
#gcode_command_slider, #gcode_layer_slider,
#renderer_options,
#control_extruder {display:none;}

View file

@ -55,15 +55,15 @@ $(function() {
}
});
});
$('#navbar_show_settings').click(function() {
settingsDialog.modal()
.css({
width: 'auto',
'margin-left': function() { return -($(this).width() /2); }
});
return false;
});
// $('#navbar_show_settings').click(function() {
// settingsDialog.modal()
// .css({
// width: 'auto',
// 'margin-left': function() { return -($(this).width() /2); }
// });
//
// return false;
// });
//~~ Initialize view models
var loginStateViewModel = new LoginStateViewModel();
@ -391,14 +391,12 @@ $(function() {
})
}
};
console.log("wavm", workingAreaViewModel);
settingsViewModel.requestData(function() {
console.log("settingsViewModel.requestData");
ko.applyBindings(settingsViewModel, document.getElementById("settings_dialog"));
ko.applyBindings(connectionViewModel, document.getElementById("connection_accordion"));
ko.applyBindings(printerStateViewModel, document.getElementById("state_accordion"));
ko.applyBindings(connectionViewModel, document.getElementById("connection"));
ko.applyBindings(printerStateViewModel, document.getElementById("state"));
ko.applyBindings(gcodeFilesViewModel, document.getElementById("files_accordion"));
//ko.applyBindings(temperatureViewModel, document.getElementById("temp"));
ko.applyBindings(controlViewModel, document.getElementById("control"));
@ -421,7 +419,6 @@ $(function() {
//
// ko.applyBindings(slicingViewModel, document.getElementById("slicing_configuration_dialog"));
// ko.applyBindings(vectorConversionViewModel, document.getElementById("dialog_vector_graphics_conversion"));
// console.log("settingsViewModel.requestData wavm", document.getElementById("working_area"));
ko.applyBindings(workingAreaViewModel, document.getElementById("area_preview"));
// apply bindings and signal startup

View file

@ -79,10 +79,10 @@ function ConnectionViewModel(loginStateViewModel, settingsViewModel) {
if (self.previousIsOperational != self.isOperational()) {
if (self.isOperational() && connectionTab.hasClass("in")) {
// connection just got established, close connection tab for now
connectionTab.collapse("hide");
// connectionTab.collapse("hide");
} else if (!connectionTab.hasClass("in")) {
// connection just dropped, make sure connection tab is open
connectionTab.collapse("show");
// connectionTab.collapse("show");
}
}
}

View file

@ -116,7 +116,6 @@ function PrinterStateViewModel(loginStateViewModel) {
self._processStateData = function(data) {
var prevPaused = self.isPaused();
self.stateString(gettext(data.text));
self.isErrorOrClosed(data.flags.closedOrError);
self.isOperational(data.flags.operational);

View file

@ -138,6 +138,7 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) {
self.feature_sdAlwaysAvailable = ko.observable(undefined);
self.feature_swallowOkAfterResend = ko.observable(undefined);
self.feature_repetierTargetTemp = ko.observable(undefined);
self.feature_zaxis = ko.observable(undefined);
self.serial_port = ko.observable();
self.serial_baudrate = ko.observable();
@ -223,6 +224,7 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) {
};
self.fromResponse = function(response) {
console.log("settings resp", response)
if (self.settings === undefined) {
self.settings = ko.mapping.fromJS(response);
} else {
@ -262,6 +264,7 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) {
self.feature_sdAlwaysAvailable(response.feature.sdAlwaysAvailable);
self.feature_swallowOkAfterResend(response.feature.swallowOkAfterResend);
self.feature_repetierTargetTemp(response.feature.repetierTargetTemp);
self.feature_zaxis(response.feature.zaxis);
self.serial_port(response.serial.port);
self.serial_baudrate(response.serial.baudrate);
@ -294,7 +297,7 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) {
self.saveData = function() {
var data = ko.mapping.toJS(self.settings);
console.log("settings save", data)
data = _.extend(data, {
"api" : {
"enabled": self.api_enabled(),
@ -333,7 +336,8 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) {
"sdSupport": self.feature_sdSupport(),
"sdAlwaysAvailable": self.feature_sdAlwaysAvailable(),
"swallowOkAfterResend": self.feature_swallowOkAfterResend(),
"repetierTargetTemp": self.feature_repetierTargetTemp()
"repetierTargetTemp": self.feature_repetierTargetTemp(),
"zaxis": self.feature_zaxis()
},
"serial": {
"port": self.serial_port(),
@ -375,7 +379,8 @@ function SettingsViewModel(loginStateViewModel, usersViewModel) {
data: JSON.stringify(data),
success: function(response) {
self.fromResponse(response);
$("#settings_dialog").modal("hide");
// $("#settings_dialog").modal("hide");
$("#settings_save_btn").attr("disabled", "disabled");
}
});
};

View file

@ -134,3 +134,25 @@
<a href="#" class="btn btn-primary" data-bind="click: keepAccessControl, enable: validData(), css: {disabled: !validData()}">{{ _('Keep Access Control Enabled') }}</a>
</div>
</div>
<!--
<div class="modal hide fade" data-bind="visible: loginState.isUser" id="connection_popup">
<div class="modal-header">
<a class="" href="#connection"><i class="icon-signal"></i> {{ _('Connection') }}</a>
</div>
<div class="modal-body in" id="connection">
<div class="">
<label for="connection_ports" data-bind="css: {disabled: !isErrorOrClosed()}, enable: isErrorOrClosed() && loginState.isUser()">{{ _('Serial Port') }}</label>
<select id="connection_ports" data-bind="options: portOptions, optionsCaption: 'AUTO', value: selectedPort, css: {disabled: !isErrorOrClosed()}, enable: isErrorOrClosed() && loginState.isUser()"></select>
<label for="connection_baudrates" data-bind="css: {disabled: !isErrorOrClosed()}, enable: isErrorOrClosed() && loginState.isUser()">{{ _('Baudrate') }}</label>
<select id="connection_baudrates" data-bind="options: baudrateOptions, optionsCaption: 'AUTO', value: selectedBaudrate, css: {disabled: !isErrorOrClosed()}, enable: isErrorOrClosed() && loginState.isUser()"></select>
<label class="checkbox">
<input type="checkbox" id="connection_save" data-bind="checked: saveSettings, css: {disabled: !isErrorOrClosed()}, enable: isErrorOrClosed() && loginState.isUser()"> {{ _('Save connection settings') }}
</label>
<label class="checkbox">
<input type="checkbox" id="connection_autoconnect" data-bind="checked: settings.serial_autoconnect, css: {disabled: !isErrorOrClosed()}, enable: isErrorOrClosed() && loginState.isUser()"> {{ _('Auto-connect on server startup') }}
</label>
<button class="btn btn-block" id="printer_connect" data-bind="click: connect, text: buttonText(), enable: loginState.isUser()">{{ _('Connect') }}</button>
</div>
</div>
<div class="modal-footer"></div>
</div>-->

View file

@ -0,0 +1,501 @@
<div id="settings_dialog" class="container" xtabindex="-1" role="xdialog" aria-labelledby="settings_dialog_label" aria-hidden="true">
<div class="xmodal-header">
<!--<button type="button" class="close" data-dismiss="modal">&times;</button>-->
<!--<h3 id="settings_dialog_label">{{ _('Mr Beam Settings') }}</h3>-->
</div>
<div class="">
<div class="tabbable">
<ul class="nav nav-list span3" id="settingsTabs">
<li class="active"><a href="#settings_serialConnection" data-toggle="tab">{{ _('Serial Connection') }}</a></li>
<li><a href="#settings_printerParameters" data-toggle="tab">{{ _('Parameters') }}</a></li>
{% if enableAccessControl %}
<li><a href="#settings_users" data-toggle="tab">{{ _('Access Control') }}</a></li>
{% endif %}
<li><a href="#settings_folder" data-toggle="tab">{{ _('Folders') }}</a></li>
<li><a href="#settings_logs" data-toggle="tab">{{ _('Logs') }}</a></li>
{% if settingsPlugins %}
<li class="nav-header">Plugins</li>
{% for plugin_name, vars in settingsPlugins.items() %}
{% if vars._settings_menu_entry %}
<li><a href="#settings_plugin_{{ plugin_name }}" data-toggle="tab">{{ vars._settings_menu_entry }}</a></li>
{% endif %}
{% endfor %}
{% endif %}
</ul>
<div class="tab-content span8">
<div class="tab-pane active" id="settings_serialConnection">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="settings-serialPort">{{ _('Serial Port') }}</label>
<div class="controls">
<select id="settings-serialPort" data-bind="options: serial_portOptions, optionsCaption: 'AUTO', value: serial_port"></select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="settings-serialTimeoutCommunication">{{ _('Communication timeout') }}</label>
<div class="controls">
<div class="input-append">
<input type="number" step="any" min="0" class="input-mini text-right" data-bind="value: serial_timeoutCommunication" id="settings-serialTimeoutCommunication">
<span class="add-on">s</span>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="settings-serialTimeoutConnection">{{ _('Connection timeout') }}</label>
<div class="controls">
<div class="input-append">
<input type="number" step="any" min="0" class="input-mini text-right" data-bind="value: serial_timeoutConnection" id="settings-serialTimeoutConnection">
<span class="add-on">s</span>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="settings-serialTimeoutDetection">{{ _('Autodetection timeout') }}</label>
<div class="controls">
<div class="input-append">
<input type="number" step="any" min="0" class="input-mini text-right" data-bind="value: serial_timeoutDetection" id="settings-serialTimeoutDetection">
<span class="add-on">s</span>
</div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: serial_log" id="settings-serialLog"> {{ _('Log communication to serial.log (might negatively impact performance)') }} <span class="label label-important">{{ _('Warning') }}</span>
</label>
</div>
</div>
</form>
</div>
<div class="tab-pane" id="settings_printerParameters">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="settings-bedSize">{{ _('Working area') }}</label>
<div class="controls form-inline">
<label>{{ _('X') }}:</label>
<div class="input-append">
<input type="number" step="0.01" class="input-mini text-right" data-bind="value: printer_bedDimensionX" id="settings-bedX">
<span class="add-on">mm</span>
</div>
<label>{{ _('Y') }}:</label>
<div class="input-append">
<input type="number" step="0.01" class="input-mini text-right" data-bind="value: printer_bedDimensionY" id="settings-bedY">
<span class="add-on">mm</span>
</div>
</div>
<label class="control-label" for="settings-zaxis">{{ _('Z Axis') }}</label>
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_zaxis" id="settings-zaxis"> {{ _('Show controls for z-axis') }}
</label>
</div>
</div>
</form>
</div>
<div class="tab-pane" id="settings_features">
<form class="form-horizontal">
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_temperatureGraph" id="settings-featureTemperatureGraph"> {{ _('Enable Temperature Graph') }}
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_gcodeViewer" id="settings-featureGcodeViewer"> {{ _('Enable GCode Visualizer') }}
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_sdSupport" id="settings-featureSdSupport"> {{ _('Enable SD support') }}
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_sdAlwaysAvailable" id="settings-featureSdAlwaysAvailable"> {{ _('Always assume SD card is present') }} <span class="label">{{ _('Repetier') }}</span>
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_waitForStart" id="settings-featureWaitForStart"> {{ _('Wait for <code>start</code> on connect') }}
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_alwaysSendChecksum" id="settings-featureAlwaysSendChecksum"> {{ _('Send a checksum with <strong>every</strong> command') }} <span class="label">{{ _('Repetier') }}</span>
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_repetierTargetTemp" id="settings-featureRepetierTargetTemp"> {{ _('Support <code>TargetExtr%%n</code>/<code>TargetBed</code> target temperature format') }} <span class="label">{{ _('Repetier') }}</span>
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: feature_swallowOkAfterResend" id="settings-swallowOkAfterResend"> {{ _('Swallow the first "ok" after a resend response') }}
</label>
</div>
</div>
</form>
</div>
<div class="tab-pane" id="settings_folder">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="settings-folderUploads">{{ _('Upload Folder') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: folder_uploads" id="settings-folderUploads">
</div>
</div>
<div class="control-group">
<label class="control-label" for="settings-folderLogs">{{ _('Logs Folder') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: folder_logs" id="settings-folderLogs">
</div>
</div>
</form>
</div>
<div class="tab-pane" id="settings_temperature">
<form class="form-horizontal">
<div class="row-fluid">
<div class="offset3 span3"><h4>{{ _('Extruder') }}</h4></div>
<div class="span3"><h4>{{ _('Bed') }}</h4></div>
</div>
<div data-bind="foreach: temperature_profiles">
<div class="row-fluid" style="margin-bottom: 5px">
<div class="span3">
<input type="text" class="span12 text-right" data-bind="value: name">
</div>
<div class="input-append span3">
<input type="number" class="input-mini text-right" data-bind="value: extruder">
<span class="add-on">&deg;C</span>
</div>
<div class="input-append span3">
<input type="number" class="input-mini text-right" data-bind="value: bed">
<span class="add-on">&deg;C</span>
</div>
<div class="span2">
<a title="Remove profile" class="btn btn-danger" data-bind="click: $parent.removeTemperatureProfile"><i class="icon-trash"></i></a>
</div>
</div>
</div>
<div class="row-fluid">
<div class="offset9 span2">
<a title="Add Profile" class="btn btn-primary" data-bind="click: addTemperatureProfile"><i class="icon-plus"></i></a>
</div>
</div>
</form>
</div>
<div class="tab-pane" id="settings_terminalFilters">
<form class="form-horizontal">
<div class="row-fluid">
<div class="span4"><h4>{{ _('Name') }}</h4></div>
<div class="span6"><h4>{{ _('RegExp') }} <small><a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions">?</a></small></h4></div>
</div>
<div data-bind="foreach: terminalFilters">
<div class="row-fluid" style="margin-bottom: 5px">
<div class="span4">
<input type="text" class="span12" data-bind="value: name">
</div>
<div class="span6">
<input type="text" class="span12" data-bind="value: regex">
</div>
<div class="span2">
<a title="Remove Filter" class="btn btn-danger" data-bind="click: $parent.removeTerminalFilter"><i class="icon-trash"></i></a>
</div>
</div>
</div>
<div class="row-fluid">
<div class="offset10 span2">
<a title="Add Filter" class="btn btn-primary" data-bind="click: addTerminalFilter"><i class="icon-plus"></i></a>
</div>
</div>
</form>
</div>
<div class="tab-pane" id="settings_appearance">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="settings-appearanceName">{{ _('Title') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: appearance_name" id="settings-appearanceName">
</div>
</div>
<div class="control-group">
<label class="control-label" for="settings-appearanceColor">{{ _('Color') }}</label>
<div class="controls">
<select id="settings-appearanceColor" data-bind="value: appearance_color, options: appearance_available_colors, optionsText: 'name', optionsValue: 'key'">
</select>
</div>
</div>
</form>
</div>
<div class="tab-pane" id="settings_api">
<form class="form-horizontal">
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" id="settings-apiEnabled" data-bind="checked: api_enabled"> {{ _('Enable') }}
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" id="settings-apiCors" data-bind="checked: api_allowCrossOrigin"> {{ _('Allow <a href="%(url)s">Cross Origin Resource Sharing (CORS)</a>', url = "https://en.wikipedia.org/wiki/Cross-origin_resource_sharing") }}
</label>
</div>
</div>
<div class="control-group">
<label class="control-label" for="settings-apiKey">{{ _('API Key') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: api_key" id="settings-apikey">
</div>
</div>
</form>
</div>
{% if enableAccessControl %}
<div class="tab-pane" id="settings_users">
<table class="table table-condensed table-hover" id="system_users">
<thead>
<tr>
<th class="settings_users_name">{{ _('Name') }}</th>
<th class="settings_users_active">{{ _('Active') }}</th>
<th class="settings_users_admin">{{ _('Admin') }}</th>
<th class="settings_users_actions">{{ _('Action') }}</th>
</tr>
</thead>
<tbody data-bind="foreach: users.listHelper.paginatedItems">
<tr>
<td class="settings_users_name"><span data-bind="text: name"></span><span class="muted" data-bind="visible: $root.api_enabled() && apikey"><br /><small>{{ _('API Key') }}: <span data-bind="text: apikey"></span></small></span></td>
<td class="settings_users_active"><i data-bind="css: { 'icon-check': active, 'icon-check-empty': !active }"></i></td>
<td class="settings_users_admin"><i data-bind="css: { 'icon-check': admin, 'icon-check-empty': !admin }"></i></td>
<td class="settings_users_actions" class="system_users_action">
<a href="#" class="icon-pencil" title="{{ _('Update User') }}" data-bind="click: function() { $root.users.showEditUserDialog($data); }"></a>&nbsp;|&nbsp;<a href="#" class="icon-key" title="{{ _('Change password') }}" data-bind="click: function() { $root.users.showChangePasswordDialog($data); }"></a>&nbsp;|&nbsp;<a href="#" class="icon-trash" title="{{ _('Delete user') }}" data-bind="click: function() { $root.users.removeUser($data); }"></a>
</td>
</tr>
</tbody>
</table>
<div class="pagination pagination-mini pagination-centered">
<ul>
<li data-bind="css: {disabled: users.listHelper.currentPage() === 0}"><a href="#" data-bind="click: users.listHelper.prevPage">«</a></li>
</ul>
<ul data-bind="foreach: users.listHelper.pages">
<li data-bind="css: { active: $data.number === $root.users.listHelper.currentPage(), disabled: $data.number === -1 }"><a href="#" data-bind="text: $data.text, click: function() { $root.users.listHelper.changePage($data.number); }"></a></li>
</ul>
<ul>
<li data-bind="css: {disabled: users.listHelper.currentPage() === users.listHelper.lastPage()}"><a href="#" data-bind="click: users.listHelper.nextPage">»</a></li>
</ul>
</div>
<button title="Add user" class="btn" data-bind="click: $root.users.showAddUserDialog"><i class="icon-plus"></i> {{ _('Add user') }}</button>
<!-- Modals for user management -->
<div id="settings-usersDialogAddUser" class="xmodal xhide xfade">
<div class="xmodal-header">
<a href="#" xclass="close" data-dismiss="modal" aria-hidden="true">&times;</a>
<h3>{{ _('Add user') }}</h3>
</div>
<div class="xmodal-body">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="settings-usersDialogAddUserName">{{ _('Username') }}</label>
<div class="controls">
<input type="text" class="input-block-level" id="settings-usersDialogAddUserName" data-bind="value: $root.users.editorUsername" required>
</div>
</div>
<div class="control-group">
<label class="control-label" for="settings-usersDialogAddUserPassword1">{{ _('Password') }}</label>
<div class="controls">
<input type="password" class="input-block-level" id="settings-usersDialogAddUserPassword1" data-bind="value: $root.users.editorPassword" required>
</div>
</div>
<div class="control-group" data-bind="css: {error: $root.users.editorPasswordMismatch()}">
<label class="control-label" for="settings-usersDialogAddUserPassword2">{{ _('Repeat Password') }}</label>
<div class="controls">
<input type="password" class="input-block-level" id="settings-usersDialogAddUserPassword2" data-bind="value: $root.users.editorRepeatedPassword, valueUpdate: 'afterkeydown'" required>
<span class="help-inline" data-bind="visible: $root.users.editorPasswordMismatch()">{{ _('Passwords do not match') }}</span>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" id="settings-usersDialogAddUserActive" data-bind="checked: $root.users.editorActive"> {{ _('Active') }}
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" id="settings-usersDialogAddUserAdmin" data-bind="checked: $root.users.editorAdmin"> {{ _('Admin') }}
</label>
</div>
</div>
</form>
</div>
<div class="xmodal-footer">
<button class="btn" data-dismiss="xmodal" aria-hidden="true">{{ _('Abort') }}</button>
<button class="btn btn-primary" data-bind="click: function() { $root.users.confirmAddUser(); }, enable: !$root.users.editorPasswordMismatch()">{{ _('Confirm') }}</button>
</div>
</div>
<div id="settings-usersDialogEditUser" class="xmodal hide fade">
<div class="xmodal-header">
<a href="#" class="close" data-dismiss="xmodal" aria-hidden="true">&times;</a>
<h3>{{ _('Edit user "%(user)s"', user = '<span data-bind="text: $root.users.editorUsername"></span>') }}</h3>
</div>
<div class="xmodal-body">
<form class="form-horizontal">
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" id="settings-usersDialogEditUserActive" data-bind="checked: $root.users.editorActive"> {{ _('Active') }}
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" id="settings-usersDialogEditUserAdmin" data-bind="checked: $root.users.editorAdmin"> {{ _('Admin') }}
</label>
</div>
</div>
</form>
</div>
<div class="xmodal-footer">
<button class="btn" data-dismiss="xmodal" aria-hidden="true">{{ _('Abort') }}</button>
<button class="btn btn-primary" data-bind="click: function() { $root.users.confirmEditUser(); }">{{ _('Confirm') }}</button>
</div>
</div>
<div id="settings-usersDialogChangePassword" class="xmodal hide fade">
<div class="xmodal-header">
<a href="#" class="close" data-dismiss="xmodal" aria-hidden="true">&times;</a>
<h3>{{ _('Change password for user "%(user)s"', user='<span data-bind="text: $root.users.editorUsername"></span>') }}</h3>
</div>
<div class="xmodal-body">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="settings-usersDialogChangePasswordPassword1">{{ _('New Password') }}</label>
<div class="controls">
<input type="password" class="input-block-level" id="settings-usersDialogChangePasswordPassword1" data-bind="value: $root.users.editorPassword" required>
</div>
</div>
<div class="control-group" data-bind="css: {error: $root.users.editorPasswordMismatch()}">
<label class="control-label" for="settings-usersDialogChangePasswordPassword2">{{ _('Repeat Password') }}</label>
<div class="controls">
<input type="password" class="input-block-level" id="settings-usersDialogChangePasswordPassword2" data-bind="value: $root.users.editorRepeatedPassword, valueUpdate: 'afterkeydown'" required>
<span class="help-inline" data-bind="visible: $root.users.editorPasswordMismatch()">{{ _('Passwords do not match') }}</span>
</div>
</div>
<fieldset data-bind="visible: api_enabled">
<legend>Apikey</legend>
<div class="control-group">
<label class="control-label">{{ _('Current API Key') }}</label>
<div class="controls">
<div class="input-append">
<input type="text" class="input-block-level uneditable-input" data-bind="value: $root.users.editorApikey, attr: {placeholder: '{{ _('N/A') }}'}">
<a class="btn" title="Generate new Apikey" data-bind="click: function() { $root.users.confirmGenerateApikey(); }"><i class="icon-refresh"></i></a>
<a class="btn btn-danger" title="Delete Apikey" data-bind="click: function() { $root.users.confirmDeleteApikey(); }"><i class="icon-trash"></i></a>
</div>
</div>
</div>
</fieldset>
</form>
</div>
<div class="xmodal-footer">
<button class="btn" data-dismiss="xmodal" aria-hidden="true">{{ _('Abort') }}</button>
<button class="btn btn-primary" data-bind="click: function() { $root.users.confirmChangePassword(); }, enable: !$root.users.editorPasswordMismatch()">{{ _('Confirm') }}</button>
</div>
</div>
</div>
{% endif %}
{% for plugin_name, vars in settingsPlugins.items() %}
<div class="tab-pane" id="settings_plugin_{{ plugin_name }}" data-bind="allowBindings: false">
{% include plugin_name+"_settings_dialog.jinja2" ignore missing %}
</div>
{% endfor %}
<div class="tab-pane" id="settings_logs" data-bind="allowBindings: false">
<div id="logs">
<div class="pull-right">
<small>
{{ _('Sort by') }}: <a href="#" data-bind="click: function() { listHelper.changeSorting('name'); }">{{ _('Name') }} ({{ _('ascending') }})</a> | <a href="#" data-bind="click: function() { listHelper.changeSorting('modification'); }">{{ _('Modification date') }} ({{ _('descending') }})</a> | <a href="#" data-bind="click: function() { listHelper.changeSorting('size'); }">{{ _('Size') }} ({{ _('descending') }})</a>
</small>
</div>
<table class="table table-striped table-hover table-condensed table-hover" id="log_files">
<thead>
<tr>
<th class="settings_logs_name">{{ _('Name') }}</th>
<th class="settings_logs_size">{{ _('Size') }}</th>
<th class="settings_logs_date">{{ _('Date') }}</th>
<th class="settings_logs_action">{{ _('Action') }}</th>
</tr>
</thead>
<tbody data-bind="foreach: listHelper.paginatedItems">
<tr data-bind="attr: {title: name}">
<td class="settings_logs_name" data-bind="text: name"></td>
<td class="settings_logs_size" data-bind="text: formatSize(size)"></td>
<td class="settings_logs_date" data-bind="text: formatDate(date)"></td>
<td class="settings_logs_action">
<a href="#" class="icon-trash" data-bind="click: function() { if ($root.loginState.isUser()) { $parent.removeFile($data.name); } else { return; } }, css: {disabled: !$root.loginState.isUser()}"></a>&nbsp;|&nbsp;<a href="#" class="icon-download" data-bind="attr: {href: refs.download}"></a>
</td>
</tr>
</tbody>
</table>
<div class="pagination pagination-mini pagination-centered">
<ul>
<li data-bind="css: {disabled: listHelper.currentPage() === 0}">
<a href="#" data-bind="click: listHelper.prevPage">«</a>
</li>
</ul>
<ul data-bind="foreach: listHelper.pages">
<li data-bind="css: { active: $data.number === $root.listHelper.currentPage(), disabled: $data.number === -1 }">
<a href="#" data-bind="text: $data.text, click: function() { $root.listHelper.changePage($data.number); }"></a>
</li>
</ul>
<ul>
<li data-bind="css: {disabled: listHelper.currentPage() === listHelper.lastPage()}">
<a href="#" data-bind="click: listHelper.nextPage">»</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="">
<!--<button class="btn" data-dismiss="xmodal" aria-hidden="true">{{ _('Cancel') }}</button>-->
<button id="settings_save_btn" class="btn btn-primary" data-bind="click: saveData">{{ _('Save') }}</button>
</div>
</div>