gui: Modal tweaks

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3292
LGTM: AudriusButkevicius, calmh
This commit is contained in:
Daniel Harte 2016-06-12 14:06:48 +00:00 committed by Jakob Borg
parent 6f5ca53f99
commit de298da532
44 changed files with 750 additions and 962 deletions

View File

@ -45,7 +45,7 @@
</button> </button>
</li> </li>
<li ng-if="upgradeInfo && upgradeInfo.majorNewer" class="upgrade-newer-major"> <li ng-if="upgradeInfo && upgradeInfo.majorNewer" class="upgrade-newer-major">
<button type="button" class="btn navbar-btn btn-danger btn-sm" ng-click="upgradeMajor()"> <button type="button" class="btn navbar-btn btn-danger btn-sm" data-toggle="modal" data-target="#majorUpgrade">
<span class="fa fa-arrow-circle-up"></span> <span class="fa fa-arrow-circle-up"></span>
<span class="hidden-xs" translate translate-value-version="{{upgradeInfo.latest}}">Upgrade To {%version%}</span> <span class="hidden-xs" translate translate-value-version="{{upgradeInfo.latest}}">Upgrade To {%version%}</span>
</button> </button>
@ -65,7 +65,7 @@
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="" ng-click="editSettings()"><span class="fa fa-fw fa-cog"></span>&nbsp;<span translate>Settings</span></a></li> <li><a href="" ng-click="editSettings()"><span class="fa fa-fw fa-cog"></span>&nbsp;<span translate>Settings</span></a></li>
<li><a href="" ng-click="idDevice(thisDevice())"><span class="fa fa-fw fa-qrcode"></span>&nbsp;<span translate>Show ID</span></a></li> <li><a href="" data-toggle="modal" data-target="#idqr" ng-click="currentDevice=thisDevice()"><span class="fa fa-fw fa-qrcode"></span>&nbsp;<span translate>Show ID</span></a></li>
<li class="divider"></li> <li class="divider"></li>
<li><a href="" ng-click="shutdown()"><span class="fa fa-fw fa-power-off"></span>&nbsp;<span translate>Shutdown</span></a></li> <li><a href="" ng-click="shutdown()"><span class="fa fa-fw fa-power-off"></span>&nbsp;<span translate>Shutdown</span></a></li>
<li><a href="" ng-click="restart()"><span class="fa fa-fw fa-refresh"></span>&nbsp;<span translate>Restart</span></a></li> <li><a href="" ng-click="restart()"><span class="fa fa-fw fa-refresh"></span>&nbsp;<span translate>Restart</span></a></li>
@ -75,7 +75,7 @@
<span class="fa fa-fw fa-book"></span>&nbsp;<span translate>Help</span> <span class="fa fa-fw fa-book"></span>&nbsp;<span translate>Help</span>
</a> </a>
</li> </li>
<li><a href="" ng-click="about()"><span class="fa fa-fw fa-heart-o"></span>&nbsp;<span translate>About</span></a></li> <li><a href="" data-toggle="modal" data-target="#about"><span class="fa fa-fw fa-heart-o"></span>&nbsp;<span translate>About</span></a></li>
<li class="divider"></li> <li class="divider"></li>
<li><a href="" ng-click="advanced()"><span class="fa fa-fw fa-cogs"></span>&nbsp;<span translate>Advanced</span></a></li> <li><a href="" ng-click="advanced()"><span class="fa fa-fw fa-cogs"></span>&nbsp;<span translate>Advanced</span></a></li>
</ul> </ul>
@ -628,23 +628,23 @@
</div> </div>
</nav> </nav>
<div network-error-dialog></div> <ng-include src="'syncthing/core/networkErrorDialogView.html'"></ng-include>
<div http-error-dialog></div> <ng-include src="'syncthing/core/httpErrorDialogView.html'"></ng-include>
<div restarting-dialog></div> <ng-include src="'syncthing/core/restartingDialogView.html'"></ng-include>
<div upgrading-dialog></div> <ng-include src="'syncthing/core/upgradingDialogView.html'"></ng-include>
<div shutdown-dialog></div> <ng-include src="'syncthing/core/shutdownDialogView.html'"></ng-include>
<div idqr-modal></div> <ng-include src="'syncthing/device/idqrModalView.html'"></ng-include>
<div major-upgrade-modal></div> <ng-include src="'syncthing/device/editDeviceModalView.html'"></ng-include>
<div edit-device-modal></div> <ng-include src="'syncthing/folder/editFolderModalView.html'"></ng-include>
<div edit-folder-modal></div> <ng-include src="'syncthing/folder/editIgnoresModalView.html'"></ng-include>
<div edit-ignores-modal></div> <ng-include src="'syncthing/settings/settingsModalView.html'"></ng-include>
<div settings-modal></div> <ng-include src="'syncthing/settings/advancedSettingsModalView.html'"></ng-include>
<div advanced-settings-modal></div> <ng-include src="'syncthing/usagereport/usageReportModalView.html'"></ng-include>
<div usage-report-modal></div> <ng-include src="'syncthing/usagereport/usageReportPreviewModalView.html'"></ng-include>
<div usage-report-preview-modal></div> <ng-include src="'syncthing/transfer/neededFilesModalView.html'"></ng-include>
<div needed-files-modal></div> <ng-include src="'syncthing/transfer/failedFilesModalView.html'"></ng-include>
<div failed-files-modal></div> <ng-include src="'syncthing/core/majorUpgradeModalView.html'"></ng-include>
<div about-modal></div> <ng-include src="'syncthing/core/aboutModalView.html'"></ng-include>
<!-- vendor scripts --> <!-- vendor scripts -->
<script src="vendor/jquery/jquery-2.2.2.js"></script> <script src="vendor/jquery/jquery-2.2.2.js"></script>
@ -657,52 +657,24 @@
<!-- gui application code --> <!-- gui application code -->
<script src="syncthing/core/module.js"></script> <script src="syncthing/core/module.js"></script>
<script src="syncthing/core/aboutModalDirective.js"></script>
<script src="syncthing/core/alwaysNumberFilter.js"></script> <script src="syncthing/core/alwaysNumberFilter.js"></script>
<script src="syncthing/core/basenameFilter.js"></script> <script src="syncthing/core/basenameFilter.js"></script>
<script src="syncthing/core/binaryFilter.js"></script> <script src="syncthing/core/binaryFilter.js"></script>
<script src="syncthing/core/durationFilter.js"></script> <script src="syncthing/core/durationFilter.js"></script>
<script src="syncthing/core/eventService.js"></script> <script src="syncthing/core/eventService.js"></script>
<script src="syncthing/core/httpErrorDialogDirective.js"></script>
<script src="syncthing/core/identiconDirective.js"></script> <script src="syncthing/core/identiconDirective.js"></script>
<script src="syncthing/core/languageSelectDirective.js"></script> <script src="syncthing/core/languageSelectDirective.js"></script>
<script src="syncthing/core/lastErrorComponentFilter.js"></script> <script src="syncthing/core/lastErrorComponentFilter.js"></script>
<script src="syncthing/core/localeService.js"></script> <script src="syncthing/core/localeService.js"></script>
<script src="syncthing/core/majorUpgradeModalDirective.js"></script>
<script src="syncthing/core/modalDirective.js"></script> <script src="syncthing/core/modalDirective.js"></script>
<script src="syncthing/core/naturalFilter.js"></script> <script src="syncthing/core/naturalFilter.js"></script>
<script src="syncthing/core/networkErrorDialogDirective.js"></script>
<script src="syncthing/core/pathIsSubDirDirective.js"></script> <script src="syncthing/core/pathIsSubDirDirective.js"></script>
<script src="syncthing/core/popoverDirective.js"></script> <script src="syncthing/core/popoverDirective.js"></script>
<script src="syncthing/core/restartingDialogDirective.js"></script>
<script src="syncthing/core/selectOnClickDirective.js"></script> <script src="syncthing/core/selectOnClickDirective.js"></script>
<script src="syncthing/core/shutdownDialogDirective.js"></script>
<script src="syncthing/core/syncthingController.js"></script> <script src="syncthing/core/syncthingController.js"></script>
<script src="syncthing/core/tooltipDirective.js"></script> <script src="syncthing/core/tooltipDirective.js"></script>
<script src="syncthing/core/uniqueFolderDirective.js"></script> <script src="syncthing/core/uniqueFolderDirective.js"></script>
<script src="syncthing/core/upgradingDialogDirective.js"></script>
<script src="syncthing/core/validDeviceidDirective.js"></script> <script src="syncthing/core/validDeviceidDirective.js"></script>
<script src="syncthing/device/module.js"></script>
<script src="syncthing/device/editDeviceModalDirective.js"></script>
<script src="syncthing/device/idqrModalDirective.js"></script>
<script src="syncthing/folder/module.js"></script>
<script src="syncthing/folder/editFolderModalDirective.js"></script>
<script src="syncthing/folder/editIgnoresModalDirective.js"></script>
<script src="syncthing/settings/module.js"></script>
<script src="syncthing/settings/settingsModalDirective.js"></script>
<script src="syncthing/settings/advancedSettingsModalDirective.js"></script>
<script src="syncthing/transfer/module.js"></script>
<script src="syncthing/transfer/failedFilesModalDirective.js"></script>
<script src="syncthing/transfer/neededFilesModalDirective.js"></script>
<script src="syncthing/usagereport/module.js"></script>
<script src="syncthing/usagereport/usageReportModalDirective.js"></script>
<script src="syncthing/usagereport/usageReportPreviewModalDirective.js"></script>
<script src="assets/lang/valid-langs.js"></script> <script src="assets/lang/valid-langs.js"></script>
<script src="assets/lang/prettyprint.js"></script> <script src="assets/lang/prettyprint.js"></script>
<script src="meta.js"></script> <script src="meta.js"></script>

View File

@ -1,4 +1,4 @@
<div class="modal fade" tabindex="-1" ng-attr-data-backdrop="{{ close ? true : 'static' }}" ng-attr-data-keyboard="{{ Boolean(close) }}"> <div class="modal fade" tabindex="-1" ng-attr-data-backdrop="{{ closeable == 'yes' ? true : 'static' }}" ng-attr-data-keyboard="{{ closeable == 'yes' ? true : false }}">
<!-- <!--
// Copyright (C) 2014 The Syncthing Authors. // Copyright (C) 2014 The Syncthing Authors.
// //
@ -6,23 +6,17 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file, // License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/. // You can obtain one at http://mozilla.org/MPL/2.0/.
--> -->
<div class="modal-dialog" ng-class="{'modal-lg': large}"> <div class="modal-dialog {{ large == 'yes' ? 'modal-lg' : '' }}">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header alert alert-{{status}}"> <div class="modal-header {{status == 'default' ? '' : 'alert alert-'+status }}">
<h4 class="modal-title"> <h4 class="modal-title">
<div class="panel-icon"> <div ng-if="icon" class="panel-icon">
<span ng-if="icon" class="fa fa-{{icon}}"></span> <span class="fa fa-{{icon}}"></span>
</div> </div>
{{heading}} {{heading}}
</h4> </h4>
</div> </div>
<div class="modal-body" ng-transclude> <div ng-transclude></div>
</div>
<div ng-if="close" class="modal-footer">
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -12,12 +12,7 @@ var syncthing = angular.module('syncthing', [
'angularUtils.directives.dirPagination', 'angularUtils.directives.dirPagination',
'pascalprecht.translate', 'pascalprecht.translate',
'syncthing.core', 'syncthing.core'
'syncthing.device',
'syncthing.folder',
'syncthing.settings',
'syncthing.transfer',
'syncthing.usagereport'
]); ]);
var urlbase = 'rest'; var urlbase = 'rest';

View File

@ -1,7 +0,0 @@
angular.module('syncthing.core')
.directive('aboutModal', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/core/aboutModalView.html'
};
});

View File

