Merge pull request #2023 from calmh/advedit

Advanced configuration dialog
This commit is contained in:
Audrius Butkevicius 2015-07-04 15:08:40 +01:00
commit 966a2b1df5
5 changed files with 133 additions and 17 deletions

View File

@ -10,6 +10,8 @@
"Add new folder?": "Add new folder?", "Add new folder?": "Add new folder?",
"Address": "Address", "Address": "Address",
"Addresses": "Addresses", "Addresses": "Addresses",
"Advanced": "Advanced",
"Advanced Configuration": "Advanced Configuration",
"All Data": "All Data", "All Data": "All Data",
"Allow Anonymous Usage Reporting?": "Allow Anonymous Usage Reporting?", "Allow Anonymous Usage Reporting?": "Allow Anonymous Usage Reporting?",
"Alphabetic": "Alphabetic", "Alphabetic": "Alphabetic",
@ -17,6 +19,7 @@
"Anonymous Usage Reporting": "Anonymous Usage Reporting", "Anonymous Usage Reporting": "Anonymous Usage Reporting",
"Any devices configured on an introducer device will be added to this device as well.": "Any devices configured on an introducer device will be added to this device as well.", "Any devices configured on an introducer device will be added to this device as well.": "Any devices configured on an introducer device will be added to this device as well.",
"Automatic upgrades": "Automatic upgrades", "Automatic upgrades": "Automatic upgrades",
"Be careful!": "Be careful!",
"Bugs": "Bugs", "Bugs": "Bugs",
"CPU Utilization": "CPU Utilization", "CPU Utilization": "CPU Utilization",
"Changelog": "Changelog", "Changelog": "Changelog",
@ -57,10 +60,12 @@
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Files are moved to .stversions folder when replaced or deleted by Syncthing.", "Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Files are moved to .stversions folder when replaced or deleted by Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.", "Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.", "Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.",
"Folder": "Folder",
"Folder ID": "Folder ID", "Folder ID": "Folder ID",
"Folder Master": "Folder Master", "Folder Master": "Folder Master",
"Folder Path": "Folder Path", "Folder Path": "Folder Path",
"Folders": "Folders", "Folders": "Folders",
"GUI": "GUI",
"GUI Authentication Password": "GUI Authentication Password", "GUI Authentication Password": "GUI Authentication Password",
"GUI Authentication User": "GUI Authentication User", "GUI Authentication User": "GUI Authentication User",
"GUI Listen Addresses": "GUI Listen Addresses", "GUI Listen Addresses": "GUI Listen Addresses",
@ -73,6 +78,7 @@
"Ignore Patterns": "Ignore Patterns", "Ignore Patterns": "Ignore Patterns",
"Ignore Permissions": "Ignore Permissions", "Ignore Permissions": "Ignore Permissions",
"Incoming Rate Limit (KiB/s)": "Incoming Rate Limit (KiB/s)", "Incoming Rate Limit (KiB/s)": "Incoming Rate Limit (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Incorrect configuration may damage your folder contents and render Syncthing inoperable.",
"Introducer": "Introducer", "Introducer": "Introducer",
"Inversion of the given condition (i.e. do not exclude)": "Inversion of the given condition (i.e. do not exclude)", "Inversion of the given condition (i.e. do not exclude)": "Inversion of the given condition (i.e. do not exclude)",
"Keep Versions": "Keep Versions", "Keep Versions": "Keep Versions",
@ -98,6 +104,7 @@
"OK": "OK", "OK": "OK",
"Off": "Off", "Off": "Off",
"Oldest First": "Oldest First", "Oldest First": "Oldest First",
"Options": "Options",
"Out of Sync": "Out of Sync", "Out of Sync": "Out of Sync",
"Out of Sync Items": "Out of Sync Items", "Out of Sync Items": "Out of Sync Items",
"Outgoing Rate Limit (KiB/s)": "Outgoing Rate Limit (KiB/s)", "Outgoing Rate Limit (KiB/s)": "Outgoing Rate Limit (KiB/s)",

View File

