diff --git a/awx/ui/client/src/license/license.block.less b/awx/ui/client/src/license/license.block.less index aa306a1983..0625568fff 100644 --- a/awx/ui/client/src/license/license.block.less +++ b/awx/ui/client/src/license/license.block.less @@ -139,3 +139,7 @@ .License-detailsGroup { margin-bottom: 20px; } + +.License-detailsGroup--withSeparator { + border-top: 1px solid @default-icon-hov; +} diff --git a/awx/ui/client/src/license/license.controller.js b/awx/ui/client/src/license/license.controller.js index c5b5fcf532..35323e4458 100644 --- a/awx/ui/client/src/license/license.controller.js +++ b/awx/ui/client/src/license/license.controller.js @@ -9,35 +9,43 @@ import {N_} from "../i18n"; export default ['Wait', '$state', '$scope', '$rootScope', 'ProcessErrors', 'CheckLicense', 'moment','$window', - 'ConfigService', 'FeaturesService', 'pendoService', 'i18n', 'config', - function( Wait, $state, $scope, $rootScope, - ProcessErrors, CheckLicense, moment, $window, ConfigService, - FeaturesService, pendoService, i18n, config){ + 'ConfigService', 'FeaturesService', 'pendoService', 'i18n', 'config', 'Rest', 'GetBasePath', + function(Wait, $state, $scope, $rootScope, ProcessErrors, CheckLicense, moment, + $window, ConfigService, FeaturesService, pendoService, i18n, config, Rest, GetBasePath) { - var calcDaysRemaining = function(seconds){ - // calculate the number of days remaining on the license - var duration = moment.duration(seconds, 'seconds').asDays(); - duration = Math.floor(duration); - if(duration < 0 ){ - duration = 0; - } - duration = (duration!==1) ? `${duration} Days` : `${duration} Day`; - return duration; - }; + const calcDaysRemaining = function(seconds) { + // calculate the number of days remaining on the license + let duration = moment.duration(seconds, 'seconds').asDays(); - var calcExpiresOn = function(seconds){ + duration = Math.floor(duration); + if(duration < 0){ + duration = 0; + } + + duration = (duration!==1) ? `${duration} Days` : `${duration} Day`; + + return duration; + }; + + const calcExpiresOn = function(seconds) { // calculate the expiration date of the license return moment.unix(seconds).calendar(); }; - var reset = function(){ + const reset = function() { document.getElementById('License-form').reset(); }; - var init = function(config){ + const init = function(config) { // license/license.partial.html compares fileName $scope.fileName = N_("No file selected."); - $scope.title = $rootScope.licenseMissing ? ($rootScope.BRAND_NAME + i18n._(" License")) : i18n._("License Management"); + + if ($rootScope.licenseMissing) { + $scope.title = $rootScope.BRAND_NAME + i18n._(" License"); + } else { + $scope.title = i18n._("License Management"); + } + $scope.license = config; $scope.license.version = config.version.split('-')[0]; $scope.time = {}; @@ -45,71 +53,94 @@ export default $scope.time.expiresOn = calcExpiresOn($scope.license.license_info.license_date); $scope.valid = CheckLicense.valid($scope.license.license_info); $scope.compliant = $scope.license.license_info.compliant; + $scope.newLicense = {}; + + Rest.setUrl(`${GetBasePath('settings')}ui`); + Rest.get() + .then(({data}) => { + if (data.PENDO_TRACKING_STATE === 'off' && !$rootScope.licenseMissing) { + $scope.newLicense.pendo = false; + } else { + $scope.newLicense.pendo = true; + } + }) + .catch(() => { + // default pendo tracking to true when settings is not accessible + $scope.newLicense.pendo = true; + }); }; init(config); - $scope.getKey = function(event){ + $scope.getKey = function(event) { // Mimic HTML5 spec, show filename $scope.fileName = event.target.files[0].name; // Grab the key from the raw license file - var raw = new FileReader(); + const raw = new FileReader(); // readAsFoo runs async - raw.onload = function(){ + raw.onload = function() { try { $scope.newLicense.file = JSON.parse(raw.result); - } - catch(err) { - ProcessErrors($rootScope, null, null, null, {msg: i18n._('Invalid file format. Please upload valid JSON.')}); + } catch(err) { + ProcessErrors($rootScope, null, null, null, + {msg: i18n._('Invalid file format. Please upload valid JSON.')}); } }; + try { raw.readAsText(event.target.files[0]); - } - catch(err) { - ProcessErrors($rootScope, null, null, null, {msg: i18n._('Invalid file format. Please upload valid JSON.')}); + } catch(err) { + ProcessErrors($rootScope, null, null, null, + {msg: i18n._('Invalid file format. Please upload valid JSON.')}); } }; + // HTML5 spec doesn't provide a way to customize file input css // So we hide the default input, show our own, and simulate clicks to the hidden input - $scope.fakeClick = function(){ + $scope.fakeClick = function() { if($scope.user_is_superuser) { $('#License-file').click(); } }; - $scope.downloadLicense = function(){ + $scope.downloadLicense = function() { $window.open('https://www.ansible.com/license', '_blank'); }; - $scope.newLicense = {}; - $scope.submit = function(){ - Wait('start'); - CheckLicense.post($scope.newLicense.file, $scope.newLicense.eula) - .then(() => { - reset(); + $scope.submit = function() { + Wait('start'); + CheckLicense.post($scope.newLicense.file, $scope.newLicense.eula) + .then(() => { + reset(); + ConfigService.delete(); - ConfigService.getConfig().then(function(config){ - delete($rootScope.features); - FeaturesService.get(); - pendoService.issuePendoIdentity(); - if($rootScope.licenseMissing === true){ - $state.go('dashboard', { - licenseMissing: false - }); - } - else{ - init(config); - $scope.success = true; - $rootScope.licenseMissing = false; - // for animation purposes - var successTimeout = setTimeout(function(){ - $scope.success = false; - clearTimeout(successTimeout); - }, 4000); - } - }); - }); - }; - } -]; + ConfigService.getConfig() + .then(function(config) { + delete($rootScope.features); + FeaturesService.get(); + + if ($scope.newLicense.pendo) { + pendoService.updatePendoTrackingState('detailed'); + pendoService.issuePendoIdentity(); + } else { + pendoService.updatePendoTrackingState('off'); + } + + if ($rootScope.licenseMissing === true) { + $state.go('dashboard', { + licenseMissing: false + }); + } else { + init(config); + $scope.success = true; + $rootScope.licenseMissing = false; + // for animation purposes + const successTimeout = setTimeout(function() { + $scope.success = false; + clearTimeout(successTimeout); + }, 4000); + } + }); + }); + }; +}]; diff --git a/awx/ui/client/src/license/license.partial.html b/awx/ui/client/src/license/license.partial.html index 7b8bfe3499..5c2acf0e5d 100644 --- a/awx/ui/client/src/license/license.partial.html +++ b/awx/ui/client/src/license/license.partial.html @@ -122,6 +122,19 @@ +
+
+ +
+
Save successful! diff --git a/awx/ui/client/src/login/authenticationServices/pendo.service.js b/awx/ui/client/src/login/authenticationServices/pendo.service.js index 977fddc15c..a7296f6d8b 100644 --- a/awx/ui/client/src/login/authenticationServices/pendo.service.js +++ b/awx/ui/client/src/login/authenticationServices/pendo.service.js @@ -5,87 +5,84 @@ *************************************************/ -export default - [ '$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', '$q', - 'ConfigService', '$log', 'AppStrings', - function ($rootScope, Rest, GetBasePath, ProcessErrors, $q, - ConfigService, $log, AppStrings) { - return { +export default ['$rootScope', 'Rest', 'GetBasePath', 'ProcessErrors', '$q', 'ConfigService', '$log', + 'AppStrings', + function ($rootScope, Rest, GetBasePath, ProcessErrors, $q, ConfigService, $log, AppStrings) { + return { setPendoOptions: function (config) { - var tower_version = config.version.split('-')[0], - trial = (config.trial) ? config.trial : false, - options = { + const tower_version = config.version.split('-')[0]; + const trial = (config.trial) ? config.trial : false; + let options = { apiKey: AppStrings.get('PENDO_API_KEY'), visitor: { - id: null, - role: null, + id: null, + role: null, }, account: { - id: null, - planLevel: config.license_type, - planPrice: config.instance_count, - creationDate: config.license_date, - trial: trial, - tower_version: tower_version, - ansible_version: config.ansible_version + id: null, + planLevel: config.license_type, + planPrice: config.instance_count, + creationDate: config.license_date, + trial: trial, + tower_version: tower_version, + ansible_version: config.ansible_version } }; - if(config.analytics_status === 'detailed'){ + + if (config.analytics_status === 'detailed') { this.setDetailed(options, config); - } - else if(config.analytics_status === 'anonymous'){ + } else if (config.analytics_status === 'anonymous') { this.setAnonymous(options); } - return options; + return options; }, + // Detailed mode sends: + // VisitorId: userid+hash of license_key + // AccountId: hash of license_key from license setDetailed: function(options, config) { - // Detailed mode - // VisitorId: userid+hash of license_key - // AccountId: hash of license_key from license - + // config.deployment_id is a hash of the tower license_key options.visitor.id = $rootScope.current_user.id + '@' + config.deployment_id; options.account.id = config.deployment_id; }, + // Anonymous mode sends: + // VisitorId: + // AccountId: setAnonymous: function (options) { - //Anonymous mode - // VisitorId: - // AccountId: - options.visitor.id = 0; options.account.id = "tower.ansible.com"; }, setRole: function(options) { - var deferred = $q.defer(); - if($rootScope.current_user.is_superuser === true){ + const deferred = $q.defer(); + + if ($rootScope.current_user.is_superuser === true) { options.visitor.role = 'admin'; deferred.resolve(options); + } else { + Rest.setUrl(GetBasePath('users') + $rootScope.current_user.id + + '/admin_of_organizations/'); + Rest.get() + .then(function (response) { + if (response.data.count > 0) { + options.visitor.role = "orgadmin"; + deferred.resolve(options); + } else { + options.visitor.role = "user"; + deferred.resolve(options); + } + }) + .catch(function (response) { + ProcessErrors($rootScope, response.data, response.status, null, { + hdr: 'Error!', + msg: 'Failed to get admin of org user list. GET returned status: ' + + response.status }); + deferred.reject('Could not resolve pendo role.'); + }); } - else{ - var url = GetBasePath('users') + $rootScope.current_user.id + '/admin_of_organizations/'; - Rest.setUrl(url); - var promise = Rest.get(); - promise.then(function (response) { - if(response.data.count > 0 ) { - options.visitor.role = "orgadmin"; - deferred.resolve(options); - } - else { - options.visitor.role = "user"; - deferred.resolve(options); - } - }); - promise.catch(function (response) { - ProcessErrors($rootScope, response.data, response.status, null, { - hdr: 'Error!', - msg: 'Failed to get inventory name. GET returned status: ' + - response.status }); - deferred.reject('Could not resolve pendo role.'); - }); - } + return deferred.promise; }, @@ -100,31 +97,52 @@ export default }, issuePendoIdentity: function () { - var options, - c = ConfigService.get(), - config = c.license_info; + const c = ConfigService.get(); + + let options; + let config = c.license_info; config.analytics_status = c.analytics_status; config.version = c.version; config.ansible_version = c.ansible_version; - if(config.analytics_status === 'detailed' || config.analytics_status === 'anonymous'){ - this.bootstrap(); - options = this.setPendoOptions(config); - this.setRole(options).then(function(options){ - $log.debug('Pendo status is '+ config.analytics_status + '. Object below:'); - $log.debug(options); - /* jshint ignore:start */ - pendo.initialize(options); - /* jshint ignore:end */ - }, function(reason){ - // reject function for setRole - $log.debug(reason); - }); - } - else { + + if (config.analytics_status === 'detailed' || + config.analytics_status === 'anonymous') { + this.bootstrap(); + options = this.setPendoOptions(config); + this.setRole(options) + .then(function(options){ + $log.debug('Pendo status is '+ config.analytics_status + + '. Object below:'); + $log.debug(options); + + /* jshint ignore:start */ + pendo.initialize(options); + /* jshint ignore:end */ + }, function(reason){ + // reject function for setRole + $log.debug(reason); + }); + } else { $log.debug('Pendo is turned off.'); } - } + }, + + updatePendoTrackingState: function(tracking_type) { + if (tracking_type === 'off' || tracking_type === 'anonymous' || + tracking_type === 'detailed') { + Rest.setUrl(`${GetBasePath('settings')}ui`); + Rest.patch({ PENDO_TRACKING_STATE: tracking_type }) + .catch(function ({data, status}) { + ProcessErrors($rootScope, data, status, null, { + hdr: 'Error!', + msg: 'Failed to patch PENDO_TRACKING_STATE in settings: ' + + status }); + }); + } else { + throw new Error(`Can't update pendo tracking state in settings to + "${tracking_type}"`); + } + } }; - } -]; + }];