gui: Add copy to clipboard, share by email, and share by SMS buttons to device IDs (fixes #2771, ref #3868) Add buttons to allow for simpler sharing device IDs with others. The first one copies the ID to clipboard (trying to use three different methods, depending on the browser). The second one triggers a mailto link with prefilled subject and body. The third one triggers an sms link with prefilled body. The short description of Syncthing included in the latter part of the body is a direct copy from the description at the official website https://syncthing.net. Issue #3868 is referred here, because the copy to clipboard button offers an alternative method for IE11 users to actually be able to copy device IDs without having to select it manually (which doesn't work). Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
190 lines
13 KiB
HTML
190 lines
13 KiB
HTML
<modal id="editDevice" status="default" icon="{{editDeviceModalIcon()}}" heading="{{editDeviceModalTitle()}}" large="yes" closeable="yes">
|
|
<div class="modal-body">
|
|
<form role="form" name="deviceEditor">
|
|
<ul class="nav nav-tabs" ng-init="loadFormIntoScope(deviceEditor)">
|
|
<li class="active"><a data-toggle="tab" href="#device-general"><span class="fas fa-cog"></span> <span translate>General</span></a></li>
|
|
<li ng-if="!editingDeviceDefaults()"><a data-toggle="tab" href="#device-sharing"><span class="fas fa-share-alt"></span> <span translate>Sharing</span></a></li>
|
|
<li><a data-toggle="tab" href="#device-advanced"><span class="fas fa-cogs"></span> <span translate>Advanced</span></a></li>
|
|
</ul>
|
|
<div class="tab-content">
|
|
<div id="device-general" class="tab-pane in active">
|
|
<div ng-if="!editingDeviceDefaults()" class="form-group" ng-class="{'has-error': deviceEditor.deviceID.$invalid && deviceEditor.deviceID.$dirty}" ng-init="loadFormIntoScope(deviceEditor)">
|
|
<label translate for="deviceID">Device ID</label>
|
|
<div class="input-group">
|
|
<input ng-if="editingDeviceNew()" name="deviceID" id="deviceID" class="form-control text-monospace" type="text" ng-model="currentDevice.deviceID" required="" valid-deviceid list="discovery-list" aria-required="true" />
|
|
<div ng-if="!editingDeviceNew()" class="well well-sm form-control text-monospace" style="height: auto;" select-on-click>{{currentDevice.deviceID}}</div>
|
|
<div id="shareDeviceIdButtons" class="input-group-btn">
|
|
<button type="button" class="btn btn-default" ng-click="copyToClipboard($event, currentDevice.deviceID)" ng-disabled="editingDeviceNew() && !deviceEditor.deviceID.$valid" tooltip data-original-title="{{ 'Copy' | translate }}">
|
|
<span class="fa fa-lg fa-clone"></span>
|
|
</button>
|
|
<button type="button" class="btn btn-default" ng-click="shareDeviceIdDialog('email')" ng-disabled="editingDeviceNew() && !deviceEditor.deviceID.$valid" tooltip data-original-title="{{ 'Share by Email' | translate }}">
|
|
<span class="fa fa-lg fa-envelope-o"></span>
|
|
</button>
|
|
<button type="button" class="btn btn-default" ng-click="shareDeviceIdDialog('sms')" ng-disabled="editingDeviceNew() && !deviceEditor.deviceID.$valid" tooltip data-original-title="{{ 'Share by SMS' | translate }}">
|
|
<span class="fa fa-lg fa-comments-o"></span>
|
|
</button>
|
|
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#idqr" ng-disabled="editingDeviceNew() && !deviceEditor.deviceID.$valid" tooltip data-original-title="{{ 'Show QR' | translate }}">
|
|
<span class="fa fa-lg fa-qrcode"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div ng-if="editingDeviceNew()">
|
|
<datalist id="discovery-list">
|
|
<option ng-repeat="id in discoveryUnknown" value="{{id}}" />
|
|
</datalist>
|
|
<div class="help-block" ng-if="discoveryUnknown && discoveryUnknown.length !== 0">
|
|
<span translate>You can also select one of these nearby devices:</span>
|
|
<ul>
|
|
<li ng-repeat="id in discoveryUnknown.slice(0, 5)" style="list-style-type: none;">
|
|
<a href="#" ng-click="currentDevice.deviceID = id">
|
|
<identicon data-value="id"></identicon> {{id}}
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</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 "Actions > Show ID" dialog on the other device. Spaces and dashes are optional (ignored).</span>
|
|
<span translate ng-show="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>
|
|
<span translate ng-if="deviceEditor.deviceID.$error.unique && deviceEditor.deviceID.$dirty">A device with that ID is already added.</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label translate for="name">Device Name</label>
|
|
<input id="name" class="form-control" type="text" ng-model="currentDevice.name" />
|
|
<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>
|
|
<div ng-if="!editingDeviceDefaults()" id="device-sharing" class="tab-pane">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<div class="checkbox">
|
|
<label>
|
|
<input type="checkbox" ng-model="currentDevice.introducer">
|
|
<span translate>Introducer</span>
|
|
<p translate class="help-block">Add devices from the introducer to our device list, for mutually shared folders.</p>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<div class="checkbox">
|
|
<label>
|
|
<input type="checkbox" ng-model="currentDevice.autoAcceptFolders">
|
|
<span translate>Auto Accept</span>
|
|
<p translate class="help-block">Automatically create or share folders that this device advertises at the default path.</p>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<div class="form-horizontal" ng-if="currentSharing.shared.length">
|
|
<label translate for="folders">Shared Folders</label>
|
|
<p class="help-block">
|
|
<span translate>Deselect folders to stop sharing with this device.</span> 
|
|
<small><a href="#" ng-click="selectAllSharedFolders(true)" translate>Select All</a> 
|
|
<a href="#" ng-click="selectAllSharedFolders(false)" translate>Deselect All</a></small>
|
|
</p>
|
|
<div class="form-group" ng-repeat="folder in currentSharing.shared">
|
|
<share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{folder.id}}" label="{{folderLabelMarkRemoteState(folder.id, currentDevice.deviceID)}}" folder-type="{{folder.type}}" untrusted="currentDevice.untrusted" />
|
|
</div>
|
|
<p class="help-block" ng-if="deviceHasUnacceptedFolders(currentDevice)">
|
|
<sup>1</sup> <span translate>The remote device has not accepted sharing this folder.</span>
|
|
</p>
|
|
<p class="help-block" ng-if="deviceHasPausedFolders(currentDevice)">
|
|
<sup>2</sup> <span translate>The remote device has paused this folder.</span>
|
|
</p>
|
|
</div>
|
|
<div class="form-horizontal" ng-if="currentSharing.unrelated.length">
|
|
<label translate for="folders">Unshared Folders</label>
|
|
<p class="help-block" ng-if="folderList().length > 0">
|
|
<span translate>Select additional folders to share with this device.</span> 
|
|
<small><a href="#" ng-click="selectAllUnrelatedFolders(true)" translate>Select All</a> 
|
|
<a href="#" ng-click="selectAllUnrelatedFolders(false)" translate>Deselect All</a></small>
|
|
</p>
|
|
<p class="help-block" ng-if="folderList().length == 0">
|
|
<span translate>There are no folders to share with this device.</span>
|
|
</p>
|
|
<div class="form-group" ng-repeat="folder in currentSharing.unrelated">
|
|
<share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{folder.id}}" label="{{folderLabel(folder.id)}}" folder-type="{{folder.type}}" untrusted="currentDevice.untrusted" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="device-advanced" class="tab-pane">
|
|
<div class="row form-group">
|
|
<div class="col-md-6">
|
|
<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 ("tcp://ip:port", "tcp://host:port") addresses or "dynamic" to perform automatic discovery of the address.</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label translate>Compression</label>
|
|
<select class="form-control" ng-model="currentDevice.compression">
|
|
<option value="always" translate>All Data</option>
|
|
<option value="metadata" translate>Metadata Only</option>
|
|
<option value="never" translate>Off</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row form-group">
|
|
<div class="col-md-12">
|
|
<label translate>Device rate limits</label>
|
|
<div class="row">
|
|
<div class="col-md-6" ng-class="{'has-error': deviceEditor.maxRecvKbps.$invalid && deviceEditor.maxRecvKbps.$dirty}">
|
|
<div class="row">
|
|
<span class="col-md-8" translate>Incoming Rate Limit (KiB/s)</span>
|
|
<div class="col-md-4">
|
|
<input name="maxRecvKbps" id="maxRecvKbps" class="form-control" type="number" pattern="\d+" ng-model="currentDevice.maxRecvKbps" min="0" />
|
|
</div>
|
|
</div>
|
|
<p class="help-block" ng-if="!deviceEditor.maxRecvKbps.$valid && deviceEditor.maxRecvKbps.$dirty" translate>The rate limit must be a non-negative number (0: no limit)</p>
|
|
</div>
|
|
<div class="col-md-6" ng-class="{'has-error': deviceEditor.maxSendKbps.$invalid && deviceEditor.maxSendKbps.$dirty}">
|
|
<div class="row">
|
|
<span class="col-md-8" translate>Outgoing Rate Limit (KiB/s)</span>
|
|
<div class="col-md-4">
|
|
<input name="maxSendKbps" id="maxSendKbps" class="form-control" type="number" pattern="\d+" ng-model="currentDevice.maxSendKbps" min="0" />
|
|
</div>
|
|
</div>
|
|
<p class="help-block" ng-if="!deviceEditor.maxSendKbps.$valid && deviceEditor.maxSendKbps.$dirty" translate>The rate limit must be a non-negative number (0: no limit)</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="form-group col-md-6">
|
|
<input type="checkbox" id="untrusted" ng-model="currentDevice.untrusted" />
|
|
<label for="untrusted" translate>Untrusted</label>
|
|
<p translate class="help-block">All folders shared with this device must be protected by a password, such that all sent data is unreadable without the given password.</p>
|
|
</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="fas fa-check"></span> <span translate>Save</span>
|
|
</button>
|
|
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
|
|
<span class="fas fa-times"></span> <span translate>Close</span>
|
|
</button>
|
|
<div ng-if="editingDeviceExisting()" class="pull-left">
|
|
<button type="button" class="btn btn-warning btn-sm" data-toggle="modal" data-target="#remove-device-confirmation">
|
|
<span class="fas fa-minus-circle"></span> <span translate>Remove</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</modal>
|