index.html 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. <!DOCTYPE html>
  2. <!--
  3. Copyright (C) 2014 Jakob Borg and other contributors. All rights reserved.
  4. Use of this source code is governed by an MIT-style license that can be
  5. found in the LICENSE file.
  6. -->
  7. <html lang="en" ng-app="syncthing" ng-controller="SyncthingCtrl" class="ng-cloak">
  8. <head>
  9. <meta charset="utf-8">
  10. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  11. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  12. <meta name="description" content="">
  13. <meta name="author" content="">
  14. <link rel="shortcut icon" href="favicon.png">
  15. <title>Syncthing | {{thisNodeName()}}</title>
  16. <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
  17. <style type="text/css">
  18. body {
  19. padding-bottom: 70px;
  20. font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  21. }
  22. ul+h5 {
  23. margin-top: 1.5em;
  24. }
  25. .text-monospace {
  26. font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
  27. }
  28. .table-condensed>thead>tr>th, .table-condensed>tbody>tr>th, .table-condensed>tfoot>tr>th, .table-condensed>thead>tr>td, .table-condensed>tbody>tr>td, .table-condensed>tfoot>tr>td {
  29. border-top: none;
  30. }
  31. .logo {
  32. margin: 0;
  33. padding: 0;
  34. top: -5px;
  35. position: relative;
  36. }
  37. .list-no-bullet {
  38. list-style-type: none
  39. }
  40. .li-column {
  41. display: inline-block;
  42. min-width: 7em;
  43. margin-right: 1em;
  44. background-color: rgb(236, 240, 241);
  45. border-radius: 3px;
  46. padding: 1px 4px;
  47. margin: 2px 2px;
  48. }
  49. .li-column span.data {
  50. margin-left: 0.5em;
  51. min-width: 10em;
  52. text-align: right;
  53. display: inline-block;
  54. }
  55. .ng-cloak {
  56. display: none !important;
  57. }
  58. .table th {
  59. white-space:nowrap;
  60. font-weight: 400;
  61. }
  62. .table td {
  63. padding-left: 20px !important;
  64. }
  65. @media (max-width:767px) {
  66. .table-responsive>.table>tbody>tr>td {
  67. /* revert a bootstrap setting e.g.:
  68. * for mobile phones to allow linebreaks in long repro folder/shared with
  69. * columns. */
  70. white-space: normal;
  71. }
  72. }
  73. </style>
  74. </head>
  75. <body>
  76. <!-- Top bar -->
  77. <nav class="navbar navbar-top navbar-default" role="navigation">
  78. <div class="container">
  79. <span class="navbar-brand"><img class="logo" src="st-logo-128.png" width="32" height="32" /> Syncthing<small class="hidden-xs"> <span class="text-muted">|</span> {{thisNodeName()}}</small></span>
  80. <ul class="nav navbar-nav navbar-right">
  81. <li class="dropdown">
  82. <a href="#" class="dropdown-toggle" data-toggle="dropdown">Edit&nbsp;<b class="caret"></b></a>
  83. <ul class="dropdown-menu">
  84. <li><a href="" ng-click="addRepo()"><span class="glyphicon glyphicon-hdd"></span>&emsp;Add Repository</a></li>
  85. <li><a href="" ng-click="addNode()"><span class="glyphicon glyphicon-retweet"></span>&emsp;Add Node</a></li>
  86. <li class="divider"></li>
  87. <li><a href="" ng-click="editSettings()"><span class="glyphicon glyphicon-cog"></span>&emsp;Settings</a></li>
  88. <li><a href="" ng-click="idNode()"><span class="glyphicon glyphicon-qrcode"></span>&emsp;Show ID</a></li>
  89. <li class="divider"></li>
  90. <li><a href="" ng-click="shutdown()"><span class="glyphicon glyphicon-off"></span>&emsp;Shutdown</a></li>
  91. <li><a href="" ng-click="restart()"><span class="glyphicon glyphicon-refresh"></span>&emsp;Restart</a></li>
  92. </ul>
  93. </li>
  94. </ul>
  95. </div>
  96. </nav>
  97. <div class="container">
  98. <!-- First row, only shown if necessary; Restart warning -->
  99. <div ng-if="!configInSync" class="row">
  100. <div class="col-md-12">
  101. <div class="panel panel-warning">
  102. <div class="panel-heading"><h3 class="panel-title">Restart Needed</h3></div>
  103. <div class="panel-body">
  104. <p>The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.</p>
  105. </div>
  106. <div class="panel-footer">
  107. <button type="button" class="btn btn-sm btn-default pull-right" ng-click="restart()"><span class="glyphicon glyphicon-refresh"></span>&emsp;Restart</button>
  108. <div class="clearfix"></div>
  109. </div>
  110. </div>
  111. </div>
  112. </div>
  113. <!-- First regular row -->
  114. <div class="row">
  115. <!-- Repository list (top left) -->
  116. <div class="col-md-6">
  117. <div class="panel-group" id="repositories">
  118. <div class="panel panel-{{repoClass(repo.ID)}}" ng-repeat="repo in repoList()">
  119. <div class="panel-heading">
  120. <h3 class="panel-title">
  121. <a data-toggle="collapse" data-parent="#repositories" href="#repo-{{$index}}">
  122. <span class="glyphicon glyphicon-hdd"></span> {{repo.Directory | shortPath}}
  123. <span class="pull-right hidden-xs">{{repoStatus(repo.ID)}}</span>
  124. </a>
  125. </h3>
  126. </div>
  127. <div id="repo-{{$index}}" class="panel-collapse collapse">
  128. <div class="panel-body">
  129. <div class="table-responsive">
  130. <table class="table table-condensed table-striped">
  131. <tbody>
  132. <tr>
  133. <th><span class="glyphicon glyphicon-tag"></span>&emsp;Repository ID</th>
  134. <td class="text-right">{{repo.ID}}</td>
  135. </tr>
  136. <tr>
  137. <th><span class="glyphicon glyphicon-folder-open"></span>&emsp;Folder</th>
  138. <td class="text-right">{{repo.Directory}}</td>
  139. </tr>
  140. <tr ng-if="model[repo.ID].invalid">
  141. <th><span class="glyphicon glyphicon-warning-sign"></span>&emsp;Error</th>
  142. <td class="text-right">{{model[repo.ID].invalid}}</td>
  143. </tr>
  144. <tr>
  145. <th><span class="glyphicon glyphicon-comment"></span>&emsp;Synchronization</th>
  146. <td class="text-right">{{repoStatus(repo.ID)}}</td>
  147. </tr>
  148. <tr>
  149. <th><span class="glyphicon glyphicon-globe"></span>&emsp;Global Repository</th>
  150. <td class="text-right">{{model[repo.ID].globalFiles | alwaysNumber}} files, {{model[repo.ID].globalBytes | binary}}B</td>
  151. </tr>
  152. <tr>
  153. <th><span class="glyphicon glyphicon-home"></span>&emsp;Local Repository</th>
  154. <td class="text-right">{{model[repo.ID].localFiles | alwaysNumber}} files, {{model[repo.ID].localBytes | binary}}B</td>
  155. </tr>
  156. <tr>
  157. <th><span class="glyphicon glyphicon-cloud-download"></span>&emsp;Out of Sync</th>
  158. <td class="text-right">{{model[repo.ID].needFiles | alwaysNumber}} files, {{model[repo.ID].needBytes | binary}}B</td>
  159. </tr>
  160. <tr>
  161. <th><span class="glyphicon glyphicon-lock"></span>&emsp;Master Repository</th>
  162. <td class="text-right">
  163. <span ng-if="repo.ReadOnly">Yes</span>
  164. <span ng-if="!repo.ReadOnly">No</span>
  165. </td>
  166. </tr>
  167. <tr>
  168. <th><span class="glyphicon glyphicon-unchecked"></span>&emsp;Ignore Permissions</th>
  169. <td class="text-right">
  170. <span ng-if="repo.IgnorePerms">Yes</span>
  171. <span ng-if="!repo.IgnorePerms">No</span>
  172. </td>
  173. </tr>
  174. <tr>
  175. <th><span class="glyphicon glyphicon-share-alt"></span>&emsp;Shared With</th>
  176. <td class="text-right">{{sharesRepo(repo)}}</td>
  177. </tr>
  178. </tbody>
  179. </table>
  180. </div>
  181. <span class="pull-right"><a class="btn btn-sm btn-primary" href="" ng-click="editRepo(repo)"><span class="glyphicon glyphicon-pencil"></span>&emsp;Edit</a></span>
  182. </div>
  183. </div>
  184. </div>
  185. </div>
  186. </div>
  187. <!-- Node list (top right) -->
  188. <div class="col-md-6">
  189. <div class="panel-group" id="nodes">
  190. <div class="panel panel-default" ng-repeat="nodeCfg in [thisNode()]">
  191. <div class="panel-heading">
  192. <h3 class="panel-title">
  193. <a data-toggle="collapse" data-parent="#nodes" href="#node-this"><span class="glyphicon glyphicon-home"></span> {{nodeName(nodeCfg)}}</a>
  194. </h3>
  195. </div>
  196. <div id="node-this" class="panel-collapse collapse in">
  197. <div class="panel-body">
  198. <div class="table-responsive">
  199. <table class="table table-condensed table-striped">
  200. <tbody>
  201. <tr>
  202. <th><span class="glyphicon glyphicon-th"></span>&emsp;RAM Utilization</th>
  203. <td class="text-right">{{system.sys | binary}}B</td>
  204. </tr>
  205. <tr>
  206. <th><span class="glyphicon glyphicon-tasks"></span>&emsp;CPU Utilization</th>
  207. <td class="text-right">{{system.cpuPercent | alwaysNumber | natural:1}}%</td>
  208. </tr>
  209. <tr>
  210. <th><span class="glyphicon glyphicon-cloud-download"></span>&emsp;Download Rate</th>
  211. <td class="text-right">{{connections['total'].inbps | metric}}bps ({{connections['total'].InBytesTotal | binary}}B)</td>
  212. </tr>
  213. <tr>
  214. <th><span class="glyphicon glyphicon-cloud-upload"></span>&emsp;Upload Rate</th>
  215. <td class="text-right">{{connections['total'].outbps | metric}}bps ({{connections['total'].OutBytesTotal | binary}}B)</td>
  216. </tr>
  217. <tr ng-if="system.extAnnounceOK != undefined">
  218. <th><span class="glyphicon glyphicon-bullhorn"></span>&emsp;Announce Server</th>
  219. <td class="text-right">
  220. <span class="data text-success" ng-if="system.extAnnounceOK">Online</span>
  221. <span class="data text-danger" ng-if="!system.extAnnounceOK">Offline</span>
  222. </td>
  223. </tr>
  224. <tr>
  225. <th><span class="glyphicon glyphicon-tag"></span>&emsp;Version</th>
  226. <td class="text-right">{{version}}</td>
  227. </tr>
  228. </tbody>
  229. </table>
  230. </div>
  231. <span class="pull-right"><a class="btn btn-sm btn-primary" href="" ng-click="editNode(nodeCfg)"><span class="glyphicon glyphicon-pencil"></span>&emsp;Edit</a></span>
  232. </div>
  233. </div>
  234. </div>
  235. <div class="panel panel-{{nodeClass(nodeCfg)}}" ng-repeat="nodeCfg in otherNodes()">
  236. <div class="panel-heading">
  237. <h3 class="panel-title">
  238. <a data-toggle="collapse" data-parent="#nodes" href="#node-{{$index}}">
  239. <span class="glyphicon glyphicon-retweet"></span>
  240. {{nodeName(nodeCfg)}}
  241. <span class="pull-right hidden-xs">{{nodeStatus(nodeCfg)}}</span>
  242. </a>
  243. </h3>
  244. </div>
  245. <div id="node-{{$index}}" class="panel-collapse collapse">
  246. <div class="panel-body">
  247. <div class="table-responsive">
  248. <table class="table table-condensed table-striped">
  249. <tbody>
  250. <tr>
  251. <th><span class="glyphicon glyphicon-link"></span>&emsp;Address</th>
  252. <td class="text-right">{{nodeAddr(nodeCfg)}}</td>
  253. </tr>
  254. <tr>
  255. <th><span class="glyphicon glyphicon-comment"></span>&emsp;Synchronization</th>
  256. <td class="text-right">{{nodeStatus(nodeCfg)}}</td>
  257. </tr>
  258. <tr>
  259. <th><span class="glyphicon glyphicon-cloud-download"></span>&emsp;Download Rate</th>
  260. <td class="text-right">{{connections[nodeCfg.NodeID].inbps | metric}}bps ({{connections[nodeCfg.NodeID].InBytesTotal | binary}}B)</td>
  261. </tr>
  262. <tr>
  263. <th><span class="glyphicon glyphicon-cloud-upload"></span>&emsp;Upload Rate</th>
  264. <td class="text-right">{{connections[nodeCfg.NodeID].outbps | metric}}bps ({{connections[nodeCfg.NodeID].OutBytesTotal | binary}}B)</td>
  265. </tr>
  266. <tr>
  267. <th><span class="glyphicon glyphicon-tag"></span>&emsp;Version</th>
  268. <td class="text-right">{{nodeVer(nodeCfg)}}</td>
  269. </tr>
  270. </tbody>
  271. </table>
  272. </div>
  273. <span class="pull-right"><a class="btn btn-sm btn-primary" href="" ng-click="editNode(nodeCfg)"><span class="glyphicon glyphicon-pencil"></span>&emsp;Edit</a></span>
  274. </div>
  275. </div>
  276. </div>
  277. </div>
  278. </div>
  279. </div> <!-- /row -->
  280. <!-- Errors -->
  281. <div ng-if="errorList().length > 0" class="row">
  282. <div class="col-md-12">
  283. <div class="panel panel-warning">
  284. <div class="panel-heading"><h3 class="panel-title">Notice</h3></div>
  285. <div class="panel-body">
  286. <p ng-repeat="err in errorList()"><small>{{err.Time | date:"H:mm:ss"}}:</small> {{friendlyNodes(err.Error)}}</p>
  287. </div>
  288. <div class="panel-footer">
  289. <button type="button" class="pull-right btn btn-sm btn-default" ng-click="clearErrors()"><span class="glyphicon glyphicon-ok"></span>&emsp;OK</button>
  290. <div class="clearfix"></div>
  291. </div>
  292. </div>
  293. </div>
  294. </div>
  295. </div> <!-- /container -->
  296. <!-- Bottom bar -->
  297. <nav class="navbar navbar-default navbar-fixed-bottom hidden-xs">
  298. <div class="container">
  299. <ul class="nav navbar-nav">
  300. <li><a class="navbar-link" href="http://discourse.syncthing.net/">Support / Forum</a></li>
  301. <li><a class="navbar-link" href="https://github.com/calmh/syncthing/releases">Latest Release</a></li>
  302. <li><a class="navbar-link" href="http://discourse.syncthing.net/category/documentation">Documentation</a></li>
  303. <li><a class="navbar-link" href="https://github.com/calmh/syncthing/issues">Bugs</a></li>
  304. <li><a class="navbar-link" href="https://github.com/calmh/syncthing">Source Code</a></li>
  305. </ul>
  306. </div>
  307. </nav>
  308. <!-- Network error modal -->
  309. <div id="networkError" class="modal fade">
  310. <div class="modal-dialog">
  311. <div class="modal-content">
  312. <div class="modal-header alert alert-danger">
  313. <h4 class="modal-title">
  314. <span class="glyphicon glyphicon-exclamation-sign"></span>
  315. Connection Error
  316. </h4>
  317. </div>
  318. <div class="modal-body">
  319. <p>
  320. Syncthing seems to be down, or there is a problem with your Internet connection.
  321. Retrying&hellip;
  322. </p>
  323. </div>
  324. </div>
  325. </div>
  326. </div>
  327. <!-- Restarting modal -->
  328. <div id="restarting" class="modal fade">
  329. <div class="modal-dialog">
  330. <div class="modal-content">
  331. <div class="modal-header alert alert-info">
  332. <h4 class="modal-title">
  333. <span class="glyphicon glyphicon-refresh"></span>
  334. Restarting
  335. </h4>
  336. </div>
  337. <div class="modal-body">
  338. <p>
  339. Syncthing is restarting. Please hold&hellip;
  340. </p>
  341. </div>
  342. </div>
  343. </div>
  344. </div>
  345. <!-- Shutdown modal -->
  346. <div id="shutdown" class="modal fade">
  347. <div class="modal-dialog">
  348. <div class="modal-content">
  349. <div class="modal-header alert alert-success">
  350. <h4 class="modal-title">
  351. <span class="glyphicon glyphicon-off"></span>
  352. Shutdown Complete
  353. </h4>
  354. </div>
  355. <div class="modal-body">
  356. <p>
  357. Syncthing has been shut down.
  358. </p>
  359. </div>
  360. </div>
  361. </div>
  362. </div>
  363. <!-- ID modal -->
  364. <div id="idqr" class="modal fade">
  365. <div class="modal-dialog modal-lg">
  366. <div class="modal-content">
  367. <div class="modal-header">
  368. <h4 class="modal-title">
  369. <span class="glyphicon glyphicon-qrcode"></span>
  370. Node Identification &mdash; {{nodeName(thisNode())}}
  371. </h4>
  372. </div>
  373. <div class="modal-body">
  374. <div class="well well-sm text-monospace text-center">{{myID | chunkID}}</div>
  375. <img ng-if="myID" class="center-block img-thumbnail" src="qr/{{myID | chunkID}}"/>
  376. </div>
  377. <div class="modal-footer">
  378. <button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span>&emsp;Close</button>
  379. </div>
  380. </div>
  381. </div>
  382. </div>
  383. <!-- Node editor modal -->
  384. <div id="editNode" class="modal fade">
  385. <div class="modal-dialog modal-lg">
  386. <div class="modal-content">
  387. <div class="modal-header">
  388. <h4 ng-show="!editingExisting" class="modal-title">Add Node</h4>
  389. <h4 ng-show="editingExisting" class="modal-title">Edit Node</h4>
  390. </div>
  391. <div class="modal-body">
  392. <form role="form" name="nodeEditor">
  393. <div class="form-group" ng-class="{'has-error': nodeEditor.nodeID.$invalid && nodeEditor.nodeID.$dirty}">
  394. <label for="nodeID">Node ID</label>
  395. <input ng-if="!editingExisting" name="nodeID" id="nodeID" class="form-control text-monospace" type="text" ng-model="currentNode.NodeID" required valid-nodeid></input>
  396. <div ng-if="editingExisting" class="well well-sm text-monospace">{{currentNode.NodeID | chunkID}}</div>
  397. <p class="help-block">
  398. <span ng-if="nodeEditor.nodeID.$valid || nodeEditor.nodeID.$pristine">The node ID to enter here can be found in the "Edit > Show ID" dialog on the other node. Spaces and dashes are optional (ignored).
  399. <span ng-show="!editingExisting">When adding a new node, keep in mind that <em>this node</em> must be added on the other side too.</span>
  400. </span>
  401. <span ng-if="nodeEditor.nodeID.$error.required && nodeEditor.nodeID.$dirty">The node ID cannot be blank.</span>
  402. <span ng-if="nodeEditor.nodeID.$error.validNodeid && nodeEditor.nodeID.$dirty">The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.</span>
  403. </p>
  404. </div>
  405. <div class="form-group">
  406. <label for="name">Name</label>
  407. <input placeholder="Home Server" id="name" class="form-control" type="text" ng-model="currentNode.Name"></input>
  408. <p class="help-block">Shown instead of Node ID in the cluster status.</p>
  409. </div>
  410. <div class="form-group">
  411. <label for="addresses">Addresses</label>
  412. <input placeholder="dynamic" ng-disabled="currentNode.NodeID == myID" id="addresses" class="form-control" type="text" ng-model="currentNode.AddressesStr"></input>
  413. <p class="help-block">Enter comma separated <span class="text-monospace">ip:port</span> addresses or <span class="text-monospace">dynamic</span> to perform automatic discovery of the address.</p>
  414. </div>
  415. </form>
  416. </div>
  417. <div class="modal-footer">
  418. <button type="button" class="btn btn-primary" ng-click="saveNode()" ng-disabled="nodeEditor.$invalid"><span class="glyphicon glyphicon-ok"></span>&emsp;Save</button>
  419. <button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span>&emsp;Close</button>
  420. <button ng-if="editingExisting && !editingSelf" type="button" class="btn btn-danger pull-left" ng-click="deleteNode()"><span class="glyphicon glyphicon-minus"></span>&emsp;Delete</button>
  421. </div>
  422. </div>
  423. </div>
  424. </div>
  425. <!-- Repo editor modal -->
  426. <div id="editRepo" class="modal fade">
  427. <div class="modal-dialog modal-lg">
  428. <div class="modal-content">
  429. <div class="modal-header">
  430. <h4 ng-show="!editingExisting" class="modal-title">Add Repository</h4>
  431. <h4 ng-show="editingExisting" class="modal-title">Edit Repository</h4>
  432. </div>
  433. <div class="modal-body">
  434. <form role="form" name="repoEditor">
  435. <div class="row">
  436. <div class="col-md-12">
  437. <div class="form-group" ng-class="{'has-error': repoEditor.repoID.$invalid && repoEditor.repoID.$dirty}">
  438. <label for="repoID">Repository ID</label>
  439. <input name="repoID" placeholder="documents" ng-disabled="editingExisting" id="repoID" class="form-control" type="text" ng-model="currentRepo.ID" required unique-repo ng-pattern="/^[a-zA-Z0-9-_.]{1,64}$/"></input>
  440. <p class="help-block">
  441. <span ng-if="repoEditor.repoID.$valid || repoEditor.repoID.$pristine">Short identifier for the repository. Must be the same on all cluster nodes.</span>
  442. <span ng-if="repoEditor.repoID.$error.uniqueRepo">The repository ID must be unique.</span>
  443. <span ng-if="repoEditor.repoID.$error.required && repoEditor.repoID.$dirty">The repository ID cannot be blank.</span>
  444. <span ng-if="repoEditor.repoID.$error.pattern && repoEditor.repoID.$dirty">The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the <code>-_.</code> characters only.</span>
  445. </p>
  446. </div>
  447. <div class="form-group" ng-class="{'has-error': repoEditor.repoPath.$invalid && repoEditor.repoPath.$dirty}">
  448. <label for="repoPath">Repository Path</label>
  449. <input name="repoPath" placeholder="~/Documents" id="repoPath" class="form-control" type="text" ng-model="currentRepo.Directory" required></input>
  450. <p class="help-block">
  451. <span ng-if="repoEditor.repoPath.$valid || repoEditor.repoPath.$pristine">Path to the repository on the local computer. Will be created if it does not exist. The tilde character <code>~</code> can be used as a shortcut for <code>{{system.tilde}}</code>.</span>
  452. <span ng-if="repoEditor.repoPath.$error.required && repoEditor.repoPath.$dirty">The repository path cannot be blank.</span>
  453. </p>
  454. </div>
  455. </div>
  456. </div>
  457. <div class="row">
  458. <div class="col-md-6">
  459. <div class="form-group">
  460. <div class="checkbox">
  461. <label>
  462. <input type="checkbox" ng-model="currentRepo.ReadOnly"> Repository Master
  463. </label>
  464. </div>
  465. <p class="help-block">Files are protected from changes made on other nodes, but changes made on <em>this</em> node will be sent to the rest of the cluster.</p>
  466. </div>
  467. <div class="form-group">
  468. <div class="checkbox">
  469. <label>
  470. <input type="checkbox" ng-model="currentRepo.IgnorePerms"> Ignore Permissions
  471. </label>
  472. </div>
  473. <p class="help-block">File permission bits are ignored when looking for changes. Use on FAT filesystems.</p>
  474. </div>
  475. <div class="form-group">
  476. <label for="nodes">Share With Nodes</label>
  477. <div class="checkbox" ng-repeat="node in otherNodes()">
  478. <label>
  479. <input type="checkbox" ng-model="currentRepo.selectedNodes[node.NodeID]"> {{nodeName(node)}}
  480. </label>
  481. </div>
  482. <p class="help-block">Select the nodes to share this repository with.</p>
  483. </div>
  484. </div>
  485. <div class="col-md-6">
  486. <div class="form-group">
  487. <div class="checkbox">
  488. <label>
  489. <input type="checkbox" ng-model="currentRepo.simpleFileVersioning"> File Versioning
  490. </label>
  491. </div>
  492. <p class="help-block">Files are moved to date stamped versions in a <code>.stversions</code> folder when replaced or deleted by syncthing.</p>
  493. </div>
  494. <div class="form-group" ng-if="currentRepo.simpleFileVersioning" ng-class="{'has-error': repoEditor.simpleKeep.$invalid && repoEditor.simpleKeep.$dirty}">
  495. <label for="simpleKeep">Keep Versions</label>
  496. <input name="simpleKeep" id="simpleKeep" class="form-control" type="number" ng-model="currentRepo.simpleKeep" required min="1"></input>
  497. <p class="help-block">
  498. <span ng-if="repoEditor.simpleKeep.$valid || repoEditor.simpleKeep.$pristine">The number of old versions to keep, per file.</span>
  499. <span ng-if="repoEditor.simpleKeep.$error.required && repoEditor.simpleKeep.$dirty">The number of versions must be a number and cannot be blank.</span>
  500. <span ng-if="repoEditor.simpleKeep.$error.min && repoEditor.simpleKeep.$dirty">You must keep at least one version.</span>
  501. </p>
  502. </div>
  503. </div>
  504. </div>
  505. </form>
  506. <div ng-show="!editingExisting">
  507. When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.
  508. </div>
  509. </div>
  510. <div class="modal-footer">
  511. <button type="button" class="btn btn-primary" ng-click="saveRepo()" ng-disabled="repoEditor.$invalid"><span class="glyphicon glyphicon-ok"></span>&emsp;Save</button>
  512. <button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span>&emsp;Close</button>
  513. <button ng-if="editingExisting" type="button" class="btn btn-danger pull-left" ng-click="deleteRepo()"><span class="glyphicon glyphicon-minus"></span>&emsp;Delete</button>
  514. </div>
  515. </div>
  516. </div>
  517. </div>
  518. <!-- Settings modal -->
  519. <div id="settings" class="modal fade">
  520. <div class="modal-dialog modal-lg">
  521. <div class="modal-content">
  522. <div class="modal-header">
  523. <h4 class="modal-title"> Settings</h4>
  524. </div>
  525. <div class="modal-body">
  526. <form role="form">
  527. <div class="row">
  528. <div class="col-md-6">
  529. <div class="form-group" ng-repeat="setting in settings">
  530. <div ng-if="setting.type == 'text' || setting.type == 'number'">
  531. <label for="{{setting.id}}">{{setting.descr}}</label>
  532. <input id="{{setting.id}}" class="form-control" type="{{setting.type}}" ng-model="config.workingOptions[setting.id]"></input>
  533. </div>
  534. <div class="checkbox" ng-if="setting.type == 'bool'">
  535. <label>
  536. {{setting.descr}} <input id="{{setting.id}}" type="checkbox" ng-model="config.workingOptions[setting.id]"></input>
  537. </label>
  538. </div>
  539. </div>
  540. </div>
  541. <div class="col-md-6">
  542. <div class="form-group" ng-repeat="setting in guiSettings">
  543. <div ng-if="setting.type == 'text' || setting.type == 'number' || setting.type == 'password'">
  544. <label for="{{setting.id}}">{{setting.descr}}</label>
  545. <input id="{{setting.id}}" class="form-control" type="{{setting.type}}" ng-model="config.workingGUI[setting.id]"></input>
  546. </div>
  547. <div class="checkbox" ng-if="setting.type == 'bool'">
  548. <label>
  549. {{setting.descr}} <input id="{{setting.id}}" type="checkbox" ng-model="config.workingGUI[setting.id]"></input>
  550. </label>
  551. </div>
  552. <div ng-if="setting.type == 'apikey'">
  553. <label>{{setting.descr}} (<a href="http://discourse.syncthing.net/t/v0-8-14-api-keys/335">Usage</a>)</label>
  554. <div class="well well-sm text-monospace">{{config.workingGUI[setting.id] || "-"}}</div>
  555. <button type="button" class="btn btn-sm btn-default" ng-click="setAPIKey(config.workingGUI)">Generate</button>
  556. </div>
  557. </div>
  558. </div>
  559. </div>
  560. </form>
  561. </div>
  562. <div class="modal-footer">
  563. <button type="button" class="btn btn-primary" ng-click="saveSettings()"><span class="glyphicon glyphicon-ok"></span>&emsp;Save</button>
  564. <button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span>&emsp;Close</button>
  565. </div>
  566. </div>
  567. </div>
  568. </div>
  569. <script src="angular.min.js"></script>
  570. <script src="jquery-2.0.3.min.js"></script>
  571. <script src="bootstrap/js/bootstrap.min.js"></script>
  572. <script src="app.js"></script>
  573. </body>
  574. </html>