@ -1,33 +1,40 @@
<modal id="about" status="info" icon="heart-o" heading="{{'About' | translate}}" large="yes" close="yes"> <modal id="about" status="info" icon="heart-o" heading="{{'About' | translate}}" large="yes" closeable="yes">
<h1 class="text-center"> <div class="modal-body">
<img alt="Syncthing" src="assets/img/logo-horizontal.svg" style="vertical-align: -16px" height="100" width="366"/> <h1 class="text-center">
<br/> <img alt="Syncthing" src="assets/img/logo-horizontal.svg" style="vertical-align: -16px" height="100" width="366"/>
<small>{{versionString()}}</small> <br/>
<br/> <small>{{versionString()}}</small>
<small><i>"{{version.codename}}"</i></small> <br/>
</h1> <small><i>"{{version.codename}}"</i></small>
<hr/> </h1>
<hr/>
<p translate>Copyright &copy; 2014-2016 the following Contributors:</p> <p translate>Copyright &copy; 2014-2016 the following Contributors:</p>
<div class="row"> <div class="row">
<div class="col-md-12" id="contributor-list"> <div class="col-md-12" id="contributor-list">
Jakob Borg, Audrius Butkevicius, Alexander Graf, Anderson Mesquita, Antony Male, Ben Schulz, Caleb Callaway, Daniel Harte, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Philippe Schommers, Ryan Sullivan, Sergey Mishin, Stefan Tatschner, Aaron Bieber, Adam Piggott, Alessandro G., Alexandre Viau, Andrew Dunham, Arthur Axel fREW Schmidt, Bart De Vries, Ben Curthoys, Ben Sidhom, Benny Ng, Brandon Philips, Brendan Long, Brian R. Becker, Carsten Hagemann, Cathryne Linenweaver, Chris Howie, Chris Joel, Colin Kennedy, Daniel Bergmann, Daniel Martí, David Rimmer, Denis A., Dennis Wilson, Dominik Heidler, Elias Jarlebring, Emil Hessman, Erik Meitner, Federico Castagnini, Felix Ableitner, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gilli Sigurdsson, Jaakko Hannikainen, Jacek Szafarkiewicz, Jake Peterson, James Patterson, Jaroslav Malec, Jens Diemer, Jochen Voss, Johan Vromans, Karol Różycki, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Laurent Etiemble, Lord Landon Agahnim, Majed Abdulaziz, Marc Laporte, Marc Pujol, Marcin Dziadus, Mateusz Naściszewski, Matt Burke, Max Schulze, Michael Jephcote, Michael Tilli, Nate Morrison, Pascal Jungblut, Peter Hoeg, Phill Luby, Piotr Bejda, Scott Klupfel, Stefan Kuntz, Tim Abell, Tobias Nygren, Tomas Cerveny, Tully Robinson, Tyler Brazier, Veeti Paananen, Victor Buinsky, Vil Brekin, William A. Kennington III, Wulf Weich, Yannic A. Jakob Borg, Audrius Butkevicius, Alexander Graf, Anderson Mesquita, Antony Male, Ben Schulz, Caleb Callaway, Daniel Harte, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Philippe Schommers, Ryan Sullivan, Sergey Mishin, Stefan Tatschner, Aaron Bieber, Adam Piggott, Alessandro G., Alexandre Viau, Andrew Dunham, Arthur Axel fREW Schmidt, Bart De Vries, Ben Curthoys, Ben Sidhom, Benny Ng, Brandon Philips, Brendan Long, Brian R. Becker, Carsten Hagemann, Cathryne Linenweaver, Chris Howie, Chris Joel, Colin Kennedy, Daniel Bergmann, Daniel Martí, David Rimmer, Denis A., Dennis Wilson, Dominik Heidler, Elias Jarlebring, Emil Hessman, Erik Meitner, Federico Castagnini, Felix Ableitner, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gilli Sigurdsson, Jaakko Hannikainen, Jacek Szafarkiewicz, Jake Peterson, James Patterson, Jaroslav Malec, Jens Diemer, Jochen Voss, Johan Vromans, Karol Różycki, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Laurent Etiemble, Lord Landon Agahnim, Majed Abdulaziz, Marc Laporte, Marc Pujol, Marcin Dziadus, Mateusz Naściszewski, Matt Burke, Max Schulze, Michael Jephcote, Michael Tilli, Nate Morrison, Pascal Jungblut, Peter Hoeg, Phill Luby, Piotr Bejda, Scott Klupfel, Stefan Kuntz, Tim Abell, Tobias Nygren, Tomas Cerveny, Tully Robinson, Tyler Brazier, Veeti Paananen, Victor Buinsky, Vil Brekin, William A. Kennington III, Wulf Weich, Yannic A.
</div>
</div> </div>
</div> <hr/>
<hr/>
<p translate>Syncthing includes the following software or portions thereof:</p> <p translate>Syncthing includes the following software or portions thereof:</p>
<ul class="list-unstyled two-columns"> <ul class="list-unstyled two-columns">
<li><a href="https://golang.org">The Go Programming Language</a>, Copyright &copy; 2012 The Go Authors.</li> <li><a href="https://golang.org">The Go Programming Language</a>, Copyright &copy; 2012 The Go Authors.</li>
<li><a href="https://github.com/bkaradzic/go-lz4">bkaradzic/go-lz4</a>, Copyright &copy; 2011-2012 Branimir Karadzic, 2013 Damian Gryski.</li> <li><a href="https://github.com/bkaradzic/go-lz4">bkaradzic/go-lz4</a>, Copyright &copy; 2011-2012 Branimir Karadzic, 2013 Damian Gryski.</li>
<li><a href="https://github.com/kardianos/osext">kardianos/osext</a>, Copyright &copy; 2012 Daniel Theophanes.</li> <li><a href="https://github.com/kardianos/osext">kardianos/osext</a>, Copyright &copy; 2012 Daniel Theophanes.</li>
<li><a href="https://github.com/golang/snappy">golang/snappy</a>, Copyright &copy; 2011 The Snappy-Go Authors.</li> <li><a href="https://github.com/golang/snappy">golang/snappy</a>, Copyright &copy; 2011 The Snappy-Go Authors.</li>
<li><a href="https://github.com/juju/ratelimit">juju/ratelimit</a>, Copyright &copy; 2015 Canonical Ltd.</li> <li><a href="https://github.com/juju/ratelimit">juju/ratelimit</a>, Copyright &copy; 2015 Canonical Ltd.</li>
<li><a href="https://github.com/thejerf/suture">thejerf/suture</a>, Copyright &copy; 2014-2015 Barracuda Networks, Inc.</li> <li><a href="https://github.com/thejerf/suture">thejerf/suture</a>, Copyright &copy; 2014-2015 Barracuda Networks, Inc.</li>
<li><a href="https://github.com/syndtr/goleveldb">syndtr/goleveldb</a>, Copyright &copy; 2012, Suryandaru Triandana</li> <li><a href="https://github.com/syndtr/goleveldb">syndtr/goleveldb</a>, Copyright &copy; 2012, Suryandaru Triandana</li>
<li><a href="https://github.com/vitrun/qart">vitrun/qart</a>, Copyright &copy; The Go Authors.</li> <li><a href="https://github.com/vitrun/qart">vitrun/qart</a>, Copyright &copy; The Go Authors.</li>
<li><a href="https://angularjs.org/">AngularJS</a>, Copyright &copy; 2010-2015 Google, Inc.</li> <li><a href="https://angularjs.org/">AngularJS</a>, Copyright &copy; 2010-2015 Google, Inc.</li>
<li><a href="http://getbootstrap.com/">Bootstrap</a>, Copyright &copy; 2011-2015 Twitter, Inc.</li> <li><a href="http://getbootstrap.com/">Bootstrap</a>, Copyright &copy; 2011-2015 Twitter, Inc.</li>
<li><a href="http://fontawesome.io/">Font Awesome</a>, Copyright &copy; 2015 Dave Gandy</li> <li><a href="http://fontawesome.io/">Font Awesome</a>, Copyright &copy; 2015 Dave Gandy</li>
</ul> </ul>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
</modal> </modal>

View File

@ -1,7 +0,0 @@
angular.module('syncthing.core')
.directive('httpErrorDialog', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/core/httpErrorDialogView.html'
};
});

View File

@ -1,5 +1,7 @@
<modal id="httpError" status="danger" icon="exclamation-circle" heading="{{'Connection Error' | translate}}"> <modal id="httpError" status="danger" icon="exclamation-circle" heading="{{'Connection Error' | translate}}" large="no" closeable="no">
<p translate> <div class="modal-body">
Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists. <p translate>
</p> Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.
</p>
</div>
</modal> </modal>

View File

@ -1,7 +0,0 @@
angular.module('syncthing.core')
.directive('majorUpgradeModal', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/core/majorUpgradeModalView.html'
};
});

View File

@ -1,32 +1,20 @@
<div id="majorUpgrade" class="modal fade" tabindex="-1" data-backdrop="true" data-keyboard="true"> <modal id="majorUpgrade" status="danger" icon="arrow-circle-up" heading="{{'Major Upgrade' | translate}}" large="no" closeable="yes">
<div class="modal-dialog"> <div class="modal-body">
<div class="modal-content"> <p>
<div class="modal-header alert alert-danger"> <span translate>This is a major version upgrade.</span>
<h4 class="modal-title"> <span translate>A new major version may not be compatible with previous versions.</span>
<div class="panel-icon"> <span translate>Please consult the release notes before performing a major upgrade.</span>
<span class="fa fa-arrow-circle-up"></span> </p>
</div> <p>
<span translate>Major Upgrade</span> <a href="https://github.com/syncthing/syncthing/releases/tag/{{upgradeInfo.latest}}" target="_blank" translate>Release Notes</a>
</h4> </p>
</div>
<div class="modal-body">
<p>
<span translate>This is a major version upgrade.</span>
<span translate>A new major version may not be compatible with previous versions.</span>
<span translate>Please consult the release notes before performing a major upgrade.</span>
</p>
<p>
<a href="https://github.com/syncthing/syncthing/releases/tag/{{upgradeInfo.latest}}" target="_blank" translate>Release Notes</a>
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary btn-sm" ng-click="upgrade()">
<span class="fa fa-check"></span>&nbsp;<span translate>Upgrade</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
</div>
</div> </div>
</div> <div class="modal-footer">
<button type="button" class="btn btn-primary btn-sm" ng-click="upgrade()">
<span class="fa fa-check"></span>&nbsp;<span translate>Upgrade</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
</modal>

View File

