fix(gui): order folders alphabetically and ensure local device stays hidden (ref #10563, ref #10631)
### Purpose There were some additional regression created during #10563 and #10631 which are: * Folders were not being ordered by their label within their group * Local device could still show up randomly with the list of remote devices The respective fixes in this PR does the following: * Ensure sorting of the grouped folders (and devices) are done by group name (the top level map key) and then by the specified nested object property or a fallback property if specified property value is empty. So in the case of the folders it's `label` and device is `name`. * When populating the `devicesGrouped` using `$scope.otherDevices`, do this within a watcher on `$scope.myID` as this is what `$scope.otherDevices` relies on to determine what is a remote device. This is required because `$scope.myID` might not be populated yet given the indeterministic call order being made to `refreshSystem` and `refreshConfig`. ### Testing Populate folders and devices into different groups, and ensure the ordering is correct and the local device is not showing in remote devices even after many, many refreshes on the UI or restarts of syncthing entirely. ### Screenshots Before the fix <img width="1108" height="951" alt="Screenshot_20260409_083910" src="https://github.com/user-attachments/assets/6eb8cacc-5924-4612-aa70-29ed4f691233" /> After the fix <img width="1090" height="934" alt="Screenshot_20260409_084553" src="https://github.com/user-attachments/assets/f5b74391-228a-43d3-b5ee-433958236d84" /> ### Documentation N/A ## Authorship Ben Norcombe [bennorcombe@pm.me](mailto:bennorcombe@pm.me)
This commit is contained in:
@@ -570,14 +570,23 @@ angular.module('syncthing.core')
|
||||
|
||||
};
|
||||
|
||||
$scope.devicesGrouped = {};
|
||||
const otherDevices = $scope.otherDevices();
|
||||
for (var id in otherDevices) {
|
||||
if ($scope.devicesGrouped[otherDevices[id].group] === undefined) {
|
||||
$scope.devicesGrouped[otherDevices[id].group] = [];
|
||||
// myID is watched as $scope.otherDevices() relies on this
|
||||
// and it can potenitally not be loaded due to this function
|
||||
// scope being called in an undetermistic manner
|
||||
$scope.$watch('myID', function(myID) {
|
||||
if (myID) {
|
||||
$scope.devicesGrouped = {};
|
||||
const otherDevices = $scope.otherDevices();
|
||||
for (var id in otherDevices) {
|
||||
if ($scope.devicesGrouped[otherDevices[id].group] === undefined) {
|
||||
$scope.devicesGrouped[otherDevices[id].group] = [];
|
||||
}
|
||||
$scope.devicesGrouped[otherDevices[id].group].push(otherDevices[id]);
|
||||
};
|
||||
|
||||
$scope.devicesGrouped = sortByKeyThenProperty($scope.devicesGrouped, "name", "deviceID");
|
||||
}
|
||||
$scope.devicesGrouped[otherDevices[id].group].push(otherDevices[id]);
|
||||
};
|
||||
});
|
||||
|
||||
$scope.folders = folderMap($scope.config.folders);
|
||||
$scope.foldersGrouped = {};
|
||||
@@ -593,15 +602,7 @@ angular.module('syncthing.core')
|
||||
$scope.foldersGrouped[$scope.folders[folder].group].push($scope.folders[folder]);
|
||||
});
|
||||
|
||||
// Sort with blank group first if any then alphabetically
|
||||
const blankSort = (a, b) => {
|
||||
if (a[0] === "" && b[0] !== "") return -1;
|
||||
if (b[0] === "" && a[0] !== "") return 1;
|
||||
return a[0].localeCompare(b[0]);
|
||||
};
|
||||
|
||||
$scope.foldersGrouped = Object.fromEntries(Object.entries($scope.foldersGrouped).sort(blankSort));
|
||||
$scope.devicesGrouped = Object.fromEntries(Object.entries($scope.devicesGrouped).sort(blankSort));
|
||||
$scope.foldersGrouped = sortByKeyThenProperty($scope.foldersGrouped, "label", "id");
|
||||
|
||||
refreshNoAuthWarning();
|
||||
setDefaultTheme();
|
||||
@@ -611,6 +612,31 @@ angular.module('syncthing.core')
|
||||
}
|
||||
}
|
||||
|
||||
// Sort firstly by the top level key of the object and then by
|
||||
// prop name provided for the array of objects for each key.
|
||||
// If the prop returns has an empty value, then use the
|
||||
// fallback prop provided.
|
||||
function sortByKeyThenProperty(obj, prop, fallbackProp) {
|
||||
const sorted = {};
|
||||
Object.keys(obj)
|
||||
.sort()
|
||||
.forEach((key) => {
|
||||
sorted[key] = obj[key].sort((a, b) => {
|
||||
let aProp = prop;
|
||||
let bProp = prop;
|
||||
if (!a[aProp]) {
|
||||
aProp = fallbackProp;
|
||||
}
|
||||
if (!b[bProp]) {
|
||||
bProp = fallbackProp;
|
||||
}
|
||||
return a[aProp].localeCompare(b[bProp]);
|
||||
});
|
||||
});
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
function refreshSystem() {
|
||||
return $http.get(urlbase + '/system/status').success(function (data) {
|
||||
$scope.myID = data.myID;
|
||||
|
||||
Reference in New Issue
Block a user