diff --git a/modules/ui/app/plugins/traffic-analysis/ctrl.js b/modules/ui/app/plugins/traffic-analysis/ctrl.js index 91f31dd0e..d45ff8193 100644 --- a/modules/ui/app/plugins/traffic-analysis/ctrl.js +++ b/modules/ui/app/plugins/traffic-analysis/ctrl.js @@ -2,8 +2,8 @@ 'use strict'; angular.module('wasabi.controllers'). - controllerProvider.register('TrafficAnalysisCtrl', ['$scope', '$rootScope', 'UtilitiesFactory', '$modalInstance', 'ApplicationsFactory', 'MutualExclusionsFactory', 'PrioritiesFactory', 'ExperimentsFactory', '$cookies', - function ($scope, $rootScope, UtilitiesFactory, $modalInstance, ApplicationsFactory, MutualExclusionsFactory, PrioritiesFactory, ExperimentsFactory, $cookies) { + controllerProvider.register('TrafficAnalysisCtrl', ['$scope', '$rootScope', 'UtilitiesFactory', '$modalInstance', 'ApplicationsFactory', 'MutualExclusionsFactory', 'PrioritiesFactory', 'ExperimentsFactory', '$cookies', 'TrafficManagementShared', + function ($scope, $rootScope, UtilitiesFactory, $modalInstance, ApplicationsFactory, MutualExclusionsFactory, PrioritiesFactory, ExperimentsFactory, $cookies, TrafficManagementShared) { $scope.data = { applicationName: ($cookies.wasabiDefaultApplication ? $cookies.wasabiDefaultApplication : ''), selectedExperiment: '', @@ -15,6 +15,7 @@ angular.module('wasabi.controllers'). $scope.experiments = []; $scope.experimentNames = []; + $scope.columnNames = []; $scope.relatedExperiments = []; $scope.priorities = []; $scope.meDoneNames = []; @@ -30,7 +31,7 @@ angular.module('wasabi.controllers'). $scope.currentApplicationName = ''; $scope.priorities = []; $scope.experiments = []; - $scope.experimentNames = []; + $scope.columnNames = []; $scope.relatedExperiments = []; $scope.mutualExclusions = {}; }; @@ -84,61 +85,13 @@ angular.module('wasabi.controllers'). } else { UtilitiesFactory.displayPageError('Problem Getting Experiments', 'There was a problem retrieving the priorities for the experiment with label, ' + exp.label); - // TODO: Handle aborting? return false; } return true; }; $scope.getMutualExclusions = function(exp) { - console.log('Getting MEs for ' + exp.label); - MutualExclusionsFactory.query({ - experimentId: exp.id, - exclusiveFlag: true - }).$promise.then(function (meExperiments) { - // Keep track of the mutual exclusions for each experiment so we can calculate the - // sampling percentages that are effected by the mutual exclusions. - $scope.mutualExclusions[exp.label] = meExperiments; - meExperiments.forEach(function(nextExp) { - $scope.setPriorityOnExperiment(nextExp); - }); - - // Add all of the meExperiments that are not already there to the relatedExperiments array - for (var i = 0; i < meExperiments.length; i++) { - // Check if it is already in there - var expSearch = $scope.relatedExperiments.filter(function(exp) { - return exp.label === meExperiments[i].label; - }); - if (expSearch.length <= 0) { - // Add it to the array - console.log('Adding ' + meExperiments[i].label + ' to relatedExperiments'); - $scope.relatedExperiments.push(meExperiments[i]); - } - } - - // The priority field from the priorities was added to the - // mutual exclusion list when we saved it off above. This will - // allow us to sort by it. - $scope.relatedExperiments.sort(function (a, b) { - return a.priority > b.priority; - }); - - $scope.meDoneNames.push(exp.label); - if ($scope.meDoneNames.length === $scope.relatedExperiments.length) { - console.log('*** We have processed all the mutual exclusions'); - $scope.calculate(); - } - else { - meExperiments.forEach(function(nextExp) { - if ($scope.meDoneNames.indexOf(nextExp.label) < 0) { - // Only do this one if we haven't already done it (avoid indefinite loop!) - $scope.getMutualExclusions(nextExp); - } - }); - } - }, function(response) { - UtilitiesFactory.handleGlobalError(response, 'The mutual exclusions could not be retrieved.'); - }); + TrafficManagementShared.getMutualExclusions(exp, $scope, $scope.calculate); }; $scope.initialExperimentSelected = function() { @@ -153,7 +106,6 @@ angular.module('wasabi.controllers'). $scope.meDoneNames = []; $scope.mutualExclusions = {}; - //console.dir($scope.data.selectedExperiment); var expSearch = $scope.experiments.filter(function(exp) { return exp.label === $scope.data.selectedExperiment; }); @@ -168,16 +120,15 @@ angular.module('wasabi.controllers'). start: startTime, end: endTime }).$promise.then(function(results) { - $scope.experimentNames = ['Experiments:']; + $scope.columnNames = ['Experiments:']; $scope.dataRows = [ ['Priority'], - //['Target %'], ['Experiment %'] ]; var i = 0; if (results.experiments) { for (i = 0; i < results.experiments.length; i++) { - $scope.experimentNames.push(results.experiments[i]); + $scope.columnNames.push(results.experiments[i]); } } for (i = 0; i < results.priorities.length; i++) { @@ -192,6 +143,12 @@ angular.module('wasabi.controllers'). $scope.dataRows.push(row); } + // Prepare the structure used by TrafficManagementShared.getMutualExclusions() to keep track of which + // experiments we've gotten the mutual exclusions for. + $scope.pendingMEs = [{ + label: expSearch[0].label, + processed: false + }]; // Get the mutual exclusions data and then use that to calculate the target sampling %s $scope.getMutualExclusions($scope.relatedExperiments[0]); @@ -205,32 +162,7 @@ angular.module('wasabi.controllers'). $scope.calculate = function() { // Note that the experiments are listed in priority order. - - for (var j = 0; j < $scope.relatedExperiments.length; j++) { - var currentExp = $scope.relatedExperiments[j], mutexs, targetSamplingPercentages; - if (j === 0) { - // Highest priority experiment, message will be different. - currentExp.targetSamplingPercent = currentExp.samplingPercent.toFixed(4); - } - else { - // For all others, we need to calculate the target sampling percentage by looking at the higher - // priority experiments. - mutexs = $scope.mutualExclusions[currentExp.label]; - targetSamplingPercentages = 0.0; - - for (var k = 0; k < mutexs.length; k++) { - if (mutexs[k].priority < currentExp.priority) { - // Get the value the user entered for this mutually exclusive experiment - var relExp = $scope.relatedExperiments.filter(function(nextExp) { - return nextExp.label === mutexs[k].label; - }); - targetSamplingPercentages += parseFloat(relExp[0].targetSamplingPercent); - } - } - var newTargetSamp = parseFloat(currentExp.samplingPercent) * (1 - targetSamplingPercentages); - currentExp.targetSamplingPercent = parseFloat(newTargetSamp.toFixed(4)); - } - } + // Also note that this function is called after we have calculated the target sampling percentages. var targets = ['Target %']; for (var i = 0; i < $scope.relatedExperiments.length; i++) { targets[i + 1] = $scope.multiply100($scope.relatedExperiments[i].targetSamplingPercent) + '%'; diff --git a/modules/ui/app/plugins/traffic-analysis/template.html b/modules/ui/app/plugins/traffic-analysis/template.html index c57f577ac..59b67b80b 100644 --- a/modules/ui/app/plugins/traffic-analysis/template.html +++ b/modules/ui/app/plugins/traffic-analysis/template.html @@ -63,7 +63,7 @@

Traffic Analyzer

- + diff --git a/modules/ui/app/plugins/traffic-management-shared/ctrl.js b/modules/ui/app/plugins/traffic-management-shared/ctrl.js new file mode 100644 index 000000000..cb6c4edcb --- /dev/null +++ b/modules/ui/app/plugins/traffic-management-shared/ctrl.js @@ -0,0 +1,109 @@ +'use strict'; + +// This is code shared by the different Traffic Management plugins. It is registered as a service when the app loads. +// It can then be injected into the plugin controllers. +angular.module('wasabi.services'). + provide.factory('TrafficManagementShared', ['UtilitiesFactory', 'MutualExclusionsFactory', + function (UtilitiesFactory, MutualExclusionsFactory) { + return { + calculateTargetSamplingPercentages: function(scope) { + for (var j = 0; j < scope.relatedExperiments.length; j++) { + var currentExp = scope.relatedExperiments[j], mutexs, targetSamplingPercentages; + if (j === 0) { + // Highest priority experiment, message will be different. + currentExp.targetSamplingPercent = currentExp.samplingPercent.toFixed(4); + } + else { + // For all others, we need to calculate the target sampling percentage by looking at the higher + // priority experiments. + mutexs = scope.mutualExclusions[currentExp.label]; + targetSamplingPercentages = 0.0; + + for (var k = 0; k < mutexs.length; k++) { + if (mutexs[k].priority < currentExp.priority) { + // Get the value the user entered for this mutually exclusive experiment + var relExp = scope.relatedExperiments.filter(function(nextExp) { + return nextExp.label === mutexs[k].label; + }); + targetSamplingPercentages += parseFloat(relExp[0].targetSamplingPercent); + } + } + var newTargetSamp = parseFloat(currentExp.samplingPercent) * (1 - targetSamplingPercentages); + currentExp.targetSamplingPercent = parseFloat(newTargetSamp.toFixed(4)); + } + } + }, + + getMutualExclusions: function(exp, scope, afterFunc) { + var that = this; + + MutualExclusionsFactory.query({ + experimentId: exp.id, + exclusiveFlag: true + }).$promise.then(function (meExperiments) { + // Keep track of the mutual exclusions for each experiment so we can calculate the + // sampling percentages that are effected by the mutual exclusions. + scope.mutualExclusions[exp.label] = meExperiments; + + // Add all of the meExperiments that are not already there to the relatedExperiments array + for (var i = 0; i < meExperiments.length; i++) { + // Perform some housekeeping on each ME + scope.setPriorityOnExperiment(meExperiments[i]); + meExperiments[i].hoverContent = 'Hi There
More stuff is here...'; + + // Check if it is already in there + var expSearch = scope.relatedExperiments.filter(function(exp) { + return exp.label === meExperiments[i].label; + }); + if (expSearch.length <= 0) { + // Add it to the array + scope.relatedExperiments.push(meExperiments[i]); + + // This experiment was not already in the list, so get its MEs. + scope.pendingMEs.push({ + label: meExperiments[i].label, + processed: false + }); + scope.getMutualExclusions(meExperiments[i]); + } + } + + // Mark that we have completed the process of getting the MEs for this experiment + // and check if there are any in the list that are unprocessed. This allows us to know + // when we are done processing all the MEs for all the related experiments. + var leftUnprocessed = false; + for (var j = 0; j < scope.pendingMEs.length; j++) { + if (scope.pendingMEs[j].label === exp.label) { + scope.pendingMEs[j].processed = true; + } + else if (!scope.pendingMEs[j].processed) { + leftUnprocessed = true; + } + } + + if (!leftUnprocessed) { + // We have processed all the mutual exclusions + + // The priority field from the priorities was added to the + // mutual exclusion list when we saved it off above. This will + // allow us to sort by it. + scope.relatedExperiments.sort(function (a, b) { + return a.priority > b.priority; + }); + + // We always want to determine the target sampling percentages from the priorities, + // mutual exclusions and experiment sampling percentages. + that.calculateTargetSamplingPercentages(scope); + + if (afterFunc !== undefined) { + // Call the function to continue once we have retrieved all the mutual exclusions + afterFunc(); + } + } + }, function(response) { + UtilitiesFactory.handleGlobalError(response, 'The mutual exclusions could not be retrieved.'); + }); + } + } + } +]); diff --git a/modules/ui/app/plugins/traffic-management/ctrl.js b/modules/ui/app/plugins/traffic-management/ctrl.js index 90f2e1451..ee611b736 100644 --- a/modules/ui/app/plugins/traffic-management/ctrl.js +++ b/modules/ui/app/plugins/traffic-management/ctrl.js @@ -1,8 +1,8 @@ 'use strict'; angular.module('wasabi.controllers'). - controllerProvider.register('TrafficManagementCtrl', ['$scope', '$rootScope', 'UtilitiesFactory', '$modalInstance', 'ApplicationsFactory', 'MutualExclusionsFactory', 'PrioritiesFactory', 'ExperimentsFactory', '$cookies', - function ($scope, $rootScope, UtilitiesFactory, $modalInstance, ApplicationsFactory, MutualExclusionsFactory, PrioritiesFactory, ExperimentsFactory, $cookies) { + controllerProvider.register('TrafficManagementCtrl', ['$scope', '$rootScope', 'UtilitiesFactory', '$modalInstance', 'ApplicationsFactory', 'MutualExclusionsFactory', 'PrioritiesFactory', 'ExperimentsFactory', '$cookies', 'TrafficManagementShared', + function ($scope, $rootScope, UtilitiesFactory, $modalInstance, ApplicationsFactory, MutualExclusionsFactory, PrioritiesFactory, ExperimentsFactory, $cookies, TrafficManagementShared) { $scope.data = { applicationName: ($cookies.wasabiDefaultApplication ? $cookies.wasabiDefaultApplication : ''), selectedExperiment: '' @@ -14,7 +14,6 @@ angular.module('wasabi.controllers'). $scope.experimentNames = []; $scope.relatedExperiments = []; $scope.priorities = []; - $scope.meDoneNames = []; $scope.mutualExclusions = {}; $scope.numPendingSaves = 0; @@ -84,116 +83,45 @@ angular.module('wasabi.controllers'). if (exp.samplingPercent) { exp.originalSamplingPercent = exp.samplingPercent; exp.targetSamplingPercent = 0; + exp.oldSamplingPercent = ''; } } else { UtilitiesFactory.displayPageError('Problem Getting Experiments', 'There was a problem retrieving the priorities for the experiment with label, ' + exp.label); - // TODO: Handle aborting? return false; } return true; }; $scope.getMutualExclusions = function(exp) { - console.log('Getting MEs for ' + exp.label); - MutualExclusionsFactory.query({ - experimentId: exp.id, - exclusiveFlag: true - }).$promise.then(function (meExperiments) { - // Keep track of the mutual exclusions for each experiment so we can calculate the - // sampling percentages that are effected by the mutual exclusions. - $scope.mutualExclusions[exp.label] = meExperiments; - meExperiments.forEach(function(nextExp) { - $scope.setPriorityOnExperiment(nextExp); - nextExp.hoverContent = 'Hi There
More stuff is here...'; - }); - - // Add all of the meExperiments that are not already there to the relatedExperiments array - for (var i = 0; i < meExperiments.length; i++) { - // Check if it is already in there - var expSearch = $scope.relatedExperiments.filter(function(exp) { - return exp.label === meExperiments[i].label; - }); - if (expSearch.length <= 0) { - // Add it to the array - console.log('Adding ' + meExperiments[i].label + ' to relatedExperiments'); - $scope.relatedExperiments.push(meExperiments[i]); - } - } - - // The priority field from the priorities was added to the - // mutual exclusion list when we saved it off above. This will - // allow us to sort by it. - $scope.relatedExperiments.sort(function (a, b) { - return a.priority > b.priority; - }); - - $scope.meDoneNames.push(exp.label); - if ($scope.meDoneNames.length === $scope.relatedExperiments.length) { - console.log('*** We have processed all the mutual exclusions'); - $scope.calculateTargetSamplingPercentages(); - } - else { - meExperiments.forEach(function(nextExp) { - if ($scope.meDoneNames.indexOf(nextExp.label) < 0) { - // Only do this one if we haven't already done it (avoid indefinite loop!) - $scope.getMutualExclusions(nextExp); - } - }); - } - }, function(response) { - UtilitiesFactory.handleGlobalError(response, 'The mutual exclusions could not be retrieved.'); - }); + TrafficManagementShared.getMutualExclusions(exp, $scope); }; - $scope.calculateTargetSamplingPercentages = function() { - for (var j = 0; j < $scope.relatedExperiments.length; j++) { - var currentExp = $scope.relatedExperiments[j], mutexs, targetSamplingPercentages; - if (j === 0) { - // Highest priority experiment, message will be different. - currentExp.targetSamplingPercent = currentExp.samplingPercent.toFixed(4); - } - else { - // For all others, we need to calculate the target sampling percentage by looking at the higher - // priority experiments. - mutexs = $scope.mutualExclusions[currentExp.label]; - targetSamplingPercentages = 0.0; - - for (var k = 0; k < mutexs.length; k++) { - if (mutexs[k].priority < currentExp.priority) { - // Get the value the user entered for this mutually exclusive experiment - var relExp = $scope.relatedExperiments.filter(function(nextExp) { - return nextExp.label === mutexs[k].label; - }); - targetSamplingPercentages += parseFloat(relExp[0].targetSamplingPercent); - } - } - var newTargetSamp = parseFloat(currentExp.samplingPercent) * (1 - targetSamplingPercentages); - currentExp.targetSamplingPercent = parseFloat(newTargetSamp.toFixed(4)); - } - } - } - $scope.initialExperimentSelected = function() { var i = 0; $scope.relatedExperiments = []; - $scope.meDoneNames = []; $scope.mutualExclusions = {}; $scope.noCalc = false; - //console.dir($scope.data.selectedExperiment); + // Find the selected experiment var expSearch = $scope.experiments.filter(function(exp) { return exp.label === $scope.data.selectedExperiment; }); if (expSearch.length > 0) { + // Start the process of building the list of experiments related by mutual exclusions $scope.relatedExperiments.push(JSON.parse(JSON.stringify(expSearch[0]))); $scope.setPriorityOnExperiment($scope.relatedExperiments[0]); - console.log('Got priorities, get MEs for ' + expSearch[0].label); + // Prepare the structure used by TrafficManagementShared.getMutualExclusions() to keep track of which + // experiments we've gotten the mutual exclusions for. + $scope.pendingMEs = [{ + label: expSearch[0].label, + processed: false + }]; $scope.getMutualExclusions($scope.relatedExperiments[0]); } @@ -207,7 +135,7 @@ angular.module('wasabi.controllers'). var cannotCalc = false; for (var i = 0; i < $scope.relatedExperiments.length; i++) { if ($scope.relatedExperiments[i].targetSamplingPercent.length === 0 || - $scope.relatedExperiments[i].targetSamplingPercent === 0.0) { + parseFloat($scope.relatedExperiments[i].targetSamplingPercent) === 0.0) { UtilitiesFactory.displayPageError('Missing Target Sampling Percentage', 'Unable to calculate Experiment Sampling Percentages unless all Target Sampling Percentages have non-zero values.'); cannotCalc = true; break; @@ -280,6 +208,18 @@ angular.module('wasabi.controllers'). } } } + // Need to go through the list one more time to set up to display changes, if any. For some reason, + // the template doesn't seem able to do this. + for (var m = 0; m < $scope.relatedExperiments.length; m++) { + if (parseFloat($scope.relatedExperiments[m].originalSamplingPercent) !== parseFloat($scope.relatedExperiments[m].samplingPercent)) { + // The calculated sampling percent is new, so we want to display the old one. + $scope.relatedExperiments[m].oldSamplingPercent = $scope.multiply100($scope.relatedExperiments[m].originalSamplingPercent); + } + else { + $scope.relatedExperiments[m].oldSamplingPercent = ''; + } + } + var x = 5; }; $scope.save = function() { diff --git a/modules/ui/app/plugins/traffic-management/template.html b/modules/ui/app/plugins/traffic-management/template.html index a03cd06a2..046971d1c 100644 --- a/modules/ui/app/plugins/traffic-management/template.html +++ b/modules/ui/app/plugins/traffic-management/template.html @@ -24,7 +24,7 @@

Traffic Estimator

- +
{{name}}{{name}}
{{nextExperiment.priority}}{{nextExperiment.label}} {{nextExperiment.originalSamplingPercent !== nextExperiment.samplingPercent ? multiply100(nextExperiment.originalSamplingPercent) : ''}} {{multiply100(nextExperiment.samplingPercent)}} {{nextExperiment.oldSamplingPercent}} {{multiply100(nextExperiment.samplingPercent)}}
diff --git a/modules/ui/app/scripts/app.js b/modules/ui/app/scripts/app.js index 86a550fb5..0b991844b 100644 --- a/modules/ui/app/scripts/app.js +++ b/modules/ui/app/scripts/app.js @@ -5,7 +5,7 @@ * create sub modules (with [] in the end) */ var ctrlModule = angular.module('wasabi.controllers', ['config']); -angular.module('wasabi.services', ['ngResource']); +var svcModule = angular.module('wasabi.services', ['ngResource']); angular.module('wasabi.directives', ['ngCookies']); ctrlModule.config(['$controllerProvider', @@ -14,6 +14,12 @@ ctrlModule.config(['$controllerProvider', } ]); +svcModule.config(['$provide', + function ($provide) { + svcModule.provide = $provide; + } +]); + /* * create main wasabi module diff --git a/modules/ui/app/scripts/plugins.js b/modules/ui/app/scripts/plugins.js index 8f4b7e6dd..b9458b0bd 100644 --- a/modules/ui/app/scripts/plugins.js +++ b/modules/ui/app/scripts/plugins.js @@ -1,4 +1,9 @@ var wasabiUIPlugins = [ + { + 'pluginType': 'contributeSharedCode', + 'description': 'Shared code to be loaded by both the Traffic Management plugins.', + 'ctrl': 'plugins/traffic-management-shared/ctrl.js' + }, { 'pluginType': 'contributeAppLevelFeature', 'displayName': 'Traffic Estimator',