@ -9,10 +9,10 @@ angular.module('syncthing.core')
heading: '@', heading: '@',
status: '@', status: '@',
icon: '@', icon: '@',
close: '@', closeable: '@',
large: '@' large: '@'
}, },
link: function (scope, element, attrs, tabsCtrl) { link: function (scope, element, attrs) {
// before modal show animation // before modal show animation
$(element).on('show.bs.modal', function () { $(element).on('show.bs.modal', function () {
@ -44,7 +44,6 @@ angular.module('syncthing.core')
// find and unhide the next backdrop down in z order // find and unhide the next backdrop down in z order
var sel = false, largestZ = 0; var sel = false, largestZ = 0;
$('.modal-backdrop').each(function (i) { $('.modal-backdrop').each(function (i) {
console.log('sel each');
var thisZ = parseInt($(this).css('zIndex')); var thisZ = parseInt($(this).css('zIndex'));
if (thisZ > largestZ && $(this).attr('for-modal-id') !== $(element).attr('id')) { if (thisZ > largestZ && $(this).attr('for-modal-id') !== $(element).attr('id')) {
largestZ = thisZ; largestZ = thisZ;

View File

@ -1,7 +0,0 @@
angular.module('syncthing.core')
.directive('networkErrorDialog', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/core/networkErrorDialogView.html'
};
});

View File

@ -1,5 +1,7 @@
<modal id="networkError" status="danger" icon="exclamation-circle" heading="{{'Connection Error' | translate}}"> <modal id="networkError" status="danger" icon="exclamation-circle" heading="{{'Connection Error' | translate}}" large="no" closeable="no">
<p translate> <div class="modal-body">
Syncthing seems to be down, or there is a problem with your Internet connection. Retrying&hellip; <p translate>
</p> Syncthing seems to be down, or there is a problem with your Internet connection. Retrying&hellip;
</p>
</div>
</modal> </modal>

View File

@ -1,7 +0,0 @@
angular.module('syncthing.core')
.directive('restartingDialog', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/core/restartingDialogView.html'
};
});

View File

@ -1,3 +1,8 @@
<modal id="restarting" status="info" icon="refresh" heading="{{'Restarting' | translate}}"> <modal id="restarting" status="info" icon="refresh" heading="{{'Restarting' | translate}}" large="no" closeable="no">
<p><span translate>Syncthing is restarting.</span> <span translate>Please wait</span>...</p> <div class="modal-body">
<p>
<span translate>Syncthing is restarting.</span>
<span translate>Please wait</span>...
</p>
</div>
</modal> </modal>

View File

@ -1,7 +0,0 @@
angular.module('syncthing.core')
.directive('shutdownDialog', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/core/shutdownDialogView.html'
};
});

View File

@ -1,3 +1,7 @@
<modal id="shutdown" status="success" icon="power-off" heading="{{'Shutdown Complete' | translate}}"> <modal id="shutdown" status="success" icon="power-off" heading="{{'Shutdown Complete' | translate}}" large="no" closeable="no">
<p translate>Syncthing has been shut down.</p> <div class="modal-body">
<p translate>
Syncthing has been shut down.
</p>
</div>
</modal> </modal>

View File

@ -1028,10 +1028,6 @@ angular.module('syncthing.core')
}); });
}; };
$scope.upgradeMajor = function () {
$('#majorUpgrade').modal();
};
$scope.shutdown = function () { $scope.shutdown = function () {
restarting = true; restarting = true;
$http.post(urlbase + '/system/shutdown').success(function () { $http.post(urlbase + '/system/shutdown').success(function () {
@ -1052,12 +1048,6 @@ angular.module('syncthing.core')
$('#editDevice').modal(); $('#editDevice').modal();
}; };
$scope.idDevice = function (deviceCfg) {
$scope.currentDevice = deviceCfg;
$('#editDevice').modal('hide');
$('#idqr').modal('show');
};
$scope.addDevice = function (deviceID, name) { $scope.addDevice = function (deviceID, name) {
return $http.get(urlbase + '/system/discovery') return $http.get(urlbase + '/system/discovery')
.success(function (registry) { .success(function (registry) {
@ -1229,6 +1219,18 @@ angular.module('syncthing.core')
}).error($scope.emitHTTPError); }).error($scope.emitHTTPError);
}); });
$scope.loadFormIntoScope = function (form) {
console.log('loadFormIntoScope',form.$name);
switch (form.$name) {
case 'deviceEditor':
$scope.deviceEditor = form;
break;
case 'folderEditor':
$scope.folderEditor = form;
break;
}
}
$scope.editFolder = function (folderCfg) { $scope.editFolder = function (folderCfg) {
$scope.currentFolder = angular.copy(folderCfg); $scope.currentFolder = angular.copy(folderCfg);
if ($scope.currentFolder.path.slice(-1) === $scope.system.pathSeparator) { if ($scope.currentFolder.path.slice(-1) === $scope.system.pathSeparator) {
@ -1464,20 +1466,11 @@ angular.module('syncthing.core')
$http.get(urlbase + '/db/ignores?folder=' + encodeURIComponent($scope.currentFolder.id)) $http.get(urlbase + '/db/ignores?folder=' + encodeURIComponent($scope.currentFolder.id))
.success(function (data) { .success(function (data) {
data.ignore = data.ignore || []; data.ignore = data.ignore || [];
var textArea = $('#editIgnores textarea');
$('#editFolder').modal('hide') textArea.val(data.ignore.join('\n'));
.one('hidden.bs.modal', function() { $('#editIgnores').modal()
var textArea = $('#editIgnores textarea'); .one('shown.bs.modal', function () {
textArea.focus();
textArea.val(data.ignore.join('\n'));
$('#editIgnores').modal()
.one('hidden.bs.modal', function () {
$('#editFolder').modal();
})
.one('shown.bs.modal', function () {
textArea.focus();
});
}); });
}) })
.then(function () { .then(function () {
@ -1501,16 +1494,6 @@ angular.module('syncthing.core')
}); });
}; };
$scope.showURPreview = function () {
$('#settings').modal('hide')
.one('hidden.bs.modal', function() {
$('#urPreview').modal()
.one('hidden.bs.modal', function () {
$('#settings').modal();
});
});
};
$scope.acceptUR = function () { $scope.acceptUR = function () {
$scope.config.options.urAccepted = 1000; // Larger than the largest existing report version $scope.config.options.urAccepted = 1000; // Larger than the largest existing report version
$scope.saveConfig(); $scope.saveConfig();
@ -1555,10 +1538,6 @@ angular.module('syncthing.core')
$http.post(urlbase + "/db/override?folder=" + encodeURIComponent(folder)); $http.post(urlbase + "/db/override?folder=" + encodeURIComponent(folder));
}; };
$scope.about = function () {
$('#about').modal('show');
};
$scope.advanced = function () { $scope.advanced = function () {
$scope.advancedConfig = angular.copy($scope.config); $scope.advancedConfig = angular.copy($scope.config);
$('#advanced').modal('show'); $('#advanced').modal('show');

View File

@ -1,7 +0,0 @@
angular.module('syncthing.core')
.directive('upgradingDialog', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/core/upgradingDialogView.html'
};
});

View File

@ -1,3 +1,8 @@
<modal id="upgrading" status="info" icon="arrow-circle-up" heading="{{'Upgrading' | translate}}"> <modal id="upgrading" status="info" icon="arrow-circle-up" heading="{{'Upgrading' | translate}}" large="no" closeable="no">
<p><span translate>Syncthing is upgrading.</span> <span translate>Please wait</span>...</p> <div class="modal-body">
<p>
<span translate>Syncthing is upgrading.</span>
<span translate>Please wait</span>...
</p>
</div>
</modal> </modal>

View File

@ -1,7 +0,0 @@
angular.module('syncthing.device')
.directive('editDeviceModal', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/device/editDeviceModalView.html'
};
});

View File

@ -1,104 +1,82 @@
<div id="editDevice" class="modal fade" tabindex="-1"> <modal id="editDevice" status="default" icon="{{editingExisting ? 'pencil' : 'desktop'}}" heading="{{editingExisting ? 'Edit Device' : 'Add Device' | translate}}" large="yes" closeable="yes">
<div class="modal-dialog modal-lg"> <div class="modal-body">
<div class="modal-content"> <form role="form" name="deviceEditor">
<div class="modal-header"> <div class="form-group" ng-class="{'has-error': deviceEditor.deviceID.$invalid && deviceEditor.deviceID.$dirty}" ng-init="loadFormIntoScope(deviceEditor)">
<h4 class="modal-title"> <label translate for="deviceID">Device ID</label>
<span ng-show="!editingExisting"> <input ng-if="!editingExisting" name="deviceID" id="deviceID" class="form-control text-monospace" type="text" ng-model="currentDevice.deviceID" required valid-deviceid list="discovery-list" />
<div class="panel-icon"> <datalist id="discovery-list" ng-if="!editingExisting">
<span class="fa fa-desktop"></span> <option ng-repeat="(id, data) in discovery" value="{{id}}" />
</div> </datalist>
<span translate>Add Device</span> <div ng-if="editingExisting" class="well well-sm text-monospace" select-on-click>{{currentDevice.deviceID}}</div>
</span> <p class="help-block">
<span ng-show="editingExisting"> <span translate ng-if="deviceEditor.deviceID.$valid || deviceEditor.deviceID.$pristine">The device ID to enter here can be found in the "Actions > Show ID" dialog on the other device. Spaces and dashes are optional (ignored).</span>
<div class="panel-icon"> <span translate ng-show="!editingExisting && (deviceEditor.deviceID.$valid || deviceEditor.deviceID.$pristine)">When adding a new device, keep in mind that this device must be added on the other side too.</span>
<span class="fa fa-pencil"></span> <span translate ng-if="deviceEditor.deviceID.$error.required && deviceEditor.deviceID.$dirty">The device ID cannot be blank.</span>
</div> <span translate ng-if="deviceEditor.deviceID.$error.validDeviceid && deviceEditor.deviceID.$dirty">The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.</span>
<span translate>Edit Device</span> <span translate ng-if="deviceEditor.deviceID.$error.unique && deviceEditor.deviceID.$dirty">A device with that ID is already added.</span>
</span> </p>
</h4>
</div> </div>
<div class="modal-body"> <div class="form-group">
<form role="form" name="deviceEditor"> <label translate for="name">Device Name</label>
<div class="form-group" ng-class="{'has-error': deviceEditor.deviceID.$invalid && deviceEditor.deviceID.$dirty}"> <input id="name" class="form-control" type="text" ng-model="currentDevice.name"></input>
<label translate for="deviceID">Device ID</label> <p translate ng-if="currentDevice.deviceID == myID" class="help-block">Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.</p>
<input ng-if="!editingExisting" name="deviceID" id="deviceID" class="form-control text-monospace" type="text" ng-model="currentDevice.deviceID" required valid-deviceid list="discovery-list" /> <p translate ng-if="currentDevice.deviceID != myID" class="help-block">Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.</p>
<datalist id="discovery-list" ng-if="!editingExisting"> </div>
<option ng-repeat="(id, data) in discovery" value="{{id}}" /> <div class="form-group">
</datalist> <label translate for="addresses">Addresses</label>
<div ng-if="editingExisting" class="well well-sm text-monospace" select-on-click>{{currentDevice.deviceID}}</div> <input ng-disabled="currentDevice.deviceID == myID" id="addresses" class="form-control" type="text" ng-model="currentDevice._addressesStr"></input>
<p class="help-block"> <p translate class="help-block">Enter comma separated ("tcp://ip:port", "tcp://host:port") addresses or "dynamic" to perform automatic discovery of the address.</p>
<span translate ng-if="deviceEditor.deviceID.$valid || deviceEditor.deviceID.$pristine">The device ID to enter here can be found in the "Actions > Show ID" dialog on the other device. Spaces and dashes are optional (ignored).</span> </div>
<span translate ng-show="!editingExisting && (deviceEditor.deviceID.$valid || deviceEditor.deviceID.$pristine)">When adding a new device, keep in mind that this device must be added on the other side too.</span> <div class="form-group">
<span translate ng-if="deviceEditor.deviceID.$error.required && deviceEditor.deviceID.$dirty">The device ID cannot be blank.</span> <label translate>Compression</label>
<span translate ng-if="deviceEditor.deviceID.$error.validDeviceid && deviceEditor.deviceID.$dirty">The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.</span> <select class="form-control" ng-model="currentDevice.compression">
<span translate ng-if="deviceEditor.deviceID.$error.unique && deviceEditor.deviceID.$dirty">A device with that ID is already added.</span> <option value="always" translate>All Data</option>
</p> <option value="metadata" translate>Metadata Only</option>
</div> <option value="never" translate>Off</option>
</select>
</div>
<div class="form-group">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="currentDevice.introducer"> <span translate>Introducer</span>
</label>
<p translate class="help-block">Any devices configured on an introducer device will be added to this device as well.</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group"> <div class="form-group">
<label translate for="name">Device Name</label> <label translate for="folders">Share Folders With Device</label>
<input id="name" class="form-control" type="text" ng-model="currentDevice.name"></input> <p translate class="help-block">Select the folders to share with this device.</p>
<p translate ng-if="currentDevice.deviceID == myID" class="help-block">Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.</p> <div class="row">
<p translate ng-if="currentDevice.deviceID != myID" class="help-block">Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.</p> <div class="col-md-4" ng-repeat="folder in folderList()">
</div> <div class="checkbox">
<div class="form-group"> <label ng-if="folder.label.length == 0">
<label translate for="addresses">Addresses</label> <input type="checkbox" ng-model="currentDevice.selectedFolders[folder.id]">&nbsp;{{folder.id}}
<input ng-disabled="currentDevice.deviceID == myID" id="addresses" class="form-control" type="text" ng-model="currentDevice._addressesStr"></input> </label>
<p translate class="help-block">Enter comma separated ("tcp://ip:port", "tcp://host:port") addresses or "dynamic" to perform automatic discovery of the address.</p> <label ng-if="folder.label.length != 0">
</div> <input type="checkbox" ng-model="currentDevice.selectedFolders[folder.id]">&nbsp;<span tooltip data-original-title="{{folder.id}}">{{folder.label}}</span>
<div class="form-group"> </label>
<label translate>Compression</label>
<select class="form-control" ng-model="currentDevice.compression">
<option value="always" translate>All Data</option>
<option value="metadata" translate>Metadata Only</option>
<option value="never" translate>Off</option>
</select>
</div>
<div class="form-group">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="currentDevice.introducer"> <span translate>Introducer</span>
</label>
<p translate class="help-block">Any devices configured on an introducer device will be added to this device as well.</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label translate for="folders">Share Folders With Device</label>
<p translate class="help-block">Select the folders to share with this device.</p>
<div class="row">
<div class="col-md-4" ng-repeat="folder in folderList()">
<div class="checkbox">
<label ng-if="folder.label.length == 0">
<input type="checkbox" ng-model="currentDevice.selectedFolders[folder.id]">&nbsp;{{folder.id}}
</label>
<label ng-if="folder.label.length != 0">
<input type="checkbox" ng-model="currentDevice.selectedFolders[folder.id]">&nbsp;<span tooltip data-original-title="{{folder.id}}">{{folder.label}}</span>
</label>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
</form>
</div> </div>
<div class="modal-footer"> </form>
<button type="button" class="btn btn-primary btn-sm" ng-click="saveDevice()" ng-disabled="deviceEditor.$invalid">
<span class="fa fa-check"></span>&nbsp;<span translate>Save</span>
</button>
<button type="button" class="btn btn-default btn-sm" ng-click="idDevice(currentDevice)" ng-if="editingExisting || deviceEditor.deviceID.$valid">
<span class="fa fa-qrcode"></span>&nbsp;<span translate>Show QR</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
<button type="button" class="btn btn-warning pull-left btn-sm" ng-click="deleteDevice()" ng-if="editingExisting">
<span class="fa fa-minus-circle"></span>&nbsp;<span translate>Remove</span>
</button>
</div>
</div>
</div> </div>
</div> <div class="modal-footer">
<button type="button" class="btn btn-primary btn-sm" ng-click="saveDevice()" ng-disabled="deviceEditor.$invalid">
<span class="fa fa-check"></span>&nbsp;<span translate>Save</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-toggle="modal" data-target="#idqr" ng-if="editingExisting || deviceEditor.deviceID.$valid">
<span class="fa fa-qrcode"></span>&nbsp;<span translate>Show QR</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
<button type="button" class="btn btn-warning pull-left btn-sm" ng-click="deleteDevice()" ng-if="editingExisting">
<span class="fa fa-minus-circle"></span>&nbsp;<span translate>Remove</span>
</button>
</div>
</modal>

View File

@ -1,7 +0,0 @@
angular.module('syncthing.device')
.directive('idqrModal', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/device/idqrModalView.html'
};
});

