aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomasz1986 <twilczynski@naver.com>2023-12-10 15:14:10 +0100
committerGitHub <noreply@github.com>2023-12-10 15:14:10 +0100
commitd42fff1016304a2d824264aad10aa69d022406b1 (patch)
tree5487ca69b3b2ccf108435f2ab4044f6fc3d3eee0
parenta28de730318bf93b8ea9363f9bf2a05c178b4033 (diff)
downloadsyncthing-d42fff1016304a2d824264aad10aa69d022406b1.tar.gz
syncthing-d42fff1016304a2d824264aad10aa69d022406b1.zip
gui: Show folder/device status on small screens (#8643)
gui: Show folder/device status on small screens On larger screens, folder and device status is shown in a textual form directly next to folder and device titles. However, on small screens, only icons are currently shown, which may be ambiguous to new users, who cannot possibly know what a specific icon means (see [1]). Thus, on small screens only, display a new entry in folder/device info that contains the same textual information that is shown in the title on larger screens. Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com> Co-authored-by: André Colomb <src@andre.colomb.de>
-rw-r--r--gui/default/assets/css/overrides.css10
-rw-r--r--gui/default/assets/lang/lang-en.json2
-rw-r--r--gui/default/index.html66
-rwxr-xr-xgui/default/syncthing/core/syncthingController.js107
4 files changed, 136 insertions, 49 deletions
diff --git a/gui/default/assets/css/overrides.css b/gui/default/assets/css/overrides.css
index 2adebda39..b773cf000 100644
--- a/gui/default/assets/css/overrides.css
+++ b/gui/default/assets/css/overrides.css
@@ -180,7 +180,7 @@ input[type="checkbox"].extended-attributes-filter-rule-checkbox {
margin-right: .14285715em;
}
-.remote-devices-panel {
+.inline-icon {
display: inline-block;
}
@@ -460,15 +460,17 @@ ul.three-columns li, ul.two-columns li {
}
@media (max-width: 419px) {
- /* the selectors are build to target only the content of folder and device
- panels as it would "destroy" e.g. out of sync or recent changes listings */
+ /* The selectors are build to target only the content of folder and device
+ panels as it would "destroy" e.g. out of sync or recent changes listings.
+ The !important is needed to override .visible-xs that sets display to a
+ specific table element instead of block. */
div[id^='device-'].panel-collapse table,
div[id^='folder-'].panel-collapse table,
div[id^='device-'].panel-collapse tbody,
div[id^='folder-'].panel-collapse tbody,
div[id^='device-'].panel-collapse tr,
div[id^='folder-'].panel-collapse tr {
- display: block;
+ display: block !important;
}
div[id^='device-'].panel-collapse th,
div[id^='folder-'].panel-collapse th,
diff --git a/gui/default/assets/lang/lang-en.json b/gui/default/assets/lang/lang-en.json
index 4a34c972f..7a7731483 100644
--- a/gui/default/assets/lang/lang-en.json
+++ b/gui/default/assets/lang/lang-en.json
@@ -99,6 +99,7 @@
"Device ID": "Device ID",
"Device Identification": "Device Identification",
"Device Name": "Device Name",
+ "Device Status": "Device Status",
"Device is untrusted, enter encryption password": "Device is untrusted, enter encryption password",
"Device rate limits": "Device rate limits",
"Device that last modified the item": "Device that last modified the item",
@@ -168,6 +169,7 @@
"Folder ID": "Folder ID",
"Folder Label": "Folder Label",
"Folder Path": "Folder Path",
+ "Folder Status": "Folder Status",
"Folder Type": "Folder Type",
"Folder type \"{%receiveEncrypted%}\" can only be set when adding a new folder.": "Folder type \"{{receiveEncrypted}}\" can only be set when adding a new folder.",
"Folder type \"{%receiveEncrypted%}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.": "Folder type \"{{receiveEncrypted}}\" cannot be changed after adding the folder. You need to remove the folder, delete or decrypt the data on disk, and add the folder again.",
diff --git a/gui/default/index.html b/gui/default/index.html
index 4c55ffd7b..729e50580 100644
--- a/gui/default/index.html
+++ b/gui/default/index.html
@@ -395,37 +395,12 @@
<span ng-if="folder.type == 'receiveencrypted'" class="fas fa-fw fa-lock"></span>
</div>
<div class="panel-status pull-right text-{{folderClass(folder)}}" ng-switch="folderStatus(folder)">
- <span ng-switch-when="paused"><span class="hidden-xs" translate>Paused</span><span class="visible-xs" aria-label="{{'Paused' | translate}}"><i class="fas fa-fw fa-pause"></i></span></span>
- <span ng-switch-when="unknown"><span class="hidden-xs" translate>Unknown</span><span class="visible-xs" aria-label="{{'Unknown' | translate}}"><i class="fas fa-fw fa-question-circle"></i></span></span>
- <span ng-switch-when="unshared"><span class="hidden-xs" translate>Unshared</span><span class="visible-xs" aria-label="{{'Unshared' | translate}}"><i class="fas fa-fw fa-unlink"></i></span></span>
- <span ng-switch-when="scan-waiting"><span class="hidden-xs" translate>Waiting to Scan</span><span class="visible-xs" aria-label="{{'Waiting to Scan' | translate}}"><i class="fas fa-fw fa-hourglass-half"></i></span></span>
- <span ng-switch-when="cleaning"><span class="hidden-xs" translate>Cleaning Versions</span><span class="visible-xs" aria-label="{{'Cleaning Versions' | translate}}"><i class="fas fa-fw fa-recycle"></i></span></span>
- <span ng-switch-when="clean-waiting"><span class="hidden-xs" translate>Waiting to Clean</span><span class="visible-xs" aria-label="{{'Waiting to Clean' | translate}}"><i class="fas fa-fw fa-hourglass-half"></i></span></span>
- <span ng-switch-when="stopped"><span class="hidden-xs" translate>Stopped</span><span class="visible-xs" aria-label="{{'Stopped' | translate}}"><i class="fas fa-fw fa-stop"></i></span></span>
- <span ng-switch-when="scanning">
- <span class="hidden-xs" translate>Scanning</span>
- <span class="hidden-xs" ng-if="scanPercentage(folder.id) != undefined">
- ({{scanPercentage(folder.id) | percent}})
- </span>
- <span class="visible-xs" aria-label="{{'Scanning' | translate}}"><i class="fas fa-fw fa-search"></i></span>
- </span>
- <span ng-switch-when="idle"><span class="hidden-xs" translate>Up to Date</span><span class="visible-xs" aria-label="{{'Up to Date' | translate}}"><i class="fas fa-fw fa-check"></i></span></span>
- <span ng-switch-when="localadditions"><span class="hidden-xs" translate>Local Additions</span><span class="visible-xs" aria-label="{{'Local Additions' | translate}}"><i class="fas fa-fw fa-check"></i></span></span>
- <span ng-switch-when="sync-waiting">
- <span class="hidden-xs" translate>Waiting to Sync</span>
- <span class="visible-xs" aria-label="{{'Waiting to Sync' | translate}}"><i class="fas fa-fw fa-hourglass-half"></i></span>
- </span>
- <span ng-switch-when="sync-preparing">
- <span class="hidden-xs" translate>Preparing to Sync</span>
- <span class="visible-xs" aria-label="{{'Preparing to Sync' | translate}}"><i class="fas fa-fw fa-hourglass-half"></i></span>
- </span>
- <span ng-switch-when="syncing">
- <span class="hidden-xs" translate>Syncing</span>
- <span>({{syncPercentage(folder.id) | percent}}, {{model[folder.id].needBytes | binary}}B)</span>
- </span>
- <span ng-switch-when="outofsync"><span class="hidden-xs" translate>Out of Sync</span><span class="visible-xs" aria-label="{{'Out of Sync' | translate}}"><i class="fas fa-fw fa-exclamation-circle"></i></span></span>
- <span ng-switch-when="faileditems"><span class="hidden-xs" translate>Failed Items</span><span class="visible-xs" aria-label="{{'Failed Items' | translate}}"><i class="fas fa-fw fa-exclamation-circle"></i></span></span>
- <span ng-switch-when="localunencrypted"><span class="hidden-xs">{{'Unexpected Items' | translate}}</span><span class="visible-xs" aria-label="{{'Unexpected Items' | translate}}"><i class="fas fa-fw fa-exclamation-circle"></i></span></span>
+ <span class="hidden-xs">{{folderStatusText(folder)}}</span>
+ <span ng-switch-when="scanning" ng-if="scanPercentage(folder.id) != undefined">({{scanPercentage(folder.id) | percent}})</span>
+ <span ng-switch-when="syncing">({{syncPercentage(folder.id) | percent}}, {{model[folder.id].needBytes | binary}}B)</span>
+ <span class="inline-icon">
+ <span class="visible-xs fa fa-fw {{folderStatusIcon(folder)}}" aria-label="{{folderStatusText(folder)}}"></span>
+ </span>
</div>
<div class="panel-title-text">
<span tooltip data-original-title="{{folder.label.length != 0 ? folder.id : ''}}">{{folder.label.length != 0 ? folder.label : folder.id}}</span>
@@ -436,6 +411,10 @@
<div class="panel-body">
<table class="table table-condensed table-striped table-auto">
<tbody>
+ <tr class="visible-xs">
+ <th><span class="fa fa-fw {{folderStatusIcon(folder)}}"></span>&nbsp;<span translate>Folder Status</span></th>
+ <td class="text-right">{{folderStatusText(folder)}}</td>
+ </tr>
<tr ng-show="folder.label != undefined && folder.label.length > 0">
<th><span class="fas fa-fw fa-info-circle"></span>&nbsp;<span translate>Folder ID</span></th>
<td class="text-right no-overflow-ellipse">{{folder.id}}</td>
@@ -794,23 +773,16 @@
<div class="panel-progress" ng-show="deviceStatus(deviceCfg) == 'syncing'" ng-attr-style="width: {{completion[deviceCfg.deviceID]._total | percent}}"></div>
<h4 class="panel-title">
<identicon class="panel-icon" data-value="deviceCfg.deviceID"></identicon>
- <span class="pull-right text-{{deviceClass(deviceCfg)}}">
- <span ng-switch="deviceStatus(deviceCfg)" class="remote-devices-panel">
- <span ng-switch-when="insync"><span class="hidden-xs" translate>Up to Date</span><span class="visible-xs" aria-label="{{'Up to Date' | translate}}"><i class="fas fa-fw fa-check"></i></span></span>
- <span ng-switch-when="unused-insync"><span class="hidden-xs" translate>Connected (Unused)</span><span class="visible-xs" aria-label="{{'Connected (Unused)' | translate}}"><i class="fas fa-fw fa-unlink"></i></span></span>
- <span ng-switch-when="syncing">
- <span class="hidden-xs" translate>Syncing</span> ({{completion[deviceCfg.deviceID]._total | percent}}, {{completion[deviceCfg.deviceID]._needBytes | binary}}B)
- </span>
- <span ng-switch-when="paused"><span class="hidden-xs" translate>Paused</span><span class="visible-xs" aria-label="{{'Paused' | translate}}"><i class="fas fa-fw fa-pause"></i></span></span>
- <span ng-switch-when="unused-paused"><span class="hidden-xs" translate>Paused (Unused)</span><span class="visible-xs" aria-label="{{'Paused (Unused)' | translate}}"><i class="fas fa-fw fa-unlink"></i></span></span>
- <span ng-switch-when="disconnected"><span class="hidden-xs" translate>Disconnected</span><span class="visible-xs" aria-label="{{'Disconnected' | translate}}"><i class="fas fa-fw fa-power-off"></i></span></span>
- <span ng-switch-when="disconnected-inactive"><span class="hidden-xs" translate>Disconnected (Inactive)</span><span class="visible-xs" aria-label="{{'Disconnected (Inactive)' | translate}}"><i class="fas fa-fw fa-power-off"></i></span></span>
- <span ng-switch-when="unused-disconnected"><span class="hidden-xs" translate>Disconnected (Unused)</span><span class="visible-xs" aria-label="{{'Disconnected (Unused)' | translate}}"><i class="fas fa-fw fa-unlink"></i></span></span>
+ <div class="panel-status pull-right text-{{deviceClass(deviceCfg)}}" ng-switch="deviceStatus(deviceCfg)">
+ <span class="hidden-xs">{{deviceStatusText(deviceCfg)}}</span>
+ <span ng-switch-when="syncing">({{completion[deviceCfg.deviceID]._total | percent}}, {{completion[deviceCfg.deviceID]._needBytes | binary}}B)</span>
+ <span class="inline-icon">
+ <span class="visible-xs fa fa-fw {{deviceStatusIcon(deviceCfg)}}" aria-label="{{deviceStatusText(deviceCfg)}}"></span>
</span>
- <span class="remote-devices-panel">
+ <span class="inline-icon">
<span ng-class="rdConnTypeIcon(rdConnType(deviceCfg.deviceID))" class="reception reception-theme"></span>
</span>
- </span>
+ </div>
<div class="panel-title-text">{{deviceName(deviceCfg)}}</div>
</h4>
</button>
@@ -818,6 +790,10 @@
<div class="panel-body">
<table class="table table-condensed table-striped table-auto">
<tbody>
+ <tr class="visible-xs">
+ <th><span class="fa fa-fw {{deviceStatusIcon(deviceCfg)}}"></span>&nbsp;<span translate>Device Status</span></th>
+ <td class="text-right">{{deviceStatusText(deviceCfg)}}</td>
+ </tr>
<tr ng-if="!connections[deviceCfg.deviceID].connected">
<th><span class="fas fa-fw fa-eye"></span>&nbsp;<span translate>Last seen</span></th>
<td class="text-right">
diff --git a/gui/default/syncthing/core/syncthingController.js b/gui/default/syncthing/core/syncthingController.js
index bc04e8fe2..5b761feb2 100755
--- a/gui/default/syncthing/core/syncthingController.js
+++ b/gui/default/syncthing/core/syncthingController.js
@@ -1151,6 +1151,113 @@ angular.module('syncthing.core')
}
};
+ $scope.deviceStatusIcon = function(cfg) {
+ switch ($scope.deviceStatus(cfg)) {
+ case 'disconnected':
+ case 'disconnected-inactive':
+ return 'fa-power-off';
+ case 'insync':
+ return 'fa-check';
+ case 'paused':
+ return 'fa-pause';
+ case 'syncing':
+ return 'fa-sync';
+ case 'unused-disconnected':
+ case 'unused-insync':
+ case 'unused-paused':
+ return 'fa-unlink';
+ }
+ };
+
+ $scope.deviceStatusText = function(device) {
+ switch ($scope.deviceStatus(device)) {
+ case 'disconnected':
+ return $translate.instant('Disconnected');
+ case 'disconnected-inactive':
+ return $translate.instant('Disconnected (Inactive)');
+ case 'insync':
+ return $translate.instant('Up to Date');
+ case 'paused':
+ return $translate.instant('Paused');
+ case 'syncing':
+ return $translate.instant('Syncing');
+ case 'unused-disconnected':
+ return $translate.instant('Disconnected (Unused)');
+ case 'unused-insync':
+ return $translate.instant('Connected (Unused)');
+ case 'unused-paused':
+ return $translate.instant('Paused (Unused)');
+ }
+ };
+
+ $scope.folderStatusIcon = function(cfg) {
+ switch ($scope.folderStatus(cfg)) {
+ case 'clean-waiting':
+ case 'scan-waiting':
+ case 'sync-preparing':
+ case 'sync-waiting':
+ return 'fa-hourglass-half';
+ case 'cleaning':
+ return 'fa-recycle';
+ case 'faileditems':
+ case 'localunencrypted':
+ case 'outofsync':
+ return 'fa-exclamation-circle';
+ case 'idle':
+ case 'localadditions':
+ return 'fa-check';
+ case 'paused':
+ return 'fa-pause';
+ case 'scanning':
+ return 'fa-search';
+ case 'stopped':
+ return 'fa-stop';
+ case 'syncing':
+ return 'fa-sync';
+ case 'unknown':
+ return 'fa-question-circle';
+ case 'unshared':
+ return 'fa-unlink';
+ }
+ };
+
+ $scope.folderStatusText = function(folder) {
+ switch ($scope.folderStatus(folder)) {
+ case 'clean-waiting':
+ return $translate.instant('Waiting to Clean');
+ case 'cleaning':
+ return $translate.instant('Cleaning Versions');
+ case 'faileditems':
+ return $translate.instant('Failed Items');
+ case 'idle':
+ return $translate.instant('Up to Date');
+ case 'localadditions':
+ return $translate.instant('Local Additions');
+ case 'localunencrypted':
+ return $translate.instant('Unexpected Items');
+ case 'outofsync':
+ return $translate.instant('Out of Sync');
+ case 'paused':
+ return $translate.instant('Paused');
+ case 'scan-waiting':
+ return $translate.instant('Waiting to Scan');
+ case 'scanning':
+ return $translate.instant('Scanning');
+ case 'stopped':
+ return $translate.instant('Stopped');
+ case 'sync-preparing':
+ return $translate.instant('Preparing to Sync');
+ case 'sync-waiting':
+ return $translate.instant('Waiting to Sync');
+ case 'syncing':
+ return $translate.instant('Syncing');
+ case 'unknown':
+ return $translate.instant('Unknown');
+ case 'unshared':
+ return $translate.instant('Unshared');
+ }
+ };
+
$scope.deviceClass = function (deviceCfg) {
if (typeof $scope.connections[deviceCfg.deviceID] === 'undefined') {
return 'info';