diff options
author | tomasz1986 <twilczynski@naver.com> | 2023-12-10 15:14:10 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-10 15:14:10 +0100 |
commit | d42fff1016304a2d824264aad10aa69d022406b1 (patch) | |
tree | 5487ca69b3b2ccf108435f2ab4044f6fc3d3eee0 | |
parent | a28de730318bf93b8ea9363f9bf2a05c178b4033 (diff) | |
download | syncthing-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.css | 10 | ||||
-rw-r--r-- | gui/default/assets/lang/lang-en.json | 2 | ||||
-rw-r--r-- | gui/default/index.html | 66 | ||||
-rwxr-xr-x | gui/default/syncthing/core/syncthingController.js | 107 |
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> <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> <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> <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> <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'; |