View File

@ -1,4 +1,11 @@
<modal id="idqr" status="info" icon="qrcode" heading="{{'Device Identification' | translate}} - {{deviceName(currentDevice)}}" large="yes" close="yes"> <modal id="idqr" status="info" icon="qrcode" heading="{{'Device Identification' | translate}} - {{deviceName(currentDevice)}}" large="yes" closeable="yes">
<div class="well well-sm text-monospace text-center" select-on-click>{{currentDevice.deviceID}}</div> <div class="modal-body">
<img ng-if="currentDevice.deviceID" class="center-block img-thumbnail" ng-src="qr/?text={{currentDevice.deviceID}}"/> <div class="well well-sm text-monospace text-center" select-on-click>{{currentDevice.deviceID}}</div>
<img ng-if="currentDevice.deviceID" class="center-block img-thumbnail" ng-src="qr/?text={{currentDevice.deviceID}}"/>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
</modal> </modal>

View File

@ -1 +0,0 @@
angular.module('syncthing.device', []);

View File

@ -1,7 +0,0 @@
angular.module('syncthing.folder')
.directive('editFolderModal', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/folder/editFolderModalView.html'
};
});

View File

@ -1,214 +1,194 @@
<div id="editFolder" class="modal fade" tabindex="-1"> <modal id="editFolder" status="default" icon="{{editingExisting ? 'pencil' : 'folder'}}" heading="{{editingExisting ? 'Edit Folder' : 'Add Folder' | translate}}" large="yes" closeable="yes">
<div class="modal-dialog modal-lg"> <div class="modal-body">
<div class="modal-content"> <form role="form" name="folderEditor">
<div class="modal-header"> <div class="row" ng-init="loadFormIntoScope(folderEditor)">
<h4 class="modal-title"> <div class="col-md-12">
<span ng-show="!editingExisting"> <div class="form-group" ng-class="{'has-error': folderEditor.folderLabel.$invalid && folderEditor.folderLabel.$dirty}">
<div class="panel-icon"> <label for="folderLabel"><span translate>Folder Label</span></label>
<span class="fa fa-folder"></span> <input name="folderLabel" id="folderLabel" class="form-control" type="text" ng-model="currentFolder.label" value="{{currentFolder.label}}"/>
</div> <p class="help-block">
<span translate>Add Folder</span> <span translate ng-if="folderEditor.folderLabel.$valid || folderEditor.folderLabel.$pristine">Optional descriptive label for the folder. Can be different on each device.</span>
</span> </p>
<span ng-show="editingExisting"> </div>
<div class="panel-icon"> <div class="form-group" ng-class="{'has-error': folderEditor.folderID.$invalid && folderEditor.folderID.$dirty}">
<span class="fa fa-pencil"></span> <label for="folderID"><span translate>Folder ID</span></label>
</div> <input name="folderID" ng-readonly="editingExisting || (!editingExisting && currentFolder.viewFlags.importFromOtherDevice)" id="folderID" class="form-control" type="text" ng-model="currentFolder.id" required unique-folder value="{{currentFolder.id}}"/>
<span translate>Edit Folder</span> <p class="help-block">
</span> <span translate ng-if="folderEditor.folderID.$valid || folderEditor.folderID.$pristine">Required identifier for the folder. Must be the same on all cluster devices.</span>
</h4> <span translate ng-if="folderEditor.folderID.$error.uniqueFolder">The folder ID must be unique.</span>
<span translate ng-if="folderEditor.folderID.$error.required && folderEditor.folderID.$dirty">The folder ID cannot be blank.</span>
</p>
</div>
<div class="form-group" ng-class="{'has-error': folderEditor.folderPath.$invalid && folderEditor.folderPath.$dirty}">
<label translate for="folderPath">Folder Path</label>
<input name="folderPath" ng-readonly="editingExisting" id="folderPath" class="form-control" type="text" ng-model="currentFolder.path" list="directory-list" required path-is-sub-dir/>
<datalist id="directory-list">
<option ng-repeat="directory in directoryList" value="{{ directory }}" />
</datalist>
<p class="help-block">
<span translate ng-if="folderEditor.folderPath.$valid || folderEditor.folderPath.$pristine">Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for</span> <code>{{system.tilde}}</code>.
<span translate ng-if="folderEditor.folderPath.$error.required && folderEditor.folderPath.$dirty">The folder path cannot be blank.</span>
<span class="text-danger" translate translate-value-other-folder="{{otherFolder}}" ng-if="pathIsSubFolder">Warning, this path is a subdirectory of an existing folder "{%otherFolder%}".</span>
</p>
</div>
</div>
</div> </div>
<div class="modal-body"> <div class="row">
<form role="form" name="folderEditor"> <div class="col-md-12">
<div class="row"> <div class="form-group">
<div class="col-md-12"> <label translate for="devices">Share With Devices</label>
<div class="form-group" ng-class="{'has-error': folderEditor.folderLabel.$invalid && folderEditor.folderLabel.$dirty}"> <p translate class="help-block">Select the devices to share this folder with.</p>
<label for="folderLabel"><span translate>Folder Label</span></label>
<input name="folderLabel" id="folderLabel" class="form-control" type="text" ng-model="currentFolder.label" value="{{currentFolder.label}}"/>
<p class="help-block">
<span translate ng-if="folderEditor.folderLabel.$valid || folderEditor.folderLabel.$pristine">Optional descriptive label for the folder. Can be different on each device.</span>
</p>
</div>
<div class="form-group" ng-class="{'has-error': folderEditor.folderID.$invalid && folderEditor.folderID.$dirty}">
<label for="folderID"><span translate>Folder ID</span></label>
<input name="folderID" ng-readonly="editingExisting || (!editingExisting && currentFolder.viewFlags.importFromOtherDevice)" id="folderID" class="form-control" type="text" ng-model="currentFolder.id" required unique-folder value="{{currentFolder.id}}"/>
<p class="help-block">
<span translate ng-if="folderEditor.folderID.$valid || folderEditor.folderID.$pristine">Required identifier for the folder. Must be the same on all cluster devices.</span>
<span translate ng-if="folderEditor.folderID.$error.uniqueFolder">The folder ID must be unique.</span>
<span translate ng-if="folderEditor.folderID.$error.required && folderEditor.folderID.$dirty">The folder ID cannot be blank.</span>
</p>
</div>
<div class="form-group" ng-class="{'has-error': folderEditor.folderPath.$invalid && folderEditor.folderPath.$dirty}">
<label translate for="folderPath">Folder Path</label>
<input name="folderPath" ng-readonly="editingExisting" id="folderPath" class="form-control" type="text" ng-model="currentFolder.path" list="directory-list" required path-is-sub-dir/>
<datalist id="directory-list">
<option ng-repeat="directory in directoryList" value="{{ directory }}" />
</datalist>
<p class="help-block">
<span translate ng-if="folderEditor.folderPath.$valid || folderEditor.folderPath.$pristine">Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for</span> <code>{{system.tilde}}</code>.
<span translate ng-if="folderEditor.folderPath.$error.required && folderEditor.folderPath.$dirty">The folder path cannot be blank.</span>
<span class="text-danger" translate translate-value-other-folder="{{otherFolder}}" ng-if="pathIsSubFolder">Warning, this path is a subdirectory of an existing folder "{%otherFolder%}".</span>
</p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label translate for="devices">Share With Devices</label>
<p translate class="help-block">Select the devices to share this folder with.</p>
<div class="row">
<div class="col-md-4" ng-repeat="device in otherDevices()">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="currentFolder.selectedDevices[device.deviceID]"> {{deviceName(device)}}
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div translate ng-show="!editingExisting" class="help-block">When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.</div>
<div class="row">
<div class="col-md-12">
<label data-target="#folder-advanced" class="folder-advanced-toggle collapsed" data-toggle="collapse">
<span translate>Advanced settings</span>&nbsp;
<i class="expand fa fa-plus-square"></i>
<i class="collapse fa fa-minus-square"></i>
</label>
</div>
</div>
<div id="folder-advanced" class="folder-advanced collapse">
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-4" ng-repeat="device in otherDevices()">
<div class="form-group" ng-class="{'has-error': folderEditor.rescanIntervalS.$invalid && folderEditor.rescanIntervalS.$dirty}"> <div class="checkbox">
<label for="rescanIntervalS"><span translate>Rescan Interval</span> (s)</label> <label>
<input name="rescanIntervalS" id="rescanIntervalS" class="form-control" type="number" ng-model="currentFolder.rescanIntervalS" required min="0"> <input type="checkbox" ng-model="currentFolder.selectedDevices[device.deviceID]"> {{deviceName(device)}}
<p class="help-block"> </label>
<span translate ng-if="!folderEditor.rescanIntervalS.$valid && folderEditor.rescanIntervalS.$dirty">The rescan interval must be a non-negative number of seconds.</span>
</p>
</div>
<div class="form-group" ng-class="{'has-error': folderEditor.minDiskFreePct.$invalid && folderEditor.minDiskFreePct.$dirty}">
<label for="minDiskFreePct"><span translate>Minimum Free Disk Space</span> (0.0 - 100.0%)</label>
<input name="minDiskFreePct" id="minDiskFreePct" class="form-control" type="number" ng-model="currentFolder.minDiskFreePct" required min="0.0" max="100.0">
<p class="help-block">
<span translate ng-if="!folderEditor.minDiskFreePct.$valid && folderEditor.minDiskFreePct.$dirty">The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).</span>
</p>
</div> </div>
</div> </div>
</div> </div>
<div class="row"> </div>
<!-- Left column --> </div>
<div class="col-md-6"> </div>
<div class="form-group"> <div translate ng-show="!editingExisting" class="help-block">When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.</div>
<label translate>Folder Type</label> <div class="row">
&nbsp;<a href="http://docs.syncthing.net/users/foldermaster.html" target="_blank"><span class="fa fa-book"></span>&nbsp;<span translate>Help</span></a> <div class="col-md-12">
<select class="form-control" ng-model="currentFolder.type"> <label data-target="#folder-advanced" class="folder-advanced-toggle collapsed" data-toggle="collapse">
<option value="readwrite" translate>Normal</option> <span translate>Advanced settings</span>&nbsp;
<option value="readonly" translate>Master</option> <i class="expand fa fa-plus-square"></i>
</select> <i class="collapse fa fa-minus-square"></i>
<p ng-if="currentFolder.type == 'readonly'" translate class="help-block">Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.</p> </label>
</div> </div>
<div class="form-group"> </div>
<div class="checkbox"> <div id="folder-advanced" class="folder-advanced collapse">
<label> <div class="row">
<input type="checkbox" ng-model="currentFolder.ignorePerms"> <span translate>Ignore Permissions</span> <div class="col-md-12">
</label> <div class="form-group" ng-class="{'has-error': folderEditor.rescanIntervalS.$invalid && folderEditor.rescanIntervalS.$dirty}">
</div> <label for="rescanIntervalS"><span translate>Rescan Interval</span> (s)</label>
<p translate class="help-block">File permission bits are ignored when looking for changes. Use on FAT file systems.</p> <input name="rescanIntervalS" id="rescanIntervalS" class="form-control" type="number" ng-model="currentFolder.rescanIntervalS" required min="0">
</div> <p class="help-block">
<span translate ng-if="!folderEditor.rescanIntervalS.$valid && folderEditor.rescanIntervalS.$dirty">The rescan interval must be a non-negative number of seconds.</span>
</p>
</div>
<div class="form-group" ng-class="{'has-error': folderEditor.minDiskFreePct.$invalid && folderEditor.minDiskFreePct.$dirty}">
<label for="minDiskFreePct"><span translate>Minimum Free Disk Space</span> (0.0 - 100.0%)</label>
<input name="minDiskFreePct" id="minDiskFreePct" class="form-control" type="number" ng-model="currentFolder.minDiskFreePct" required min="0.0" max="100.0">
<p class="help-block">
<span translate ng-if="!folderEditor.minDiskFreePct.$valid && folderEditor.minDiskFreePct.$dirty">The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).</span>
</p>
</div>
</div>
</div>
<div class="row">
<!-- Left column -->
<div class="col-md-6">
<div class="form-group">
<label translate>Folder Type</label>
&nbsp;<a href="http://docs.syncthing.net/users/foldermaster.html" target="_blank"><span class="fa fa-book"></span>&nbsp;<span translate>Help</span></a>
<select class="form-control" ng-model="currentFolder.type">
<option value="readwrite" translate>Normal</option>
<option value="readonly" translate>Master</option>
</select>
<p ng-if="currentFolder.type == 'readonly'" translate class="help-block">Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.</p>
</div>
<div class="form-group">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="currentFolder.ignorePerms"> <span translate>Ignore Permissions</span>
</label>
</div> </div>
<p translate class="help-block">File permission bits are ignored when looking for changes. Use on FAT file systems.</p>
</div>
</div>
<!-- Right column--> <!-- Right column-->
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label translate>File Pull Order</label> <label translate>File Pull Order</label>
<select class="form-control" ng-model="currentFolder.order"> <select class="form-control" ng-model="currentFolder.order">
<option value="random" translate>Random</option> <option value="random" translate>Random</option>
<option value="alphabetic" translate>Alphabetic</option> <option value="alphabetic" translate>Alphabetic</option>
<option value="smallestFirst" translate>Smallest First</option> <option value="smallestFirst" translate>Smallest First</option>
<option value="largestFirst" translate>Largest First</option> <option value="largestFirst" translate>Largest First</option>
<option value="oldestFirst" translate>Oldest First</option> <option value="oldestFirst" translate>Oldest First</option>
<option value="newestFirst" translate>Newest First</option> <option value="newestFirst" translate>Newest First</option>
</select> </select>
</div> </div>
<div class="form-group"> <div class="form-group">
<label translate>File Versioning</label>&emsp;<a href="http://docs.syncthing.net/users/versioning.html" target="_blank"><span class="fa fa-book"></span>&nbsp;<span translate>Help</span></a> <label translate>File Versioning</label>&emsp;<a href="http://docs.syncthing.net/users/versioning.html" target="_blank"><span class="fa fa-book"></span>&nbsp;<span translate>Help</span></a>
<select class="form-control" ng-model="currentFolder.fileVersioningSelector"> <select class="form-control" ng-model="currentFolder.fileVersioningSelector">
<option value="none" translate>No File Versioning</option> <option value="none" translate>No File Versioning</option>
<option value="trashcan" translate>Trash Can File Versioning</option> <option value="trashcan" translate>Trash Can File Versioning</option>
<option value="simple" translate>Simple File Versioning</option> <option value="simple" translate>Simple File Versioning</option>
<option value="staggered" translate>Staggered File Versioning</option> <option value="staggered" translate>Staggered File Versioning</option>
<option value="external" translate>External File Versioning</option> <option value="external" translate>External File Versioning</option>
</select> </select>
</div> </div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='trashcan'" ng-class="{'has-error': folderEditor.trashcanClean.$invalid && folderEditor.trashcanClean.$dirty}"> <div class="form-group" ng-if="currentFolder.fileVersioningSelector=='trashcan'" ng-class="{'has-error': folderEditor.trashcanClean.$invalid && folderEditor.trashcanClean.$dirty}">
<p translate class="help-block">Files are moved to .stversions folder when replaced or deleted by Syncthing.</p> <p translate class="help-block">Files are moved to .stversions folder when replaced or deleted by Syncthing.</p>
<label translate for="trashcanClean">Clean out after</label> <label translate for="trashcanClean">Clean out after</label>
<div class="input-group"> <div class="input-group">
<input name="trashcanClean" id="trashcanClean" class="form-control text-right" type="number" ng-model="currentFolder.trashcanClean" required min="0"> <input name="trashcanClean" id="trashcanClean" class="form-control text-right" type="number" ng-model="currentFolder.trashcanClean" required min="0">
<div class="input-group-addon" translate>days</div> <div class="input-group-addon" translate>days</div>
</div>
<p class="help-block">
<span translate ng-if="folderEditor.trashcanClean.$valid || folderEditor.trashcanClean.$pristine">The number of days to keep files in the trash can. Zero means forever.</span>
<span translate ng-if="folderEditor.trashcanClean.$error.required && folderEditor.trashcanClean.$dirty">The number of days must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.trashcanClean.$error.min && folderEditor.trashcanClean.$dirty">A negative number of days doesn't make sense.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='simple'" ng-class="{'has-error': folderEditor.simpleKeep.$invalid && folderEditor.simpleKeep.$dirty}">
<p translate class="help-block">Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.</p>
<label translate for="simpleKeep">Keep Versions</label>
<input name="simpleKeep" id="simpleKeep" class="form-control" type="number" ng-model="currentFolder.simpleKeep" required min="1">
<p class="help-block">
<span translate ng-if="folderEditor.simpleKeep.$valid || folderEditor.simpleKeep.$pristine">The number of old versions to keep, per file.</span>
<span translate ng-if="folderEditor.simpleKeep.$error.required && folderEditor.simpleKeep.$dirty">The number of versions must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.simpleKeep.$error.min && folderEditor.simpleKeep.$dirty">You must keep at least one version.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='staggered'" ng-class="{'has-error': folderEditor.staggeredMaxAge.$invalid && folderEditor.staggeredMaxAge.$dirty}">
<p class="help-block"><span translate>Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.</span> <span translate>Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.</span></p>
<p translate class="help-block">The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.</p>
<label translate for="staggeredMaxAge">Maximum Age</label>
<input name="staggeredMaxAge" id="staggeredMaxAge" class="form-control" type="number" ng-model="currentFolder.staggeredMaxAge" required min="0">
<p class="help-block">
<span translate ng-if="folderEditor.staggeredMaxAge.$valid || folderEditor.staggeredMaxAge.$pristine">The maximum time to keep a version (in days, set to 0 to keep versions forever).</span>
<span translate ng-if="folderEditor.staggeredMaxAge.$error.required && folderEditor.staggeredMaxAge.$dirty">The maximum age must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.staggeredMaxAge.$error.min && folderEditor.staggeredMaxAge.$dirty">A negative number of days doesn't make sense.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector == 'staggered'">
<label translate for="staggeredVersionsPath">Versions Path</label>
<input name="staggeredVersionsPath" id="staggeredVersionsPath" class="form-control" type="text" ng-model="currentFolder.staggeredVersionsPath">
<p translate class="help-block">Path where versions should be stored (leave empty for the default .stversions folder in the folder).</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='external'" ng-class="{'has-error': folderEditor.externalCommand.$invalid && folderEditor.externalCommand.$dirty}">
<p translate class="help-block">An external command handles the versioning. It has to remove the file from the synced folder.</p>
<label translate for="externalCommand">Command</label>
<input name="externalCommand" id="externalCommand" class="form-control" type="text" ng-model="currentFolder.externalCommand" required>
<p class="help-block">
<span translate ng-if="folderEditor.externalCommand.$valid || folderEditor.externalCommand.$pristine">The first command line parameter is the folder path and the second parameter is the relative path in the folder.</span>
<span translate ng-if="folderEditor.externalCommand.$error.required && folderEditor.externalCommand.$dirty">The path cannot be blank.</span>
</p>
</div>
</div> </div>
<p class="help-block">
<span translate ng-if="folderEditor.trashcanClean.$valid || folderEditor.trashcanClean.$pristine">The number of days to keep files in the trash can. Zero means forever.</span>
<span translate ng-if="folderEditor.trashcanClean.$error.required && folderEditor.trashcanClean.$dirty">The number of days must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.trashcanClean.$error.min && folderEditor.trashcanClean.$dirty">A negative number of days doesn't make sense.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='simple'" ng-class="{'has-error': folderEditor.simpleKeep.$invalid && folderEditor.simpleKeep.$dirty}">
<p translate class="help-block">Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.</p>
<label translate for="simpleKeep">Keep Versions</label>
<input name="simpleKeep" id="simpleKeep" class="form-control" type="number" ng-model="currentFolder.simpleKeep" required min="1">
<p class="help-block">
<span translate ng-if="folderEditor.simpleKeep.$valid || folderEditor.simpleKeep.$pristine">The number of old versions to keep, per file.</span>
<span translate ng-if="folderEditor.simpleKeep.$error.required && folderEditor.simpleKeep.$dirty">The number of versions must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.simpleKeep.$error.min && folderEditor.simpleKeep.$dirty">You must keep at least one version.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='staggered'" ng-class="{'has-error': folderEditor.staggeredMaxAge.$invalid && folderEditor.staggeredMaxAge.$dirty}">
<p class="help-block"><span translate>Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.</span> <span translate>Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.</span></p>
<p translate class="help-block">The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.</p>
<label translate for="staggeredMaxAge">Maximum Age</label>
<input name="staggeredMaxAge" id="staggeredMaxAge" class="form-control" type="number" ng-model="currentFolder.staggeredMaxAge" required min="0">
<p class="help-block">
<span translate ng-if="folderEditor.staggeredMaxAge.$valid || folderEditor.staggeredMaxAge.$pristine">The maximum time to keep a version (in days, set to 0 to keep versions forever).</span>
<span translate ng-if="folderEditor.staggeredMaxAge.$error.required && folderEditor.staggeredMaxAge.$dirty">The maximum age must be a number and cannot be blank.</span>
<span translate ng-if="folderEditor.staggeredMaxAge.$error.min && folderEditor.staggeredMaxAge.$dirty">A negative number of days doesn't make sense.</span>
</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector == 'staggered'">
<label translate for="staggeredVersionsPath">Versions Path</label>
<input name="staggeredVersionsPath" id="staggeredVersionsPath" class="form-control" type="text" ng-model="currentFolder.staggeredVersionsPath">
<p translate class="help-block">Path where versions should be stored (leave empty for the default .stversions folder in the folder).</p>
</div>
<div class="form-group" ng-if="currentFolder.fileVersioningSelector=='external'" ng-class="{'has-error': folderEditor.externalCommand.$invalid && folderEditor.externalCommand.$dirty}">
<p translate class="help-block">An external command handles the versioning. It has to remove the file from the synced folder.</p>
<label translate for="externalCommand">Command</label>
<input name="externalCommand" id="externalCommand" class="form-control" type="text" ng-model="currentFolder.externalCommand" required>
<p class="help-block">
<span translate ng-if="folderEditor.externalCommand.$valid || folderEditor.externalCommand.$pristine">The first command line parameter is the folder path and the second parameter is the relative path in the folder.</span>
<span translate ng-if="folderEditor.externalCommand.$error.required && folderEditor.externalCommand.$dirty">The path cannot be blank.</span>
</p>
</div> </div>
</div> </div>
</form> </div>
</div> </div>
<div class="modal-footer"> </form>
<button type="button" class="btn btn-primary btn-sm" ng-click="saveFolder()" ng-disabled="folderEditor.$invalid">
<span class="fa fa-check"></span>&nbsp;<span translate>Save</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
<button type="button" class="btn btn-warning pull-left btn-sm" ng-click="deleteFolder(currentFolder.id)" ng-if="editingExisting">
<span class="fa fa-minus-circle"></span>&nbsp;<span translate>Remove</span>
</button>
<button type="button" class="btn btn-default pull-left btn-sm" id="editIgnoresButton" ng-click="editIgnores()" ng-if="editingExisting">
<span class="fa fa-eye-slash"></span>&nbsp;<span translate>Ignore Patterns</span>
</button>
</div>
</div>
</div> </div>
</div> <div class="modal-footer">
<button type="button" class="btn btn-primary btn-sm" ng-click="saveFolder()" ng-disabled="folderEditor.$invalid">
<span class="fa fa-check"></span>&nbsp;<span translate>Save</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
<button type="button" class="btn btn-warning pull-left btn-sm" ng-click="deleteFolder(currentFolder.id)" ng-if="editingExisting">
<span class="fa fa-minus-circle"></span>&nbsp;<span translate>Remove</span>
</button>
<button type="button" class="btn btn-default pull-left btn-sm" id="editIgnoresButton" ng-click="editIgnores()" ng-if="editingExisting">
<span class="fa fa-eye-slash"></span>&nbsp;<span translate>Ignore Patterns</span>
</button>
</div>
</modal>

