diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 97abad5a7f..feed022c3d 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -67,7 +67,7 @@ import './shared/InventoryTree'; import './shared/Socket'; import './job-templates/main'; import './shared/features/main'; - +import pendolytics from './login/authenticationServices/pendo/ng-pendo'; /*#if DEBUG#*/ import {__deferLoadIfEnabled} from './debug'; diff --git a/awx/ui/client/src/login/authenticationServices/pendo/ng-pendo.js b/awx/ui/client/src/login/authenticationServices/pendo/ng-pendo.js new file mode 100644 index 0000000000..3d6e86ae02 --- /dev/null +++ b/awx/ui/client/src/login/authenticationServices/pendo/ng-pendo.js @@ -0,0 +1,129 @@ +/* +* pendo.io Angular Module +* +* (c) 2013 pendo.io +*/ + + + +(function(angular) { + + 'use strict'; + + var ap = {}; + ap.waitForPendo = function(delay, registerFn) { + var waitFn = function() { ap.waitForPendo( delay, registerFn); }; + + if (ap.disabled) { + ap.afterReenable = waitFn; + return; + } + + if(window.hasOwnProperty('pendo') && window.pendo.initialize) { + registerFn(pendo); + } else { + setTimeout(waitFn, delay); + } + }; + + angular.module('pendolytics', []) + .provider('$pendolytics', function() { + + var eventCache = []; + var service = {}; + + var serviceImpl = { + pageLoad: function() { + eventCache.push( {method: 'pageLoad', args: [] }); + }, + identify: function( newName, accountId, props ) { + var saveMe = { method: 'identify', args: [ newName, accountId, props ] }; + eventCache.push(saveMe); + }, + updateOptions: function( obj ) { + eventCache.push({ method: 'updateOptions', args: [obj]}); + }, + + /* + * This will allow for initalizing the Agent asynchronously + * with an API key that is set after the agent has been set. + */ + initialize: function(options) { + eventCache.unshift({ + method: 'initialize', + args: [options] + }); + } + }; + + service.pageLoad = function() { + serviceImpl.pageLoad(); + }; + + service.load = function() { + pendo.log("PENDO LOADED!!!"); + + serviceImpl = pendo; + + // Flush the cache + angular.forEach(eventCache, function(item) { + pendo[item.method].apply(pendo, item.args); + }); + + }; + + service.identify = function(newName, accountId, props){ + serviceImpl.identify(newName, accountId, props); + }; + + service.updateOptions = function(json_obj) { + serviceImpl.updateOptions(json_obj); + }; + + service.initialize = function(options){ + serviceImpl.initialize(options); + }; + + service.enable = function(){ + if (ap.disabled) { + ap.disabled = false; + ap.afterReenable(); + } + }; + + service.disable = function(){ + ap.disabled = true; + }; + + service.bootstrap = function() { + if (!service.bootstrapped) { + var script = document.createElement('script'); + script.type = 'text/javascript'; + script.async = true; + script.src = ('https:' === document.location.protocol ? 'https://' : 'http://' ) + 'd3accju1t3mngt.cloudfront.net/js/pa.min.js'; + var firstScript = document.getElementsByTagName('script')[0]; + firstScript.parentNode.insertBefore(script, firstScript); + service.bootstrapped = true; + } + }; + + return { + $get: function(){ return service; }, + doNotAutoStart: function() { + service.doNotAutoStart = true; + } + }; + + }).run(['$rootScope', '$pendolytics', function($rootScope, $pendolytics) { + if (!$pendolytics.doNotAutoStart) { + $pendolytics.bootstrap(); + } + ap.waitForPendo( 500, function( p ) { + $pendolytics.load(); + $rootScope.$on('$locationChangeSuccess', function() { + $pendolytics.pageLoad(); + }); + }); + }]); + +})(angular); diff --git a/awx/ui/client/src/login/authenticationServices/pendo/pendo.service.js b/awx/ui/client/src/login/authenticationServices/pendo/pendo.service.js new file mode 100644 index 0000000000..82af8ade88 --- /dev/null +++ b/awx/ui/client/src/login/authenticationServices/pendo/pendo.service.js @@ -0,0 +1,152 @@ +/************************************************* +* Copyright (c) 2015 Ansible, Inc. +* +* All Rights Reserved +*************************************************/ + + +export default + [ '$rootScope', '$pendolytics', 'Rest', 'GetBasePath', 'ProcessErrors', '$q', + 'Store', '$log', + function ($rootScope, $pendolytics, Rest, GetBasePath, ProcessErrors, $q, + Store, $log) { + return { + setPendoOptions: function (config) { + var tower_version = config.version.split('-')[0], + options = { + visitor: { + id: null, + role: null, + email: null + }, + account: { + id: null, + planLevel: config.license_type, + planPrice: config.instance_count, + creationDate: config.license_date, + trial: config.trial, + tower_version: tower_version, + ansible_version: config.ansible_version + } + }; + if(config.analytics_status === 'detailed'){ + this.setDetailed(options, config); + } + else if(config.analytics_status === 'anonymous'){ + this.setAnonymous(options); + } + return options; + + }, + + setDetailed: function(options, config) { + // Detailed mode + // VisitorId: username+hash of license_key + // AccountId: hash of license_key from license + // email: contact_email from license OR email from Tower account + + options.visitor.id = $rootScope.current_user.username + '@' + config.deployment_id; + options.account.id = config.deployment_id; + options.visitor.email = $rootScope.current_user.email; + }, + + setAnonymous: function (options) { + //Anonymous mode + // VisitorId: + // AccountId: + // email: + + options.visitor.id = 0; + options.account.id = "tower.ansible.com"; + options.visitor.email = ""; + }, + + setRole: function(options) { + var deferred = $q.defer(); + if($rootScope.current_user.is_superuser === true){ + options.visitor.role = 'admin'; + deferred.resolve(options); + } + 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; + }, + + getConfig: function () { + var config = Store('license'), + deferred = $q.defer(); + if(_.isEmpty(config)){ + var url = GetBasePath('config'); + Rest.setUrl(url); + var promise = Rest.get(); + promise.then(function (response) { + config = response.data.license_info; + config.analytics_status = response.data.analytics_status; + config.version = response.data.version; + config.ansible_version = response.data.ansible_version; + if(config.analytics_status === 'detailed' || config.analytics_status === 'anonymous'){ + $pendolytics.bootstrap(); + deferred.resolve(config); + } + else { + deferred.reject('Pendo is turned off.'); + } + }); + 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 config.'); + }); + } + else if(config.analytics_status === 'detailed' || config.analytics_status === 'anonymous'){ + $pendolytics.bootstrap(); + deferred.resolve(config); + } + else { + deferred.reject('Pendo is turned off.'); + } + return deferred.promise; + }, + + issuePendoIdentity: function () { + var that = this; + this.getConfig().then(function(config){ + var options = that.setPendoOptions(config); + that.setRole(options).then(function(options){ + $log.debug('Pendo status is '+ config.analytics_status + '. Object below:'); + $log.debug(options); + $pendolytics.identify(options); + }, function(reason){ + // reject function for setRole + $log.debug(reason); + }); + }, function(reason){ + // reject function for getConfig + $log.debug(reason); + }); + } + }; + } +]; diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index 3f51e62440..ea180697f2 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -26,7 +26,6 @@ -