mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-19 19:45:12 +00:00
1027 lines
60 KiB
HTML
1027 lines
60 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
// Copyright (C) 2014 The Syncthing Authors.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify it
|
|
// under the terms of the GNU General Public License as published by the Free
|
|
// Software Foundation, either version 3 of the License, or (at your option)
|
|
// any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
// more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License along
|
|
// with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
-->
|
|
<html lang="en" ng-app="syncthing" ng-controller="SyncthingController" 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="assets/img/favicon.png">
|
|
|
|
<title>Syncthing | {{thisDeviceName()}}</title>
|
|
<link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
|
<link href="assets/font/raleway.css" rel="stylesheet">
|
|
<link href="assets/css/overrides.css" rel="stylesheet">
|
|
</head>
|
|
|
|
<body>
|
|
<div ng-controller="EventController"></div>
|
|
|
|
<!-- Top bar -->
|
|
|
|
<nav class="navbar navbar-top navbar-default" role="navigation">
|
|
<div class="container">
|
|
<span class="navbar-brand"><img class="logo" src="assets/img/logo-text-64.png" height="32" width="117"/></span>
|
|
<p class="navbar-text hidden-xs">{{thisDeviceName()}}</p>
|
|
<ul class="nav navbar-nav navbar-right">
|
|
<li ng-if="upgradeInfo && upgradeInfo.newer">
|
|
<button type="button" class="btn navbar-btn btn-primary btn-sm" href="" ng-click="upgrade()">
|
|
<span class="glyphicon glyphicon-chevron-up"></span> 
|
|
<span translate translate-value-version="{{upgradeInfo.latest}}">Upgrade To {%version%}</span>
|
|
</button>
|
|
</li>
|
|
<li class="dropdown">
|
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-cog" aria-label="Edit"></span></a>
|
|
<ul class="dropdown-menu">
|
|
<li><a href="" ng-click="editSettings()"><span class="glyphicon glyphicon-cog"></span> <span translate>Settings</span></a></li>
|
|
<li><a href="" ng-click="idDevice()"><span class="glyphicon glyphicon-qrcode"></span> <span translate>Show ID</span></a></li>
|
|
<li class="divider"></li>
|
|
<li><a href="" ng-click="shutdown()"><span class="glyphicon glyphicon-off"></span> <span translate>Shutdown</span></a></li>
|
|
<li><a href="" ng-click="restart()"><span class="glyphicon glyphicon-refresh"></span> <span translate>Restart</span></a></li>
|
|
<li class="divider"></li>
|
|
<li><a href="" ng-click="about()"><span class="glyphicon glyphicon-heart-empty"></span> <span translate>About</span></a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="container">
|
|
|
|
<!-- Panel: Restart Needed -->
|
|
|
|
<div ng-if="!configInSync" class="row">
|
|
<div class="col-md-12">
|
|
<div class="panel panel-warning">
|
|
<div class="panel-heading"><h3 class="panel-title"><span class="glyphicon glyphicon-exclamation-sign"></span><span translate>Restart Needed</span></h3></div>
|
|
<div class="panel-body">
|
|
<p translate>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> <span translate>Restart</span></button>
|
|
<div class="clearfix"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Panel: New Device -->
|
|
|
|
<div ng-repeat="(device, event) in deviceRejections" class="row">
|
|
<div class="col-md-12">
|
|
<div class="panel panel-warning">
|
|
<div class="panel-heading">
|
|
<h3 class="panel-title">
|
|
<identicon data-value="device"></identicon> <span translate>New Device</span>
|
|
</h3>
|
|
</div>
|
|
<div class="panel-body">
|
|
<p>
|
|
<small>{{ event.time | date:"H:mm:ss" }}:</small>
|
|
<span translate translate-value-device="{{ device }}" translate-value-address="{{ event.data.address }}">
|
|
Device {%device%} ({%address%}) wants to connect. Add new device?
|
|
<span>
|
|
</p>
|
|
</div>
|
|
<div class="panel-footer clearfix">
|
|
<div class="pull-right">
|
|
<button class="btn btn-sm btn-success" ng-click="addNewDeviceID(device)"><span class="glyphicon glyphicon-ok"></span> <span translate>Add</span></button>
|
|
<button class="btn btn-sm btn-danger" ng-click="ignoreRejectedDevice(device)"><span class="glyphicon glyphicon-remove"></span> <span translate>Ignore</span></button>
|
|
<button class="btn btn-sm btn-default" ng-click="dismissDeviceRejection(device)"><span class="glyphicon glyphicon-time"></span> <span translate>Later</span></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Panel: New Folder -->
|
|
|
|
<div ng-repeat="(key, event) in folderRejections" class="row reject">
|
|
<div class="col-md-12">
|
|
<div class="panel panel-warning">
|
|
<div class="panel-heading">
|
|
<h3 class="panel-title"><span class="glyphicon glyphicon-hdd"></span>
|
|
<span translate ng-if="!folders[event.data.folder]">New Folder</span>
|
|
<span translate ng-if="folders[event.data.folder]">Share Folder</span>
|
|
</h3>
|
|
</div>
|
|
<div class="panel-body">
|
|
<p>
|
|
<small>{{ event.time | date:"H:mm:ss" }}:</small>
|
|
<span translate translate-value-device="{{ deviceName(findDevice(event.data.device)) }}" translate-value-folder="{{ event.data.folder }}">
|
|
{%device%} wants to share folder "{%folder%}".
|
|
</span>
|
|
<span translate ng-if="folders[event.data.folder]">Share this folder?</span>
|
|
<span translate ng-if="!folders[event.data.folder]">Add new folder?</span>
|
|
</p>
|
|
</div>
|
|
<div class="panel-footer clearfix">
|
|
<div class="pull-right">
|
|
<button class="btn btn-sm btn-success" ng-click="addFolderAndShare(event.data.folder, event.data.device)" ng-if="!folders[event.data.folder]">
|
|
<span class="glyphicon glyphicon-ok"></span> <span translate>Add</span>
|
|
</button>
|
|
<button class="btn btn-sm btn-success" ng-click="shareFolderWithDevice(event.data.folder, event.data.device)" ng-if="folders[event.data.folder]">
|
|
<span class="glyphicon glyphicon-ok"></span> <span translate>Share</span>
|
|
</button>
|
|
<button class="btn btn-sm btn-default" ng-click="dismissFolderRejection(event.data.folder, event.data.device)">
|
|
<span class="glyphicon glyphicon-time"></span> <span translate>Later</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Panel: Notice -->
|
|
|
|
<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"><span class="glyphicon glyphicon-exclamation-sign"></span><span translate>Notice</span></h3></div>
|
|
<div class="panel-body">
|
|
<p ng-repeat="err in errorList()"><small>{{err.Time | date:"H:mm:ss"}}:</small> {{friendlyDevices(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> <span translate>OK</span></button>
|
|
<div class="clearfix"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- First regular row -->
|
|
|
|
<div class="row">
|
|
|
|
<!-- Folder list (top left) -->
|
|
|
|
<div class="col-md-6">
|
|
<div class="panel-group" id="folders">
|
|
<div class="visible-xs"><h3><span translate>Folders</span></h3><hr></div>
|
|
<div class="panel panel-default" ng-repeat="folder in folderList()">
|
|
<div class="panel-heading" data-toggle="collapse" data-parent="#folders" href="#folder-{{$index}}" style="cursor: pointer">
|
|
<div class="panel-progress" ng-show="folderStatus(folder) == 'syncing'" ng-attr-style="width: {{syncPercentage(folder.ID)}}%"></div>
|
|
<h3 class="panel-title">
|
|
<span class="glyphicon glyphicon-hdd hidden-xs"></span>{{folder.ID}}
|
|
<span class="pull-right text-{{folderClass(folder)}}" ng-switch="folderStatus(folder)">
|
|
<span ng-switch-when="unknown"><span class="hidden-xs" translate>Unknown</span><span class="visible-xs">◼</span></span>
|
|
<span ng-switch-when="unshared"><span class="hidden-xs" translate>Unshared</span><span class="visible-xs">◼</span></span>
|
|
<span ng-switch-when="stopped"><span class="hidden-xs" translate>Stopped</span><span class="visible-xs">◼</span></span>
|
|
<span ng-switch-when="scanning"><span class="hidden-xs" translate>Scanning</span><span class="visible-xs">◼</span></span>
|
|
<span ng-switch-when="idle"><span class="hidden-xs" translate>Up to Date</span><span class="visible-xs">◼</span></span>
|
|
<span ng-switch-when="syncing">
|
|
<span class="hidden-xs" translate>Syncing</span>
|
|
({{syncPercentage(folder.ID)}}%)
|
|
</span>
|
|
</span>
|
|
</h3>
|
|
</div>
|
|
<div id="folder-{{$index}}" class="panel-collapse collapse" ng-class="{in: $index === 0}">
|
|
<div class="panel-body">
|
|
<table class="table table-condensed table-striped">
|
|
<tbody>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-folder-open"></span> <span translate>Folder Path</span></th>
|
|
<td class="text-right">{{folder.Path}}</td>
|
|
</tr>
|
|
<tr ng-if="model[folder.ID].invalid">
|
|
<th><span class="glyphicon glyphicon-warning-sign"></span> <span translate>Error</span></th>
|
|
<td class="text-right">{{model[folder.ID].invalid}}</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-globe"></span> <span translate>Global State</span></th>
|
|
<td class="text-right">{{model[folder.ID].globalFiles | alwaysNumber}} <span translate>items</span>, ~{{model[folder.ID].globalBytes | binary}}B</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-home"></span> <span translate>Local State</span></th>
|
|
<td class="text-right">{{model[folder.ID].localFiles | alwaysNumber}} <span translate>items</span>, ~{{model[folder.ID].localBytes | binary}}B</td>
|
|
</tr>
|
|
<tr ng-if="model[folder.ID].needFiles > 0">
|
|
<th><span class="glyphicon glyphicon-cloud-download"></span> <span translate>Out Of Sync</span></th>
|
|
<td class="text-right">
|
|
<a ng-click="showNeed(folder.ID)" href="">{{model[folder.ID].needFiles | alwaysNumber}} <span translate>items</span>, ~{{model[folder.ID].needBytes | binary}}B</a>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="folder.ReadOnly">
|
|
<th><span class="glyphicon glyphicon-lock"></span> <span translate>Folder Master</span></th>
|
|
<td class="text-right">
|
|
<span translate>Yes</span>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="model[folder.ID].ignorePatterns">
|
|
<th><span class="glyphicon glyphicon-eye-close"></span> <span translate>Ignore Patterns</span></th>
|
|
<td class="text-right">
|
|
<span translate>Yes</span>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="folder.IgnorePerms">
|
|
<th><span class="glyphicon glyphicon-unchecked"></span> <span translate>Ignore Permissions</span></th>
|
|
<td class="text-right">
|
|
<span translate>Yes</span>
|
|
</td>
|
|
</tr>
|
|
<tr ng-if="folder.RescanIntervalS != 60">
|
|
<th><span class="glyphicon glyphicon-refresh"></span> <span translate>Rescan Interval</span></th>
|
|
<td class="text-right">{{folder.RescanIntervalS}} s</td>
|
|
</tr>
|
|
<tr ng-if="folder.Versioning.Type">
|
|
<th><span class="glyphicon glyphicon-tags"></span> <span translate>File Versioning</span></th>
|
|
<td class="text-right" ng-switch="folder.Versioning.Type">
|
|
<span ng-switch-when="staggered" translate>Staggered File Versioning</span>
|
|
<span ng-switch-when="simple" translate>Simple File Versioning</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-share-alt"></span> <span translate>Shared With</span></th>
|
|
<td class="text-right">{{sharesFolder(folder)}}</td>
|
|
</tr>
|
|
<tr ng-if="folderStats[folder.ID].LastFile">
|
|
<th><span class="glyphicon glyphicon-transfer"></span> <span translate>Last File Received</span></th>
|
|
<td class="text-right">
|
|
<span title="{{folderStats[folder.ID].LastFile.Filename}} @ {{folderStats[folder.ID].LastFile.At | date:'yyyy-MM-dd HH:mm'}}">
|
|
{{folderStats[folder.ID].LastFile.Filename | basename}}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="panel-footer">
|
|
<button class="btn btn-sm btn-danger pull-left" ng-if="folder.ReadOnly && model[folder.ID].needFiles > 0" ng-click="override(folder.ID)" href=""><span class="glyphicon glyphicon-upload"></span> <span translate>Override Changes</span></button>
|
|
<span class="pull-right">
|
|
<button class="btn btn-sm btn-default" href="" ng-show="folderStatus(folder) == 'idle'" ng-click="rescanFolder(folder.ID)"><span class="glyphicon glyphicon-refresh"></span> <span translate>Rescan</span></button>
|
|
<button class="btn btn-sm btn-default" href="" ng-click="editFolder(folder)"><span class="glyphicon glyphicon-pencil"></span> <span translate>Edit</span></button>
|
|
</span>
|
|
<div class="clearfix"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<button class="btn btn-sm btn-default pull-right" ng-click="addFolder()"><span class="glyphicon glyphicon-plus"></span> <span translate>Add Folder</span></button>
|
|
<div class="clearfix"></div>
|
|
</div>
|
|
<hr class="visible-sm"/>
|
|
</div>
|
|
|
|
<!-- Device list (top right) -->
|
|
|
|
<!-- This device -->
|
|
|
|
<div class="col-md-6">
|
|
<div class="visible-xs"><h3><span translate>Devices</span></h3><hr></div>
|
|
<div class="panel panel-default" ng-repeat="deviceCfg in [thisDevice()]">
|
|
<div class="panel-heading" data-toggle="collapse" href="#device-this" style="cursor: pointer">
|
|
<h3 class="panel-title">
|
|
<identicon data-value="deviceCfg.DeviceID"></identicon> {{deviceName(deviceCfg)}}
|
|
</h3>
|
|
</div>
|
|
<div id="device-this" class="panel-collapse collapse in">
|
|
<div class="panel-body">
|
|
<table class="table table-condensed table-striped">
|
|
<tbody>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-cloud-download"></span> <span translate>Download Rate</span></th>
|
|
<td class="text-right">{{connections['total'].inbps | binary}}B/s ({{connections['total'].InBytesTotal | binary}}B)</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-cloud-upload"></span> <span translate>Upload Rate</span></th>
|
|
<td class="text-right">{{connections['total'].outbps | binary}}B/s ({{connections['total'].OutBytesTotal | binary}}B)</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-th"></span> <span translate>RAM Utilization</span></th>
|
|
<td class="text-right">{{system.sys | binary}}B</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-dashboard"></span> <span translate>CPU Utilization</span></th>
|
|
<td class="text-right">{{system.cpuPercent | alwaysNumber | natural:1}}%</td>
|
|
</tr>
|
|
<tr ng-if="system.extAnnounceOK != undefined && announceServersTotal > 0">
|
|
<th><span class="glyphicon glyphicon-bullhorn"></span> <span translate>Global Discovery</span></th>
|
|
<td class="text-right">
|
|
<span ng-if="announceServersFailed.length == 0" class="data text-success">
|
|
<span>OK</span>
|
|
</span>
|
|
<span ng-if="announceServersFailed.length != 0" class="data text-danger">
|
|
<span popover data-trigger="hover" data-placement="bottom" data-content="{{announceServersFailed.join('\n')}}">
|
|
{{announceServersTotal-announceServersFailed.length}}/{{announceServersTotal}}
|
|
</span>
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-tag"></span> <span translate>Version</span></th>
|
|
<td class="text-right">{{version}}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Remote devices -->
|
|
|
|
<div class="panel-group" id="devices">
|
|
<div class="panel panel-default" ng-repeat="deviceCfg in otherDevices()">
|
|
<div class="panel-heading" data-toggle="collapse" data-parent="#devices" href="#device-{{$index}}" style="cursor: pointer">
|
|
<div class="panel-progress" ng-show="deviceStatus(deviceCfg) == 'syncing'" ng-attr-style="width: {{completion[deviceCfg.DeviceID]._total | number:0}}%"></div>
|
|
<h3 class="panel-title">
|
|
<identicon data-value="deviceCfg.DeviceID"></identicon> {{deviceName(deviceCfg)}}
|
|
<span ng-switch="deviceStatus(deviceCfg)" class="pull-right text-{{deviceClass(deviceCfg)}}">
|
|
<span ng-switch-when="insync"><span class="hidden-xs" translate>Up to Date</span><span class="visible-xs">◼</span></span>
|
|
<span ng-switch-when="syncing">
|
|
<span class="hidden-xs" translate>Syncing</span> ({{completion[deviceCfg.DeviceID]._total | number:0}}%)
|
|
</span>
|
|
<span ng-switch-when="disconnected"><span class="hidden-xs" translate>Disconnected</span><span class="visible-xs">◼</span></span>
|
|
<span ng-switch-when="unused"><span class="hidden-xs" translate>Unused</span><span class="visible-xs">◼</span></span>
|
|
</span>
|
|
</h3>
|
|
</div>
|
|
<div id="device-{{$index}}" class="panel-collapse collapse">
|
|
<div class="panel-body">
|
|
<table class="table table-condensed table-striped">
|
|
<tbody>
|
|
<tr ng-if="connections[deviceCfg.DeviceID]">
|
|
<th><span class="glyphicon glyphicon-cloud-download"></span> <span translate>Download Rate</span></th>
|
|
<td class="text-right">{{connections[deviceCfg.DeviceID].inbps | binary}}B/s ({{connections[deviceCfg.DeviceID].InBytesTotal | binary}}B)</td>
|
|
</tr>
|
|
<tr ng-if="connections[deviceCfg.DeviceID]">
|
|
<th><span class="glyphicon glyphicon-cloud-upload"></span> <span translate>Upload Rate</span></th>
|
|
<td class="text-right">{{connections[deviceCfg.DeviceID].outbps | binary}}B/s ({{connections[deviceCfg.DeviceID].OutBytesTotal | binary}}B)</td>
|
|
</tr>
|
|
<tr>
|
|
<th><span class="glyphicon glyphicon-link"></span> <span translate>Address</span></th>
|
|
<td class="text-right">{{deviceAddr(deviceCfg)}}</td>
|
|
</tr>
|
|
<tr ng-if="!deviceCfg.Compression">
|
|
<th><span class="glyphicon glyphicon-compressed"></span> <span translate>Use Compression</span></th>
|
|
<td translate class="text-right">No</td>
|
|
</tr>
|
|
<tr ng-if="deviceCfg.Introducer">
|
|
<th><span class="glyphicon glyphicon-thumbs-up"></span> <span translate>Introducer</span></th>
|
|
<td translate class="text-right">Yes</td>
|
|
</tr>
|
|
<tr ng-if="connections[deviceCfg.DeviceID]">
|
|
<th><span class="glyphicon glyphicon-tag"></span> <span translate>Version</span></th>
|
|
<td class="text-right">{{connections[deviceCfg.DeviceID].ClientVersion}}</td>
|
|
</tr>
|
|
<tr ng-if="!connections[deviceCfg.DeviceID]">
|
|
<th><span class="glyphicon glyphicon-eye-open"></span> <span translate>Last seen</span></th>
|
|
<td translate ng-if="!deviceStats[deviceCfg.DeviceID].LastSeenDays || deviceStats[deviceCfg.DeviceID].LastSeenDays >= 365" class="text-right">Never</td>
|
|
<td ng-if="deviceStats[deviceCfg.DeviceID].LastSeenDays < 365" class="text-right">{{deviceStats[deviceCfg.DeviceID].LastSeen | date:"yyyy-MM-dd HH:mm"}}</td>
|
|
</tr>
|
|
<tr ng-if="deviceFolders(deviceCfg).length > 0">
|
|
<th><span class="glyphicon glyphicon-hdd"></span> <span translate>Folders</span></th>
|
|
<td class="text-right">{{deviceFolders(deviceCfg).join(", ")}}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="panel-footer">
|
|
<span class="pull-right"><a class="btn btn-sm btn-default" href="" ng-click="editDevice(deviceCfg)"><span class="glyphicon glyphicon-pencil"></span> <span translate>Edit</span></a></span>
|
|
<div class="clearfix"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<button class="btn btn-sm btn-default pull-right" ng-click="addDevice()"><span class="glyphicon glyphicon-plus"></span> <span translate>Add Device</span></button>
|
|
<div class="clearfix"></div>
|
|
</div>
|
|
</div>
|
|
</div> <!-- /row -->
|
|
|
|
</div> <!-- /container -->
|
|
|
|
<!-- Bottom bar -->
|
|
|
|
<nav class="navbar navbar-default navbar-fixed-bottom">
|
|
<div class="container">
|
|
<ul class="nav navbar-nav">
|
|
<li><a class="navbar-link" href="https://github.com/syncthing/syncthing/wiki" target="_blank"><span class="glyphicon glyphicon-book"></span> <span translate>Documentation</span></a></li>
|
|
<li><a class="navbar-link" href="https://discourse.syncthing.net" target="_blank"><span class="glyphicon glyphicon-question-sign"></span> <span translate>Support</span></a></li>
|
|
<li><a class="navbar-link" href="https://github.com/syncthing/syncthing/releases" target="_blank"><span class="glyphicon glyphicon-info-sign"></span> <span translate>Changelog</span></a></li>
|
|
<li><a class="navbar-link" href="https://github.com/syncthing/syncthing/issues" target="_blank"><span class="glyphicon glyphicon-warning-sign"></span> <span translate>Bugs</span></a></li>
|
|
<li><a class="navbar-link" href="https://github.com/syncthing/syncthing" target="_blank"><span class="glyphicon glyphicon-wrench"></span> <span translate>Source Code</span></a></li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Network error modal -->
|
|
|
|
<modal id="networkError" status="danger" icon="exclamation-sign" title="{{'Connection Error' | translate}}">
|
|
<p translate>
|
|
Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…
|
|
</p>
|
|
</modal>
|
|
|
|
<!-- HTTP error modal -->
|
|
|
|
<modal id="httpError" status="danger" icon="exclamation-sign" title="{{'Connection Error' | translate}}">
|
|
<p translate>
|
|
Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.
|
|
</p>
|
|
</modal>
|
|
|
|
<!-- Restarting modal -->
|
|
|
|
<modal id="restarting" icon="refresh" title="{{'Restarting' | translate}}" status="info">
|
|
<p><span translate>Syncthing is restarting.</span> <span translate>Please wait</span>...</p>
|
|
</modal>
|
|
|
|
<!-- Upgrading modal -->
|
|
|
|
<modal id="upgrading" icon="refresh" title="{{'Upgrading' | translate}}" status="info">
|
|
<p><span translate>Syncthing is upgrading.</span> <span translate>Please wait</span>...</p>
|
|
</modal>
|
|
|
|
<!-- Shutdown modal -->
|
|
|
|
<modal id="shutdown" icon="off" status="success" title="{{'Shutdown Complete' | translate}}">
|
|
<p translate>Syncthing has been shut down.</p>
|
|
</modal>
|
|
|
|
<!-- ID modal -->
|
|
|
|
<modal id="idqr" large="yes" status="info" close="yes" icon="qrcode" title="{{'Device Identification' | translate}} — {{deviceName(thisDevice())}}">
|
|
<div class="well well-sm text-monospace text-center">{{myID}}</div>
|
|
<img ng-if="myID" class="center-block img-thumbnail" src="qr/?text={{myID}}"/>
|
|
</modal>
|
|
|
|
<!-- Device editor modal -->
|
|
|
|
<div id="editDevice" class="modal fade" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 translate ng-show="!editingExisting" class="modal-title">Add Device</h4>
|
|
<h4 translate ng-show="editingExisting" class="modal-title">Edit Device</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form role="form" name="deviceEditor">
|
|
<div class="form-group" ng-class="{'has-error': deviceEditor.deviceID.$invalid && deviceEditor.deviceID.$dirty}">
|
|
<label translate for="deviceID">Device ID</label>
|
|
<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" />
|
|
<datalist id="discovery-list" ng-if="!editingExisting">
|
|
<option ng-repeat="(id,address) in discovery" value="{{ id }}" />
|
|
</datalist>
|
|
<div ng-if="editingExisting" class="well well-sm text-monospace">{{currentDevice.DeviceID}}</div>
|
|
<p class="help-block">
|
|
<span translate ng-if="deviceEditor.deviceID.$valid || deviceEditor.deviceID.$pristine">The device ID to enter here can be found in the "Edit > Show ID" dialog on the other device. Spaces and dashes are optional (ignored).</span>
|
|
<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 translate ng-if="deviceEditor.deviceID.$error.required && deviceEditor.deviceID.$dirty">The device ID cannot be blank.</span>
|
|
<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>
|
|
</p>
|
|
</div>
|
|
<div class="form-group">
|
|
<label translate for="name">Device Name</label>
|
|
<input id="name" class="form-control" type="text" ng-model="currentDevice.Name"></input>
|
|
<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>
|
|
<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>
|
|
<div class="form-group">
|
|
<label translate for="addresses">Addresses</label>
|
|
<input ng-disabled="currentDevice.DeviceID == myID" id="addresses" class="form-control" type="text" ng-model="currentDevice.AddressesStr"></input>
|
|
<p translate class="help-block">Enter comma separated "ip:port" addresses or "dynamic" to perform automatic discovery of the address.</p>
|
|
</div>
|
|
<div ng-if="!editingSelf" class="form-group">
|
|
<div class="checkbox">
|
|
<label>
|
|
<input type="checkbox" ng-model="currentDevice.Compression"> <span translate>Use Compression</span>
|
|
</label>
|
|
<p translate class="help-block">Compression is recommended in most setups.</p>
|
|
</div>
|
|
</div>
|
|
<div ng-if="!editingSelf" 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" ng-if="!editingSelf">
|
|
<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="three-columns">
|
|
<div class="checkbox" ng-repeat="folder in folderList()">
|
|
<label>
|
|
<input type="checkbox" ng-model="currentDevice.selectedFolders[folder.ID]"> {{folder.ID}}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary btn-sm" ng-click="saveDevice()" ng-disabled="deviceEditor.$invalid"><span class="glyphicon glyphicon-ok"></span> <span translate>Save</span></button>
|
|
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> <span translate>Close</span></button>
|
|
<button ng-if="editingExisting && !editingSelf" type="button" class="btn btn-danger pull-left btn-sm" ng-click="deleteDevice()"><span class="glyphicon glyphicon-minus"></span> <span translate>Delete</span></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Folder editor modal -->
|
|
|
|
<div id="editFolder" class="modal fade" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 ng-show="!editingExisting" class="modal-title"><span translate>Add Folder</span></h4>
|
|
<h4 ng-show="editingExisting" class="modal-title"><span translate>Edit Folder</span></h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form role="form" name="folderEditor">
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<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" id="folderID" class="form-control" type="text" ng-model="currentFolder.ID" required unique-folder ng-pattern="/^[a-zA-Z0-9-_.]{1,64}$/"></input>
|
|
<p class="help-block">
|
|
<span translate ng-if="folderEditor.folderID.$valid || folderEditor.folderID.$pristine">Short 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>
|
|
<span translate ng-if="folderEditor.folderID.$error.pattern && folderEditor.folderID.$dirty">The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.</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 />
|
|
<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>
|
|
</p>
|
|
</div>
|
|
<div class="form-group" ng-class="{'has-error': folderEditor.rescanIntervalS.$invalid && folderEditor.rescanIntervalS.$dirty}">
|
|
<label for="rescanIntervalS"><span translate>Rescan Interval</span> (s)</label>
|
|
<input name="rescanIntervalS" id="rescanIntervalS" class="form-control" type="number" ng-model="currentFolder.RescanIntervalS" required min="0"></input>
|
|
<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>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<div class="checkbox">
|
|
<label>
|
|
<input type="checkbox" ng-model="currentFolder.ReadOnly"> <span translate>Folder Master</span>
|
|
</label>
|
|
</div>
|
|
<p 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>
|
|
<p translate class="help-block">File permission bits are ignored when looking for changes. Use on FAT filesystems.</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label translate>File Versioning</label>
|
|
<div class="radio">
|
|
<label>
|
|
<input type="radio" ng-model="currentFolder.FileVersioningSelector" value="none"> <span translate>No File Versioning</span>
|
|
</label>
|
|
</div>
|
|
<div class="radio">
|
|
<label>
|
|
<input type="radio" ng-model="currentFolder.FileVersioningSelector" value="simple"> <span translate>Simple File Versioning</span>
|
|
</label>
|
|
</div>
|
|
<div class="radio">
|
|
<label>
|
|
<input type="radio" ng-model="currentFolder.FileVersioningSelector" value="staggered"> <span translate>Staggered File Versioning</span>
|
|
</label>
|
|
</div>
|
|
</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"></input>
|
|
<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></input>
|
|
<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>
|
|
</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"></input>
|
|
<p translate class="help-block">Path where versions should be stored (leave empty for the default .stversions folder in the folder).</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="three-columns">
|
|
<div class="checkbox" ng-repeat="device in otherDevices()">
|
|
<label>
|
|
<input type="checkbox" ng-model="currentFolder.selectedDevices[device.DeviceID]"> {{deviceName(device)}}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</form>
|
|
<div translate ng-show="!editingExisting">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>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary btn-sm" ng-click="saveFolder()" ng-disabled="folderEditor.$invalid"><span class="glyphicon glyphicon-ok"></span> <span translate>Save</span></button>
|
|
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> <span translate>Close</span></button>
|
|
<button ng-if="editingExisting" type="button" class="btn btn-danger pull-left btn-sm" ng-click="deleteFolder()"><span class="glyphicon glyphicon-minus"></span> <span translate>Delete</span></button>
|
|
<button id="editIgnoresButton" ng-if="editingExisting" type="button" class="btn btn-default pull-left btn-sm" ng-click="editIgnores()"><span class="glyphicon glyphicon-eye-close"></span> <span translate>Ignore Patterns</span></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Ignores editor modal -->
|
|
|
|
<div id="editIgnores" class="modal fade" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<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/>
|
|
|
|
<p class="small"><span translate>Quick guide to supported patterns</span> (<a href="https://github.com/syncthing/syncthing/wiki/Ignoring-Files" target="_blank" translate>full documentation</a>):</p>
|
|
<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>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>Comment, when used at the start of a line</span></dd>
|
|
</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" data-dismiss="modal" ng-click="saveIgnores()"><span class="glyphicon glyphicon-ok"></span> <span translate>Save</span></button>
|
|
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> <span translate>Close</span></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Settings modal -->
|
|
|
|
<div id="settings" class="modal fade" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 translate 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">
|
|
<label translate for="DeviceName">Device Name</label>
|
|
<input id="DeviceName" class="form-control" type="text" ng-model="tmpOptions.DeviceName">
|
|
</div>
|
|
<div class="form-group">
|
|
<label translate for="ListenAddressStr">Sync Protocol Listen Addresses</label>
|
|
<input id="ListenAddressStr" class="form-control" type="text" ng-model="tmpOptions.ListenAddressStr">
|
|
</div>
|
|
<div class="form-group">
|
|
<label translate for="MaxRecvKbps">Incoming Rate Limit (KiB/s)</label>
|
|
<input id="MaxRecvKbps" class="form-control" type="number" ng-model="tmpOptions.MaxRecvKbps">
|
|
</div>
|
|
<div class="form-group">
|
|
<label translate for="MaxSendKbps">Outgoing Rate Limit (KiB/s)</label>
|
|
<input id="MaxSendKbps" class="form-control" type="number" ng-model="tmpOptions.MaxSendKbps">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<div class="checkbox">
|
|
<label>
|
|
<input id="UPnPEnabled" type="checkbox" ng-model="tmpOptions.UPnPEnabled"> <span translate>Enable UPnP</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<div class="checkbox">
|
|
<label>
|
|
<input id="GlobalAnnEnabled" type="checkbox" ng-model="tmpOptions.GlobalAnnEnabled"> <span translate>Global Discovery</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<div class="checkbox">
|
|
<label ng-if="upgradeInfo">
|
|
<input id="AutoUpgradeEnabled" type="checkbox" ng-model="tmpOptions.AutoUpgradeEnabled"> <span translate>Automatic upgrades</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<div class="checkbox">
|
|
<label>
|
|
<input id="LocalAnnEnabled" type="checkbox" ng-model="tmpOptions.LocalAnnEnabled"> <span translate>Local Discovery</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label translate for="GlobalAnnServersStr">Global Discovery Server</label>
|
|
<input ng-disabled="!tmpOptions.GlobalAnnEnabled" id="GlobalAnnServersStr" class="form-control" type="text" ng-model="tmpOptions.GlobalAnnServersStr">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label translate for="Address">GUI Listen Addresses</label>
|
|
<input id="Address" class="form-control" type="text" ng-model="tmpGUI.Address">
|
|
</div>
|
|
<div class="form-group">
|
|
<label translate for="User">GUI Authentication User</label>
|
|
<input id="User" class="form-control" type="text" ng-model="tmpGUI.User">
|
|
</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 translate ng-click="showURPreview()" href="#">Preview</a>)
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<hr />
|
|
|
|
<div class="form-group">
|
|
<label><span translate>API Key</span></label>
|
|
<div class="well well-sm text-monospace">{{tmpGUI.APIKey || "-"}}</div>
|
|
<button translate type="button" class="btn btn-sm btn-default" ng-click="setAPIKey(tmpGUI)">Generate</button>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary btn-sm" ng-click="saveSettings()"><span class="glyphicon glyphicon-ok"></span> <span translate>Save</span></button>
|
|
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> <span translate>Close</span></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Usage report modal -->
|
|
|
|
<div id="ur" class="modal fade" data-backdrop="static" data-keyboard="false" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header alert alert-success">
|
|
<h4 translate class="modal-title">Allow Anonymous Usage Reporting?</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<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>
|
|
<p translate translate-value-url="<a href="https://data.syncthing.net" target="_blank">https://data.syncthing.net</a>">The aggregated statistics are publicly available at {%url%}.</p>
|
|
<button translate type="button" class="btn btn-default btn-sm" ng-show="!reportPreview" ng-click="showReportPreview()">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 btn-sm" ng-click="acceptUR()"><span class="glyphicon glyphicon-ok"></span> <span translate>Yes</span></button>
|
|
<button type="button" class="btn btn-danger btn-sm" ng-click="declineUR()"><span class="glyphicon glyphicon-remove"></span> <span translate>No</span></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Usage report preview modal -->
|
|
|
|
<div id="urPreview" class="modal fade" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header alert alert-success">
|
|
<h4 translate class="modal-title">Anonymous Usage Reporting</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<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>
|
|
<p translate translate-value-url="<a href="https://data.syncthing.net" target="_blank">https://data.syncthing.net</a>">The aggregated statistics are publicly available at {%url%}.</p>
|
|
<pre><small>{{reportData | json}}</small></pre>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-success btn-sm" data-dismiss="modal"><span class="glyphicon glyphicon-ok"></span> <span translate>OK</span></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Needed files modal -->
|
|
|
|
<modal id="needed" large="yes" status="info" icon="cloud-download" close="yes" title="{{'Out of Sync Items' | translate}}">
|
|
<div class="progress">
|
|
<div class="progress-bar progress-bar-success" style="width: 20%"><span translate class="show">Reused</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 ng-repeat="f in needed.progress" 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 ng-if="a == '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="a != 'sync' || !progress[neededFolder] || !progress[neededFolder][f.Name]">
|
|
<span ng-if="f.Size > 0">{{f.Size | binary}}B</span>
|
|
</td>
|
|
</tr>
|
|
<tr ng-repeat="f in needed.queued" ng-init="a = needAction(f)">
|
|
<td class="small-data"><span class="glyphicon glyphicon-{{needIcons[a]}}"></span> {{needActions[a]}}</td>
|
|
<td><a href="" ng-if="$index != 0" ng-click="bumpFile(neededFolder, f.Name)" title="{{'Move to top of queue' | translate}}"><span class="glyphicon glyphicon-eject"></span></a><span ng-if="$index != 0"> </span><span title="{{f.Name}}">{{f.Name | basename}}</span></td>
|
|
<td class="text-right small-data">
|
|
<span ng-if="f.Size > 0">{{f.Size | binary}}B</span>
|
|
</td>
|
|
</tr>
|
|
<tr ng-repeat="f in needed.rest" 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>
|
|
|
|
</modal>
|
|
|
|
<!-- About modal -->
|
|
|
|
<modal id="about" large="yes" close="yes" status="info" title="{{'About' | translate}}">
|
|
<h1 class="text-center"><img alt="Syncthing" title="Syncthing" src="assets/img/logo-text-256.png" style="vertical-align: -16px" height="100" width="366"/><br/><small>{{version}}</small></h1>
|
|
<hr/>
|
|
|
|
<p translate>Copyright © 2014 Jakob Borg and the following Contributors:</p>
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<ul class="list-unstyled three-columns">
|
|
<li>Aaron Bieber</li>
|
|
<li>Andrew Dunham</li>
|
|
<li>Alexander Graf</li>
|
|
<li>Arthur Axel fREW Schmidt</li>
|
|
<li>Audrius Butkevicius</li>
|
|
<li>Ben Schulz</li>
|
|
<li>Ben Sidhom</li>
|
|
<li>Brandon Philips</li>
|
|
<li>Brendan Long</li>
|
|
<li>Caleb Callaway</li>
|
|
<li>Cathryne Linenweaver</li>
|
|
<li>Chris Joel</li>
|
|
<li>Daniel Martí</li>
|
|
<li>Dennis Wilson</li>
|
|
<li>Dominik Heidler</li>
|
|
<li>Emil Hessman</li>
|
|
<li>Federico Castagnini</li>
|
|
<li>Felix Ableitner</li>
|
|
<li>Felix Unterpaintner</li>
|
|
<li>Gilli Sigurdsson</li>
|
|
<li>James Patterson</li>
|
|
<li>Jens Diemer</li>
|
|
<li>Jochen Voss</li>
|
|
<li>Karol Różycki</li>
|
|
<li>Lode Hoste</li>
|
|
<li>Marc Laporte</li>
|
|
<li>Marcin Dziadus</li>
|
|
<li>Michael Jephcote</li>
|
|
<li>Michael Tilli</li>
|
|
<li>Peter Hoeg</li>
|
|
<li>Philippe Schommers</li>
|
|
<li>Phill Luby</li>
|
|
<li>Piotr Bejda</li>
|
|
<li>Ryan Sullivan</li>
|
|
<li>Stefan Tatschner</li>
|
|
<li>Tim Abell</li>
|
|
<li>Tomas Cerveny</li>
|
|
<li>Tully Robinson</li>
|
|
<li>Veeti Paananen</li>
|
|
<li>Vil Brekin</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<hr/>
|
|
|
|
<p translate>Syncthing includes the following software or portions thereof:</p>
|
|
<ul class="list-unstyled two-columns">
|
|
<li><a href="http://golang.org/">The Go Programming Language</a>, Copyright © 2012 The Go Authors.</li>
|
|
<li><a href="https://bitbucket.org/kardianos/osext">kardianos/osext</a>, Copyright © 2012 Daniel Theophanes.</li>
|
|
<li><a href="https://code.google.com/p/snappy-go/">snappy-go</a>, Copyright © 2011 The Snappy-Go Authors.</li>
|
|
<li><a href="https://github.com/golang/groupcache">groupcache/lru</a>, Copyright © 2013 Google Inc.</li>
|
|
<li><a href="https://github.com/juju/ratelimit">juju/ratelimit</a>, Copyright © 2014 Canonical Ltd.</li>
|
|
<li><a href="https://github.com/syndtr/goleveldb">syndtr/goleveldb</a>, Copyright © 2012, Suryandaru Triandana</li>
|
|
<li><a href="https://github.com/vitrun/qart">vitrun/qart</a>, Copyright © The Go Authors.</li>
|
|
<li><a href="https://angularjs.org/">AngularJS</a>, Copyright © 2010-2014 Google, Inc.</li>
|
|
<li><a href="http://getbootstrap.com/">Bootstrap</a>, Copyright © 2011-2014 Twitter, Inc.</li>
|
|
</ul>
|
|
</modal>
|
|
|
|
<!-- vendor scripts -->
|
|
<script src="vendor/angular/angular.min.js"></script>
|
|
<script src="vendor/angular/angular-translate.min.js"></script>
|
|
<script src="vendor/angular/angular-translate-loader.min.js"></script>
|
|
<script src="vendor/jquery/jquery-2.0.3.min.js"></script>
|
|
<script src="vendor/bootstrap/js/bootstrap.min.js"></script>
|
|
<!-- / vendor scripts -->
|
|
|
|
<!-- gui application code -->
|
|
<script src="scripts/syncthing/core/module.js"></script>
|
|
<script src="scripts/syncthing/core/controllers/eventController.js"></script>
|
|
<script src="scripts/syncthing/core/controllers/syncthingController.js"></script>
|
|
<script src="scripts/syncthing/core/directives/identiconDirective.js"></script>
|
|
<script src="scripts/syncthing/core/directives/modalDirective.js"></script>
|
|
<script src="scripts/syncthing/core/directives/uniqueFolderDirective.js"></script>
|
|
<script src="scripts/syncthing/core/directives/validDeviceidDirective.js"></script>
|
|
<script src="scripts/syncthing/core/directives/popoverDirective.js"></script>
|
|
<script src="scripts/syncthing/core/filters/alwaysNumberFilter.js"></script>
|
|
<script src="scripts/syncthing/core/filters/basenameFilter.js"></script>
|
|
<script src="scripts/syncthing/core/filters/binaryFilter.js"></script>
|
|
<script src="scripts/syncthing/core/filters/naturalFilter.js"></script>
|
|
<script src="scripts/syncthing/core/services/localeService.js"></script>
|
|
|
|
<script src="assets/lang/valid-langs.js"></script>
|
|
<script src="scripts/syncthing/app.js"></script>
|
|
<!-- / gui application code -->
|
|
|
|
</body>
|
|
</html>
|