View File

@ -1,7 +0,0 @@
angular.module('syncthing.folder')
.directive('editIgnoresModal', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/folder/editIgnoresModalView.html'
};
});

View File

@ -1,32 +1,25 @@
<div id="editIgnores" class="modal fade" tabindex="-1"> <modal id="editIgnores" status="default" heading="{{'Ignore Patterns' | translate}}" large="yes" closeable="yes">
<div class="modal-dialog modal-lg"> <div class="modal-body">
<div class="modal-content"> <p translate>Enter ignore patterns, one per line.</p>
<div class="modal-header"> <textarea class="form-control" rows="15"></textarea>
<h4 class="modal-title" translate>Ignore Patterns</h4>
</div>
<div class="modal-body">
<p translate>Enter ignore patterns, one per line.</p>
<textarea class="form-control" rows="15"></textarea>
<hr/> <hr/>
<p class="small"><span translate>Quick guide to supported patterns</span> (<a href="http://docs.syncthing.net/users/ignoring.html" target="_blank" translate>full documentation</a>):</p> <p class="small"><span translate>Quick guide to supported patterns</span> (<a href="http://docs.syncthing.net/users/ignoring.html" target="_blank" translate>full documentation</a>):</p>
<dl class="dl-horizontal dl-narrow small"> <dl class="dl-horizontal dl-narrow small">
<dt><code>!</code></dt> <dd><span translate>Inversion of the given condition (i.e. do not exclude)</span></dd> <dt><code>!</code></dt> <dd><span translate>Inversion of the given condition (i.e. do not exclude)</span></dd>
<dt><code>*</code></dt> <dd><span translate>Single level wildcard (matches within a directory only)</span></dd> <dt><code>*</code></dt> <dd><span translate>Single level wildcard (matches within a directory only)</span></dd>
<dt><code>**</code></dt> <dd><span translate>Multi level wildcard (matches multiple directory levels)</span></dd> <dt><code>**</code></dt> <dd><span translate>Multi level wildcard (matches multiple directory levels)</span></dd>
<dt><code>//</code></dt> <dd><span translate>Comment, when used at the start of a line</span></dd> <dt><code>//</code></dt> <dd><span translate>Comment, when used at the start of a line</span></dd>
</dl> </dl>
</div>
<div class="modal-footer">
<div class="pull-left"><span translate>Editing</span> <code>{{currentFolder.path}}{{system.pathSeparator}}.stignore</code></div>
<button type="button" class="btn btn-primary btn-sm" ng-click="saveIgnores()" data-dismiss="modal">
<span class="fa fa-check"></span>&nbsp;<span translate>Save</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
</div>
</div> </div>
</div> <div class="modal-footer">
<div class="pull-left"><span translate>Editing</span> <code>{{currentFolder.path}}{{system.pathSeparator}}.stignore</code></div>
<button type="button" class="btn btn-primary btn-sm" ng-click="saveIgnores()" data-dismiss="modal">
<span class="fa fa-check"></span>&nbsp;<span translate>Save</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
</modal>

