Skip to content

Commit 35a641f

Browse files
maen-bntomasz1986
authored andcommitted
feat(gui, config): support simple folder grouping (fixes syncthing#2070) (syncthing#10563)
Adds a very simple way to group up folders to help with organising from the GUI. Signed-off-by: Ben Norcombe <bennorcombe@pm.me> Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
1 parent 13b5592 commit 35a641f

File tree

6 files changed

+512
-455
lines changed

6 files changed

+512
-455
lines changed

gui/default/index.html

Lines changed: 465 additions & 455 deletions
Large diffs are not rendered by default.

gui/default/syncthing/core/syncthingController.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,14 @@ angular.module('syncthing.core')
8181
$scope.model = {};
8282
$scope.myID = '';
8383
$scope.devices = {};
84+
$scope.devicesGrouped = {};
8485
$scope.discoveryCache = {};
8586
$scope.protocolChanged = false;
8687
$scope.reportData = {};
8788
$scope.reportDataPreview = '';
8889
$scope.reportPreview = false;
8990
$scope.folders = {};
91+
$scope.foldersGrouped = {};
9092
$scope.seenError = '';
9193
$scope.upgradeInfo = null;
9294
$scope.deviceStats = {};
@@ -559,21 +561,44 @@ angular.module('syncthing.core')
559561
$scope.config.options._urAcceptedStr = "" + $scope.config.options.urAccepted;
560562

561563
$scope.devices = deviceMap($scope.config.devices);
564+
$scope.devicesGrouped = {};
562565
for (var id in $scope.devices) {
563566
$scope.completion[id] = {
564567
_total: 100,
565568
_needBytes: 0,
566569
_needItems: 0
567570
};
571+
572+
if ($scope.devicesGrouped[$scope.devices[id].group] === undefined) {
573+
$scope.devicesGrouped[$scope.devices[id].group] = [];
574+
}
575+
$scope.devicesGrouped[$scope.devices[id].group].push($scope.devices[id]);
568576
};
577+
569578
$scope.folders = folderMap($scope.config.folders);
579+
$scope.foldersGrouped = {};
570580
Object.keys($scope.folders).forEach(function (folder) {
571581
refreshFolder(folder);
572582
$scope.folders[folder].devices.forEach(function (deviceCfg) {
573583
refreshCompletion(deviceCfg.deviceID, folder);
574584
});
585+
586+
if ($scope.foldersGrouped[$scope.folders[folder].group] === undefined) {
587+
$scope.foldersGrouped[$scope.folders[folder].group] = [];
588+
}
589+
$scope.foldersGrouped[$scope.folders[folder].group].push($scope.folders[folder]);
575590
});
576591

592+
// Sort with blank group first if any then alphabetically
593+
const blankSort = (a, b) => {
594+
if (a[0] === "" && b[0] !== "") return -1;
595+
if (b[0] === "" && a[0] !== "") return 1;
596+
return a[0].localeCompare(b[0]);
597+
};
598+
599+
$scope.foldersGrouped = Object.fromEntries(Object.entries($scope.foldersGrouped).sort(blankSort));
600+
$scope.devicesGrouped = Object.fromEntries(Object.entries($scope.devicesGrouped).sort(blankSort));
601+
577602
refreshNoAuthWarning();
578603
setDefaultTheme();
579604

gui/default/syncthing/device/editDeviceModalView.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,16 @@
5454
<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>
5555
<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>
5656
</div>
57+
<div class="form-group" ng-class="{'has-error': deviceEditor.deviceGroup.$invalid && deviceEditor.deviceGroup.$dirty && !editingDeviceDefaults()}">
58+
<label for="deviceGroup"><span translate>Device Group</span></label>
59+
<input name="deviceGroup" id="deviceGroup" class="form-control" type="text" ng-model="currentDevice.group" value="{{currentDevice.group}}" list="device-group-list"/>
60+
<datalist id="device-group-list">
61+
<option ng-repeat="(group, device) in devicesGrouped" value="{{group}}" />
62+
</datalist>
63+
<p class="help-block">
64+
<span translate ng-if="deviceEditor.deviceGroup.$valid || deviceEditor.deviceGroup.$pristine">Optional group for the device. Can be different on each device.</span>
65+
</p>
66+
</div>
5767
</div>
5868
<div ng-if="!editingDeviceDefaults()" id="device-sharing" class="tab-pane">
5969
<div class="row">

gui/default/syncthing/folder/editFolderModalView.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@
1818
<span translate ng-if="folderEditor.folderLabel.$valid || folderEditor.folderLabel.$pristine">Optional descriptive label for the folder. Can be different on each device.</span>
1919
</p>
2020
</div>
21+
<div class="form-group" ng-class="{'has-error': folderEditor.folderGroup.$invalid && folderEditor.folderGroup.$dirty && !editingFolderDefaults()}">
22+
<label for="folderGroup"><span translate>Folder Group</span></label>
23+
<input name="folderGroup" id="folderGroup" class="form-control" type="text" ng-model="currentFolder.group" value="{{currentFolder.group}}" list="folder-group-list"/>
24+
<datalist id="folder-group-list">
25+
<option ng-repeat="(group, folders) in foldersGrouped" value="{{group}}" />
26+
</datalist>
27+
<p class="help-block">
28+
<span translate ng-if="folderEditor.folderGroup.$valid || folderEditor.folderGroup.$pristine">Optional group for the folder. Can be different on each device.</span>
29+
</p>
30+
</div>
2131
<div ng-if="!editingFolderDefaults()" class="form-group" ng-class="{'has-error': folderEditor.folderID.$invalid && folderEditor.folderID.$dirty}">
2232
<label for="folderID"><span translate>Folder ID</span></label>
2333
<input name="folderID" ng-readonly="has(['existing', 'new-pending'], currentFolder._editing)" id="folderID" class="form-control" type="text" ng-model="currentFolder.id" required="" aria-required="true" unique-folder value="{{currentFolder.id}}" />

lib/config/deviceconfiguration.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type DeviceConfiguration struct {
3636
Untrusted bool `json:"untrusted" xml:"untrusted"`
3737
RemoteGUIPort int `json:"remoteGUIPort" xml:"remoteGUIPort"`
3838
RawNumConnections int `json:"numConnections" xml:"numConnections"`
39+
Group string `json:"group" xml:"group,attr,omitempty"`
3940
}
4041

4142
func (cfg DeviceConfiguration) Copy() DeviceConfiguration {

lib/config/folderconfiguration.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ type FolderConfiguration struct {
5454
Path string `json:"path" xml:"path,attr"`
5555
Type FolderType `json:"type" xml:"type,attr"`
5656
Devices []FolderDeviceConfiguration `json:"devices" xml:"device"`
57+
Group string `json:"group" xml:"group,attr,omitempty" restart:"false"`
5758
RescanIntervalS int `json:"rescanIntervalS" xml:"rescanIntervalS,attr" default:"86400"`
5859
FSWatcherEnabled bool `json:"fsWatcherEnabled" xml:"fsWatcherEnabled,attr" default:"true"`
5960
FSWatcherDelayS float64 `json:"fsWatcherDelayS" xml:"fsWatcherDelayS,attr" default:"5"`

0 commit comments

Comments
 (0)