@ -63,6 +63,8 @@
</a> </a>
</li> </li>
<li><a href="" ng-click="about()"><span class="glyphicon glyphicon-heart-empty"></span>&nbsp;<span translate>About</span></a></li> <li><a href="" ng-click="about()"><span class="glyphicon glyphicon-heart-empty"></span>&nbsp;<span translate>About</span></a></li>
<li class="divider"></li>
<li><a href="" ng-click="advanced()"><span class="glyphicon glyphicon-cog"></span>&nbsp;<span translate>Advanced</span></a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -221,7 +223,7 @@
<td class="text-right">{{model[folder.id].localFiles | alwaysNumber}} <span translate>items</span>, ~{{model[folder.id].localBytes | binary}}B</td> <td class="text-right">{{model[folder.id].localFiles | alwaysNumber}} <span translate>items</span>, ~{{model[folder.id].localBytes | binary}}B</td>
</tr> </tr>
<tr ng-if="model[folder.id].needFiles > 0"> <tr ng-if="model[folder.id].needFiles > 0">
<th><span class="glyphicon glyphicon-cloud-download"></span>&nbsp;<span translate>Out Of Sync</span></th> <th><span class="glyphicon glyphicon-cloud-download"></span>&nbsp;<span translate>Out of Sync</span></th>
<td class="text-right"> <td class="text-right">
<a ng-click="showNeed(folder.id)" href="">{{model[folder.id].needFiles | alwaysNumber}} <span translate>items</span>, ~{{model[folder.id].needBytes | binary}}B</a> <a ng-click="showNeed(folder.id)" href="">{{model[folder.id].needFiles | alwaysNumber}} <span translate>items</span>, ~{{model[folder.id].needBytes | binary}}B</a>
</td> </td>
@ -573,7 +575,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label translate for="addresses">Addresses</label> <label translate for="addresses">Addresses</label>
<input ng-disabled="currentDevice.deviceID == myID" id="addresses" class="form-control" type="text" ng-model="currentDevice.addressesStr"></input> <input ng-disabled="currentDevice.deviceID == myID" id="addresses" class="form-control" type="text" ng-model="currentDevice._addressesStr"></input>
<p translate class="help-block">Enter comma separated "ip:port" addresses or "dynamic" to perform automatic discovery of the address.</p> <p translate class="help-block">Enter comma separated "ip:port" addresses or "dynamic" to perform automatic discovery of the address.</p>
</div> </div>
<div ng-if="!editingSelf" class="form-group"> <div ng-if="!editingSelf" class="form-group">
@ -837,7 +839,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label translate for="ListenAddressStr">Sync Protocol Listen Addresses</label> <label translate for="ListenAddressStr">Sync Protocol Listen Addresses</label>
<input id="ListenAddressStr" class="form-control" type="text" ng-model="tmpOptions.listenAddressStr"> <input id="ListenAddressStr" class="form-control" type="text" ng-model="tmpOptions._listenAddressStr">
</div> </div>
<div class="form-group"> <div class="form-group">
<label translate for="MaxRecvKbps">Incoming Rate Limit (KiB/s)</label> <label translate for="MaxRecvKbps">Incoming Rate Limit (KiB/s)</label>
@ -881,7 +883,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label translate for="GlobalAnnServersStr">Global Discovery Server</label> <label translate for="GlobalAnnServersStr">Global Discovery Server</label>
<input ng-disabled="!tmpOptions.globalAnnounceEnabled" id="GlobalAnnServersStr" class="form-control" type="text" ng-model="tmpOptions.globalAnnounceServersStr"> <input ng-disabled="!tmpOptions.globalAnnounceEnabled" id="GlobalAnnServersStr" class="form-control" type="text" ng-model="tmpOptions._globalAnnounceServersStr">
</div> </div>
</div> </div>
@ -1149,12 +1151,95 @@
</ul> </ul>
</modal> </modal>
<!-- Advanced modal -->
<div id="advanced" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header alert alert-danger">
<h4 translate class="modal-title">Advanced Configuration</h4>
</div>
<div class="modal-body">
<p class="text-danger">
<b translate>Be careful!</b>
<span translate>Incorrect configuration may damage your folder contents and render Syncthing inoperable.</span>
</p>
<div class="panel-group" id="advancedAccordion" role="tablist" aria-multiselectable="true">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="guiHeading" data-toggle="collapse" data-parent="#advancedAccordion" href="#guiConfig" aria-expanded="true" aria-controls="guiConfig" style="cursor: pointer">
<h4 class="panel-title" translate>GUI</h4>
</div>
<div id="guiConfig" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="guiHeading">
<div class="panel-body">
<form class="form-horizontal" role="form">
<div ng-repeat="(key, value) in config.gui" ng-init="type = inputTypeFor(key, value)" ng-if="type != 'skip'" class="form-group">
<label for="guiInput{{$index}}" class="col-sm-4 control-label">{{key}}</label>
<div class="col-sm-8">
<input id="guiInput{{$index}}" class="form-control" type="{{type}}" ng-model="config.gui[key]" />
</div>
</div>
</form>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="optionsHeading" data-toggle="collapse" data-parent="#advancedAccordion" href="#optionsConfig" aria-expanded="true" aria-controls="optionsConfig" style="cursor: pointer">
<h4 class="panel-title" translate>Options</h4>
</div>
<div id="optionsConfig" class="panel-collapse collapse" role="tabpanel" aria-labelledby="optionsHeading">
<div class="panel-body">
<form class="form-horizontal" role="form">
<div ng-repeat="(key, value) in config.options" ng-if="inputTypeFor(key, value) != 'skip'" class="form-group">
<label for="optionsInput{{$index}}" class="col-sm-4 control-label">{{key}}</label>
<div class="col-sm-8">
<input id="optionsInput{{$index}}" class="form-control" type="{{inputTypeFor(key, value)}}" ng-model="config.options[key]" />
</div>
</div>
</form>
</div>
</div>
</div>
<div class="panel panel-default" ng-repeat="(folder, _) in folders">
<div class="panel-heading" role="tab" id="folder{{folder}}Heading" data-toggle="collapse" data-parent="#advancedAccordion" href="#folder{{folder}}Config" aria-expanded="true" aria-controls="folder{{folder}}Config" style="cursor: pointer">
<h4 class="panel-title">
<span translate>Folder</span> "{{folder}}"
</h4>
</div>
<div id="folder{{folder}}Config" class="panel-collapse collapse" role="tabpanel" aria-labelledby="folder{{folder}}Heading">
<div class="panel-body">
<form class="form-horizontal" role="form">
<div ng-repeat="(key, value) in folders[folder]" ng-if="inputTypeFor(key, value) != 'skip'" class="form-group">
<label for="foldre{{folder}}Input{{$index}}" class="col-sm-4 control-label">{{key}}</label>
<div class="col-sm-8">
<input id="folder{{folder}}Input{{$index}}" class="form-control" type="{{inputTypeFor(key, value)}}" ng-model="folders[folder][key]" />
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary btn-sm" ng-click="saveAdvanced()"><span class="glyphicon glyphicon-ok"></span>&nbsp;<span translate>Save</span></button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span>&nbsp;<span translate>Close</span></button>
</div>
</div>
</div>
</div>
</div>
<!-- vendor scripts --> <!-- vendor scripts -->
<script src="vendor/jquery/jquery-2.0.3.min.js"></script>
<script src="vendor/angular/angular.min.js"></script> <script src="vendor/angular/angular.min.js"></script>
<script src="vendor/angular/angular-translate.min.js"></script> <script src="vendor/angular/angular-translate.min.js"></script>
<script src="vendor/angular/angular-translate-loader.min.js"></script> <script src="vendor/angular/angular-translate-loader.min.js"></script>
<script src="vendor/angular/angular-dirPagination.js"></script> <script src="vendor/angular/angular-dirPagination.js"></script>
<script src="vendor/jquery/jquery-2.0.3.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.min.js"></script> <script src="vendor/bootstrap/js/bootstrap.min.js"></script>
<!-- / vendor scripts --> <!-- / vendor scripts -->