View File

@ -1 +0,0 @@
angular.module('syncthing.folder', []);

View File

@ -1,7 +0,0 @@
angular.module('syncthing.settings')
.directive('advancedSettingsModal', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/settings/advancedSettingsModalView.html'
};
});

View File

@ -1,92 +1,82 @@
<div id="advanced" class="modal fade" tabindex="-1"> <modal id="advanced" status="danger" icon="cog" heading="{{'Advanced Configuration' | translate}}" large="yes" closeable="yes">
<div class="modal-dialog modal-lg"> <div class="modal-body">
<div class="modal-content">
<div class="modal-header alert alert-danger"> <p class="text-danger">
<h4 class="modal-title"> <b translate>Be careful!</b>
<div class="panel-icon"> <span translate>Incorrect configuration may damage your folder contents and render Syncthing inoperable.</span>
<span class="fa fa-cog"></span> </p>
</div>
<span translate>Advanced Configuration</span> <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 advancedConfig.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="advancedConfig.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 advancedConfig.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="advancedConfig.options[key]" />
</div>
</div>
</form>
</div>
</div>
</div>
<div class="panel panel-default" ng-repeat="folder in advancedConfig.folders">
<div class="panel-heading" role="tab" id="folder{{$index}}Heading" data-toggle="collapse" data-parent="#advancedAccordion" href="#folder{{$index}}Config" aria-expanded="true" aria-controls="folder{{$index}}Config" style="cursor: pointer">
<h4 ng-if="folder.label.length == 0" class="panel-title">
<span translate>Folder</span> "{{folder.id}}"
</h4>
<h4 ng-if="folder.label.length != 0" class="panel-title">
<span translate>Folder</span> "{{folder.label}}" ({{folder.id}})
</h4> </h4>
</div> </div>
<div class="modal-body"> <div id="folder{{$index}}Config" class="panel-collapse collapse" role="tabpanel" aria-labelledby="folder{{$index}}Heading">
<div class="panel-body">
<p class="text-danger"> <form class="form-horizontal" role="form">
<b translate>Be careful!</b> <div ng-repeat="(key, value) in folder" ng-if="inputTypeFor(key, value) != 'skip'" class="form-group">
<span translate>Incorrect configuration may damage your folder contents and render Syncthing inoperable.</span> <label for="folder{{$index}}Input{{$index}}" class="col-sm-4 control-label">{{key}}</label>
</p> <div class="col-sm-8">
<input id="folder{{$index}}Input{{$index}}" class="form-control" type="{{inputTypeFor(key, value)}}" ng-model="folder[key]" />
<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 advancedConfig.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="advancedConfig.gui[key]" />
</div>
</div>
</form>
</div> </div>
</div> </div>
</div> </form>
<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 advancedConfig.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="advancedConfig.options[key]" />
</div>
</div>
</form>
</div>
</div>
</div>
<div class="panel panel-default" ng-repeat="folder in advancedConfig.folders">
<div class="panel-heading" role="tab" id="folder{{$index}}Heading" data-toggle="collapse" data-parent="#advancedAccordion" href="#folder{{$index}}Config" aria-expanded="true" aria-controls="folder{{$index}}Config" style="cursor: pointer">
<h4 ng-if="folder.label.length == 0" class="panel-title">
<span translate>Folder</span> "{{folder.id}}"
</h4>
<h4 ng-if="folder.label.length != 0" class="panel-title">
<span translate>Folder</span> "{{folder.label}}" ({{folder.id}})
</h4>
</div>
<div id="folder{{$index}}Config" class="panel-collapse collapse" role="tabpanel" aria-labelledby="folder{{$index}}Heading">
<div class="panel-body">
<form class="form-horizontal" role="form">
<div ng-repeat="(key, value) in folder" ng-if="inputTypeFor(key, value) != 'skip'" class="form-group">
<label for="folder{{$index}}Input{{$index}}" class="col-sm-4 control-label">{{key}}</label>
<div class="col-sm-8">
<input id="folder{{$index}}Input{{$index}}" class="form-control" type="{{inputTypeFor(key, value)}}" ng-model="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="fa fa-check"></span>&nbsp;<span translate>Save</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="modal-footer">
<button type="button" class="btn btn-primary btn-sm" ng-click="saveAdvanced()">
<span class="fa fa-check"></span>&nbsp;<span translate>Save</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
</div> </div>
</modal>

View File

@ -1 +0,0 @@
angular.module('syncthing.settings', []);

View File

@ -1,7 +0,0 @@
angular.module('syncthing.settings')
.directive('settingsModal', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/settings/settingsModalView.html'
};
});

View File

