|
|
@@ -18,8 +18,7 @@ angular.module('syncthing.core')
|
|
|
Events.start();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- // pubic/scope definitions
|
|
|
+ // public/scope definitions
|
|
|
|
|
|
$scope.completion = {};
|
|
|
$scope.config = {};
|
|
|
@@ -47,6 +46,10 @@ angular.module('syncthing.core')
|
|
|
$scope.neededPageSize = 10;
|
|
|
$scope.foldersTotalLocalBytes = 0;
|
|
|
$scope.foldersTotalLocalFiles = 0;
|
|
|
+ $scope.failed = {};
|
|
|
+ $scope.failedCurrentPage = 1;
|
|
|
+ $scope.failedCurrentFolder = undefined;
|
|
|
+ $scope.failedPageSize = 10;
|
|
|
|
|
|
$(window).bind('beforeunload', function () {
|
|
|
navigatingAway = true;
|
|
|
@@ -144,6 +147,13 @@ angular.module('syncthing.core')
|
|
|
if ($scope.model[data.folder]) {
|
|
|
$scope.model[data.folder].state = data.to;
|
|
|
$scope.model[data.folder].error = data.error;
|
|
|
+
|
|
|
+ // If a folder has started syncing, then any old list of
|
|
|
+ // errors is obsolete. We may get a new list of errors very
|
|
|
+ // shortly though.
|
|
|
+ if (data.to === 'syncing') {
|
|
|
+ $scope.failed[data.folder] = [];
|
|
|
+ }
|
|
|
}
|
|
|
});
|
|
|
|
|
|
@@ -151,14 +161,6 @@ angular.module('syncthing.core')
|
|
|
refreshFolderStats();
|
|
|
});
|
|
|
|
|
|
- /* currently not using
|
|
|
-
|
|
|
- $scope.$on('Events.REMOTE_INDEX_UPDATED', function (event, arg) {
|
|
|
- // Nothing
|
|
|
- });
|
|
|
-
|
|
|
- */
|
|
|
-
|
|
|
$scope.$on(Events.DEVICE_DISCONNECTED, function (event, arg) {
|
|
|
delete $scope.connections[arg.data.id];
|
|
|
refreshDeviceStats();
|
|
|
@@ -284,6 +286,11 @@ angular.module('syncthing.core')
|
|
|
$scope.completion[data.device]._total = tot / cnt;
|
|
|
});
|
|
|
|
|
|
+ $scope.$on(Events.FOLDER_ERRORS, function (event, arg) {
|
|
|
+ var data = arg.data;
|
|
|
+ $scope.failed[data.folder] = data.errors;
|
|
|
+ });
|
|
|
+
|
|
|
$scope.emitHTTPError = function (data, status, headers, config) {
|
|
|
$scope.$emit('HTTPError', {data: data, status: status, headers: headers, config: config});
|
|
|
};
|
|
|
@@ -492,6 +499,14 @@ angular.module('syncthing.core')
|
|
|
refreshNeed($scope.neededFolder);
|
|
|
};
|
|
|
|
|
|
+ $scope.failedPageChanged = function (page) {
|
|
|
+ $scope.failedCurrentPage = page;
|
|
|
+ };
|
|
|
+
|
|
|
+ $scope.failedChangePageSize = function (perpage) {
|
|
|
+ $scope.failedPageSize = perpage;
|
|
|
+ };
|
|
|
+
|
|
|
var refreshDeviceStats = debounce(function () {
|
|
|
$http.get(urlbase + "/stats/device").success(function (data) {
|
|
|
$scope.deviceStats = data;
|
|
|
@@ -526,6 +541,11 @@ angular.module('syncthing.core')
|
|
|
return 'unknown';
|
|
|
}
|
|
|
|
|
|
+ // after restart syncthing process state may be empty
|
|
|
+ if (!$scope.model[folderCfg.id].state) {
|
|
|
+ return 'unknown';
|
|
|
+ }
|
|
|
+
|
|
|
if (folderCfg.devices.length <= 1) {
|
|
|
return 'unshared';
|
|
|
}
|
|
|
@@ -534,47 +554,36 @@ angular.module('syncthing.core')
|
|
|
return 'stopped';
|
|
|
}
|
|
|
|
|
|
- if ($scope.model[folderCfg.id].state == 'error') {
|
|
|
+ var state = '' + $scope.model[folderCfg.id].state;
|
|
|
+ if (state === 'error') {
|
|
|
return 'stopped'; // legacy, the state is called "stopped" in the GUI
|
|
|
}
|
|
|
-
|
|
|
- // after restart syncthing process state may be empty
|
|
|
- if (!$scope.model[folderCfg.id].state) {
|
|
|
- return 'unknown';
|
|
|
+ if (state === 'idle' && $scope.model[folderCfg.id].needFiles > 0) {
|
|
|
+ return 'outofsync';
|
|
|
}
|
|
|
|
|
|
- return '' + $scope.model[folderCfg.id].state;
|
|
|
+ return state;
|
|
|
};
|
|
|
|
|
|
$scope.folderClass = function (folderCfg) {
|
|
|
- if (typeof $scope.model[folderCfg.id] === 'undefined') {
|
|
|
- // Unknown
|
|
|
- return 'info';
|
|
|
- }
|
|
|
-
|
|
|
- if (folderCfg.devices.length <= 1) {
|
|
|
- // Unshared
|
|
|
- return 'warning';
|
|
|
- }
|
|
|
-
|
|
|
- if ($scope.model[folderCfg.id].invalid !== '') {
|
|
|
- // Errored
|
|
|
- return 'danger';
|
|
|
- }
|
|
|
+ var status = $scope.folderStatus(folderCfg);
|
|
|
|
|
|
- var state = '' + $scope.model[folderCfg.id].state;
|
|
|
- if (state == 'idle') {
|
|
|
+ if (status == 'idle') {
|
|
|
return 'success';
|
|
|
}
|
|
|
- if (state == 'syncing') {
|
|
|
+ if (status == 'syncing' || status == 'scanning') {
|
|
|
return 'primary';
|
|
|
}
|
|
|
- if (state == 'scanning') {
|
|
|
- return 'primary';
|
|
|
+ if (status === 'unknown') {
|
|
|
+ return 'info';
|
|
|
+ }
|
|
|
+ if (status === 'unshared') {
|
|
|
+ return 'warning';
|
|
|
}
|
|
|
- if (state == 'error') {
|
|
|
+ if (status === 'stopped' || status === 'outofsync' || status === 'error') {
|
|
|
return 'danger';
|
|
|
}
|
|
|
+
|
|
|
return 'info';
|
|
|
};
|
|
|
|
|
|
@@ -1277,6 +1286,23 @@ angular.module('syncthing.core')
|
|
|
});
|
|
|
};
|
|
|
|
|
|
+ $scope.showFailed = function (folder) {
|
|
|
+ $scope.failedCurrent = $scope.failed[folder]
|
|
|
+ $('#failed').modal().on('hidden.bs.modal', function () {
|
|
|
+ $scope.failedCurrent = undefined;
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ $scope.hasFailedFiles = function (folder) {
|
|
|
+ if (!$scope.failed[folder]) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if ($scope.failed[folder].length == 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ };
|
|
|
+
|
|
|
$scope.override = function (folder) {
|
|
|
$http.post(urlbase + "/db/override?folder=" + encodeURIComponent(folder));
|
|
|
};
|