View File

@ -11,7 +11,6 @@
var syncthing = angular.module('syncthing', [ var syncthing = angular.module('syncthing', [
'angularUtils.directives.dirPagination', 'angularUtils.directives.dirPagination',
'pascalprecht.translate', 'pascalprecht.translate',
'syncthing.core' 'syncthing.core'
]); ]);

View File

@ -314,8 +314,8 @@ angular.module('syncthing.core')
var hasConfig = !isEmptyObject($scope.config); var hasConfig = !isEmptyObject($scope.config);
$scope.config = config; $scope.config = config;
$scope.config.options.listenAddressStr = $scope.config.options.listenAddress.join(', '); $scope.config.options._listenAddressStr = $scope.config.options.listenAddress.join(', ');
$scope.config.options.globalAnnounceServersStr = $scope.config.options.globalAnnounceServers.join(', '); $scope.config.options._globalAnnounceServersStr = $scope.config.options.globalAnnounceServers.join(', ');
$scope.devices = $scope.config.devices; $scope.devices = $scope.config.devices;
$scope.devices.forEach(function (deviceCfg) { $scope.devices.forEach(function (deviceCfg) {
@ -746,7 +746,7 @@ angular.module('syncthing.core')
$scope.config.gui = angular.copy($scope.tmpGUI); $scope.config.gui = angular.copy($scope.tmpGUI);
['listenAddress', 'globalAnnounceServers'].forEach(function (key) { ['listenAddress', 'globalAnnounceServers'].forEach(function (key) {
$scope.config.options[key] = $scope.config.options[key + "Str"].split(/[ ,]+/).map(function (x) { $scope.config.options[key] = $scope.config.options["_" + key + "Str"].split(/[ ,]+/).map(function (x) {
return x.trim(); return x.trim();
}); });
}); });
@ -757,6 +757,11 @@ angular.module('syncthing.core')
$('#settings').modal("hide"); $('#settings').modal("hide");
}; };
$scope.saveAdvanced = function () {
$scope.saveConfig();
$('#advanced').modal("hide");
};
$scope.restart = function () { $scope.restart = function () {
restarting = true; restarting = true;
$('#restarting').modal(); $('#restarting').modal();
@ -807,7 +812,7 @@ angular.module('syncthing.core')
$scope.currentDevice = $.extend({}, deviceCfg); $scope.currentDevice = $.extend({}, deviceCfg);
$scope.editingExisting = true; $scope.editingExisting = true;
$scope.editingSelf = (deviceCfg.deviceID == $scope.myID); $scope.editingSelf = (deviceCfg.deviceID == $scope.myID);
$scope.currentDevice.addressesStr = deviceCfg.addresses.join(', '); $scope.currentDevice._addressesStr = deviceCfg.addresses.join(', ');
if (!$scope.editingSelf) { if (!$scope.editingSelf) {
$scope.currentDevice.selectedFolders = {}; $scope.currentDevice.selectedFolders = {};
$scope.deviceFolders($scope.currentDevice).forEach(function (folder) { $scope.deviceFolders($scope.currentDevice).forEach(function (folder) {
@ -829,7 +834,7 @@ angular.module('syncthing.core')
}) })
.then(function () { .then(function () {
$scope.currentDevice = { $scope.currentDevice = {
addressesStr: 'dynamic', _addressesStr: 'dynamic',
compression: 'metadata', compression: 'metadata',
introducer: false, introducer: false,
selectedFolders: {} selectedFolders: {}
@ -874,7 +879,7 @@ angular.module('syncthing.core')
$scope.addNewDeviceID = function (device) { $scope.addNewDeviceID = function (device) {
var deviceCfg = { var deviceCfg = {
deviceID: device, deviceID: device,
addressesStr: 'dynamic', _addressesStr: 'dynamic',
compression: 'metadata', compression: 'metadata',
introducer: false, introducer: false,
selectedFolders: {} selectedFolders: {}
@ -885,7 +890,7 @@ angular.module('syncthing.core')
$scope.saveDeviceConfig = function (deviceCfg) { $scope.saveDeviceConfig = function (deviceCfg) {
var done, i; var done, i;
deviceCfg.addresses = deviceCfg.addressesStr.split(',').map(function (x) { deviceCfg.addresses = deviceCfg._addressesStr.split(',').map(function (x) {
return x.trim(); return x.trim();
}); });
@ -1311,6 +1316,10 @@ angular.module('syncthing.core')
$('#about').modal('show'); $('#about').modal('show');
}; };
$scope.advanced = function () {
$('#advanced').modal('show');
};
$scope.showReportPreview = function () { $scope.showReportPreview = function () {
$scope.reportPreview = true; $scope.reportPreview = true;
}; };
@ -1361,6 +1370,22 @@ angular.module('syncthing.core')
return $scope.version.version + ', ' + os + ' (' + arch + ')'; return $scope.version.version + ', ' + os + ' (' + arch + ')';
}; };
$scope.inputTypeFor = function (key, value) {
if (key.substr(0, 1) === '_') {
return 'skip';
}
if (typeof value === 'number') {
return 'number';
}
if (typeof value === 'boolean') {
return 'checkbox';
}
if (typeof value === 'object') {
return 'skip';
}
return 'text';
};
// pseudo main. called on all definitions assigned // pseudo main. called on all definitions assigned
initController(); initController();
}); });

File diff suppressed because one or more lines are too long