@ -1,167 +1,157 @@
<div id="settings" class="modal fade" tabindex="-1"> <modal id="settings" status="default" icon="cog" heading="{{'Settings' | translate}}" large="yes" closeable="yes">
<div class="modal-dialog modal-lg"> <div class="modal-body">
<div class="modal-content"> <form role="form" name="settingsEditor">
<div class="modal-header"> <div class="row">
<h4 class="modal-title">
<div class="panel-icon">
<span class="fa fa-cog"></span>
</div>
<span translate>Settings</span>
</h4>
</div>
<div class="modal-body">
<form role="form" name="settingsEditor">
<div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label translate for="DeviceName">Device Name</label> <label translate for="DeviceName">Device Name</label>
<input id="DeviceName" class="form-control" type="text" ng-model="tmpOptions.deviceName"> <input id="DeviceName" class="form-control" type="text" ng-model="tmpOptions.deviceName">
</div> </div>
<div class="form-group"> <div class="form-group">
<label translate for="ListenAddressesStr">Sync Protocol Listen Addresses</label> <label translate for="ListenAddressesStr">Sync Protocol Listen Addresses</label>
<input id="ListenAddressesStr" class="form-control" type="text" ng-model="tmpOptions._listenAddressesStr"> <input id="ListenAddressesStr" class="form-control" type="text" ng-model="tmpOptions._listenAddressesStr">
</div> </div>
<div class="form-group" ng-class="{'has-error': settingsEditor.MaxRecvKbps.$invalid && settingsEditor.MaxRecvKbps.$dirty}"> <div class="form-group" ng-class="{'has-error': settingsEditor.MaxRecvKbps.$invalid && settingsEditor.MaxRecvKbps.$dirty}">
<label translate for="MaxRecvKbps">Incoming Rate Limit (KiB/s)</label> <label translate for="MaxRecvKbps">Incoming Rate Limit (KiB/s)</label>
<input id="MaxRecvKbps" name="MaxRecvKbps" class="form-control" type="number" ng-model="tmpOptions.maxRecvKbps" min="0"> <input id="MaxRecvKbps" name="MaxRecvKbps" class="form-control" type="number" ng-model="tmpOptions.maxRecvKbps" min="0">
<p class="help-block"> <p class="help-block">
<span translate ng-if="settingsEditor.MaxRecvKbps.$error.min && settingsEditor.MaxRecvKbps.$dirty">The rate limit must be a non-negative number (0: no limit)</span> <span translate ng-if="settingsEditor.MaxRecvKbps.$error.min && settingsEditor.MaxRecvKbps.$dirty">The rate limit must be a non-negative number (0: no limit)</span>
</p> </p>
</div> </div>
<div class="form-group" ng-class="{'has-error': settingsEditor.MaxSendKbps.$invalid && settingsEditor.MaxSendKbps.$dirty}"> <div class="form-group" ng-class="{'has-error': settingsEditor.MaxSendKbps.$invalid && settingsEditor.MaxSendKbps.$dirty}">
<label translate for="MaxSendKbps">Outgoing Rate Limit (KiB/s)</label> <label translate for="MaxSendKbps">Outgoing Rate Limit (KiB/s)</label>
<input id="MaxSendKbps" name="MaxSendKbps" class="form-control" type="number" ng-model="tmpOptions.maxSendKbps" min="0"> <input id="MaxSendKbps" name="MaxSendKbps" class="form-control" type="number" ng-model="tmpOptions.maxSendKbps" min="0">
<p class="help-block"> <p class="help-block">
<span translate ng-if="settingsEditor.MaxSendKbps.$error.min && settingsEditor.MaxSendKbps.$dirty">The rate limit must be a non-negative number (0: no limit)</span> <span translate ng-if="settingsEditor.MaxSendKbps.$error.min && settingsEditor.MaxSendKbps.$dirty">The rate limit must be a non-negative number (0: no limit)</span>
</p> </p>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input id="NATEnabled" type="checkbox" ng-model="tmpOptions.natEnabled"> <span translate>Enable NAT traversal</span> <input id="NATEnabled" type="checkbox" ng-model="tmpOptions.natEnabled"> <span translate>Enable NAT traversal</span>
</label> </label>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<div class="checkbox">
<label>
<input id="LocalAnnEnabled" type="checkbox" ng-model="tmpOptions.localAnnounceEnabled"> <span translate>Local Discovery</span>
</label>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-6">
<div class="row"> <div class="form-group">
<div class="col-md-6"> <div class="checkbox">
<div class="form-group"> <label>
<div class="checkbox"> <input id="LocalAnnEnabled" type="checkbox" ng-model="tmpOptions.localAnnounceEnabled"> <span translate>Local Discovery</span>
<label> </label>
<input id="GlobalAnnEnabled" type="checkbox" ng-model="tmpOptions.globalAnnounceEnabled"> <span translate>Global Discovery</span>
</label>
</div>
</div> </div>
</div> </div>
<div class="col-md-6">
<div class="form-group">
<div class="checkbox">
<label>
<input id="RelaysEnabled" type="checkbox" ng-model="tmpOptions.relaysEnabled"> <span translate>Enable Relaying</span>
</label>
</div>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="form-group">
<label translate for="GlobalAnnServersStr">Global Discovery Servers</label>
<input ng-disabled="!tmpOptions.globalAnnounceEnabled" id="GlobalAnnServersStr" class="form-control" type="text" ng-model="tmpOptions._globalAnnounceServersStr">
</div> </div>
</div> </div>
<div class="col-md-6"> <div class="row">
<div class="form-group"> <div class="col-md-6">
<label translate for="Address">GUI Listen Addresses</label> <div class="form-group">
<input id="Address" class="form-control" type="text" ng-model="tmpGUI.address"> <div class="checkbox">
</div> <label>
<div class="form-group"> <input id="GlobalAnnEnabled" type="checkbox" ng-model="tmpOptions.globalAnnounceEnabled"> <span translate>Global Discovery</span>
<label translate for="User">GUI Authentication User</label> </label>
<input id="User" class="form-control" type="text" ng-model="tmpGUI.user"> </div>
</div>
<div class="form-group">
<label translate for="Password">GUI Authentication Password</label>
<input id="Password" class="form-control" type="password" ng-model="tmpGUI.password">
</div>
<div class="form-group">
<div class="checkbox">
<label>
<input id="UseTLS" type="checkbox" ng-model="tmpGUI.useTLS"> <span translate>Use HTTPS for GUI</span>
</label>
</div> </div>
</div> </div>
<div class="form-group"> <div class="col-md-6">
<div class="checkbox"> <div class="form-group">
<label> <div class="checkbox">
<input id="StartBrowser" type="checkbox" ng-model="tmpOptions.startBrowser"> <span translate>Start Browser</span> <label>
</label> <input id="RelaysEnabled" type="checkbox" ng-model="tmpOptions.relaysEnabled"> <span translate>Enable Relaying</span>
</div> </label>
</div> </div>
<div class="form-group">
<div class="checkbox">
<label>
<input id="UREnabled" type="checkbox" ng-model="tmpOptions.urEnabled"> <span translate>Anonymous Usage Reporting</span> (<a translate ng-click="showURPreview()" href="#">Preview</a>)
</label>
</div>
</div>
<div class="form-group" ng-if="upgradeInfo">
<div class="checkbox">
<label>
<input id="AutoUpgradeEnabled" type="checkbox" ng-model="tmpOptions.autoUpgradeEnabled"> <span translate>Automatic upgrades</span>
</label>
</div> </div>
</div> </div>
</div>
<hr /> <div class="clearfix"></div>
<div class="form-group">
<div class="form-group"> <label translate for="GlobalAnnServersStr">Global Discovery Servers</label>
<label translate>API Key</label> <input ng-disabled="!tmpOptions.globalAnnounceEnabled" id="GlobalAnnServersStr" class="form-control" type="text" ng-model="tmpOptions._globalAnnounceServersStr">
<div class="well well-sm text-monospace" select-on-click>{{tmpGUI.apiKey || "-"}}</div>
<button type="button" class="btn btn-sm btn-default" ng-click="setAPIKey(tmpGUI)">
<span class="fa fa-repeat"></span>&nbsp;<span translate>Generate</span>
</button>
</div>
<div class="form-group" ng-if="themes.length > 1">
<label>GUI Theme</label>
<select class="form-control" ng-model="tmpGUI.theme">
<option ng-repeat="theme in themes.sort()" value="{{ theme }}">
{{ themeName(theme) }}
</option>
</select>
</div>
</div> </div>
</div> </div>
</form>
</div> <div class="col-md-6">
<div class="modal-footer"> <div class="form-group">
<button type="button" class="btn btn-primary btn-sm" ng-click="saveSettings()"> <label translate for="Address">GUI Listen Addresses</label>
<span class="fa fa-check"></span>&nbsp;<span translate>Save</span> <input id="Address" class="form-control" type="text" ng-model="tmpGUI.address">
</button> </div>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal"> <div class="form-group">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span> <label translate for="User">GUI Authentication User</label>
</button> <input id="User" class="form-control" type="text" ng-model="tmpGUI.user">
</div> </div>
<div class="form-group">
<label translate for="Password">GUI Authentication Password</label>
<input id="Password" class="form-control" type="password" ng-model="tmpGUI.password">
</div>
<div class="form-group">
<div class="checkbox">
<label>
<input id="UseTLS" type="checkbox" ng-model="tmpGUI.useTLS"> <span translate>Use HTTPS for GUI</span>
</label>
</div>
</div>
<div class="form-group">
<div class="checkbox">
<label>
<input id="StartBrowser" type="checkbox" ng-model="tmpOptions.startBrowser"> <span translate>Start Browser</span>
</label>
</div>
</div>
<div class="form-group">
<div class="checkbox">
<label>
<input id="UREnabled" type="checkbox" ng-model="tmpOptions.urEnabled"> <span translate>Anonymous Usage Reporting</span> (<a href="" translate data-toggle="modal" data-target="#urPreview">Preview</a>)
</label>
</div>
</div>
<div class="form-group" ng-if="upgradeInfo">
<div class="checkbox">
<label>
<input id="AutoUpgradeEnabled" type="checkbox" ng-model="tmpOptions.autoUpgradeEnabled"> <span translate>Automatic upgrades</span>
</label>
</div>
</div>
<hr />
<div class="form-group">
<label translate>API Key</label>
<div class="well well-sm text-monospace" select-on-click>{{tmpGUI.apiKey || "-"}}</div>
<button type="button" class="btn btn-sm btn-default" ng-click="setAPIKey(tmpGUI)">
<span class="fa fa-repeat"></span>&nbsp;<span translate>Generate</span>
</button>
</div>
<div class="form-group" ng-if="themes.length > 1">
<label>GUI Theme</label>
<select class="form-control" ng-model="tmpGUI.theme">
<option ng-repeat="theme in themes.sort()" value="{{ theme }}">
{{ themeName(theme) }}
</option>
</select>
</div>
</div>
</div>
</form>
</div> </div>
</div>
</div> <div class="modal-footer">
<button type="button" class="btn btn-primary btn-sm" ng-click="saveSettings()">
<span class="fa fa-check"></span>&nbsp;<span translate>Save</span>
</button>
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
</modal>

View File

@ -1,7 +0,0 @@
angular.module('syncthing.transfer')
.directive('failedFilesModal', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/transfer/failedFilesModalView.html'
};
});

View File

