mirror of
https://github.com/octoleo/syncthing.git
synced 2024-12-23 11:28:59 +00:00
681 lines
32 KiB
HTML
681 lines
32 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
Copyright (C) 2014 Jakob Borg and other contributors. All rights reserved.
|
|
Use of this source code is governed by an MIT-style license that can be
|
|
found in the LICENSE file.
|
|
-->
|
|
<html lang="en" ng-app="syncthing" ng-controller="SyncthingCtrl" class="ng-cloak">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="description" content="">
|
|
<meta name="author" content="">
|
|
<link rel="shortcut icon" href="favicon.png">
|
|
|
|
<title>Syncthing | {{thisNodeName()}}</title>
|
|
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
|
<style type="text/css">
|
|
body {
|
|
padding-bottom: 70px;
|
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
}
|
|
|
|
ul+h5 {
|
|
margin-top: 1.5em;
|
|
}
|
|
|
|
.text-monospace {
|
|
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
|
}
|
|
|
|
.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 {
|
|
border-top: none;
|
|
}
|
|
|
|
.logo {
|
|
margin: 0;
|
|
padding: 0;
|
|
top: -5px;
|
|
position: relative;
|
|
}
|
|
|
|
.list-no-bullet {
|
|
list-style-type: none
|
|
}
|
|
|
|
.li-column {
|
|
display: inline-block;
|
|
min-width: 7em;
|
|
margin-right: 1em;
|
|
background-color: rgb(236, 240, 241);
|
|
border-radius: 3px;
|
|
padding: 1px 4px;
|
|
margin: 2px 2px;
|
|
}
|
|
.li-column span.data {
|
|
margin-left: 0.5em;
|
|
min-width: 10em;
|
|
text-align: right;
|
|
display: inline-block;
|
|
}
|
|
|
|
.ng-cloak {
|
|
display: none !important;
|
|
}
|
|
|
|
.table th {
|
|
white-space: nowrap;
|
|
font-weight: 400;
|
|
}
|
|
|
|
.table td {
|
|
padding-left: 20px !important;
|
|
}
|
|
|
|
.table td.small-data {
|
|
white-space: nowrap;
|
|
}
|
|
|
|
@media (max-width:767px) {
|
|
.table-responsive>.table>tbody>tr>td {
|
|
/* revert a bootstrap setting e.g.:
|
|
* for mobile phones to allow linebreaks in long repro folder/shared with
|
|
* columns. */
|
|
white-space: normal;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<!-- Top bar -->
|
|
|
|
<nav class="navbar navbar-top navbar-default" role="navigation">
|
|
<div class="container">
|
|
<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>
|
|
<ul class="nav navbar-nav navbar-right">
|
|
<li class="dropdown">
|
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Edit <b class="caret"></b></a>
|
|
<ul class="dropdown-menu">
|
|
<li><a href="" ng-click="addRepo()"><span class="glyphicon glyphicon-hdd"></span> Add Repository</a></li>
|
|
<li><a href="" ng-click="addNode()"><span class="glyphicon glyphicon-retweet"></span> Add Node</a></li>
|
|
<li class="divider"></li>
|
|
<li><a href="" ng-click="editSettings()"><span class="glyphicon glyphicon-cog"></span> Settings</a></li>
|
|
<li><a href="" ng-click="idNode()"><span class="glyphicon glyphicon-qrcode"></span> Show ID</a></li>
|
|
<li class="divider"></li>
|
|
<li><a href="" ng-click="shutdown()"><span class="glyphicon glyphicon-off"></span> Shutdown</a></li>
|
|
<li><a href="" ng-click="restart()"><span class="glyphicon glyphicon-refresh"></span> Restart</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="container">
|
|
|
|
<!-- First row, only shown if necessary; Restart warning -->
|
|
|
|
<div ng-if="!configInSync" class="row">
|
|
<div class="col-md-12">
|
|
<div class="panel panel-warning">
|
|
<div class="panel-heading"><h3 class="panel-title">Restart Needed</h3></div>
|
|
<div class="panel-body">
|
|
<p>The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.</p>
|
|
</div>
|
|
<div class="panel-footer">
|
|
<button type="button" class="btn btn-sm btn-default pull-right" ng-click="restart()"><span class="glyphicon glyphicon-refresh"></span> Restart</button>
|
|
<div class="clearfix"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- First regular row -->
|
|
|
|
<div class="row">
|
|
|
|
<!-- Repository list (top left) -->
|
|
|
|
<div class="col-md-6">
|
|
<div class="panel-group" id="repositories">
|
|
<div class="panel panel-{{repoClass(repo.ID)}}" ng-repeat="repo in repoList()">
|
|
<div class="panel-heading">
|
|
<h3 class="panel-title">
|
|
<a data-toggle="collapse" data-parent="#repositories" href="#repo-{{$index}}">
|
|
<span class="glyphicon glyphicon-hdd"></span> {{repo.Directory | shortPath}}
|
|
<span class="pull-right hidden-xs">{{repoStatus(repo.ID)}}</span>
|
|
</a>
|
|
</h3>
|
|
</div>
|
|
<div id="repo-{{$index}}" class="panel-collapse collapse">
|
|
<div class="panel-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-condensed table-striped">
|
|
<tbody>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-tag"></span> Repository ID</th>
|
|
<td class="text-right">{{repo.ID}}</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-folder-open"></span> Folder</th>
|
|
<td class="text-right">{{repo.Directory}}</td>
|
|
</tr>
|
|
<tr ng-if="model[repo.ID].invalid">
|
|
<th><span class="glyphicon glyphicon-warning-sign"></span> Error</th>
|
|
<td class="text-right">{{model[repo.ID].invalid}}</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-comment"></span> Synchronization</th>
|
|
<td class="text-right">{{repoStatus(repo.ID)}}</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-globe"></span> Global Repository</th>
|
|
<td class="text-right">{{model[repo.ID].globalFiles | alwaysNumber}} items, {{model[repo.ID].globalBytes | binary}}B</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-home"></span> Local Repository</th>
|
|
<td class="text-right">{{model[repo.ID].localFiles | alwaysNumber}} items, {{model[repo.ID].localBytes | binary}}B</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-cloud-download"></span> Out of Sync</th>
|
|
<td class="text-right">
|
|
<a ng-if="model[repo.ID].needFiles > 0" ng-click="showNeed(repo.ID)" href="">{{model[repo.ID].needFiles | alwaysNumber}} items, {{model[repo.ID].needBytes | binary}}B</a>
|
|
<span ng-if="model[repo.ID].needFiles == 0">0 items, 0 B</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-lock"></span> Master Repository</th>
|
|
<td class="text-right">
|
|
<span ng-if="repo.ReadOnly">Yes</span>
|
|
<span ng-if="!repo.ReadOnly">No</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-unchecked"></span> Ignore Permissions</th>
|
|
<td class="text-right">
|
|
<span ng-if="repo.IgnorePerms">Yes</span>
|
|
<span ng-if="!repo.IgnorePerms">No</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-share-alt"></span> Shared With</th>
|
|
<td class="text-right">{{sharesRepo(repo)}}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<span class="pull-right">
|
|
<a class="btn btn-sm btn-primary" href="" ng-click="editRepo(repo)"><span class="glyphicon glyphicon-pencil"></span> Edit</a>
|
|
<a class="btn btn-sm btn-danger" ng-if="repo.ReadOnly && model[repo.ID].needFiles > 0" ng-click="override(repo.ID)" href=""><span class="glyphicon glyphicon-upload"></span> Override Changes</a>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Node list (top right) -->
|
|
|
|
<div class="col-md-6">
|
|
<div class="panel-group" id="nodes">
|
|
<div class="panel panel-default" ng-repeat="nodeCfg in [thisNode()]">
|
|
<div class="panel-heading">
|
|
<h3 class="panel-title">
|
|
<a data-toggle="collapse" data-parent="#nodes" href="#node-this"><span class="glyphicon glyphicon-home"></span> {{nodeName(nodeCfg)}}</a>
|
|
</h3>
|
|
</div>
|
|
<div id="node-this" class="panel-collapse collapse in">
|
|
<div class="panel-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-condensed table-striped">
|
|
<tbody>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-th"></span> RAM Utilization</th>
|
|
<td class="text-right">{{system.sys | binary}}B</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-tasks"></span> CPU Utilization</th>
|
|
<td class="text-right">{{system.cpuPercent | alwaysNumber | natural:1}}%</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-cloud-download"></span> Download Rate</th>
|
|
<td class="text-right">{{connections['total'].inbps | metric}}bps ({{connections['total'].InBytesTotal | binary}}B)</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-cloud-upload"></span> Upload Rate</th>
|
|
<td class="text-right">{{connections['total'].outbps | metric}}bps ({{connections['total'].OutBytesTotal | binary}}B)</td>
|
|
</tr>
|
|
<tr ng-if="system.extAnnounceOK != undefined">
|
|
<th><span class="glyphicon glyphicon-bullhorn"></span> Announce Server</th>
|
|
<td class="text-right">
|
|
<span class="data text-success" ng-if="system.extAnnounceOK">Online</span>
|
|
<span class="data text-danger" ng-if="!system.extAnnounceOK">Offline</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-tag"></span> Version</th>
|
|
<td class="text-right">{{version}}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<span class="pull-right"><a class="btn btn-sm btn-primary" href="" ng-click="editNode(nodeCfg)"><span class="glyphicon glyphicon-pencil"></span> Edit</a></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel panel-{{nodeClass(nodeCfg)}}" ng-repeat="nodeCfg in otherNodes()">
|
|
<div class="panel-heading">
|
|
<h3 class="panel-title">
|
|
<a data-toggle="collapse" data-parent="#nodes" href="#node-{{$index}}">
|
|
<span class="glyphicon glyphicon-retweet"></span>
|
|
{{nodeName(nodeCfg)}}
|
|
<span class="pull-right hidden-xs">{{nodeStatus(nodeCfg)}}</span>
|
|
</a>
|
|
</h3>
|
|
</div>
|
|
<div id="node-{{$index}}" class="panel-collapse collapse">
|
|
<div class="panel-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-condensed table-striped">
|
|
<tbody>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-link"></span> Address</th>
|
|
<td class="text-right">{{nodeAddr(nodeCfg)}}</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-comment"></span> Synchronization</th>
|
|
<td class="text-right">{{nodeStatus(nodeCfg)}}</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-cloud-download"></span> Download Rate</th>
|
|
<td class="text-right">{{connections[nodeCfg.NodeID].inbps | metric}}bps ({{connections[nodeCfg.NodeID].InBytesTotal | binary}}B)</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-cloud-upload"></span> Upload Rate</th>
|
|
<td class="text-right">{{connections[nodeCfg.NodeID].outbps | metric}}bps ({{connections[nodeCfg.NodeID].OutBytesTotal | binary}}B)</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-tag"></span> Version</th>
|
|
<td class="text-right">{{nodeVer(nodeCfg)}}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<span class="pull-right"><a class="btn btn-sm btn-primary" href="" ng-click="editNode(nodeCfg)"><span class="glyphicon glyphicon-pencil"></span> Edit</a></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div> <!-- /row -->
|
|
|
|
<!-- Errors -->
|
|
|
|
<div ng-if="errorList().length > 0" class="row">
|
|
<div class="col-md-12">
|
|
<div class="panel panel-warning">
|
|
<div class="panel-heading"><h3 class="panel-title">Notice</h3></div>
|
|
<div class="panel-body">
|
|
<p ng-repeat="err in errorList()"><small>{{err.Time | date:"H:mm:ss"}}:</small> {{friendlyNodes(err.Error)}}</p>
|
|
</div>
|
|
<div class="panel-footer">
|
|
<button type="button" class="pull-right btn btn-sm btn-default" ng-click="clearErrors()"><span class="glyphicon glyphicon-ok"></span> OK</button>
|
|
<div class="clearfix"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div> <!-- /container -->
|
|
|
|
<!-- Bottom bar -->
|
|
|
|
<nav class="navbar navbar-default navbar-fixed-bottom hidden-xs">
|
|
<div class="container">
|
|
<ul class="nav navbar-nav">
|
|
<li><a class="navbar-link" href="http://discourse.syncthing.net/">Support / Forum</a></li>
|
|
<li><a class="navbar-link" href="https://github.com/calmh/syncthing/releases">Latest Release</a></li>
|
|
<li><a class="navbar-link" href="http://discourse.syncthing.net/category/documentation">Documentation</a></li>
|
|
<li><a class="navbar-link" href="https://github.com/calmh/syncthing/issues">Bugs</a></li>
|
|
<li><a class="navbar-link" href="https://github.com/calmh/syncthing">Source Code</a></li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Network error modal -->
|
|
|
|
<div id="networkError" class="modal fade">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header alert alert-danger">
|
|
<h4 class="modal-title">
|
|
<span class="glyphicon glyphicon-exclamation-sign"></span>
|
|
Connection Error
|
|
</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>
|
|
Syncthing seems to be down, or there is a problem with your Internet connection.
|
|
Retrying…
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Restarting modal -->
|
|
|
|
<div id="restarting" class="modal fade">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header alert alert-info">
|
|
<h4 class="modal-title">
|
|
<span class="glyphicon glyphicon-refresh"></span>
|
|
Restarting
|
|
</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>
|
|
Syncthing is restarting. Please hold…
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Shutdown modal -->
|
|
|
|
<div id="shutdown" class="modal fade">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header alert alert-success">
|
|
<h4 class="modal-title">
|
|
<span class="glyphicon glyphicon-off"></span>
|
|
Shutdown Complete
|
|
</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>
|
|
Syncthing has been shut down.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ID modal -->
|
|
|
|
<div id="idqr" class="modal fade">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">
|
|
<span class="glyphicon glyphicon-qrcode"></span>
|
|
Node Identification — {{nodeName(thisNode())}}
|
|
</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="well well-sm text-monospace text-center">{{myID | chunkID}}</div>
|
|
<img ng-if="myID" class="center-block img-thumbnail" src="qr/{{myID | chunkID}}"/>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Node editor modal -->
|
|
|
|
<div id="editNode" class="modal fade">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 ng-show="!editingExisting" class="modal-title">Add Node</h4>
|
|
<h4 ng-show="editingExisting" class="modal-title">Edit Node</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form role="form" name="nodeEditor">
|
|
<div class="form-group" ng-class="{'has-error': nodeEditor.nodeID.$invalid && nodeEditor.nodeID.$dirty}">
|
|
<label for="nodeID">Node ID</label>
|
|
<input ng-if="!editingExisting" name="nodeID" id="nodeID" class="form-control text-monospace" type="text" ng-model="currentNode.NodeID" required valid-nodeid></input>
|
|
<div ng-if="editingExisting" class="well well-sm text-monospace">{{currentNode.NodeID | chunkID}}</div>
|
|
<p class="help-block">
|
|
<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).
|
|
<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>
|
|
</span>
|
|
<span ng-if="nodeEditor.nodeID.$error.required && nodeEditor.nodeID.$dirty">The node ID cannot be blank.</span>
|
|
<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>
|
|
</p>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="name">Node Name</label>
|
|
<input placeholder="Home Server" id="name" class="form-control" type="text" ng-model="currentNode.Name"></input>
|
|
<p class="help-block">Shown instead of Node ID in the cluster status.</p>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="addresses">Addresses</label>
|
|
<input placeholder="dynamic" ng-disabled="currentNode.NodeID == myID" id="addresses" class="form-control" type="text" ng-model="currentNode.AddressesStr"></input>
|
|
<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>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary" ng-click="saveNode()" ng-disabled="nodeEditor.$invalid"><span class="glyphicon glyphicon-ok"></span> Save</button>
|
|
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> Close</button>
|
|
<button ng-if="editingExisting && !editingSelf" type="button" class="btn btn-danger pull-left" ng-click="deleteNode()"><span class="glyphicon glyphicon-minus"></span> Delete</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Repo editor modal -->
|
|
|
|
<div id="editRepo" class="modal fade">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 ng-show="!editingExisting" class="modal-title">Add Repository</h4>
|
|
<h4 ng-show="editingExisting" class="modal-title">Edit Repository</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form role="form" name="repoEditor">
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="form-group" ng-class="{'has-error': repoEditor.repoID.$invalid && repoEditor.repoID.$dirty}">
|
|
<label for="repoID">Repository ID</label>
|
|
<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>
|
|
<p class="help-block">
|
|
<span ng-if="repoEditor.repoID.$valid || repoEditor.repoID.$pristine">Short identifier for the repository. Must be the same on all cluster nodes.</span>
|
|
<span ng-if="repoEditor.repoID.$error.uniqueRepo">The repository ID must be unique.</span>
|
|
<span ng-if="repoEditor.repoID.$error.required && repoEditor.repoID.$dirty">The repository ID cannot be blank.</span>
|
|
<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>
|
|
</p>
|
|
</div>
|
|
<div class="form-group" ng-class="{'has-error': repoEditor.repoPath.$invalid && repoEditor.repoPath.$dirty}">
|
|
<label for="repoPath">Repository Path</label>
|
|
<input name="repoPath" placeholder="~/Documents" id="repoPath" class="form-control" type="text" ng-model="currentRepo.Directory" required></input>
|
|
<p class="help-block">
|
|
<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>
|
|
<span ng-if="repoEditor.repoPath.$error.required && repoEditor.repoPath.$dirty">The repository path cannot be blank.</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<div class="checkbox">
|
|
<label>
|
|
<input type="checkbox" ng-model="currentRepo.ReadOnly"> Repository Master
|
|
</label>
|
|
</div>
|
|
<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>
|
|
</div>
|
|
<div class="form-group">
|
|
<div class="checkbox">
|
|
<label>
|
|
<input type="checkbox" ng-model="currentRepo.IgnorePerms"> Ignore Permissions
|
|
</label>
|
|
</div>
|
|
<p class="help-block">File permission bits are ignored when looking for changes. Use on FAT filesystems.</p>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="nodes">Share With Nodes</label>
|
|
<div class="checkbox" ng-repeat="node in otherNodes()">
|
|
<label>
|
|
<input type="checkbox" ng-model="currentRepo.selectedNodes[node.NodeID]"> {{nodeName(node)}}
|
|
</label>
|
|
</div>
|
|
<p class="help-block">Select the nodes to share this repository with.</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<div class="checkbox">
|
|
<label>
|
|
<input type="checkbox" ng-model="currentRepo.simpleFileVersioning"> File Versioning
|
|
</label>
|
|
</div>
|
|
<p class="help-block">Files are moved to date stamped versions in a <code>.stversions</code> folder when replaced or deleted by syncthing.</p>
|
|
</div>
|
|
<div class="form-group" ng-if="currentRepo.simpleFileVersioning" ng-class="{'has-error': repoEditor.simpleKeep.$invalid && repoEditor.simpleKeep.$dirty}">
|
|
<label for="simpleKeep">Keep Versions</label>
|
|
<input name="simpleKeep" id="simpleKeep" class="form-control" type="number" ng-model="currentRepo.simpleKeep" required min="1"></input>
|
|
<p class="help-block">
|
|
<span ng-if="repoEditor.simpleKeep.$valid || repoEditor.simpleKeep.$pristine">The number of old versions to keep, per file.</span>
|
|
<span ng-if="repoEditor.simpleKeep.$error.required && repoEditor.simpleKeep.$dirty">The number of versions must be a number and cannot be blank.</span>
|
|
<span ng-if="repoEditor.simpleKeep.$error.min && repoEditor.simpleKeep.$dirty">You must keep at least one version.</span>
|
|
</p>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</form>
|
|
<div ng-show="!editingExisting">
|
|
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.
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary" ng-click="saveRepo()" ng-disabled="repoEditor.$invalid"><span class="glyphicon glyphicon-ok"></span> Save</button>
|
|
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> Close</button>
|
|
<button ng-if="editingExisting" type="button" class="btn btn-danger pull-left" ng-click="deleteRepo()"><span class="glyphicon glyphicon-minus"></span> Delete</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Settings modal -->
|
|
|
|
<div id="settings" class="modal fade">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">Settings</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form role="form">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group" ng-repeat="setting in settings">
|
|
<div ng-if="setting.type == 'text' || setting.type == 'number'">
|
|
<label for="{{setting.id}}">{{setting.descr}}</label>
|
|
<input id="{{setting.id}}" class="form-control" type="{{setting.type}}" ng-model="tmpOptions[setting.id]"></input>
|
|
</div>
|
|
<div class="checkbox" ng-if="setting.type == 'bool'">
|
|
<label>
|
|
{{setting.descr}} <input id="{{setting.id}}" type="checkbox" ng-model="tmpOptions[setting.id]"></input>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group" ng-repeat="setting in guiSettings">
|
|
<div ng-if="setting.type == 'text' || setting.type == 'number' || setting.type == 'password'">
|
|
<label for="{{setting.id}}">{{setting.descr}}</label>
|
|
<input id="{{setting.id}}" class="form-control" type="{{setting.type}}" ng-model="tmpGUI[setting.id]"></input>
|
|
</div>
|
|
<div class="checkbox" ng-if="setting.type == 'bool'">
|
|
<label>
|
|
{{setting.descr}} <input id="{{setting.id}}" type="checkbox" ng-model="tmpGUI[setting.id]"></input>
|
|
</label>
|
|
</div>
|
|
<div ng-if="setting.type == 'apikey'">
|
|
<label>{{setting.descr}} (<a href="http://discourse.syncthing.net/t/v0-8-14-api-keys/335">Usage</a>)</label>
|
|
<div class="well well-sm text-monospace">{{tmpGUI[setting.id] || "-"}}</div>
|
|
<button type="button" class="btn btn-sm btn-default" ng-click="setAPIKey(tmpGUI)">Generate</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary" ng-click="saveSettings()"><span class="glyphicon glyphicon-ok"></span> Save</button>
|
|
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Usage report modal -->
|
|
|
|
<div id="ur" class="modal fade">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header alert alert-success">
|
|
<h4 class="modal-title">Allow Anonymous Usage Reporting?</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>
|
|
The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.
|
|
</p>
|
|
<p>
|
|
The aggregated statistics are publicly available at <a href="https://data.syncthing.net/">https://data.syncthing.net/</a>.
|
|
</p>
|
|
<button type="button" class="btn btn-default" ng-show="!reportPreview" ng-click="reportPreview = true">Preview Usage Report</button>
|
|
<pre ng-if="reportPreview"><small>{{reportData | json}}</small></pre>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-success" ng-click="acceptUR()"><span class="glyphicon glyphicon-ok"></span> Yes</button>
|
|
<button type="button" class="btn btn-danger" ng-click="declineUR()"><span class="glyphicon glyphicon-remove"></span> No</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Needed files modal -->
|
|
|
|
<div id="needed" class="modal fade">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header alert alert-info">
|
|
<h4 class="modal-title">Out of Sync Items</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<table class="table table-striped table-condensed">
|
|
<tr ng-repeat="f in needed" ng-init="a = needAction(f)">
|
|
<td class="small-data"><span class="glyphicon glyphicon-{{needIcons[a]}}"></span> {{needActions[a]}}</td>
|
|
<td title="{{f.Name}}">{{f.Name | basename}}</td>
|
|
<td class="text-right small-data"><span ng-if="f.Size > 0">{{f.Size | binary}}B</span></td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<script src="angular.min.js"></script>
|
|
<script src="jquery-2.0.3.min.js"></script>
|
|
<script src="bootstrap/js/bootstrap.min.js"></script>
|
|
<script src="app.js"></script>
|
|
</body>
|
|
</html>
|