2014-01-05 22:54:57 +00:00
<!DOCTYPE html>
< html lang = "en" ng-app = "syncthing" >
< head >
2014-04-09 21:00:23 +00:00
< 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< / 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;
}
h1, h2, h3, h4, h5, h6 {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: 300;
}
a.btn {
text-decoration: none;
}
ul+h5 {
margin-top: 1.5em;
}
.text-monospace {
font-family: 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;
}
thead tr th {
text-align: center;
}
.logo {
margin: 0;
padding: 0;
top: -5px;
position: relative;
}
.progress {
height: 21px;
margin-bottom: inherit;
}
.progress .progress-bar {
line-height: 21px;
font-size: 12px;
}
.collapsed-visible {
display: none;
}
.collapsed .collapsed-visible {
display: inline;
}
.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;
}
2014-04-15 17:14:31 +00:00
.ng-cloak {
display: none !important;
}
2014-04-09 21:00:23 +00:00
< / style >
2014-01-05 22:54:57 +00:00
< / head >
2014-04-15 17:14:31 +00:00
< body ng-controller = "SyncthingCtrl" class = "ng-cloak" >
2014-04-09 21:00:23 +00:00
<!-- Top bar -->
< nav class = "navbar navbar-top navbar-default" role = "navigation" >
2014-01-08 12:52:17 +00:00
< div class = "container" >
2014-04-09 21:00:23 +00:00
< span class = "navbar-brand" > < img class = "logo" src = "st-logo-128.png" width = "32" height = "32" > Syncthing< / span >
< button type = "button" class = "btn btn-default btn-sm pull-right navbar-btn" ng-click = "editSettings()" > < span class = "glyphicon glyphicon-cog" > < / span > Settings< / button >
2014-02-12 11:10:44 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< / nav >
2014-01-05 22:54:57 +00:00
2014-04-09 21:00:23 +00:00
< div class = "container" >
2014-02-12 22:18:41 +00:00
2014-04-09 21:00:23 +00:00
<!-- 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" >
2014-04-16 13:16:44 +00:00
< button type = "button" class = "btn btn-sm btn-default pull-right" ng-click = "restart()" > < span class = "glyphicon glyphicon-refresh" > < / span > Restart Now< / button >
2014-04-09 21:00:23 +00:00
< div class = "clearfix" > < / div >
< / div >
2014-01-05 22:54:57 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< / div >
2014-02-12 11:10:44 +00:00
< / div >
2014-04-09 21:00:23 +00:00
<!-- First regular row -->
2014-02-12 11:10:44 +00:00
< div class = "row" >
2014-04-09 21:00:23 +00:00
<!-- Repository list (top left) -->
< div class = "col-md-6" >
< div class = "panel panel-default" >
< div class = "panel-heading" > < h3 class = "panel-title" > Repositories< / h3 > < / div >
< div class = "panel-body" >
< ul class = "list-unstyled" ng-repeat = "repo in repos" >
< li >
< span class = "text-monospace" > {{repo.Directory}}< / span >
2014-04-27 19:53:27 +00:00
< span ng-if = "repo.Invalid" class = "label label-danger" > Invalid: {{repo.Invalid}}< / span >
2014-04-09 21:00:23 +00:00
< ul class = "list-no-bullet" >
< li >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Repository ID" >
2014-04-09 21:00:23 +00:00
< span class = "text-muted glyphicon glyphicon-tag" > < / span >
< span class = "data" > {{repo.ID}}< / span >
2014-01-09 23:09:27 +00:00
< / div >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Repository synchronization status" >
2014-04-14 07:58:17 +00:00
< span class = "text-muted glyphicon glyphicon-comment" > < / span >
< span class = "data" ng-class = "repoClass(repo.ID)" > {{repoStatus(repo.ID)}}< / span >
2014-04-09 21:00:23 +00:00
< / div >
< / li >
< li >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Global repository files" >
2014-04-09 21:00:23 +00:00
< span class = "text-muted glyphicon glyphicon-globe" > < / span >
< span class = "data" > {{model[repo.ID].globalFiles | alwaysNumber}} files, {{model[repo.ID].globalBytes | binary}}B< / span >
< / div >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Local repository files" >
2014-04-09 21:00:23 +00:00
< span class = "text-muted glyphicon glyphicon-home" > < / span >
< span class = "data" > {{model[repo.ID].localFiles | alwaysNumber}} files, {{model[repo.ID].localBytes | binary}}B< / span >
< / div >
< / li >
< li >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Unsynchronized files" >
2014-04-09 21:00:23 +00:00
< span class = "text-muted glyphicon glyphicon-cloud-download" > < / span >
< span class = "data" > {{model[repo.ID].needFiles | alwaysNumber}} files, {{model[repo.ID].needBytes | binary}}B< / span >
< / div >
< div class = "li-column" >
< span class = "text-muted glyphicon glyphicon-cog" > < / span >
< span class = "data" > < a href = "" ng-click = "editRepo(repo)" > < span class = "glyphicon glyphicon-pencil" > < / span > Edit< / a > < / span >
< / div >
< / li >
< / ul >
< / li >
< / ul >
< / div >
< div class = "panel-footer" >
< button type = "button" class = "pull-right btn btn-sm btn-default" ng-click = "addRepo()" > < span class = "glyphicon glyphicon-plus" > < / span > Add Repository< / button >
< div class = "clearfix" > < / div >
< / div >
2014-02-12 11:10:44 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< / div >
2014-01-05 22:54:57 +00:00
2014-04-09 21:00:23 +00:00
<!-- Node list (top right) -->
< div class = "col-md-6" >
< div class = "panel panel-default" >
< div class = "panel-heading" > < h3 class = "panel-title" > Nodes< / h3 > < / div >
< div class = "panel-body" >
< h5 > Peer Nodes< / h5 >
< ul class = "list-unstyled" ng-repeat = "nodeCfg in otherNodes()" >
< li >
< span class = "text-monospace" > {{nodeName(nodeCfg)}}< / span >
< ul class = "list-no-bullet" >
< li >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Node address" >
2014-04-09 21:00:23 +00:00
< span class = "text-muted glyphicon glyphicon-link" > < / span >
< span class = "data" > {{nodeAddr(nodeCfg)}}< / span >
2014-02-13 11:41:37 +00:00
< / div >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Node synchronization status" >
2014-04-14 07:58:17 +00:00
< span class = "text-muted glyphicon glyphicon-comment" > < / span >
2014-04-09 21:00:23 +00:00
< span class = "data text-{{nodeClass(nodeCfg)}}" > {{nodeStatus(nodeCfg)}}< / span >
2014-02-12 11:10:44 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< / li >
< li >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Download rate" >
2014-04-09 21:00:23 +00:00
< span class = "text-muted glyphicon glyphicon-cloud-download" > < / span >
< span class = "data" > {{connections[nodeCfg.NodeID].inbps | metric}}bps< / span >
2014-02-01 19:23:19 +00:00
< / div >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Upload rate" >
2014-04-09 21:00:23 +00:00
< span class = "text-muted glyphicon glyphicon-cloud-upload" > < / span >
< span class = "data" > {{connections[nodeCfg.NodeID].outbps | metric}}bps< / span >
< / div >
< / li >
< li >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Node version" >
2014-04-09 21:00:23 +00:00
< span class = "text-muted glyphicon glyphicon-tag" > < / span >
< span class = "data" > {{nodeVer(nodeCfg)}}< / span >
< / div >
< div class = "li-column" >
< span class = "text-muted glyphicon glyphicon-cog" > < / span >
< span class = "data" > < a href = "" ng-click = "editNode(nodeCfg)" > < span class = "glyphicon glyphicon-pencil" > < / span > Edit< / a > < / span >
< / div >
< / li >
< / ul >
< / li >
< / ul >
< h5 > This Node< / h5 >
< ul class = "list-unstyled" ng-repeat = "nodeCfg in thisNode()" >
< li >
< span class = "text-monospace" > {{nodeName(nodeCfg)}}< / span >  
< ul class = "list-no-bullet" >
< li >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Current RAM utilization" >
2014-04-09 21:00:23 +00:00
< span class = "text-muted glyphicon glyphicon-th" > < / span >
< span class = "data" > {{system.sys | binary}}B RAM< / span >
< / div >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Current CPU utilization (10 s)" >
2014-04-09 21:00:23 +00:00
< span class = "text-muted glyphicon glyphicon-tasks" > < / span >
< span class = "data" > {{system.cpuPercent | alwaysNumber | natural:1}}% CPU< / span >
< / div >
< / li >
< li >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Download rate (total)" >
2014-04-09 21:00:23 +00:00
< span class = "text-muted glyphicon glyphicon-cloud-download" > < / span >
< span class = "data" > {{inbps | metric}}bps< / span >
< / div >
2014-04-15 08:34:34 +00:00
< div class = "li-column" title = "Upload rate (total)" >
2014-04-09 21:00:23 +00:00
< span class = "text-muted glyphicon glyphicon-cloud-upload" > < / span >
< span class = "data" > {{outbps | metric}}bps< / span >
< / div >
< / li >
< li >
2014-04-16 15:36:09 +00:00
< div ng-if = "system.extAnnounceOK != undefined" class = "li-column" title = "Global announce server" >
< span class = "text-muted glyphicon glyphicon-bullhorn" > < / span >
< span class = "data text-success" ng-if = "system.extAnnounceOK" > Online< / span >
< span class = "data text-danger" ng-if = "!system.extAnnounceOK" > Offline< / span >
< / div >
2014-04-09 21:00:23 +00:00
< div class = "li-column" >
< span class = "text-muted glyphicon glyphicon-cog" > < / span >
< span class = "data" > < a href = "" ng-click = "editNode(nodeCfg)" > < span class = "glyphicon glyphicon-pencil" > < / span > Edit< / a > < / span >
< / div >
< / li >
< / ul >
< / li >
< / ul >
< / div >
< div class = "panel-footer" >
< button type = "button" class = "pull-right btn btn-sm btn-default" ng-click = "addNode()" > < span class = "glyphicon glyphicon-plus" > < / span > Add Node< / button >
< div class = "clearfix" > < / div >
< / div >
2014-01-05 22:54:57 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< / 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" >
2014-04-22 13:59:16 +00:00
< p ng-repeat = "err in errorList()" > < small > {{err.Time | date:"H:mm:ss"}}:< / small > {{friendlyNodes(err.Error)}}< / p >
2014-04-09 21:00:23 +00:00
< / div >
< div class = "panel-footer" >
< button type = "button" class = "pull-right btn btn-sm btn-default" ng-click = "clearErrors()" > OK< / button >
< div class = "clearfix" > < / div >
< / div >
< / div >
< / div >
2014-01-05 22:54:57 +00:00
< / div >
2014-02-12 11:10:44 +00:00
2014-04-09 21:00:23 +00:00
< / div > <!-- /container -->
<!-- Bottom bar -->
< nav class = "navbar navbar-default navbar-fixed-bottom hidden-xs" >
2014-02-12 11:10:44 +00:00
< div class = "container" >
2014-04-09 21:00:23 +00:00
< p class = "navbar-text" > {{version}}< / p >
< ul class = "nav navbar-nav navbar-right" >
< li > < a class = "navbar-link" href = "http://discourse.syncthing.net/" > Support / Forum< / a > < / li >
< li > < a class = "navbar-link hidden-sm" href = "https://github.com/calmh/syncthing/releases" > Latest Release< / a > < / li >
< li > < a class = "navbar-link" href = "https://github.com/calmh/syncthing/wiki" > Documentation< / a > < / li >
< li > < a class = "navbar-link hidden-sm" href = "https://github.com/calmh/syncthing/issues" > Bugs< / a > < / li >
< li > < a class = "navbar-link hidden-sm" href = "https://github.com/calmh/syncthing" > Source Code< / a > < / li >
< / ul >
2014-02-12 11:10:44 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< / nav >
<!-- Network error modal -->
2014-01-05 22:54:57 +00:00
2014-04-09 21:00:23 +00:00
< div id = "networkError" class = "modal fade" >
2014-01-09 09:31:27 +00:00
< div class = "modal-dialog" >
2014-04-09 21:00:23 +00:00
< 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 >
2014-04-16 13:16:44 +00:00
<!-- 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 >
2014-04-09 21:00:23 +00:00
<!-- Node editor modal -->
< div id = "editNode" class = "modal fade" >
< div class = "modal-dialog modal-lg" >
< div class = "modal-content" >
< div class = "modal-header" >
< button type = "button" class = "close" data-dismiss = "modal" aria-hidden = "true" > × < / button >
< 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" >
< div class = "form-group" >
< label for = "nodeID" > Node ID< / label >
2014-04-30 20:42:39 +00:00
< input ng-if = "!editingExisting" id = "nodeID" class = "form-control" type = "text" ng-model = "currentNode.NodeID" > < / input >
< div ng-if = "editingExisting" class = "well well-sm" > {{currentNode.NodeID}}< / div >
< p class = "help-block" > The node ID can be found in the "Add Node" dialog on the other node.< / p >
2014-04-09 21:00:23 +00:00
< / div >
< div class = "form-group" >
< label for = "name" > 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 >
2014-01-09 09:31:27 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< 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 >
2014-01-09 09:31:27 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< / form >
< div ng-show = "!editingExisting" >
When adding a new node, keep in mind that < em > this node< / em > must be added on the other side too. The Node ID of this node is:
< pre > {{myID}}< / pre >
< / div >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-primary" ng-click = "saveNode()" > Save< / button >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > Close< / button >
2014-04-22 10:01:09 +00:00
< button ng-if = "editingExisting && !editingSelf" type = "button" class = "btn btn-danger pull-left" ng-click = "deleteNode()" > Delete< / button >
2014-01-09 09:31:27 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< / div >
2014-01-09 09:31:27 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< / div >
2014-01-09 09:31:27 +00:00
2014-04-09 21:00:23 +00:00
<!-- Repo editor modal -->
< div id = "editRepo" class = "modal fade" >
2014-02-01 19:23:19 +00:00
< div class = "modal-dialog modal-lg" >
2014-04-09 21:00:23 +00:00
< div class = "modal-content" >
< div class = "modal-header" >
< button type = "button" class = "close" data-dismiss = "modal" aria-hidden = "true" > × < / button >
< 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" >
< div class = "form-group" >
< label for = "repoID" > Repository ID< / label >
< input placeholder = "documents" ng-disabled = "editingExisting" id = "repoID" class = "form-control" type = "text" ng-model = "currentRepo.ID" > < / input >
< p class = "help-block" > Short, unique identifier for the repository. Must be the same on all cluster nodes.< / p >
2014-02-01 19:23:19 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< div class = "form-group" >
< label for = "repoPath" > Repository Path< / label >
< input placeholder = "~/Documents" id = "repoPath" class = "form-control" type = "text" ng-model = "currentRepo.Directory" > < / input >
< p class = "help-block" > Path to the repository on the local computer. Will be created if it does not exist.< / p >
< / div >
< div class = "form-group" >
< div class = "checkbox" >
< label >
< input type = "checkbox" ng-model = "currentRepo.ReadOnly" > Read Only
< / label >
< / div >
< / div >
< div class = "form-group" >
< label for = "nodes" > 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 >
2014-02-01 19:23:19 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< / 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()" > Save< / button >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > Close< / button >
< button ng-if = "editingExisting" type = "button" class = "btn btn-danger pull-left" ng-click = "deleteRepo()" > 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" >
< button type = "button" class = "close" data-dismiss = "modal" aria-hidden = "true" > × < / button >
< 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 = "config.Options[setting.id]" > < / input >
< / div >
< div class = "checkbox" ng-if = "setting.type == 'bool'" >
< label >
{{setting.descr}} < input id = "{{setting.id}}" type = "checkbox" ng-model = "config.Options[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 = "config.GUI[setting.id]" > < / input >
< / div >
< div class = "checkbox" ng-if = "setting.type == 'bool'" >
< label >
{{setting.descr}} < input id = "{{setting.id}}" type = "checkbox" ng-model = "config.GUI[setting.id]" > < / input >
< / label >
< / div >
< / div >
< / div >
2014-02-01 19:23:19 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< / form >
2014-02-01 19:23:19 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< div class = "modal-footer" >
< button type = "button" class = "btn btn-primary" ng-click = "saveSettings()" > Save< / button >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > Close< / button >
< / div >
< / div >
2014-02-01 19:23:19 +00:00
< / div >
2014-04-09 21:00:23 +00:00
< / div >
2014-02-01 19:23:19 +00:00
2014-04-09 21:00:23 +00:00
< 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 >
2014-01-05 22:54:57 +00:00
< / body >
< / html >