@ -1,19 +1,26 @@
<modal id="failed" status="warning" icon="exclamation-circle" heading="{{'Failed Items' | translate}}" large="yes" close="yes"> <modal id="failed" status="warning" icon="exclamation-circle" heading="{{'Failed Items' | translate}}" large="yes" closeable="yes">
<p> <div class="modal-body">
<span translate>The following items could not be synchronized.</span> <p>
<span translate>They are retried automatically and will be synced when the error is resolved.</span> <span translate>The following items could not be synchronized.</span>
</p> <span translate>They are retried automatically and will be synced when the error is resolved.</span>
<table class="table table-striped table-condensed"> </p>
<tr dir-paginate="e in failedCurrent | itemsPerPage: failedPageSize" current-page="failedCurrentPage" pagination-id="failed"> <table class="table table-striped table-condensed">
<td><abbr tooltip data-original-title="{{e.path}}">{{e.path | basename}}</abbr></td> <tr dir-paginate="e in failedCurrent | itemsPerPage: failedPageSize" current-page="failedCurrentPage" pagination-id="failed">
<td><abbr tooltip data-original-title="{{e.error}}">{{e.error | lastErrorComponent}}</abbr></td> <td><abbr tooltip data-original-title="{{e.path}}">{{e.path | basename}}</abbr></td>
</tr> <td><abbr tooltip data-original-title="{{e.error}}">{{e.error | lastErrorComponent}}</abbr></td>
</table> </tr>
<dir-pagination-controls on-page-change="failedPageChanged(newPageNumber)" pagination-id="failed"></dir-pagination-controls> </table>
<ul class="pagination pull-right"> <dir-pagination-controls on-page-change="failedPageChanged(newPageNumber)" pagination-id="failed"></dir-pagination-controls>
<li ng-repeat="option in [10, 25, 50]" ng-class="{ active: failedPageSize == option }"> <ul class="pagination pull-right">
<a href="#" ng-click="failedChangePageSize(option)">{{option}}</a> <li ng-repeat="option in [10, 25, 50]" ng-class="{ active: failedPageSize == option }">
<li> <a href="#" ng-click="failedChangePageSize(option)">{{option}}</a>
</ul> <li>
<div class="clearfix"></div> </ul>
<div class="clearfix"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
</modal> </modal>

View File

@ -1 +0,0 @@
angular.module('syncthing.transfer', []);

View File

@ -1,7 +0,0 @@
angular.module('syncthing.transfer')
.directive('neededFilesModal', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/transfer/neededFilesModalView.html'
};
});

View File

@ -1,54 +1,65 @@
<modal id="needed" status="info" icon="cloud-download" heading="{{'Out of Sync Items' | translate}}" large="yes" close="yes" tabindex="-1"> <modal id="needed" status="info" icon="cloud-download" heading="{{'Out of Sync Items' | translate}}" large="yes" closeable="yes">
<div class="progress">
<div class="progress-bar progress-bar-success" style="width: 20%"><span translate class="show">Reused</span></div> <div class="modal-body">
<div class="progress-bar" style="width: 20%"><span translate class="show">Copied from original</span></div>
<div class="progress-bar progress-bar-info" style="width: 20%"><span translate class="show">Copied from elsewhere</span></div> <div class="progress">
<div class="progress-bar progress-bar-warning" style="width: 20%"><span translate class="show">Downloaded</span></div> <div class="progress-bar progress-bar-success" style="width: 20%"><span translate class="show">Reused</span></div>
<div class="progress-bar progress-bar-danger progress-bar-striped active" style="width: 20%"><span translate class="show">Downloading</span></div> <div class="progress-bar" style="width: 20%"><span translate class="show">Copied from original</span></div>
<div class="progress-bar progress-bar-info" style="width: 20%"><span translate class="show">Copied from elsewhere</span></div>
<div class="progress-bar progress-bar-warning" style="width: 20%"><span translate class="show">Downloaded</span></div>
<div class="progress-bar progress-bar-danger progress-bar-striped active" style="width: 20%"><span translate class="show">Downloading</span></div>
</div>
<hr/>
<table class="table table-striped table-condensed">
<tr dir-paginate="f in needed | itemsPerPage: neededPageSize" current-page="neededCurrentPage" total-items="neededTotal" pagination-id="needed">
<!-- Icon -->
<td class="small-data"><span class="fa fa-fw fa-{{needIcons[f.action]}}"></span> {{needActions[f.action]}}</td>
<!-- Name -->
<td ng-if="f.type != 'queued'" tooltip data-original-title="{{f.name}}">{{f.name | basename}}</td>
<td ng-if="f.type == 'queued'">
<a href="" ng-click="bumpFile(neededFolder, f.name)" tooltip data-original-title="{{'Move to top of queue' | translate}}">
<span class="fa fa-eject"></span>
</a>
<span tooltip data-original-title="{{f.name}}">&nbsp;{{f.name | basename}}</span>
</td>
<!-- Size/Progress -->
<td ng-if="f.type == 'progress' && f.action == 'sync' && progress[neededFolder] && progress[neededFolder][f.name]">
<div class="progress">
<div class="progress-bar progress-bar-success" style="width: {{progress[neededFolder][f.name].reused}}%"></div>
<div class="progress-bar" style="width: {{progress[neededFolder][f.name].copiedFromOrigin}}%"></div>
<div class="progress-bar progress-bar-info" style="width: {{progress[neededFolder][f.name].copiedFromElsewhere}}%"></div>
<div class="progress-bar progress-bar-warning" style="width: {{progress[neededFolder][f.name].pulled}}%"></div>
<div class="progress-bar progress-bar-danger progress-bar-striped active" style="width: {{progress[neededFolder][f.name].pulling}}%"></div>
<span class="show frontal">
{{progress[neededFolder][f.name].bytesDone | binary}}B / {{progress[neededFolder][f.name].bytesTotal | binary}}B
</span>
</div>
</td>
<td class="text-right small-data" ng-if="f.type != 'progress' || f.action != 'sync' || !progress[neededFolder] || !progress[neededFolder][f.name]">
<span ng-if="f.size > 0">{{f.size | binary}}B</span>
</td>
</tr>
</table>
<dir-pagination-controls on-page-change="neededPageChanged(newPageNumber)" pagination-id="needed"></dir-pagination-controls>
<ul class="pagination pull-right">
<li ng-repeat="option in [10, 25, 50]" ng-class="{ active: neededPageSize == option }">
<a href="#" ng-click="neededChangePageSize(option)">{{option}}</a>
<li>
</ul>
<div class="clearfix"></div>
</div> </div>
<hr/> <div class="modal-footer">
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
<table class="table table-striped table-condensed">
<tr dir-paginate="f in needed | itemsPerPage: neededPageSize" current-page="neededCurrentPage" total-items="neededTotal" pagination-id="needed">
<!-- Icon -->
<td class="small-data"><span class="fa fa-fw fa-{{needIcons[f.action]}}"></span> {{needActions[f.action]}}</td>
<!-- Name -->
<td ng-if="f.type != 'queued'" tooltip data-original-title="{{f.name}}">{{f.name | basename}}</td>
<td ng-if="f.type == 'queued'">
<a href="" ng-click="bumpFile(neededFolder, f.name)" tooltip data-original-title="{{'Move to top of queue' | translate}}">
<span class="fa fa-eject"></span>
</a>
<span tooltip data-original-title="{{f.name}}">&nbsp;{{f.name | basename}}</span>
</td>
<!-- Size/Progress -->
<td ng-if="f.type == 'progress' && f.action == 'sync' && progress[neededFolder] && progress[neededFolder][f.name]">
<div class="progress">
<div class="progress-bar progress-bar-success" style="width: {{progress[neededFolder][f.name].reused}}%"></div>
<div class="progress-bar" style="width: {{progress[neededFolder][f.name].copiedFromOrigin}}%"></div>
<div class="progress-bar progress-bar-info" style="width: {{progress[neededFolder][f.name].copiedFromElsewhere}}%"></div>
<div class="progress-bar progress-bar-warning" style="width: {{progress[neededFolder][f.name].pulled}}%"></div>
<div class="progress-bar progress-bar-danger progress-bar-striped active" style="width: {{progress[neededFolder][f.name].pulling}}%"></div>
<span class="show frontal">
{{progress[neededFolder][f.name].bytesDone | binary}}B / {{progress[neededFolder][f.name].bytesTotal | binary}}B
</span>
</div>
</td>
<td class="text-right small-data" ng-if="f.type != 'progress' || f.action != 'sync' || !progress[neededFolder] || !progress[neededFolder][f.name]">
<span ng-if="f.size > 0">{{f.size | binary}}B</span>
</td>
</tr>
</table>
<dir-pagination-controls on-page-change="neededPageChanged(newPageNumber)" pagination-id="needed"></dir-pagination-controls>
<ul class="pagination pull-right">
<li ng-repeat="option in [10, 25, 50]" ng-class="{ active: neededPageSize == option }">
<a href="#" ng-click="neededChangePageSize(option)">{{option}}</a>
<li>
</ul>
<div class="clearfix"></div>
</modal> </modal>

View File

@ -1 +0,0 @@
angular.module('syncthing.usagereport', []);

View File

@ -1,7 +0,0 @@
angular.module('syncthing.usagereport')
.directive('usageReportModal', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/usagereport/usageReportModalView.html'
};
});

View File

@ -1,26 +1,19 @@
<div id="ur" class="modal fade" data-backdrop="static" data-keyboard="false" tabindex="-1"> <modal id="ur" status="info" icon="bar-chart" heading="{{'Allow Anonymous Usage Reporting?' | translate}}" large="yes" closeable="no">
<div class="modal-dialog modal-lg"> <div class="modal-body">
<div class="modal-content"> <p translate>The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.</p>
<div class="modal-header alert alert-info"> <p translate>The aggregated statistics are publicly available at the URL below.</p>
<h4 class="modal-title"><span class="fa fa-bar-chart"></span><span translate>Allow Anonymous Usage Reporting?</span></h4> <p><a href="https://data.syncthing.net/" target="_blank">https://data.syncthing.net/</a></p>
</div> <button type="button" class="btn btn-default btn-sm" ng-click="showReportPreview()" ng-show="!reportPreview">
<div class="modal-body"> <span class="fa fa-file-text-o"></span>&nbsp;<span translate>Preview Usage Report</span>
<p translate>The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.</p> </button>
<p translate>The aggregated statistics are publicly available at the URL below.</p> <pre ng-if="reportPreview"><small>{{reportData | json}}</small></pre>
<p><a href="https://data.syncthing.net/" target="_blank">https://data.syncthing.net/</a></p>
<button type="button" class="btn btn-default btn-sm" ng-click="showReportPreview()" ng-show="!reportPreview">
<span class="fa fa-file-text-o"></span>&nbsp;<span translate>Preview Usage Report</span>
</button>
<pre ng-if="reportPreview"><small>{{reportData | json}}</small></pre>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success btn-sm" ng-click="acceptUR()">
<span class="fa fa-check"></span>&nbsp;<span translate>Yes</span>
</button>
<button type="button" class="btn btn-danger btn-sm" ng-click="declineUR()">
<span class="fa fa-times"></span>&nbsp;<span translate>No</span>
</button>
</div>
</div> </div>
</div> <div class="modal-footer">
</div> <button type="button" class="btn btn-success btn-sm" ng-click="acceptUR()">
<span class="fa fa-check"></span>&nbsp;<span translate>Yes</span>
</button>
<button type="button" class="btn btn-danger btn-sm" ng-click="declineUR()">
<span class="fa fa-times"></span>&nbsp;<span translate>No</span>
</button>
</div>
</modal>

View File

@ -1,7 +0,0 @@
angular.module('syncthing.usagereport')
.directive('usageReportPreviewModal', function () {
return {
restrict: 'A',
templateUrl: 'syncthing/usagereport/usageReportPreviewModalView.html'
};
});

View File

@ -1,7 +1,18 @@
<modal id="urPreview" status="success" icon="bar-chart" heading="{{'Anonymous Usage Reporting' | translate}}" large="yes" close="yes" tabindex="-1"> <modal id="urPreview" status="success" icon="bar-chart" heading="{{'Anonymous Usage Reporting' | translate}}" large="yes" closeable="yes">
<p translate>The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.</p> <div class="modal-body">
<p translate translate-value-url="<a href=&quot;https://data.syncthing.net&quot; target=&quot;_blank&quot;>https://data.syncthing.net</a>">The aggregated statistics are publicly available at {%url%}.</p> <p translate>
<form> The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.
<textarea class="form-control" rows="20">{{reportData | json}}</textarea> </p>
</form> <p translate translate-value-url="<a href=&quot;https://data.syncthing.net&quot; target=&quot;_blank&quot;>https://data.syncthing.net</a>">
The aggregated statistics are publicly available at {%url%}.
</p>
<form>
<textarea class="form-control" rows="20">{{reportData | json}}</textarea>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
</modal> </modal>