diff --git a/gui/default/assets/lang/lang-en.json b/gui/default/assets/lang/lang-en.json
index 4d58f890b..0b03c2d55 100644
--- a/gui/default/assets/lang/lang-en.json
+++ b/gui/default/assets/lang/lang-en.json
@@ -234,6 +234,7 @@
"Release Notes": "Release Notes",
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.",
"Remote Devices": "Remote Devices",
+ "Remote GUI": "Remote GUI",
"Remove": "Remove",
"Remove Device": "Remove Device",
"Remove Folder": "Remove Folder",
diff --git a/gui/default/index.html b/gui/default/index.html
index c965153cf..b980ccf5c 100644
--- a/gui/default/index.html
+++ b/gui/default/index.html
@@ -806,8 +806,8 @@
Remote GUI |
- {{idToRemoteGUI[deviceCfg.deviceID]}}
- Unreachable
+ {{remoteGUIAddress(deviceCfg)}}
+ Unknown
|
diff --git a/gui/default/syncthing/core/syncthingController.js b/gui/default/syncthing/core/syncthingController.js
index 7dd60ef5f..7462315e4 100755
--- a/gui/default/syncthing/core/syncthingController.js
+++ b/gui/default/syncthing/core/syncthingController.js
@@ -24,9 +24,6 @@ angular.module('syncthing.core')
$scope.config = {};
$scope.configInSync = true;
$scope.connections = {};
- $scope.idToRemoteGUI = {};
- $scope.remoteGUICache = {};
- $scope.showRemoteGUI = true;
$scope.errors = [];
$scope.model = {};
$scope.myID = '';
@@ -64,10 +61,6 @@ angular.module('syncthing.core')
$scope.metricRates = (window.localStorage["metricRates"] == "true");
} catch (exception) { }
- if ("showRemoteGUI" in window.localStorage) {
- $scope.showRemoteGUI = (window.localStorage["showRemoteGUI"] == "true");
- }
-
$scope.folderDefaults = {
devices: [],
type: "sendreceive",
@@ -382,7 +375,6 @@ angular.module('syncthing.core')
$scope.config.options._globalAnnounceServersStr = $scope.config.options.globalAnnounceServers.join(', ');
$scope.config.options._urAcceptedStr = "" + $scope.config.options.urAccepted;
- $scope.config.gui["showRemoteGUI"] = $scope.showRemoteGUI;
$scope.devices = deviceMap($scope.config.devices);
for (var id in $scope.devices) {
$scope.completion[id] = {
@@ -525,16 +517,6 @@ angular.module('syncthing.core')
console.log("recalcCompletion", device, $scope.completion[device]);
}
- function replaceAddressPort(address, newPort) {
- var lastColonIndex = address.length;
- for (var index = 0; index < address.length; index++) {
- if (address[index] === ":") {
- lastColonIndex = index;
- }
- }
- return address.substr(0, lastColonIndex) + ":" + newPort.toString();
- }
-
function refreshCompletion(device, folder) {
if (device === $scope.myID) {
return;
@@ -581,50 +563,9 @@ angular.module('syncthing.core')
}
$scope.connections = data;
console.log("refreshConnections", data);
-
- refreshRemoteGUI(data);
}).error($scope.emitHTTPError);
}
- function refreshRemoteGUI(connections) {
- if (!$scope.showRemoteGUI) {
- $scope.idToRemoteGUI = {}
- return
- }
- var newCache = {};
- for (var id in connections) {
- if (!(id in $scope.devices)) {
- // Avoid errors when called before first updateLocalConfig()
- continue;
- }
- var port = $scope.devices[id].remoteGUIPort;
- if (port <= 0
- || !connections[id].address
- || connections[id].type.includes("relay")) {
- // Relay connections never work as desired here, nor incomplete addresses
- $scope.idToRemoteGUI[id] = "";
- continue;
- }
- var newAddress = "http://" + replaceAddressPort(connections[id].address, port);
- if (!(newAddress in $scope.remoteGUICache)) {
- // No cached result, trigger a new port probing asynchronously
- $scope.probeRemoteGUIAddress(id, newAddress);
- } else {
- newCache[newAddress] = $scope.remoteGUICache[newAddress];
- // Copy cached probing result in the corner case of duplicate GUI
- // addresses for different devices. Which is useless, but
- // possible when behind the same NAT router.
- if (newCache[newAddress]) {
- $scope.idToRemoteGUI[id] = newAddress;
- } else {
- $scope.idToRemoteGUI[id] = "";
- }
- }
- }
- // Replace the cache to discard stale addresses
- $scope.remoteGUICache = newCache;
- }
-
function refreshErrors() {
$http.get(urlbase + '/system/error').success(function (data) {
$scope.errors = data.errors;
@@ -643,22 +584,6 @@ angular.module('syncthing.core')
}).error($scope.emitHTTPError);
}
- $scope.probeRemoteGUIAddress = function (deviceId, address) {
- // Strip off possible IPv6 link-local zone identifier, as Angular chokes on it
- // with an (ugly, unjustified) console error message.
- var urlAddress = address.replace(/%[a-zA-Z0-9_\.\-]*\]/, ']');
- $http({
- method: "OPTIONS",
- url: urlAddress,
- }).success(function (data) {
- $scope.remoteGUICache[address] = true;
- $scope.idToRemoteGUI[deviceId] = address;
- }).error(function (err) {
- $scope.remoteGUICache[address] = false;
- $scope.idToRemoteGUI[deviceId] = "";
- });
- }
-
$scope.refreshNeed = function (page, perpage) {
if (!$scope.neededFolder) {
return;
@@ -1140,6 +1065,28 @@ angular.module('syncthing.core')
return '?';
};
+ $scope.hasRemoteGUIAddress = function (deviceCfg) {
+ if (!deviceCfg.remoteGUIPort)
+ return false;
+ var conn = $scope.connections[deviceCfg.deviceID];
+ return conn && conn.connected && conn.address && conn.type.indexOf('Relay') == -1;
+ };
+
+ $scope.remoteGUIAddress = function (deviceCfg) {
+ // Assume hasRemoteGUIAddress is true or we would not be here
+ var conn = $scope.connections[deviceCfg.deviceID];
+ return 'http://' + replaceAddressPort(conn.address, deviceCfg.remoteGUIPort);
+ };
+
+ function replaceAddressPort(address, newPort) {
+ for (var index = address.length - 1; index >= 0; index--) {
+ if (address[index] === ":") {
+ return address.substr(0, index) + ":" + newPort.toString();
+ }
+ }
+ return address;
+ }
+
$scope.friendlyNameFromShort = function (shortID) {
var matches = Object.keys($scope.devices).filter(function (id) {
return id.substr(0, 7) === shortID;
@@ -1317,11 +1264,6 @@ angular.module('syncthing.core')
};
$scope.saveConfig = function (callback) {
- // set local storage feature and delete from post request
- window.localStorage.setItem("showRemoteGUI", $scope.config.gui.showRemoteGUI ? "true" : "false");
- $scope.showRemoteGUI = $scope.config.gui.showRemoteGUI;
- delete $scope.config.gui.showRemoteGUI;
-
var cfg = JSON.stringify($scope.config);
var opts = {
headers: {
diff --git a/gui/default/untrusted/index.html b/gui/default/untrusted/index.html
index 83b65286f..b2a95c9f9 100644
--- a/gui/default/untrusted/index.html
+++ b/gui/default/untrusted/index.html
@@ -815,12 +815,12 @@
{{deviceFolders(deviceCfg).map(folderLabel).join(", ")}} |
- Remote GUI |
-
+ | Remote GUI |
+
- {{idToRemoteGUI[deviceCfg.deviceID]}}
- Unreachable
- |
+ {{remoteGUIAddress(deviceCfg)}}
+ Unknown
+
diff --git a/gui/default/untrusted/syncthing/core/syncthingController.js b/gui/default/untrusted/syncthing/core/syncthingController.js
index 74d8dc8c7..4f2a20e74 100755
--- a/gui/default/untrusted/syncthing/core/syncthingController.js
+++ b/gui/default/untrusted/syncthing/core/syncthingController.js
@@ -24,9 +24,6 @@ angular.module('syncthing.core')
$scope.config = {};
$scope.configInSync = true;
$scope.connections = {};
- $scope.idToRemoteGUI = {};
- $scope.remoteGUICache = {};
- $scope.showRemoteGUI = true;
$scope.errors = [];
$scope.model = {};
$scope.myID = '';
@@ -64,10 +61,6 @@ angular.module('syncthing.core')
$scope.metricRates = (window.localStorage["metricRates"] == "true");
} catch (exception) { }
- if ("showRemoteGUI" in window.localStorage) {
- $scope.showRemoteGUI = (window.localStorage["showRemoteGUI"] == "true");
- }
-
$scope.folderDefaults = {
devices: [],
type: "sendreceive",
@@ -382,7 +375,6 @@ angular.module('syncthing.core')
$scope.config.options._globalAnnounceServersStr = $scope.config.options.globalAnnounceServers.join(', ');
$scope.config.options._urAcceptedStr = "" + $scope.config.options.urAccepted;
- $scope.config.gui["showRemoteGUI"] = $scope.showRemoteGUI;
$scope.devices = deviceMap($scope.config.devices);
for (var id in $scope.devices) {
$scope.completion[id] = {
@@ -525,16 +517,6 @@ angular.module('syncthing.core')
console.log("recalcCompletion", device, $scope.completion[device]);
}
- function replaceAddressPort(address, newPort) {
- var lastColonIndex = address.length;
- for (var index = 0; index < address.length; index++) {
- if (address[index] === ":") {
- lastColonIndex = index;
- }
- }
- return address.substr(0, lastColonIndex) + ":" + newPort.toString();
- }
-
function refreshCompletion(device, folder) {
if (device === $scope.myID) {
return;
@@ -581,50 +563,9 @@ angular.module('syncthing.core')
}
$scope.connections = data;
console.log("refreshConnections", data);
-
- refreshRemoteGUI(data);
}).error($scope.emitHTTPError);
}
- function refreshRemoteGUI(connections) {
- if (!$scope.showRemoteGUI) {
- $scope.idToRemoteGUI = {}
- return
- }
- var newCache = {};
- for (var id in connections) {
- if (!(id in $scope.devices)) {
- // Avoid errors when called before first updateLocalConfig()
- continue;
- }
- var port = $scope.devices[id].remoteGUIPort;
- if (port <= 0
- || !connections[id].address
- || connections[id].type.includes("relay")) {
- // Relay connections never work as desired here, nor incomplete addresses
- $scope.idToRemoteGUI[id] = "";
- continue;
- }
- var newAddress = "http://" + replaceAddressPort(connections[id].address, port);
- if (!(newAddress in $scope.remoteGUICache)) {
- // No cached result, trigger a new port probing asynchronously
- $scope.probeRemoteGUIAddress(id, newAddress);
- } else {
- newCache[newAddress] = $scope.remoteGUICache[newAddress];
- // Copy cached probing result in the corner case of duplicate GUI
- // addresses for different devices. Which is useless, but
- // possible when behind the same NAT router.
- if (newCache[newAddress]) {
- $scope.idToRemoteGUI[id] = newAddress;
- } else {
- $scope.idToRemoteGUI[id] = "";
- }
- }
- }
- // Replace the cache to discard stale addresses
- $scope.remoteGUICache = newCache;
- }
-
function refreshErrors() {
$http.get(urlbase + '/system/error').success(function (data) {
$scope.errors = data.errors;
@@ -643,23 +584,6 @@ angular.module('syncthing.core')
}).error($scope.emitHTTPError);
}
- $scope.probeRemoteGUIAddress = function (deviceId, address) {
- // Strip off possible IPv6 link-local zone identifier, as Angular chokes on it
- // with an (ugly, unjustified) console error message.
- var urlAddress = address.replace(/%[a-zA-Z0-9_\.\-]*\]/, ']');
- console.log(urlAddress);
- $http({
- method: "OPTIONS",
- url: urlAddress,
- }).success(function (data) {
- $scope.remoteGUICache[address] = true;
- $scope.idToRemoteGUI[deviceId] = address;
- }).error(function (err) {
- $scope.remoteGUICache[address] = false;
- $scope.idToRemoteGUI[deviceId] = "";
- });
- }
-
$scope.refreshNeed = function (page, perpage) {
if (!$scope.neededFolder) {
return;
@@ -1145,6 +1069,28 @@ angular.module('syncthing.core')
return '?';
};
+ $scope.hasRemoteGUIAddress = function (deviceCfg) {
+ if (!deviceCfg.remoteGUIPort)
+ return false;
+ var conn = $scope.connections[deviceCfg.deviceID];
+ return conn && conn.connected && conn.address && conn.type.indexOf('Relay') == -1;
+ };
+
+ $scope.remoteGUIAddress = function (deviceCfg) {
+ // Assume hasRemoteGUIAddress is true or we would not be here
+ var conn = $scope.connections[deviceCfg.deviceID];
+ return 'http://' + replaceAddressPort(conn.address, deviceCfg.remoteGUIPort);
+ };
+
+ function replaceAddressPort(address, newPort) {
+ for (var index = address.length - 1; index >= 0; index--) {
+ if (address[index] === ":") {
+ return address.substr(0, index) + ":" + newPort.toString();
+ }
+ }
+ return address;
+ }
+
$scope.friendlyNameFromShort = function (shortID) {
var matches = Object.keys($scope.devices).filter(function (id) {
return id.substr(0, 7) === shortID;
@@ -1322,11 +1268,6 @@ angular.module('syncthing.core')
};
$scope.saveConfig = function (callback) {
- // set local storage feature and delete from post request
- window.localStorage.setItem("showRemoteGUI", $scope.config.gui.showRemoteGUI ? "true" : "false");
- $scope.showRemoteGUI = $scope.config.gui.showRemoteGUI;
- delete $scope.config.gui.showRemoteGUI;
-
var cfg = JSON.stringify($scope.config);
var opts = {
headers: {