diff --git a/src/js/index.js b/src/js/index.js index 177cfc322..f03aca8d5 100644 --- a/src/js/index.js +++ b/src/js/index.js @@ -218,7 +218,10 @@ app.filter('selectedDomainFilter', function () { if (selectedDomain._alldomains) return true; // magic domain for single select, see apps.js ALL_DOMAINS_DOMAIN if (selectedDomain.domain === app.domain) return true; - return !!app.alternateDomains.find(function (ad) { return ad.domain === selectedDomain.domain; }); + if (app.aliasDomains.find(function (ad) { return ad.domain === selectedDomain.domain; })) return true; + if (app.alternateDomains.find(function (ad) { return ad.domain === selectedDomain.domain; })) return true; + + return false; }); }; }); diff --git a/src/theme.scss b/src/theme.scss index e15d88808..e977227e5 100644 --- a/src/theme.scss +++ b/src/theme.scss @@ -484,6 +484,19 @@ multiselect { } } +.alias-domains .col-lg-11 { + padding-right: 5px; +} + +.alias-domains .col-lg-1 { + padding-left: 0px; + padding-right: 0px; +} + +.alias-domains .row { + margin-top: 5px; +} + .alternate-domains .col-lg-11 { padding-right: 5px; } diff --git a/src/views/activity.js b/src/views/activity.js index c77e4e8df..8ef198fa8 100644 --- a/src/views/activity.js +++ b/src/views/activity.js @@ -211,6 +211,9 @@ angular.module('Application').controller('ActivityController', ['$scope', '$loca } else if (!angular.equals(data.alternateDomains, data.app.alternateDomains)) { var altFqdns = data.alternateDomains.map(function (a) { return a.fqdn; }); return 'Alternate domains of ' + appName(app) + ' was ' + (altFqdns.length ? 'set to ' + altFqdns.join(', ') : 'reset'); + } else if (!angular.equals(data.aliasDomains, data.app.aliasDomains)) { + var aliasDomains = data.aliasDomains.map(function (a) { return a.fqdn; }); + return 'Alias domains of ' + appName(app) + ' was ' + (aliasDomains.length ? 'set to ' + aliasDomains.join(', ') : 'reset'); } else if (!angular.equals(data.portBindings, data.app.portBindings)) { return 'Port bindings of ' + appName(app) + ' was changed'; } diff --git a/src/views/app.html b/src/views/app.html index 97ff631b4..2b10c9b35 100644 --- a/src/views/app.html +++ b/src/views/app.html @@ -106,6 +106,14 @@ +
+

+ +

+
+

+
+ +
{{ location.error.aliasDomains }}
+ +
+
+
+ + +
+ + +
+
+
+
+ +
+
+
{{ 'app.location.noAliases' | tr }}
+
{{ 'app.location.addAliasAction' | tr }}
+
+
{{ location.error.alternateDomains }}
@@ -585,8 +623,8 @@
-

{{ 'appstore.installDialog.userManagementNone' | tr }} {{ 'app.accessControl.userManagement.sftpAccessControl' | tr }}

-

{{ 'appstore.installDialog.configuredForCloudronEmail' | tr:{ emailDocsLink: 'https://docs.cloudron.io/email/' } }}

+

{{ 'appstore.installDialog.userManagementNone' | tr }} {{ 'app.accessControl.userManagement.sftpAccessControl' | tr }}

+

{{ 'appstore.installDialog.configuredForCloudronEmail' | tr:{ emailDocsLink: 'https://docs.cloudron.io/email/' } }}

diff --git a/src/views/app.js b/src/views/app.js index 9fa1842fb..7d027abb2 100644 --- a/src/views/app.js +++ b/src/views/app.js @@ -268,6 +268,7 @@ angular.module('Application').controller('AppController', ['$scope', '$location' domain: null, location: '', alternateDomains: [], + aliasDomains: [], portBindings: {}, portBindingsEnabled: {}, portBindingsInfo: {}, @@ -285,6 +286,19 @@ angular.module('Application').controller('AppController', ['$scope', '$location' $scope.location.alternateDomains.splice(index, 1); }, + addAliasDomain: function (event) { + event.preventDefault(); + $scope.location.aliasDomains.push({ + domain: $scope.domains.filter(function (d) { return d.domain === $scope.app.domain; })[0], // pre-select app's domain by default + subdomain: '' + }); + }, + + delAliasDomain: function (event, index) { + event.preventDefault(); + $scope.location.aliasDomains.splice(index, 1); + }, + show: function () { var app = $scope.app; @@ -294,6 +308,7 @@ angular.module('Application').controller('AppController', ['$scope', '$location' $scope.location.domain = $scope.domains.filter(function (d) { return d.domain === app.domain; })[0]; $scope.location.portBindingsInfo = angular.extend({}, app.manifest.tcpPorts, app.manifest.udpPorts); // Portbinding map only for information $scope.location.alternateDomains = app.alternateDomains.map(function (a) { return { subdomain: a.subdomain, domain: $scope.domains.filter(function (d) { return d.domain === a.domain; })[0] };}); + $scope.location.aliasDomains = app.aliasDomains.map(function (a) { return { subdomain: a.subdomain, domain: $scope.domains.filter(function (d) { return d.domain === a.domain; })[0] };}); // fill the portBinding structures. There might be holes in the app.portBindings, which signalizes a disabled port for (var env in $scope.location.portBindingsInfo) { @@ -327,15 +342,20 @@ angular.module('Application').controller('AppController', ['$scope', '$location' location: $scope.location.location, domain: $scope.location.domain.domain, portBindings: portBindings, - alternateDomains: $scope.location.alternateDomains.map(function (a) { return { subdomain: a.subdomain, domain: a.domain.domain };}) + alternateDomains: $scope.location.alternateDomains.map(function (a) { return { subdomain: a.subdomain, domain: a.domain.domain };}), + aliasDomains: $scope.location.aliasDomains.map(function (a) { return { subdomain: a.subdomain, domain: a.domain.domain };}) }; // pre-flight only for changed domains var domains = []; - if ($scope.app.domain !== data.domain || $scope.app.location !== data.location) domains.push({ subdomain: data.location, domain: data.domain }); + if ($scope.app.domain !== data.domain || $scope.app.location !== data.location) domains.push({ subdomain: data.location, domain: data.domain, type: 'main' }); data.alternateDomains.forEach(function (a) { if ($scope.app.alternateDomains.some(function (d) { return d.domain === a.domain && d.subdomain === a.subdomain; })) return; - domains.push({ subdomain: a.subdomain, domain: a.domain }); + domains.push({ subdomain: a.subdomain, domain: a.domain, type: 'redirect' }); + }); + data.aliasDomains.forEach(function (a) { + if ($scope.app.aliasDomains.some(function (d) { return d.domain === a.domain && d.subdomain === a.subdomain; })) return; + domains.push({ subdomain: a.subdomain, domain: a.domain, type: 'alias' }); }); async.eachSeries(domains, function (domain, callback) { @@ -344,8 +364,10 @@ angular.module('Application').controller('AppController', ['$scope', '$location' Client.checkDNSRecords(domain.domain, domain.subdomain, function (error, result) { if (error) return callback(error); if (result.error) { - if (data.domain === domain.domain && data.location === domain.subdomain) { + if (domain.type === 'main') { $scope.location.error.location = domain.domain + ' ' + result.error.message; + } else if (domain.type === 'alias') { + $scope.location.error.aliasDomains = domain.domain + ' ' + result.error.message; } else { $scope.location.error.alternateDomains = domain.domain + ' ' + result.error.message; } @@ -374,7 +396,7 @@ angular.module('Application').controller('AppController', ['$scope', '$location' if (data.domain === error.domain && data.location === error.subdomain) { // the primary $scope.location.error.location = error.message; $scope.locationForm.$setPristine(); - } else { + } else { // FIXME: check error in aliasDomains $scope.location.error.alternateDomains = error.message; } } else if (error.portName || error.field === 'portBindings') { @@ -1287,6 +1309,7 @@ angular.module('Application').controller('AppController', ['$scope', '$location' location: null, domain: null, alternateDomains: [], + aliasDomains: [], backups: [], backupId: '', @@ -1300,6 +1323,7 @@ angular.module('Application').controller('AppController', ['$scope', '$location' $scope.repair.location = null; $scope.repair.domain = null; $scope.repair.alternateDomains = []; + $scope.repair.aliasDomains = []; $scope.repair.backupId = ''; var app = $scope.app; @@ -1309,6 +1333,16 @@ angular.module('Application').controller('AppController', ['$scope', '$location' if (errorState === ISTATES.PENDING_LOCATION_CHANGE) { $scope.repair.location = app.location; $scope.repair.domain = $scope.domains.filter(function (d) { return d.domain === app.domain; })[0]; + + $scope.repair.aliasDomains = $scope.app.aliasDomains; + $scope.repair.aliasDomains = $scope.app.aliasDomains.map(function (aliasDomain) { + return { + subdomain: aliasDomain.subdomain, + enabled: true, + domain: $scope.domains.filter(function (d) { return d.domain === aliasDomain.domain; })[0] + }; + }); + $scope.repair.alternateDomains = $scope.app.alternateDomains; $scope.repair.alternateDomains = $scope.app.alternateDomains.map(function (altDomain) { return { @@ -1351,6 +1385,8 @@ angular.module('Application').controller('AppController', ['$scope', '$location' case ISTATES.PENDING_LOCATION_CHANGE: data.location = $scope.repair.location; data.domain = $scope.repair.domain.domain; + data.aliasDomains = $scope.repair.aliasDomains.filter(function (a) { return a.enabled; }) + .map(function (d) { return { subdomain: d.subdomain, domain: d.domain.domain }; }); data.alternateDomains = $scope.repair.alternateDomains.filter(function (a) { return a.enabled; }) .map(function (d) { return { subdomain: d.subdomain, domain: d.domain.domain }; }); data.overwriteDns = true; // always overwriteDns. user can anyway check and uncheck above