From df771d5c0d75c57632ea9547677048d0ef621702 Mon Sep 17 00:00:00 2001 From: Joe Fiorini Date: Mon, 18 May 2015 15:36:13 -0400 Subject: [PATCH] Display comparisons with data from API See https://gist.github.com/joefiorini/3a8c36bcedf7ad954952 for an explanation of the comparison logic. --- .jshintrc | 4 + awx/ui/static/js/controllers/Inventories.js | 11 +- .../route-params.decorator.js | 16 + .../route-extensions/transition-to.factory.js | 2 +- awx/ui/static/js/shared/text-label.less | 20 + .../js/system-tracking/compare-facts.js | 10 + .../js/system-tracking/compare-facts/flat.js | 57 + .../compare-facts/nested-helpers.js | 169 ++ .../system-tracking/compare-facts/nested.js | 63 + .../system-tracking/compare-hosts.factory.js | 7 - .../fact-scan-data.service.js} | 30 +- .../get-data-for-comparison.factory.js | 42 + .../date-picker/date-picker.block.less | 38 + .../date-picker/date-picker.directive.js | 44 + .../date-picker/date-picker.partial.html | 9 + .../js/system-tracking/date-picker/main.js | 7 + .../fact-data-group.block.less | 16 + .../fact-data-service.factory.js | 63 - .../fact-data-table.block.less | 13 + .../fact-data-table.partial.html | 38 + .../js/system-tracking/fact-datum.block.less | 7 + .../fact-module-pickers.block.less | 56 +- awx/ui/static/js/system-tracking/fake-data.js | 2514 ----------------- .../system-tracking/format-results.factory.js | 13 - awx/ui/static/js/system-tracking/main.js | 25 +- .../static/js/system-tracking/nested-facts.md | 168 -- .../js/system-tracking/search-date-range.js | 6 + .../system-tracking/string-or-date.filter.js | 2 +- .../system-tracking.controller.js | 136 +- .../system-tracking.partial.html | 90 +- .../system-tracking/system-tracking.route.js | 87 +- .../js/system-tracking/xor-objects.factory.js | 28 - awx/ui/static/less/text-label.less | 17 +- .../single-host-data.service-test.js | 2 +- 34 files changed, 855 insertions(+), 2955 deletions(-) create mode 100644 awx/ui/static/js/shared/route-extensions/route-params.decorator.js create mode 100644 awx/ui/static/js/shared/text-label.less create mode 100644 awx/ui/static/js/system-tracking/compare-facts.js create mode 100644 awx/ui/static/js/system-tracking/compare-facts/flat.js create mode 100644 awx/ui/static/js/system-tracking/compare-facts/nested-helpers.js create mode 100644 awx/ui/static/js/system-tracking/compare-facts/nested.js delete mode 100644 awx/ui/static/js/system-tracking/compare-hosts.factory.js rename awx/ui/static/js/system-tracking/{single-host-data.service.js => data-services/fact-scan-data.service.js} (64%) create mode 100644 awx/ui/static/js/system-tracking/data-services/get-data-for-comparison.factory.js create mode 100644 awx/ui/static/js/system-tracking/date-picker/date-picker.block.less create mode 100644 awx/ui/static/js/system-tracking/date-picker/date-picker.directive.js create mode 100644 awx/ui/static/js/system-tracking/date-picker/date-picker.partial.html create mode 100644 awx/ui/static/js/system-tracking/date-picker/main.js create mode 100644 awx/ui/static/js/system-tracking/fact-data-group.block.less delete mode 100644 awx/ui/static/js/system-tracking/fact-data-service.factory.js create mode 100644 awx/ui/static/js/system-tracking/fact-data-table.block.less create mode 100644 awx/ui/static/js/system-tracking/fact-data-table.partial.html create mode 100644 awx/ui/static/js/system-tracking/fact-datum.block.less delete mode 100644 awx/ui/static/js/system-tracking/fake-data.js delete mode 100644 awx/ui/static/js/system-tracking/format-results.factory.js delete mode 100644 awx/ui/static/js/system-tracking/nested-facts.md create mode 100644 awx/ui/static/js/system-tracking/search-date-range.js delete mode 100644 awx/ui/static/js/system-tracking/xor-objects.factory.js diff --git a/.jshintrc b/.jshintrc index 0239abbde6..e44155d984 100644 --- a/.jshintrc +++ b/.jshintrc @@ -11,6 +11,9 @@ "maxerr": 10000, "notypeof": true, "globals": { + "beforeEach": false, + "inject": false, + "module": false, "angular":false, "alert":false, "$AnsibleConfig":true, @@ -21,6 +24,7 @@ "Donut3D":false, "nv":false, "it": false, + "xit": false, "expect": false, "context": false, "describe": false, diff --git a/awx/ui/static/js/controllers/Inventories.js b/awx/ui/static/js/controllers/Inventories.js index f18d7116f4..9453902e0a 100644 --- a/awx/ui/static/js/controllers/Inventories.js +++ b/awx/ui/static/js/controllers/Inventories.js @@ -802,7 +802,7 @@ export function InventoriesManage ($log, $scope, $rootScope, $location, ViewUpdateStatus, GroupsDelete, Store, HostsEdit, HostsDelete, EditInventoryProperties, ToggleHostEnabled, Stream, ShowJobSummary, InventoryGroupsHelp, HelpDialog, ViewJob, - GroupsCopy, HostsCopy) { + GroupsCopy, HostsCopy, transitionTo) { var PreviousSearchParams, url, @@ -864,9 +864,10 @@ export function InventoriesManage ($log, $scope, $rootScope, $location, }); $scope.systemTracking = function() { - $location.path('/inventories/' + $scope.inventory.id + - '/system-tracking/' + - _.pluck($scope.hostsSelectedItems, "id").join(",")); + transitionTo('systemTracking', + { inventory: $scope.inventory, + hosts: $scope.hostsSelectedItems + }); }; // populates host patterns based on selected hosts/groups @@ -1411,5 +1412,5 @@ InventoriesManage.$inject = ['$log', '$scope', '$rootScope', '$location', 'GroupsDelete', 'Store', 'HostsEdit', 'HostsDelete', 'EditInventoryProperties', 'ToggleHostEnabled', 'Stream', 'ShowJobSummary', 'InventoryGroupsHelp', 'HelpDialog', 'ViewJob', 'GroupsCopy', - 'HostsCopy' + 'HostsCopy', 'transitionTo' ]; diff --git a/awx/ui/static/js/shared/route-extensions/route-params.decorator.js b/awx/ui/static/js/shared/route-extensions/route-params.decorator.js new file mode 100644 index 0000000000..e1b68484be --- /dev/null +++ b/awx/ui/static/js/shared/route-extensions/route-params.decorator.js @@ -0,0 +1,16 @@ +export function wrapDelegate($delegate) { + $delegate.hasModelKey = function hasModelKey(key) { + return $delegate.hasOwnProperty('model') && + $delegate.model.hasOwnProperty(key); + }; + + return $delegate; +} + +export default + [ '$provide', + function($provide) { + $provide.decorator('$routeParams', wrapDelegate); + + } + ]; diff --git a/awx/ui/static/js/shared/route-extensions/transition-to.factory.js b/awx/ui/static/js/shared/route-extensions/transition-to.factory.js index 6acee4326f..17558a8397 100644 --- a/awx/ui/static/js/shared/route-extensions/transition-to.factory.js +++ b/awx/ui/static/js/shared/route-extensions/transition-to.factory.js @@ -91,7 +91,7 @@ export default function($location, $rootScope, $route, $q) { return function(routeName, model) { var deferred = $q.defer(); - var url = lookupRouteUrl(routeName, $route.routes, model); + var url = lookupRouteUrl(routeName, $route.routes, model, true); var offRouteChangeStart = $rootScope.$on('$routeChangeStart', function(e, newRoute) { diff --git a/awx/ui/static/js/shared/text-label.less b/awx/ui/static/js/shared/text-label.less new file mode 100644 index 0000000000..66ef5f3fec --- /dev/null +++ b/awx/ui/static/js/shared/text-label.less @@ -0,0 +1,20 @@ +/* oops */ + +.include-text-label(@background-color; @color; @content) { + display: inline-block; + content: @content; + + border-radius: 3px; + background-color: @background-color; + color: @color; + text-transform: uppercase; + font-size: .7em; + font-weight: bold; + font-style: normal; + margin-left: 0.5em; + padding: 0.35em; + padding-bottom: 0.2em; + line-height: 1.1; +} + + diff --git a/awx/ui/static/js/system-tracking/compare-facts.js b/awx/ui/static/js/system-tracking/compare-facts.js new file mode 100644 index 0000000000..c7f7f85f63 --- /dev/null +++ b/awx/ui/static/js/system-tracking/compare-facts.js @@ -0,0 +1,10 @@ +import compareNestedFacts from './compare-facts/nested'; +import compareFlatFacts from './compare-facts/flat'; + +export function compareFacts(module, facts) { + if (module.displayType === 'nested') { + return compareNestedFacts(facts); + } else { + return compareFlatFacts(facts, module.nameKey, module.compareKey); + } +} diff --git a/awx/ui/static/js/system-tracking/compare-facts/flat.js b/awx/ui/static/js/system-tracking/compare-facts/flat.js new file mode 100644 index 0000000000..747def2b77 --- /dev/null +++ b/awx/ui/static/js/system-tracking/compare-facts/flat.js @@ -0,0 +1,57 @@ +export default + function flatCompare(facts, nameKey, compareKeys) { + + var leftFacts = facts[0]; + var rightFacts = facts[1]; + + return rightFacts.reduce(function(arr, rightFact) { + var searcher = {}; + searcher[nameKey] = rightFact[nameKey]; + + var isNewFactValue = false; + + var matchingFact = _.where(leftFacts, searcher); + var diffs; + + if (_.isEmpty(matchingFact)) { + isNewFactValue = true; + + diffs = + _.map(rightFact, function(value, key) { + return { keyName: key, + value1: value, + value2: '' + }; + }); + } else { + matchingFact = matchingFact[0]; + + diffs = _(compareKeys) + .map(function(key) { + var leftValue = rightFact[key]; + var rightValue = matchingFact[key]; + if (leftValue !== rightValue) { + return { + keyName: key, + value1: leftValue, + value2: rightValue + }; + } + }).compact() + .value(); + + } + + var descriptor = + { displayKeyPath: rightFact[nameKey], + isNew: isNewFactValue, + nestingLevel: 0, + facts: diffs + }; + + return arr.concat(descriptor); + }, []).filter(function(diff) { + return !_.isEmpty(diff.facts); + }); + + } diff --git a/awx/ui/static/js/system-tracking/compare-facts/nested-helpers.js b/awx/ui/static/js/system-tracking/compare-facts/nested-helpers.js new file mode 100644 index 0000000000..ba3e9c99e7 --- /dev/null +++ b/awx/ui/static/js/system-tracking/compare-facts/nested-helpers.js @@ -0,0 +1,169 @@ +export function formatFacts(diffedResults) { + + var loggingEnabled = false; + + function log(msg, obj) { + if (loggingEnabled) { + /* jshint ignore:start */ + console.log(msg, obj); + /* jshint ignore:end */ + } + return obj; + } + + function isFlatFactArray(fact) { + // Flat arrays will have the index as their + // keyName + return !_.isNaN(Number(fact.keyName)); + } + + function isNestedFactArray(fact) { + // Nested arrays will have the index as the last element + // in the keypath + return !_.isNaN(Number(_.last(fact.keyPath))); + } + function isFactArray(fact) { + return isNestedFactArray(fact) || isFlatFactArray(fact); + } + + // Explode flat results into groups based matching + // parent keypaths + var grouped = _.groupBy(diffedResults, function(obj) { + var leftKeyPathStr = obj.keyPath.join('.'); + log('obj.keyPath', obj.keyPath); + return log(' reduced key', _.reduce(diffedResults, function(result, obj2) { + log(' obj2.keyPath', obj2.keyPath); + var rightKeyPathStr = obj2.keyPath.join('.'); + if (isFactArray(obj)) { + log(' number hit!', Number(_.last(obj.keyPath))); + return obj.keyPath.slice(0,-1); + } else if (rightKeyPathStr && leftKeyPathStr !== rightKeyPathStr && log(' intersection', _.intersection(obj.keyPath, obj2.keyPath).join('.')) === rightKeyPathStr) { + log(' hit!'); + return obj2.keyPath; + } else { + log(' else hit!'); + return result; + } + }, obj.keyPath)).join('.'); + }); + + var normalized = _.mapValues(grouped, function(arr, rootKey) { + log('processing', rootKey); + var nestingLevel = 0; + var trailingLength; + return _(arr).sortBy('keyPath.length').tap(function(arr) { + // Initialize trailing length to the shortest keyPath length + // in the array (first item because we know it's sorted now) + trailingLength = arr[0].keyPath.length; + }).map(function(obj) { + var keyPathStr = obj.keyPath.join('.'); + log(' calculating displayKeyPath for', keyPathStr); + var rootKeyPath = rootKey.split('.'); + var displayKeyPath; + // var factArrayIndex; + var isFactArrayProp = isFactArray(obj); + + if (obj.keyPath.length > trailingLength) { + nestingLevel++; + trailingLength = obj.keyPath.length; + } + + if (isNestedFactArray(obj)) { + // factArrayIndex = obj.keyPath.length > 1 ? Number(_.last(obj.keyPath)) : obj.keyName; + displayKeyPath = _.initial(obj.keyPath).join('.'); + } else if (keyPathStr !== rootKey) { + displayKeyPath = _.difference(obj.keyPath, rootKeyPath).join('.'); + } else { + displayKeyPath = rootKeyPath.join('.'); + } + + + obj.displayKeyPath = displayKeyPath; + obj.nestingLevel = nestingLevel; + // obj.arrayPosition = factArrayIndex; + obj.isArrayMember = isFactArrayProp; + return obj; + }).value(); + }); + + var flattened = _.reduce(normalized, function(flat, value) { + + var groupedValues = _.groupBy(value, 'displayKeyPath'); + + var groupArr = + _.reduce(groupedValues, function(groupArr, facts, key) { + var isArray = facts[0].isArrayMember; + var nestingLevel = facts[0].nestingLevel; + + if (isArray) { + facts = _(facts) + .groupBy('arrayPosition') + .values() + .value(); + } + + var displayObj = + { keyPath: key.split('.'), + displayKeyPath: key, + facts: facts, + isFactArray: isArray, + nestingLevel: nestingLevel + }; + return groupArr.concat(displayObj); + }, []); + + return flat.concat(groupArr); + + }, []); + + return flattened; +} + +export function findFacts(factData) { + var rightData = factData[0]; + var leftData = factData[1]; + + function factObject(keyPath, key, leftValue, rightValue) { + var obj = + { keyPath: keyPath, + keyName: key, + value1: leftValue, + value2: rightValue + }; + return obj; + } + + function descend(parentValue, parentKey, parentKeys) { + if (_.isObject(parentValue)) { + return _.reduce(parentValue, function(all, value, key) { + var merged = descend(value, key, parentKeys.concat(key)); + return all.concat(merged); + }, []); + } else { + + var rightValue = + _.get(rightData, + parentKeys, + 'absent'); + + return factObject( + // TODO: Currently parentKeys is getting passed with the final key + // as the last element. Figure out how to have it passed + // in correctly, so that it's all the keys leading up to + // the value, but not the value's key itself + // In the meantime, slicing the last element off the array + parentKeys.slice(0,-1), + parentKey, + parentValue, + rightValue); + } + } + + return _.reduce(leftData, function(mergedFacts, parentValue, parentKey) { + + var merged = descend(parentValue, parentKey, [parentKey]); + + return _.flatten(mergedFacts.concat(merged)); + + }, []); +} diff --git a/awx/ui/static/js/system-tracking/compare-facts/nested.js b/awx/ui/static/js/system-tracking/compare-facts/nested.js new file mode 100644 index 0000000000..7c5955e48b --- /dev/null +++ b/awx/ui/static/js/system-tracking/compare-facts/nested.js @@ -0,0 +1,63 @@ +import {formatFacts, findFacts} from './nested-helpers'; + +export default function nestedCompare(factsList) { + + factsList = findFacts(factsList); + factsList = compareFacts(factsList); + return formatFacts(factsList); + + function compareFacts(factsList) { + + function serializedFactKey(fact) { + return fact.keyPath.join('.'); + } + + var groupedByParent = + _.groupBy(factsList, function(fact) { + return serializedFactKey(fact); + }); + + + var diffed = _.mapValues(groupedByParent, function(facts) { + return facts.filter(function(fact) { + return fact.value1 !== fact.value2; + }).map(function(fact) { + // TODO: Can we determine a "compare order" and be able say + // which property is actually divergent? + return _.merge({}, fact, { isDivergent: true }); + }); + }); + + var itemsWithDiffs = + _.filter(factsList, function(facts) { + var groupedData = diffed[serializedFactKey(facts)]; + return !_.isEmpty(groupedData); + }); + + var keysWithDiffs = + _.reduce(diffed, function(diffs, facts, key) { + diffs[key] = + facts.reduce(function(diffKeys, fact) { + if (fact.isDivergent) { + return diffKeys.concat(fact.keyName); + } + return diffKeys; + }, []); + return diffs; + }, {}); + + var factsWithDivergence = + _.mapValues(itemsWithDiffs, function(fact) { + var divergentKeys = keysWithDiffs[serializedFactKey(fact)]; + if (divergentKeys) { + var isDivergent = _.include(divergentKeys, fact.keyName); + return _.merge({}, fact, { isDivergent: isDivergent }); + } else { + return _.merge({}, fact, { isDivergent: false }); + } + }); + + return factsWithDivergence; + + } +} diff --git a/awx/ui/static/js/system-tracking/compare-hosts.factory.js b/awx/ui/static/js/system-tracking/compare-hosts.factory.js deleted file mode 100644 index e9eb8972dd..0000000000 --- a/awx/ui/static/js/system-tracking/compare-hosts.factory.js +++ /dev/null @@ -1,7 +0,0 @@ -export default - ['xorObjects', 'formatResults', function(xorObjects, formatResults) { - return function compareHosts(module, factData1, factData2) { - var diffed = xorObjects('name', factData1, factData2); - return formatResults('name', 'version', diffed); - }; - }]; diff --git a/awx/ui/static/js/system-tracking/single-host-data.service.js b/awx/ui/static/js/system-tracking/data-services/fact-scan-data.service.js similarity index 64% rename from awx/ui/static/js/system-tracking/single-host-data.service.js rename to awx/ui/static/js/system-tracking/data-services/fact-scan-data.service.js index c83672ce11..018f3d098b 100644 --- a/awx/ui/static/js/system-tracking/single-host-data.service.js +++ b/awx/ui/static/js/system-tracking/data-services/fact-scan-data.service.js @@ -1,7 +1,22 @@ -export default ['Rest', 'GetBasePath', 'ProcessErrors', -function (Rest, GetBasePath, ProcessErrors) { +export default ['Rest', 'GetBasePath', 'ProcessErrors', 'lodashAsPromised', +function (Rest, GetBasePath, ProcessErrors, _) { return { - getFacts: function(version){ + getHostFacts: function(host, moduleName, date, fetchScanNumber) { + + var version =this.getVersion(host, moduleName, date.from, date.to, fetchScanNumber); + var getFacts = this.getFacts; + + return version + .then(function(versionData) { + if (_.isEmpty(versionData)) { + return []; + } else { + return getFacts(versionData); + } + }); + + }, + getFacts: function(version) { var promise; Rest.setUrl(version.related.fact_view); promise = Rest.get(); @@ -16,15 +31,18 @@ function (Rest, GetBasePath, ProcessErrors) { }); }, - getVersion: function(host_id, module, startDate, endDate){ + getVersion: function(host_id, module, startDate, endDate, fetchScanNumber){ //move the build url into getVersion and have the // parameters passed into this var promise, url = this.buildUrl(host_id, module, startDate, endDate); + + fetchScanNumber = fetchScanNumber || 0; + Rest.setUrl(url); promise = Rest.get(); return promise.then(function(data) { - return data.data.results[0]; + return data.data.results[fetchScanNumber]; }).catch(function (response) { ProcessErrors(null, response.data, response.status, null, { hdr: 'Error!', @@ -36,7 +54,7 @@ function (Rest, GetBasePath, ProcessErrors) { buildUrl: function(host_id, module, startDate, endDate){ var url = GetBasePath('hosts') + host_id + '/fact_versions/', - params= [["module", module] , ['startDate', startDate.format()], ['endDate', endDate.format()]]; + params= [["module", module] , ['from', startDate.format()], ['to', endDate.format()]]; params = params.filter(function(p){ return !_.isEmpty(p[1]); diff --git a/awx/ui/static/js/system-tracking/data-services/get-data-for-comparison.factory.js b/awx/ui/static/js/system-tracking/data-services/get-data-for-comparison.factory.js new file mode 100644 index 0000000000..e6f0cb2ec9 --- /dev/null +++ b/awx/ui/static/js/system-tracking/data-services/get-data-for-comparison.factory.js @@ -0,0 +1,42 @@ +export default + [ 'factScanDataService', + 'lodashAsPromised', + function(factScanDataService, _) { + return function(hostIds, moduleName, leftDate, rightDate) { + + if (hostIds.length === 1) { + hostIds = hostIds.concat(hostIds[0]); + } + + return _(hostIds) + .promise() + .thenMap(function(hostId, index) { + var date = leftDate; + var fetchScanNumber; + + if (index === 1) { + date = rightDate; + } else { + if (rightDate.from.isSame(leftDate.from, 'day')) { + fetchScanNumber = 1; + } + } + + var params = + [ hostId, + moduleName, + date, + fetchScanNumber + ]; + + return params; + }).thenMap(function(params) { + var getHostFacts = + _.spread(factScanDataService.getHostFacts) + .bind(factScanDataService); + + return getHostFacts(params); + }); + }; + } + ]; diff --git a/awx/ui/static/js/system-tracking/date-picker/date-picker.block.less b/awx/ui/static/js/system-tracking/date-picker/date-picker.block.less new file mode 100644 index 0000000000..01aa490d73 --- /dev/null +++ b/awx/ui/static/js/system-tracking/date-picker/date-picker.block.less @@ -0,0 +1,38 @@ +/** @define DatePicker */ + +.DatePicker { + flex: 1; + display: flex; + + &-icon { + flex: initial; + padding: 6px 12px; + font-size: 14px; + border-radius: 4px 0 0 4px; + border: 1px solid #ccc; + border-right: 0; + background-color: #fff; + } + + &-icon:hover { + background-color: #e8e8e8; + } + + &-icon:focus, + &-icon:active { + background-color: #ccc; + } + + &-input { + flex: 1; + border-radius: 0 4px 4px 0; + border: 1px solid #ccc; + padding: 6px 12px; + } + + &-input:focus, + &-input:active { + outline-offset: 0; + outline: 0; + } +} diff --git a/awx/ui/static/js/system-tracking/date-picker/date-picker.directive.js b/awx/ui/static/js/system-tracking/date-picker/date-picker.directive.js new file mode 100644 index 0000000000..c7820b50b7 --- /dev/null +++ b/awx/ui/static/js/system-tracking/date-picker/date-picker.directive.js @@ -0,0 +1,44 @@ +/* jshint unused: vars */ + +export default + [ '$rootScope', + function() { + return { + restrict: 'E', + scope: { + date: '=' + }, + templateUrl: '/static/js/system-tracking/date-picker/date-picker.partial.html', + link: function(scope, element, attrs) { + + // We need to make sure this _never_ recurses, which sometimes happens + // with two-way binding. + var mustUpdateValue = true; + + scope.$watch('date', function(newValue) { + if (newValue) { + mustUpdateValue = false; + scope.dateValue = newValue.format('L'); + } + }, true); + + scope.$watch('dateValue', function(newValue) { + var newDate = moment(newValue); + + if (newValue && !newDate.isValid()) { + scope.error = "That is not a valid date."; + } else if (newValue) { + scope.date = newDate; + } + mustUpdateValue = true; + }); + + element.find(".DatePicker").addClass("input-prepend date"); + element.find(".DatePicker").find(".DatePicker-icon").addClass("add-on"); + $(".date").systemTrackingDP({ + autoclose: true + }); + } + }; + } + ]; diff --git a/awx/ui/static/js/system-tracking/date-picker/date-picker.partial.html b/awx/ui/static/js/system-tracking/date-picker/date-picker.partial.html new file mode 100644 index 0000000000..46b2a0d5de --- /dev/null +++ b/awx/ui/static/js/system-tracking/date-picker/date-picker.partial.html @@ -0,0 +1,9 @@ +
+ + +

{{error}}

+
diff --git a/awx/ui/static/js/system-tracking/date-picker/main.js b/awx/ui/static/js/system-tracking/date-picker/main.js new file mode 100644 index 0000000000..f2d536cdd3 --- /dev/null +++ b/awx/ui/static/js/system-tracking/date-picker/main.js @@ -0,0 +1,7 @@ +import datePicker from './date-picker.directive'; + +export default + angular.module('systemTracking.datePicker', + []) + .directive('datePicker', datePicker); + diff --git a/awx/ui/static/js/system-tracking/fact-data-group.block.less b/awx/ui/static/js/system-tracking/fact-data-group.block.less new file mode 100644 index 0000000000..9d62b689ef --- /dev/null +++ b/awx/ui/static/js/system-tracking/fact-data-group.block.less @@ -0,0 +1,16 @@ +/** @define FactDataGroup */ + +@import 'shared/text-label.less'; + +.FactDataGroup { + &-header { + display: flex; + &--new { + &:after { + .include-text-label(#676767; white; "new"); + align-self: center; + font-size: 1rem; + } + } + } +} diff --git a/awx/ui/static/js/system-tracking/fact-data-service.factory.js b/awx/ui/static/js/system-tracking/fact-data-service.factory.js deleted file mode 100644 index 6ccf6aafa4..0000000000 --- a/awx/ui/static/js/system-tracking/fact-data-service.factory.js +++ /dev/null @@ -1,63 +0,0 @@ -import fakeData from './fake-data'; - -function getComparisonData(module) { - - var valueName, leftValue, rightValue; - - switch(module) { - case 'packages': - valueName = 'bash'; - leftValue = '5.2.3'; - rightValue = '5.2.4'; - break; - case 'services': - valueName = 'httpd'; - leftValue = 'started'; - rightValue = 'absent'; - break; - case 'files': - valueName = '/etc/sudoers'; - leftValue = 'some string'; - rightValue = 'some other string'; - break; - case 'ansible': - valueName = 'ansible_ipv4_address'; - leftValue = '192.168.0.1'; - rightValue = '192.168.0.2'; - break; - } - - return [{ module: module, - valueName: valueName, - leftValue: leftValue, - rightValue: rightValue - }]; -} - -export default - ['$q', 'compareHosts', function factDataServiceFactory($q, compareHosts) { - return function(type) { - if (type === 'multiHost') { - return { get: function(inventoryId, module, host1, host2) { - var result = {}; - result.leftFilterValue = host1; - result.rightFilterValue = host2; - - result.factComparisonData = compareHosts(module, fakeData.host1, fakeData.host2); - - return result; - } - }; - } else if (type === 'singleHost') { - return { get: function(inventoryId, module, startDate, endDate) { - var result = {}; - result.leftFilterValue = startDate; - result.rightFilterValue = endDate; - - result.factComparisonData = getComparisonData(module); - return result; - } - }; - } - }; - }] diff --git a/awx/ui/static/js/system-tracking/fact-data-table.block.less b/awx/ui/static/js/system-tracking/fact-data-table.block.less new file mode 100644 index 0000000000..910acc2ccc --- /dev/null +++ b/awx/ui/static/js/system-tracking/fact-data-table.block.less @@ -0,0 +1,13 @@ +/** @define FactDataTable */ + +.FactDataTable { + &-row { + display: flex; + } + &-column { + flex: 1; + &--offsetLeft { + padding-left: 33%; + } + } +} diff --git a/awx/ui/static/js/system-tracking/fact-data-table.partial.html b/awx/ui/static/js/system-tracking/fact-data-table.partial.html new file mode 100644 index 0000000000..22e17b1d4b --- /dev/null +++ b/awx/ui/static/js/system-tracking/fact-data-table.partial.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + +
{{comparisonLeftHeader|stringOrDate:'L'}}{{comparisonRightHeader|stringOrDate:'L'}}
+

{{group.displayKeyPath}}

+
+

{{group.displayKeyPath}}

+
+

{{group.displayKeyPath}}

+
+
{{group.displayKeyPath}}
+
{{fact.keyName}} +

+ {{fact.value1}} +

+
+

+ {{fact.value2}} +

+
diff --git a/awx/ui/static/js/system-tracking/fact-datum.block.less b/awx/ui/static/js/system-tracking/fact-datum.block.less new file mode 100644 index 0000000000..a12ab5aa80 --- /dev/null +++ b/awx/ui/static/js/system-tracking/fact-datum.block.less @@ -0,0 +1,7 @@ +/** @define FactDatum */ + +.FactDatum { + &--divergent { + font-style: italic; + } +} diff --git a/awx/ui/static/js/system-tracking/fact-module-pickers.block.less b/awx/ui/static/js/system-tracking/fact-module-pickers.block.less index 5aa588bd4a..f40d580164 100644 --- a/awx/ui/static/js/system-tracking/fact-module-pickers.block.less +++ b/awx/ui/static/js/system-tracking/fact-module-pickers.block.less @@ -5,65 +5,23 @@ display: flex; margin-bottom: 15px; - &-dateSpacer { - flex: initial; - width: 0px; - } - &-dateContainer { flex: 1; display: flex; - flex-wrap: wrap; + flex-direction: column } - &-date { - flex: 1; - // flex-wrap: wrap; - display: flex; - } - - &-date--right, - &-label--right { - margin-left: 7px; - } - - &-date--left { + &-dateContainer--left { margin-right: 7px; } + &-dateContainer--right { + margin-left: 7px; + } + &-label { - flex: initial; - width: 100%; + flex: 1; font-weight: 700; padding-bottom: 5px; } - - &-dateIcon { - flex: initial; - padding: 6px 12px; - font-size: 14px; - border-radius: 4px 0 0 4px; - border: 1px solid #ccc; - border-right: 0; - background-color: #fff; - } - - &-dateIcon:hover, - &-dateIcon:focus, - &-dateIcon:active { - background-color: #ccc; - } - - &-dateInput { - flex: 1; - border-radius: 0 4px 4px 0; - border: 1px solid #ccc; - padding: 6px 12px; - } - - &-dateInput:focus, - &-dateInput:active { - outline-offset: 0; - outline: 0; - } } diff --git a/awx/ui/static/js/system-tracking/fake-data.js b/awx/ui/static/js/system-tracking/fake-data.js deleted file mode 100644 index 6c76e4ef6e..0000000000 --- a/awx/ui/static/js/system-tracking/fake-data.js +++ /dev/null @@ -1,2514 +0,0 @@ -export default -{ - host1: [ - { - "source": "apt", - "version": "1:4.9.1-0ubuntu1", - "architecture": "amd64", - "name": "libgcc1" - }, - { - "source": "apt", - "version": "2.0.21-stable-1ubuntu1.14.04.1", - "architecture": "amd64", - "name": "libevent-2.0-5" - }, - { - "source": "apt", - "version": "0.11-3ubuntu1.2", - "architecture": "amd64", - "name": "libjson0" - }, - { - "source": "apt", - "version": "6.3-4ubuntu2", - "architecture": "amd64", - "name": "libreadline6" - }, - { - "source": "apt", - "version": "1:1.9.1-1ubuntu0.1", - "architecture": "all", - "name": "git-man" - }, - { - "source": "apt", - "version": "1.6~git20131207+dfsg-1ubuntu1.1", - "architecture": "amd64", - "name": "libgssapi3-heimdal" - }, - { - "source": "apt", - "version": "2.53", - "architecture": "amd64", - "name": "mountall" - }, - { - "source": "apt", - "version": "2.7.2-2", - "architecture": "all", - "name": "python-jinja2" - }, - { - "source": "apt", - "version": "3.4.0-2ubuntu1", - "architecture": "amd64", - "name": "python3.4-minimal" - }, - { - "source": "apt", - "version": "8.6.0+6ubuntu3", - "architecture": "amd64", - "name": "tk" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "gcc-4.8-base" - }, - { - "source": "apt", - "version": "1.0.1-1ubuntu1", - "architecture": "amd64", - "name": "libmpc3" - }, - { - "source": "apt", - "version": "2.3.1-93ubuntu1", - "architecture": "all", - "name": "makedev" - }, - { - "source": "apt", - "version": "1.10-2ubuntu1", - "architecture": "amd64", - "name": "libxcb-present0" - }, - { - "source": "apt", - "version": "3.3-1ubuntu2", - "architecture": "all", - "name": "python-setuptools" - }, - { - "source": "apt", - "version": "1:1.0.7-1ubuntu1", - "architecture": "amd64", - "name": "xauth" - }, - { - "source": "apt", - "version": "5.1.1alpha+20120614-2ubuntu2", - "architecture": "amd64", - "name": "liblzma5" - }, - { - "source": "apt", - "version": "1:0.4.4-1", - "architecture": "amd64", - "name": "libxcomposite1" - }, - { - "source": "apt", - "version": "0.19.6-1", - "architecture": "amd64", - "name": "libfribidi0" - }, - { - "source": "apt", - "version": "1.5.4-1ubuntu1", - "architecture": "all", - "name": "python-pip" - }, - { - "source": "apt", - "version": "2.8.2-1ubuntu1", - "architecture": "amd64", - "name": "mercurial" - }, - { - "source": "apt", - "version": "1.16-8ubuntu1", - "architecture": "amd64", - "name": "libpopt0" - }, - { - "source": "apt", - "version": "2.2.4-15ubuntu1", - "architecture": "amd64", - "name": "libslang2" - }, - { - "source": "apt", - "version": "0.1.4-3ubuntu3.1", - "architecture": "amd64", - "name": "libyaml-0-2" - }, - { - "source": "apt", - "version": "1.12+dfsg-2ubuntu5.1", - "architecture": "amd64", - "name": "libk5crypto3" - }, - { - "source": "apt", - "version": "204-5ubuntu20.7", - "architecture": "amd64", - "name": "libudev1" - }, - { - "source": "apt", - "version": "3.0pl1-124ubuntu2", - "architecture": "amd64", - "name": "cron" - }, - { - "source": "apt", - "version": "0.92.37.3", - "architecture": "all", - "name": "software-properties-common" - }, - { - "source": "apt", - "version": "2:1.4.2-1", - "architecture": "amd64", - "name": "libxrandr2" - }, - { - "source": "apt", - "version": "1.1.8-1ubuntu2", - "architecture": "all", - "name": "libpam-runtime" - }, - { - "source": "apt", - "version": "1:2.24-0ubuntu2", - "architecture": "amd64", - "name": "libcap2" - }, - { - "source": "apt", - "version": "2.7.6-8", - "architecture": "amd64", - "name": "python2.7" - }, - { - "source": "apt", - "version": "5.1.118-1~dfsg-0.1ubuntu3", - "architecture": "amd64", - "name": "libpgm-5.1-0" - }, - { - "source": "apt", - "version": "0.100.0-16", - "architecture": "amd64", - "name": "ureadahead" - }, - { - "source": "apt", - "version": "14.5.0-1chl1~trusty1", - "architecture": "amd64", - "name": "python-zmq" - }, - { - "source": "apt", - "version": "2.7.5-5ubuntu3", - "architecture": "amd64", - "name": "python-minimal" - }, - { - "source": "apt", - "version": "1.3.3-17ubuntu2", - "architecture": "amd64", - "name": "mawk" - }, - { - "source": "apt", - "version": "3.54-1ubuntu1", - "architecture": "all", - "name": "manpages-dev" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "libgcc-4.8-dev" - }, - { - "source": "apt", - "version": "0.20.2-2ubuntu2", - "architecture": "amd64", - "name": "libp11-kit0" - }, - { - "source": "apt", - "version": "1.0.33", - "architecture": "all", - "name": "ssl-cert" - }, - { - "source": "apt", - "version": "1.5.0-1", - "architecture": "amd64", - "name": "libapr1" - }, - { - "source": "apt", - "version": "2:1.1.3-1", - "architecture": "amd64", - "name": "libxinerama1" - }, - { - "source": "apt", - "version": "2:1.3.2-1ubuntu0.0.14.04.1", - "architecture": "amd64", - "name": "libxext6" - }, - { - "source": "apt", - "version": "1.8-5", - "architecture": "amd64", - "name": "tmux" - }, - { - "source": "apt", - "version": "3.3-1ubuntu2", - "architecture": "all", - "name": "python-pkg-resources" - }, - { - "source": "apt", - "version": "5.1.1alpha+20120614-2ubuntu2", - "architecture": "amd64", - "name": "xz-utils" - }, - { - "source": "apt", - "version": "1.2-0ubuntu3", - "architecture": "amd64", - "name": "shared-mime-info" - }, - { - "source": "apt", - "version": "1.14", - "architecture": "all", - "name": "init-system-helpers" - }, - { - "source": "apt", - "version": "2.4.31-1+nmu2ubuntu8", - "architecture": "amd64", - "name": "libldap-2.4-2" - }, - { - "source": "apt", - "version": "1.5.51ubuntu2", - "architecture": "all", - "name": "debconf-i18n" - }, - { - "source": "apt", - "version": "5.18.2-2ubuntu1", - "architecture": "amd64", - "name": "perl" - }, - { - "source": "apt", - "version": "2014i-0ubuntu0.14.04", - "architecture": "all", - "name": "tzdata" - }, - { - "source": "apt", - "version": "3.4-3ubuntu2", - "architecture": "all", - "name": "python-ply" - }, - { - "source": "apt", - "version": "2.10.1-1ubuntu1", - "architecture": "all", - "name": "xkb-data" - }, - { - "source": "apt", - "version": "1.0.1ubuntu2.5", - "architecture": "amd64", - "name": "libapt-pkg4.12" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "gcc-4.8" - }, - { - "source": "apt", - "version": "0.158-0ubuntu5.2", - "architecture": "amd64", - "name": "libelf1" - }, - { - "source": "apt", - "version": "0.70-1", - "architecture": "all", - "name": "libarchive-extract-perl" - }, - { - "source": "apt", - "version": "3.4-3ubuntu0.1", - "architecture": "amd64", - "name": "libtasn1-6" - }, - { - "source": "apt", - "version": "1.27.1-1", - "architecture": "amd64", - "name": "tar" - }, - { - "source": "apt", - "version": "10.1.3-0ubuntu0.4", - "architecture": "amd64", - "name": "libgl1-mesa-glx" - }, - { - "source": "apt", - "version": "1.09-6ubuntu1", - "architecture": "amd64", - "name": "liblockfile-bin" - }, - { - "source": "apt", - "version": "1.8.9p5-1ubuntu1", - "architecture": "amd64", - "name": "sudo" - }, - { - "source": "apt", - "version": "1.6~git20131207+dfsg-1ubuntu1.1", - "architecture": "amd64", - "name": "libwind0-heimdal" - }, - { - "source": "apt", - "version": "1.7-5build2", - "architecture": "amd64", - "name": "libtext-iconv-perl" - }, - { - "source": "apt", - "version": "3.8.7-1ubuntu1", - "architecture": "amd64", - "name": "logrotate" - }, - { - "source": "apt", - "version": "1:3.3.9-1ubuntu2", - "architecture": "amd64", - "name": "libprocps3" - }, - { - "source": "apt", - "version": "7.2ubuntu5.1", - "architecture": "amd64", - "name": "base-files" - }, - { - "source": "apt", - "version": "4:4.8.2-1ubuntu6", - "architecture": "amd64", - "name": "gcc" - }, - { - "source": "apt", - "version": "5.9+20140118-1ubuntu1", - "architecture": "amd64", - "name": "libtinfo5" - }, - { - "source": "apt", - "version": "0~git20131104-1.1", - "architecture": "amd64", - "name": "libtxc-dxtn-s2tc0" - }, - { - "source": "apt", - "version": "9.3.6-0ubuntu0.14.04", - "architecture": "amd64", - "name": "postgresql-client-9.3" - }, - { - "source": "apt", - "version": "1:2.3.2-2ubuntu1", - "architecture": "amd64", - "name": "libaudit1" - }, - { - "source": "apt", - "version": "0.8.8-0ubuntu17", - "architecture": "amd64", - "name": "libplymouth2" - }, - { - "source": "apt", - "version": "2.10+dfsg-1ubuntu2", - "architecture": "all", - "name": "python-pycparser" - }, - { - "source": "apt", - "version": "0.4.2-1build1", - "architecture": "amd64", - "name": "python-greenlet" - }, - { - "source": "apt", - "version": "1.14.0-5ubuntu2", - "architecture": "amd64", - "name": "insserv" - }, - { - "source": "apt", - "version": "2.19-0ubuntu6.3", - "architecture": "amd64", - "name": "multiarch-support" - }, - { - "source": "apt", - "version": "2.0.3-0ubuntu1", - "architecture": "amd64", - "name": "klibc-utils" - }, - { - "source": "apt", - "version": "2.3.1-2", - "architecture": "amd64", - "name": "libxft2" - }, - { - "source": "apt", - "version": "2.7.6-8", - "architecture": "amd64", - "name": "libpython2.7-dev" - }, - { - "source": "apt", - "version": "2.1.0-4ubuntu1", - "architecture": "amd64", - "name": "libexpat1" - }, - { - "source": "apt", - "version": "2.6.1-4build1", - "architecture": "amd64", - "name": "python-crypto" - }, - { - "source": "apt", - "version": "1.1-2", - "architecture": "amd64", - "name": "libxshmfence1" - }, - { - "source": "apt", - "version": "0.92.37.3", - "architecture": "all", - "name": "python-software-properties" - }, - { - "source": "apt", - "version": "4.1+Debian11ubuntu6", - "architecture": "all", - "name": "lsb-base" - }, - { - "source": "apt", - "version": "1.15.5-1ubuntu1", - "architecture": "amd64", - "name": "kbd" - }, - { - "source": "apt", - "version": "2.34-1ubuntu1", - "architecture": "all", - "name": "fonts-dejavu-core" - }, - { - "source": "apt", - "version": "1.6~git20131207+dfsg-1ubuntu1.1", - "architecture": "amd64", - "name": "libroken18-heimdal" - }, - { - "source": "apt", - "version": "3.0.2", - "architecture": "amd64", - "name": "mongodb-org-tools" - }, - { - "source": "apt", - "version": "0.0.9", - "architecture": "all", - "name": "sensible-utils" - }, - { - "source": "apt", - "version": "2:0.1.12-23.3ubuntu1", - "architecture": "amd64", - "name": "libusb-0.1-4" - }, - { - "source": "apt", - "version": "2.7.6-8", - "architecture": "amd64", - "name": "libpython2.7-minimal" - }, - { - "source": "apt", - "version": "5.9+20140118-1ubuntu1", - "architecture": "amd64", - "name": "libncursesw5" - }, - { - "source": "apt", - "version": "1:3.5.10-1", - "architecture": "amd64", - "name": "libxpm4" - }, - { - "source": "apt", - "version": "0.52.15-2ubuntu5", - "architecture": "amd64", - "name": "whiptail" - }, - { - "source": "apt", - "version": "2:1.6.2-1ubuntu2", - "architecture": "amd64", - "name": "libx11-xcb1" - }, - { - "source": "apt", - "version": "3.4.0-0ubuntu2", - "architecture": "amd64", - "name": "libpython3-stdlib" - }, - { - "source": "apt", - "version": "1.05-7build3", - "architecture": "amd64", - "name": "liblocale-gettext-perl" - }, - { - "source": "apt", - "version": "2.4.60-2~ubuntu14.04.1", - "architecture": "amd64", - "name": "libdrm-nouveau2" - }, - { - "source": "apt", - "version": "1.70ubuntu8", - "architecture": "all", - "name": "console-setup" - }, - { - "source": "apt", - "version": "1:5.0.1-1ubuntu1.1", - "architecture": "amd64", - "name": "libxfixes3" - }, - { - "source": "apt", - "version": "2.7.5-5ubuntu3", - "architecture": "amd64", - "name": "python" - }, - { - "source": "apt", - "version": "0.100.2-1", - "architecture": "amd64", - "name": "libdbus-glib-1-2" - }, - { - "source": "apt", - "version": "2.2.52-1", - "architecture": "amd64", - "name": "libacl1" - }, - { - "source": "apt", - "version": "3.2.7-1build1", - "architecture": "amd64", - "name": "python-egenix-mxdatetime" - }, - { - "source": "apt", - "version": "1.1.8-1ubuntu2", - "architecture": "amd64", - "name": "libpam0g" - }, - { - "source": "apt", - "version": "9.3.6-0ubuntu0.14.04", - "architecture": "amd64", - "name": "postgresql-9.3" - }, - { - "source": "apt", - "version": "1.6~git20131207+dfsg-1ubuntu1.1", - "architecture": "amd64", - "name": "libkrb5-26-heimdal" - }, - { - "source": "apt", - "version": "2:1.02.77-6ubuntu2", - "architecture": "amd64", - "name": "dmsetup" - }, - { - "source": "apt", - "version": "2.11.0-0ubuntu4.1", - "architecture": "amd64", - "name": "libfontconfig1" - }, - { - "source": "apt", - "version": "2.40.2-0ubuntu1", - "architecture": "amd64", - "name": "libglib2.0-0" - }, - { - "source": "apt", - "version": "1.1.8-1ubuntu2", - "architecture": "amd64", - "name": "libpam-modules-bin" - }, - { - "source": "apt", - "version": "3.113+nmu3ubuntu3", - "architecture": "all", - "name": "adduser" - }, - { - "source": "apt", - "version": "3.13.0-52.85", - "architecture": "amd64", - "name": "linux-libc-dev" - }, - { - "source": "apt", - "version": "0.82.1ubuntu2.2", - "architecture": "all", - "name": "unattended-upgrades" - }, - { - "source": "apt", - "version": "2:1.0.12-1", - "architecture": "amd64", - "name": "libxaw7" - }, - { - "source": "apt", - "version": "1.1.5-4build1", - "architecture": "amd64", - "name": "libutempter0" - }, - { - "source": "apt", - "version": "1.10.1-1git1build1", - "architecture": "all", - "name": "python-paramiko" - }, - { - "source": "apt", - "version": "2.4.60-2~ubuntu14.04.1", - "architecture": "amd64", - "name": "libdrm-intel1" - }, - { - "source": "apt", - "version": "1:8.31-2ubuntu2", - "architecture": "amd64", - "name": "libpcre3" - }, - { - "source": "apt", - "version": "2.20.1-5.1ubuntu20.2", - "architecture": "amd64", - "name": "libmount1" - }, - { - "source": "apt", - "version": "3.1-20130712-2", - "architecture": "amd64", - "name": "libedit2" - }, - { - "source": "apt", - "version": "1.0.6-5", - "architecture": "amd64", - "name": "libbz2-1.0" - }, - { - "source": "apt", - "version": "2.7.5-5ubuntu3", - "architecture": "amd64", - "name": "libpython-stdlib" - }, - { - "source": "apt", - "version": "4.3-7ubuntu1.5", - "architecture": "amd64", - "name": "bash" - }, - { - "source": "apt", - "version": "3:3.0.0-1chl1~trusty1", - "architecture": "amd64", - "name": "redis-tools" - }, - { - "source": "apt", - "version": "1.0.1f-1ubuntu2.11", - "architecture": "amd64", - "name": "openssl" - }, - { - "source": "apt", - "version": "2.11.0-0ubuntu4.1", - "architecture": "all", - "name": "fontconfig-config" - }, - { - "source": "apt", - "version": "2.0.3-0ubuntu1", - "architecture": "amd64", - "name": "libklibc" - }, - { - "source": "apt", - "version": "2.40.2-0ubuntu1", - "architecture": "all", - "name": "libglib2.0-data" - }, - { - "source": "apt", - "version": "1.4.16-1ubuntu2.1", - "architecture": "amd64", - "name": "gpgv" - }, - { - "source": "apt", - "version": "0.08-2", - "architecture": "all", - "name": "libalgorithm-merge-perl" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "cpp-4.8" - }, - { - "source": "apt", - "version": "0.1.8-1ubuntu1", - "architecture": "all", - "name": "python-distlib" - }, - { - "source": "apt", - "version": "2.19-0ubuntu6.3", - "architecture": "amd64", - "name": "libc-bin" - }, - { - "source": "apt", - "version": "0.04-2build4", - "architecture": "amd64", - "name": "libalgorithm-diff-xs-perl" - }, - { - "source": "apt", - "version": "1.28-1ubuntu2", - "architecture": "amd64", - "name": "libidn11" - }, - { - "source": "apt", - "version": "1:4.2.6.p5+dfsg-3ubuntu2", - "architecture": "amd64", - "name": "ntpdate" - }, - { - "source": "apt", - "version": "3.1~rc1+r3.0.13-12", - "architecture": "amd64", - "name": "libffi6" - }, - { - "source": "apt", - "version": "0.06-7", - "architecture": "all", - "name": "libtext-wrapi18n-perl" - }, - { - "source": "apt", - "version": "2:5.1.3+dfsg-1ubuntu1", - "architecture": "amd64", - "name": "libgmp10" - }, - { - "source": "apt", - "version": "2:1.1.1-1", - "architecture": "amd64", - "name": "libxmuu1" - }, - { - "source": "apt", - "version": "5.1-1", - "architecture": "all", - "name": "libmodule-pluggable-perl" - }, - { - "source": "apt", - "version": "1:2.20.1-5.1ubuntu20.2", - "architecture": "amd64", - "name": "bsdutils" - }, - { - "source": "apt", - "version": "0.10-1", - "architecture": "all", - "name": "liblog-message-simple-perl" - }, - { - "source": "apt", - "version": "1.6~git20131207+dfsg-1ubuntu1.1", - "architecture": "amd64", - "name": "libheimntlm0-heimdal" - }, - { - "source": "apt", - "version": "5.9+20140118-1ubuntu1", - "architecture": "all", - "name": "ncurses-base" - }, - { - "source": "apt", - "version": "1.17.5ubuntu5.3", - "architecture": "amd64", - "name": "dpkg" - }, - { - "source": "apt", - "version": "3:20121221-4ubuntu1.1", - "architecture": "amd64", - "name": "iputils-ping" - }, - { - "source": "apt", - "version": "7.35.0-1ubuntu2.5", - "architecture": "amd64", - "name": "libcurl3-gnutls" - }, - { - "source": "apt", - "version": "2.16-1", - "architecture": "amd64", - "name": "grep" - }, - { - "source": "apt", - "version": "3.52-1", - "architecture": "all", - "name": "iso-codes" - }, - { - "source": "apt", - "version": "5.3.28-3ubuntu3", - "architecture": "amd64", - "name": "libdb5.3" - }, - { - "source": "apt", - "version": "1.4.16-1ubuntu2.1", - "architecture": "amd64", - "name": "gnupg" - }, - { - "source": "apt", - "version": "2.0.1-2build2", - "architecture": "all", - "name": "python-chardet" - }, - { - "source": "apt", - "version": "2.5.2-1ubuntu2.4", - "architecture": "amd64", - "name": "libfreetype6" - }, - { - "source": "apt", - "version": "0.5.7-4ubuntu1", - "architecture": "amd64", - "name": "dash" - }, - { - "source": "apt", - "version": "1.20-3ubuntu2", - "architecture": "amd64", - "name": "libfakeroot" - }, - { - "source": "apt", - "version": "8.6.1-3ubuntu2", - "architecture": "amd64", - "name": "tk8.6" - }, - { - "source": "apt", - "version": "1.5.3-1", - "architecture": "amd64", - "name": "libaprutil1" - }, - { - "source": "apt", - "version": "2.7.6-8", - "architecture": "amd64", - "name": "libpython2.7" - }, - { - "source": "apt", - "version": "1.6~git20131207+dfsg-1ubuntu1.1", - "architecture": "amd64", - "name": "libasn1-8-heimdal" - }, - { - "source": "apt", - "version": "0.2.5-0.1ubuntu2", - "architecture": "all", - "name": "python-colorama" - }, - { - "source": "apt", - "version": "2.1.25.dfsg1-17build1", - "architecture": "amd64", - "name": "libsasl2-modules" - }, - { - "source": "apt", - "version": "1.40.0-1ubuntu0.2", - "architecture": "amd64", - "name": "libgirepository-1.0-1" - }, - { - "source": "apt", - "version": "1.0-1ubuntu1", - "architecture": "amd64", - "name": "python-gevent" - }, - { - "source": "apt", - "version": "1.10-2ubuntu1", - "architecture": "amd64", - "name": "libxcb-shape0" - }, - { - "source": "apt", - "version": "1:4.1.5.1-1ubuntu9", - "architecture": "amd64", - "name": "passwd" - }, - { - "source": "apt", - "version": "0.24.0-1~ubuntu1", - "architecture": "all", - "name": "python-wheel" - }, - { - "source": "apt", - "version": "1.12+dfsg-2ubuntu5.1", - "architecture": "all", - "name": "krb5-locales" - }, - { - "source": "apt", - "version": "1.0.4-3ubuntu2", - "architecture": "amd64", - "name": "libustr-1.0-1" - }, - { - "source": "apt", - "version": "1:1.1.3-1", - "architecture": "amd64", - "name": "libxxf86vm1" - }, - { - "source": "apt", - "version": "0.9.3.5ubuntu1", - "architecture": "all", - "name": "python-apt-common" - }, - { - "source": "apt", - "version": "4.2.4-7ubuntu12", - "architecture": "amd64", - "name": "isc-dhcp-client" - }, - { - "source": "apt", - "version": "1.20-3ubuntu2", - "architecture": "amd64", - "name": "fakeroot" - }, - { - "source": "apt", - "version": "2.1.0-4ubuntu1", - "architecture": "amd64", - "name": "libexpat1-dev" - }, - { - "source": "apt", - "version": "2:7.4.052-1ubuntu3", - "architecture": "amd64", - "name": "vim-tiny" - }, - { - "source": "apt", - "version": "2.20.1-5.1ubuntu20.2", - "architecture": "amd64", - "name": "libuuid1" - }, - { - "source": "apt", - "version": "4.9.1-0ubuntu1", - "architecture": "amd64", - "name": "gcc-4.9-base" - }, - { - "source": "apt", - "version": "1:0.9.8-1build0.14.04.1", - "architecture": "amd64", - "name": "libxrender1" - }, - { - "source": "apt", - "version": "10.1.3-0ubuntu0.4", - "architecture": "amd64", - "name": "libglapi-mesa" - }, - { - "source": "apt", - "version": "4.4.2-7", - "architecture": "amd64", - "name": "findutils" - }, - { - "source": "apt", - "version": "0.42-1", - "architecture": "all", - "name": "libterm-ui-perl" - }, - { - "source": "apt", - "version": "2.4.5-1build5", - "architecture": "amd64", - "name": "python-psycopg2" - }, - { - "source": "apt", - "version": "2.2-1", - "architecture": "all", - "name": "libsemanage-common" - }, - { - "source": "apt", - "version": "2.4.10-1build1", - "architecture": "amd64", - "name": "python-ldap" - }, - { - "source": "apt", - "version": "0.17-1.1", - "architecture": "all", - "name": "liberror-perl" - }, - { - "source": "apt", - "version": "0.04-7build3", - "architecture": "amd64", - "name": "libtext-charwidth-perl" - }, - { - "source": "apt", - "version": "0.18.2-1", - "architecture": "amd64", - "name": "libcloog-isl4" - }, - { - "source": "apt", - "version": "2.88dsf-41ubuntu6", - "architecture": "all", - "name": "sysv-rc" - }, - { - "source": "apt", - "version": "1.12+dfsg-2ubuntu5.1", - "architecture": "amd64", - "name": "libgssapi-krb5-2" - }, - { - "source": "apt", - "version": "3.2.7-1build1", - "architecture": "amd64", - "name": "python-egenix-mxtools" - }, - { - "source": "apt", - "version": "1.5.6-1", - "architecture": "amd64", - "name": "libkeyutils1" - }, - { - "source": "apt", - "version": "1.2.0-2build2", - "architecture": "amd64", - "name": "python3-dbus" - }, - { - "source": "apt", - "version": "1.3.3-1ubuntu0.1", - "architecture": "amd64", - "name": "libserf-1-1" - }, - { - "source": "apt", - "version": "2.11+dfsg-1ubuntu1", - "architecture": "amd64", - "name": "cpio" - }, - { - "source": "apt", - "version": "5.9+20140118-1ubuntu1", - "architecture": "amd64", - "name": "libncurses5" - }, - { - "source": "apt", - "version": "0.9.3.5ubuntu1", - "architecture": "amd64", - "name": "python3-apt" - }, - { - "source": "apt", - "version": "2.20.1-5.1ubuntu20.2", - "architecture": "amd64", - "name": "util-linux" - }, - { - "source": "apt", - "version": "3.0.2", - "architecture": "amd64", - "name": "mongodb-org-shell" - }, - { - "source": "apt", - "version": "2.7.6-8", - "architecture": "amd64", - "name": "python2.7-dev" - }, - { - "source": "apt", - "version": "2.2.1-1ubuntu0.3", - "architecture": "all", - "name": "python-requests" - }, - { - "source": "apt", - "version": "2.7.1-4ubuntu2", - "architecture": "amd64", - "name": "patch" - }, - { - "source": "apt", - "version": "1.42.9-3ubuntu1", - "architecture": "amd64", - "name": "e2fslibs" - }, - { - "source": "apt", - "version": "1.60-25ubuntu2.1", - "architecture": "amd64", - "name": "net-tools" - }, - { - "source": "apt", - "version": "0.9.3.5ubuntu1", - "architecture": "amd64", - "name": "python-apt" - }, - { - "source": "apt", - "version": "1.5.51ubuntu2", - "architecture": "all", - "name": "debconf" - }, - { - "source": "apt", - "version": "1.2.50-1ubuntu2", - "architecture": "amd64", - "name": "libpng12-0" - }, - { - "source": "apt", - "version": "1:2.24-0ubuntu2", - "architecture": "amd64", - "name": "libpam-cap" - }, - { - "source": "apt", - "version": "4.2.2-4ubuntu1", - "architecture": "amd64", - "name": "sed" - }, - { - "source": "apt", - "version": "15-0ubuntu6", - "architecture": "amd64", - "name": "kmod" - }, - { - "source": "apt", - "version": "2.4.0-6", - "architecture": "amd64", - "name": "libmpdec2" - }, - { - "source": "apt", - "version": "4.2.4-7ubuntu12", - "architecture": "amd64", - "name": "isc-dhcp-common" - }, - { - "source": "apt", - "version": "4:4.8.2-1ubuntu6", - "architecture": "amd64", - "name": "g++" - }, - { - "source": "apt", - "version": "1.26+nmu4ubuntu1", - "architecture": "all", - "name": "sgml-base" - }, - { - "source": "apt", - "version": "1.325", - "architecture": "amd64", - "name": "ubuntu-minimal" - }, - { - "source": "apt", - "version": "0.187ubuntu1", - "architecture": "amd64", - "name": "libdebconfclient0" - }, - { - "source": "apt", - "version": "1.7.1-1ubuntu3", - "architecture": "all", - "name": "python-urllib3" - }, - { - "source": "apt", - "version": "1:2.4.47-1ubuntu1", - "architecture": "amd64", - "name": "libattr1" - }, - { - "source": "apt", - "version": "3.54ubuntu1", - "architecture": "all", - "name": "mime-support" - }, - { - "source": "apt", - "version": "0.8.6-2chl1~trusty1", - "architecture": "amd64", - "name": "python-cffi" - }, - { - "source": "apt", - "version": "4.0.5-1chl1~trusty1", - "architecture": "amd64", - "name": "libzmq3" - }, - { - "source": "apt", - "version": "0.37-5", - "architecture": "amd64", - "name": "rlwrap" - }, - { - "source": "apt", - "version": "1:4.1.5.1-1ubuntu9", - "architecture": "amd64", - "name": "login" - }, - { - "source": "apt", - "version": "2.24-5ubuntu3.1", - "architecture": "amd64", - "name": "binutils" - }, - { - "source": "apt", - "version": "11.6ubuntu6", - "architecture": "amd64", - "name": "build-essential" - }, - { - "source": "apt", - "version": "2:1.02.77-6ubuntu2", - "architecture": "amd64", - "name": "libdevmapper1.02.1" - }, - { - "source": "apt", - "version": "1.6~git20131207+dfsg-1ubuntu1.1", - "architecture": "amd64", - "name": "libhcrypto4-heimdal" - }, - { - "source": "apt", - "version": "1.40.0-1ubuntu0.2", - "architecture": "amd64", - "name": "gir1.2-glib-2.0" - }, - { - "source": "apt", - "version": "3.0027+nmu1", - "architecture": "all", - "name": "ucf" - }, - { - "source": "apt", - "version": "4.1+Debian11ubuntu6", - "architecture": "all", - "name": "lsb-release" - }, - { - "source": "apt", - "version": "2.8.2-1ubuntu1", - "architecture": "all", - "name": "mercurial-common" - }, - { - "source": "apt", - "version": "2:1.6.2-1ubuntu2", - "architecture": "all", - "name": "libx11-data" - }, - { - "source": "apt", - "version": "0.7.47.2ubuntu4.1", - "architecture": "amd64", - "name": "ifupdown" - }, - { - "source": "apt", - "version": "1:1.1.4-1ubuntu1", - "architecture": "amd64", - "name": "libxdamage1" - }, - { - "source": "apt", - "version": "0.52.15-2ubuntu5", - "architecture": "amd64", - "name": "libnewt0.52" - }, - { - "source": "apt", - "version": "0.14-2build1", - "architecture": "amd64", - "name": "libfile-fcntllock-perl" - }, - { - "source": "apt", - "version": "5.2", - "architecture": "all", - "name": "netbase" - }, - { - "source": "apt", - "version": "1:2.3.2-2ubuntu1", - "architecture": "all", - "name": "libaudit-common" - }, - { - "source": "apt", - "version": "1:3.4-1ubuntu3", - "architecture": "amd64", - "name": "libllvm3.4" - }, - { - "source": "apt", - "version": "8.6.1-4ubuntu1", - "architecture": "amd64", - "name": "libtcl8.6" - }, - { - "source": "apt", - "version": "0.61-1", - "architecture": "all", - "name": "libpod-latex-perl" - }, - { - "source": "apt", - "version": "2.2-1", - "architecture": "amd64", - "name": "libsepol1" - }, - { - "source": "apt", - "version": "2.2-1", - "architecture": "amd64", - "name": "libsemanage1" - }, - { - "source": "apt", - "version": "1.12.1-0ubuntu4.2", - "architecture": "amd64", - "name": "upstart" - }, - { - "source": "apt", - "version": "3.4.0-2ubuntu1", - "architecture": "amd64", - "name": "python3.4" - }, - { - "source": "apt", - "version": "2.13+git20120306-12.1", - "architecture": "all", - "name": "locales" - }, - { - "source": "apt", - "version": "1.0.1ubuntu2.5", - "architecture": "amd64", - "name": "apt-utils" - }, - { - "source": "apt", - "version": "2.20.1-5.1ubuntu20.2", - "architecture": "amd64", - "name": "mount" - }, - { - "source": "apt", - "version": "0.12.2-1", - "architecture": "amd64", - "name": "libisl10" - }, - { - "source": "apt", - "version": "1.8.8-1ubuntu3.1", - "architecture": "amd64", - "name": "libsvn1" - }, - { - "source": "apt", - "version": "1.69ubuntu1.1", - "architecture": "all", - "name": "resolvconf" - }, - { - "source": "apt", - "version": "2.12.23-12ubuntu2.1", - "architecture": "amd64", - "name": "libgnutls26" - }, - { - "source": "apt", - "version": "3.4.0-2ubuntu1", - "architecture": "amd64", - "name": "libpython3.4-minimal" - }, - { - "source": "apt", - "version": "1:1.1.2-1", - "architecture": "amd64", - "name": "libfontenc1" - }, - { - "source": "apt", - "version": "1:3.3.9-1ubuntu2", - "architecture": "amd64", - "name": "procps" - }, - { - "source": "apt", - "version": "0.10.37-1chl1~trusty1", - "architecture": "amd64", - "name": "nodejs" - }, - { - "source": "apt", - "version": "2.9.1+dfsg1-3ubuntu4.4", - "architecture": "amd64", - "name": "libxml2" - }, - { - "source": "apt", - "version": "2.7.5-5ubuntu3", - "architecture": "amd64", - "name": "libpython-dev" - }, - { - "source": "apt", - "version": "2:1.0.8-2", - "architecture": "amd64", - "name": "libice6" - }, - { - "source": "apt", - "version": "154ubuntu1", - "architecture": "all", - "name": "postgresql-client-common" - }, - { - "source": "apt", - "version": "0.103ubuntu4.2", - "architecture": "all", - "name": "initramfs-tools" - }, - { - "source": "apt", - "version": "2.1.25.dfsg1-17build1", - "architecture": "amd64", - "name": "libsasl2-2" - }, - { - "source": "apt", - "version": "3.81-8.2ubuntu3", - "architecture": "amd64", - "name": "make" - }, - { - "source": "apt", - "version": "3.15ubuntu1", - "architecture": "amd64", - "name": "hostname" - }, - { - "source": "apt", - "version": "8.21-1ubuntu5", - "architecture": "amd64", - "name": "coreutils" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "libstdc++6" - }, - { - "source": "apt", - "version": "3.0.2", - "architecture": "amd64", - "name": "mongodb-org" - }, - { - "source": "apt", - "version": "0.999-3~ubuntu1", - "architecture": "all", - "name": "python-html5lib" - }, - { - "source": "apt", - "version": "3.4.0-2ubuntu1", - "architecture": "amd64", - "name": "libpython3.4-stdlib" - }, - { - "source": "apt", - "version": "3.12.0-2", - "architecture": "amd64", - "name": "iproute2" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "libasan0" - }, - { - "source": "apt", - "version": "5.18.2-2ubuntu1", - "architecture": "all", - "name": "perl-modules" - }, - { - "source": "apt", - "version": "3.54-1ubuntu1", - "architecture": "all", - "name": "manpages" - }, - { - "source": "apt", - "version": "1:1.2.8.dfsg-1ubuntu1", - "architecture": "amd64", - "name": "zlib1g" - }, - { - "source": "apt", - "version": "2:1.1.1-1", - "architecture": "amd64", - "name": "libxmu6" - }, - { - "source": "apt", - "version": "2.19-0ubuntu6.6", - "architecture": "amd64", - "name": "libc6" - }, - { - "source": "apt", - "version": "1.10-2ubuntu1", - "architecture": "amd64", - "name": "libxcb-dri3-0" - }, - { - "source": "apt", - "version": "3.4-1build1", - "architecture": "amd64", - "name": "libtext-soundex-perl" - }, - { - "source": "apt", - "version": "2.7.6-8", - "architecture": "amd64", - "name": "python2.7-minimal" - }, - { - "source": "apt", - "version": "15-0ubuntu6", - "architecture": "all", - "name": "module-init-tools" - }, - { - "source": "apt", - "version": "1.6~git20131207+dfsg-1ubuntu1.1", - "architecture": "amd64", - "name": "libhx509-5-heimdal" - }, - { - "source": "apt", - "version": "0.8-3build1", - "architecture": "amd64", - "name": "python-netifaces" - }, - { - "source": "apt", - "version": "1.6-3ubuntu1", - "architecture": "amd64", - "name": "gzip" - }, - { - "source": "apt", - "version": "2.20.1-5.1ubuntu20.2", - "architecture": "amd64", - "name": "libblkid1" - }, - { - "source": "apt", - "version": "2:7.4.052-1ubuntu3", - "architecture": "amd64", - "name": "vim-common" - }, - { - "source": "apt", - "version": "458-2", - "architecture": "amd64", - "name": "less" - }, - { - "source": "apt", - "version": "8.6.0+6ubuntu3", - "architecture": "amd64", - "name": "tcl" - }, - { - "source": "apt", - "version": "3.0.2", - "architecture": "amd64", - "name": "mongodb-org-mongos" - }, - { - "source": "apt", - "version": "1.8.8-1ubuntu3.1", - "architecture": "amd64", - "name": "subversion" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "libquadmath0" - }, - { - "source": "apt", - "version": "1.0.3-4ubuntu25", - "architecture": "amd64", - "name": "libnih1" - }, - { - "source": "apt", - "version": "1:1.0.8-1", - "architecture": "amd64", - "name": "libxau6" - }, - { - "source": "apt", - "version": "2.12.23-12ubuntu2.1", - "architecture": "amd64", - "name": "libgnutls-openssl27" - }, - { - "source": "apt", - "version": "1.1.8-1ubuntu2", - "architecture": "amd64", - "name": "libpam-modules" - }, - { - "source": "apt", - "version": "297-1ubuntu1", - "architecture": "amd64", - "name": "xterm" - }, - { - "source": "apt", - "version": "1.10-2ubuntu1", - "architecture": "amd64", - "name": "libxcb-sync1" - }, - { - "source": "apt", - "version": "3.4.0-0ubuntu2", - "architecture": "amd64", - "name": "python3-minimal" - }, - { - "source": "apt", - "version": "2.3000-1", - "architecture": "all", - "name": "libtimedate-perl" - }, - { - "source": "apt", - "version": "20141019ubuntu0.14.04.1", - "architecture": "all", - "name": "ca-certificates" - }, - { - "source": "apt", - "version": "1:1.1.4-1", - "architecture": "amd64", - "name": "libxt6" - }, - { - "source": "apt", - "version": "1.0.1ubuntu2.5", - "architecture": "amd64", - "name": "apt" - }, - { - "source": "apt", - "version": "6.3-4ubuntu2", - "architecture": "all", - "name": "readline-common" - }, - { - "source": "apt", - "version": "1.12-0.2ubuntu1", - "architecture": "amd64", - "name": "libgpg-error0" - }, - { - "source": "apt", - "version": "8.6.1-4ubuntu1", - "architecture": "amd64", - "name": "tcl8.6" - }, - { - "source": "apt", - "version": "3.4.0-0ubuntu2", - "architecture": "amd64", - "name": "python3" - }, - { - "source": "apt", - "version": "0.18-1build2", - "architecture": "amd64", - "name": "python-markupsafe" - }, - { - "source": "apt", - "version": "1.0.1ubuntu2.5", - "architecture": "amd64", - "name": "libapt-inst1.5" - }, - { - "source": "apt", - "version": "0.92.37.3", - "architecture": "all", - "name": "python3-software-properties" - }, - { - "source": "apt", - "version": "1:1.21.0-1ubuntu1", - "architecture": "amd64", - "name": "busybox-initramfs" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "g++-4.8" - }, - { - "source": "apt", - "version": "1.1.1-2", - "architecture": "all", - "name": "xbitmaps" - }, - { - "source": "apt", - "version": "8.6.1-3ubuntu2", - "architecture": "amd64", - "name": "libtk8.6" - }, - { - "source": "apt", - "version": "1.0.1f-1ubuntu2.7", - "architecture": "amd64", - "name": "libssl1.0.0" - }, - { - "source": "apt", - "version": "2.88dsf-41ubuntu6", - "architecture": "amd64", - "name": "sysvinit-utils" - }, - { - "source": "apt", - "version": "204-5ubuntu20.7", - "architecture": "amd64", - "name": "udev" - }, - { - "source": "apt", - "version": "0.1.17", - "architecture": "amd64", - "name": "lockfile-progs" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "libatomic1" - }, - { - "source": "apt", - "version": "3.1.0-2ubuntu0.1", - "architecture": "amd64", - "name": "rsync" - }, - { - "source": "apt", - "version": "1:6.6p1-2ubuntu2", - "architecture": "amd64", - "name": "openssh-client" - }, - { - "source": "apt", - "version": "0.24-0ubuntu7", - "architecture": "amd64", - "name": "libcgmanager0" - }, - { - "source": "apt", - "version": "2.2.2-1ubuntu0.1", - "architecture": "amd64", - "name": "libselinux1" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "libitm1" - }, - { - "source": "apt", - "version": "5.9+20140118-1ubuntu1", - "architecture": "amd64", - "name": "ncurses-bin" - }, - { - "source": "apt", - "version": "3.8.2-1ubuntu2", - "architecture": "amd64", - "name": "libsqlite3-0" - }, - { - "source": "apt", - "version": "1.12+dfsg-2ubuntu5.1", - "architecture": "amd64", - "name": "libkrb5-3" - }, - { - "source": "apt", - "version": "7.19.3-0ubuntu3", - "architecture": "amd64", - "name": "python3-pycurl" - }, - { - "source": "apt", - "version": "1.42.9-3ubuntu1", - "architecture": "amd64", - "name": "libss2" - }, - { - "source": "apt", - "version": "1:5.14-2ubuntu3.2", - "architecture": "amd64", - "name": "libmagic1" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "libtsan0" - }, - { - "source": "apt", - "version": "1.42.9-3ubuntu1", - "architecture": "amd64", - "name": "libcomerr2" - }, - { - "source": "apt", - "version": "3.12.0-1ubuntu1", - "architecture": "amd64", - "name": "python3-gi" - }, - { - "source": "apt", - "version": "1.105-7ubuntu1", - "architecture": "amd64", - "name": "netcat-openbsd" - }, - { - "source": "apt", - "version": "1.10-2ubuntu1", - "architecture": "amd64", - "name": "libxcb-glx0" - }, - { - "source": "apt", - "version": "9.3+154ubuntu1", - "architecture": "all", - "name": "postgresql" - }, - { - "source": "apt", - "version": "2.19-0ubuntu6.6", - "architecture": "amd64", - "name": "libc6-dev" - }, - { - "source": "apt", - "version": "2:1.0.10-1", - "architecture": "amd64", - "name": "libxv1" - }, - { - "source": "apt", - "version": "0.1.9-0ubuntu2", - "architecture": "amd64", - "name": "libestr0" - }, - { - "source": "apt", - "version": "0.6.0-2ubuntu1", - "architecture": "amd64", - "name": "libbsd0" - }, - { - "source": "apt", - "version": "2:1.2.2-1", - "architecture": "amd64", - "name": "libxtst6" - }, - { - "source": "apt", - "version": "1.09-6ubuntu1", - "architecture": "amd64", - "name": "liblockfile1" - }, - { - "source": "apt", - "version": "1.10-2ubuntu1", - "architecture": "amd64", - "name": "libxcb1" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "libgomp1" - }, - { - "source": "apt", - "version": "2.4+20121230.gitdf6c518-1", - "architecture": "amd64", - "name": "librtmp0" - }, - { - "source": "apt", - "version": "0.13+nmu2", - "architecture": "all", - "name": "xml-core" - }, - { - "source": "apt", - "version": "1.5.3-2ubuntu4.1", - "architecture": "amd64", - "name": "libgcrypt11" - }, - { - "source": "apt", - "version": "3.10-4ubuntu0.1", - "architecture": "amd64", - "name": "python-yaml" - }, - { - "source": "apt", - "version": "1:1.9.1-1ubuntu0.1", - "architecture": "amd64", - "name": "git" - }, - { - "source": "apt", - "version": "0.13.2-1", - "architecture": "amd64", - "name": "libpciaccess0" - }, - { - "source": "apt", - "version": "7.19.3-0ubuntu3", - "architecture": "amd64", - "name": "python-pycurl" - }, - { - "source": "apt", - "version": "2:1.7.1.901-1ubuntu1.1", - "architecture": "amd64", - "name": "libxi6" - }, - { - "source": "apt", - "version": "3.0.2", - "architecture": "amd64", - "name": "mongodb-org-server" - }, - { - "source": "apt", - "version": "1:7.7+1ubuntu8.1", - "architecture": "all", - "name": "x11-common" - }, - { - "source": "apt", - "version": "154ubuntu1", - "architecture": "all", - "name": "postgresql-common" - }, - { - "source": "apt", - "version": "0.103ubuntu4.2", - "architecture": "amd64", - "name": "initramfs-tools-bin" - }, - { - "source": "apt", - "version": "10.1.3-0ubuntu0.4", - "architecture": "amd64", - "name": "libgl1-mesa-dri" - }, - { - "source": "apt", - "version": "1:2.24-0ubuntu2", - "architecture": "amd64", - "name": "libcap2-bin" - }, - { - "source": "apt", - "version": "9.3.6-0ubuntu0.14.04", - "architecture": "amd64", - "name": "libpq5" - }, - { - "source": "apt", - "version": "4.4", - "architecture": "amd64", - "name": "debianutils" - }, - { - "source": "apt", - "version": "3:3.0.0-1chl1~trusty1", - "architecture": "amd64", - "name": "redis-server" - }, - { - "source": "apt", - "version": "2:1.1.4-1", - "architecture": "amd64", - "name": "libxxf86dga1" - }, - { - "source": "apt", - "version": "1.10-2ubuntu1", - "architecture": "amd64", - "name": "libxcb-dri2-0" - }, - { - "source": "apt", - "version": "2.1.5+deb1+cvs20081104-13.1", - "architecture": "amd64", - "name": "eject" - }, - { - "source": "apt", - "version": "2.88dsf-41ubuntu6", - "architecture": "amd64", - "name": "initscripts" - }, - { - "source": "apt", - "version": "0.8.8-0ubuntu17", - "architecture": "amd64", - "name": "plymouth" - }, - { - "source": "apt", - "version": "0.1.4-3ubuntu3.1", - "architecture": "amd64", - "name": "libyaml-dev" - }, - { - "source": "apt", - "version": "1.19.02-3", - "architecture": "all", - "name": "libalgorithm-diff-perl" - }, - { - "source": "apt", - "version": "1:1.1.1-1", - "architecture": "amd64", - "name": "libxdmcp6" - }, - { - "source": "apt", - "version": "7.7+1", - "architecture": "amd64", - "name": "x11-utils" - }, - { - "source": "apt", - "version": "0.11-3ubuntu1.2", - "architecture": "amd64", - "name": "libjson-c2" - }, - { - "source": "apt", - "version": "1:1.2.2-1", - "architecture": "amd64", - "name": "libxss1" - }, - { - "source": "apt", - "version": "3.1.2-1", - "architecture": "amd64", - "name": "libmpfr4" - }, - { - "source": "apt", - "version": "2.4.60-2~ubuntu14.04.1", - "architecture": "amd64", - "name": "libdrm-radeon1" - }, - { - "source": "apt", - "version": "1:5.14-2ubuntu3.2", - "architecture": "amd64", - "name": "file" - }, - { - "source": "apt", - "version": "7.4.4-1ubuntu2.3", - "architecture": "amd64", - "name": "rsyslog" - }, - { - "source": "apt", - "version": "2:1.2.1-2", - "architecture": "amd64", - "name": "libsm6" - }, - { - "source": "apt", - "version": "2.7.6-8", - "architecture": "amd64", - "name": "libpython2.7-stdlib" - }, - { - "source": "apt", - "version": "1.12+dfsg-2ubuntu5.1", - "architecture": "amd64", - "name": "libkrb5support0" - }, - { - "source": "apt", - "version": "2.7.5-5ubuntu3", - "architecture": "amd64", - "name": "python-dev" - }, - { - "source": "apt", - "version": "1.0.6-5", - "architecture": "amd64", - "name": "bzip2" - }, - { - "source": "apt", - "version": "1.5.2-1ubuntu1", - "architecture": "all", - "name": "python-six" - }, - { - "source": "apt", - "version": "1.0.3-4ubuntu25", - "architecture": "amd64", - "name": "libnih-dbus1" - }, - { - "source": "apt", - "version": "1.8.3-12build1", - "architecture": "amd64", - "name": "libgdbm3" - }, - { - "source": "apt", - "version": "3.6.0-1chl1~trusty1", - "architecture": "amd64", - "name": "libjemalloc1" - }, - { - "source": "apt", - "version": "1.17.5ubuntu5.4", - "architecture": "all", - "name": "dpkg-dev" - }, - { - "source": "apt", - "version": "15-0ubuntu6", - "architecture": "amd64", - "name": "libkmod2" - }, - { - "source": "apt", - "version": "2:1.6.2-1ubuntu2", - "architecture": "amd64", - "name": "libx11-6" - }, - { - "source": "apt", - "version": "1.17.5ubuntu5.4", - "architecture": "all", - "name": "libdpkg-perl" - }, - { - "source": "apt", - "version": "2012.05.19", - "architecture": "all", - "name": "ubuntu-keyring" - }, - { - "source": "apt", - "version": "1:3.3-1", - "architecture": "amd64", - "name": "diffutils" - }, - { - "source": "apt", - "version": "1.42.9-3ubuntu1", - "architecture": "amd64", - "name": "e2fsprogs" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "libstdc++-4.8-dev" - }, - { - "source": "apt", - "version": "5.18.2-2ubuntu1", - "architecture": "amd64", - "name": "perl-base" - }, - { - "source": "apt", - "version": "2.1.25.dfsg1-17build1", - "architecture": "amd64", - "name": "libsasl2-modules-db" - }, - { - "source": "apt", - "version": "2.19-0ubuntu6.6", - "architecture": "amd64", - "name": "libc-dev-bin" - }, - { - "source": "apt", - "version": "4:4.8.2-1ubuntu6", - "architecture": "amd64", - "name": "cpp" - }, - { - "source": "apt", - "version": "1.6.18-0ubuntu4.2", - "architecture": "amd64", - "name": "libdbus-1-3" - }, - { - "source": "apt", - "version": "3.5.33", - "architecture": "amd64", - "name": "base-passwd" - }, - { - "source": "apt", - "version": "1.20140128-1ubuntu8", - "architecture": "all", - "name": "dh-python" - } - ], - host2: - [{ - "source": "apt", - "version": "1:4.9.1-0ubuntu1", - "architecture": "amd64", - "name": "libgcc1" - }, - { - "source": "apt", - "version": "2.0.21-stable-1ubuntu1.14.04.1", - "architecture": "amd64", - "name": "libevent-2.0-5" - }, - { - "source": "apt", - "version": "0.11-3ubuntu1.2", - "architecture": "amd64", - "name": "libjson0" - }, - { - "source": "apt", - "version": "6.3-4ubuntu2", - "architecture": "amd64", - "name": "libreadline6" - }, - { - "source": "apt", - "version": "1:1.9.1-1ubuntu0.1", - "architecture": "all", - "name": "git-man" - }, - { - "source": "apt", - "version": "1.6~git20131207+dfsg-1ubuntu1.1", - "architecture": "amd64", - "name": "libgssapi3-heimdal" - }, - { - "source": "apt", - "version": "2.53", - "architecture": "amd64", - "name": "mountall" - }, - { - "source": "apt", - "version": "2.7.2-2", - "architecture": "all", - "name": "python-jinja2" - }, - { - "source": "apt", - "version": "3.4.0-2ubuntu1", - "architecture": "amd64", - "name": "python3.4-minimal" - }, - { - "source": "apt", - "version": "8.6.0+6ubuntu3", - "architecture": "amd64", - "name": "tk" - }, - { - "source": "apt", - "version": "4.8.2-19ubuntu1", - "architecture": "amd64", - "name": "gcc-4.8-base" - }, - { - "source": "apt", - "version": "1.0.1-1ubuntu1", - "architecture": "amd64", - "name": "libmpc3" - }, - { - "source": "apt", - "version": "2.3.1-93ubuntu1", - "architecture": "all", - "name": "makedev" - }, - { - "source": "apt", - "version": "1.10-2ubuntu1", - "architecture": "amd64", - "name": "libxcb-present0" - }, - { - "source": "apt", - "version": "2.4.52-1", - "architecture": "amd64", - "name": "libdrm2" - }, - { - "source": "apt", - "version": "1.70ubuntu8", - "architecture": "all", - "name": "keyboard-configuration" - }, - { - "source": "apt", - "version": "1.6~git20131207+dfsg-1ubuntu1.1", - "architecture": "amd64", - "name": "libheimbase1-heimdal" - }] -}; diff --git a/awx/ui/static/js/system-tracking/format-results.factory.js b/awx/ui/static/js/system-tracking/format-results.factory.js deleted file mode 100644 index 2789950c43..0000000000 --- a/awx/ui/static/js/system-tracking/format-results.factory.js +++ /dev/null @@ -1,13 +0,0 @@ -export default - function() { - return function formatResults(compareKey, displayKey, results) { - return results.reduce(function(arr, value) { - var obj = - { keyName: value[compareKey], - value1: value.position === 0 ? value[displayKey] : 'absent', - value2: value.position === 1 ? value[displayKey] : 'absent' - }; - return arr.concat(obj); - }, []); - }; - } diff --git a/awx/ui/static/js/system-tracking/main.js b/awx/ui/static/js/system-tracking/main.js index df92fd86f4..0361ab502c 100644 --- a/awx/ui/static/js/system-tracking/main.js +++ b/awx/ui/static/js/system-tracking/main.js @@ -1,21 +1,21 @@ import route from './system-tracking.route'; -import singleHostDataService from './single-host-data.service'; -import factDataServiceFactory from './fact-data-service.factory'; +import factScanDataService from './data-services/fact-scan-data.service'; +import getDataForComparison from './data-services/get-data-for-comparison.factory'; import controller from './system-tracking.controller'; import stringOrDateFilter from './string-or-date.filter'; -import xorObjects from './xor-objects.factory'; -import formatResults from './format-results.factory'; -import compareHosts from './compare-hosts.factory'; +import shared from 'tower/shared/main'; +import utilities from 'tower/shared/Utilities'; +import datePicker from './date-picker/main'; export default angular.module('systemTracking', - [ 'angularMoment' + [ 'angularMoment', + utilities.name, + shared.name, + datePicker.name ]) - .factory('factDataServiceFactory', factDataServiceFactory) - .service('singleHostDataService', singleHostDataService) - .factory('xorObjects', xorObjects) - .factory('formatResults', formatResults) - .factory('compareHosts', compareHosts) + .service('factScanDataService', factScanDataService) + .factory('getDataForComparison', getDataForComparison) .filter('stringOrDate', stringOrDateFilter) .controller('systemTracking', controller) .config(['$routeProvider', function($routeProvider) { @@ -23,6 +23,3 @@ export default delete route.route; $routeProvider.when(url, route); }]); - - - diff --git a/awx/ui/static/js/system-tracking/nested-facts.md b/awx/ui/static/js/system-tracking/nested-facts.md deleted file mode 100644 index e74b38bf3d..0000000000 --- a/awx/ui/static/js/system-tracking/nested-facts.md +++ /dev/null @@ -1,168 +0,0 @@ -## How I will do it - -1. Find all facts from results -2. Filter out all "same facts" -3. Transform for display - -### Finding facts from results - -Iterate over fact collection. Check if a thing is a fact or not (it is a fact when all of its key's values are comparable (not an object or array). If it's a fact, then transform it to an object that contains the nested key and value from each candidate. If it's not a fact, then recurse passing in the parent keys & value until we find a fact. - -To accomplish this we'll reduce over the values in the fact collection to create a new array. For each key, we'll check the type of its value. If it's an object or an array, we'll append the key to an array of parent keys and pass that and the value into a recursive call. If it's not an object or array, we'll record the parent key path as an array & both left & right values. We'll return the accumulator array with that object concatenated to it. - -End result example (FactComparison): - -[{ keyPath: ['sda', 'partitions', 'sda1'], - key: 'sectors', - leftValue: '39843840', - rightValue: '13254121' - }, - { keyPath: ['sda', partitions', 'sda1'], - key: 'model', - leftValue: 'VMware Virtual S", - rightValue: '' - }]; - -### Filtering out "same" facts - -This needs to look at all of the facts by parent key and remove any of those that have one or more differences. This will leave plenty of context for the user to determine exactly what is different here. For example, given the facts: - -#### Left Host - -```json -{ "ansible_mounts": - [{ - "device": "/dev/sda1", - "fstype": "ext4", - "mount": "/", - "options": "rw,errors=remount-ro", - "size_available": 15032406016, - "size_total": 20079898624 - }] -} -``` - -#### Right Host - -```json -{ "ansible_mounts": - [{ - "device": "/dev/sda1", - "fstype": "btrfs", - "mount": "/", - "options": "rw,errors=remount-ro", - "size_available": 153985231054, - "size_total": 53056978564321 - }] -} -``` - -If all the user could see was that the `fstype` fields were different, this would leave them wondering "what device is that on? where did that come from?" We are solving this problem by displaying all sibling properties of a fact regardless of whether they are different when at least one of those properties contains a difference. - -Therefore, to compare facts we need to first group them by their keys. Once we do that, we'll have a structure like: - -```json -{ 'sda.partitions.sda1': - [{ keyPath: ['sda', 'partitions', 'sda1'], - key: 'sectors', - leftValue: '39843840', - rightValue: '13254121' - }, - { keyPath: ['sda', partitions', 'sda1'], - key: 'model', - leftValue: 'VMware Virtual S", - rightValue: '' - }] -} -``` - -The simplest way to handle this would be to map over each key in this grouped object and return a filtered array of only objects with differences. Then we could iterate over the resulting object and filter out any keys whose value is an empty array, leaving us with only the keys that contain at least a single difference. Finally, we iterate over the original collection keeping only those values whose `keyPath` is in the previous collection of keys and return that result. - -### Transforming for display - -Given fact comparisons of: - -[{ keyPath: ['ansible_devices', 'sda'], - key: 'host', - leftValue: 'SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01)', - rightValue: '' - - }, - { keyPath: ['ansible_devices', 'sda'], - key: 'model', - leftValue: 'VMWare Virtual S', - rightValue: 'APPLE SSD SM256C' - }, - { keyPath: ['ansible_devices', 'sda', 'partitions', 'sda1'], - key: 'sectors', - leftValue: '39843840', - rightValue: '13254121' - }, - { keyPath: ['ansible_devices', 'sda', partitions', 'sda1'], - key: 'sectorsize', - leftValue: '512', - rightValue: '512' - }, - { keyPath: ['ansible_mounts', '0'], - key: 'device', - leftValue: '/dev/sda5', - rightValue: '/dev/sda1' - }, - { keyPath: ['ansible_mounts', '0'], - key: 'fstype', - leftValue: 'ext4', - rightValue: 'btrfs' - }, - { keyPath: ['ansible_mounts', '1'], - key: 'device', - leftValue: 'absent', - rightValue: '/dev/sda5' - }]; - -We need to transform that to something like: - -[{ keyPath: ['ansible_devices', 'sda'], - displayKeyPath: 'ansible_devices.sda', - nestingLevel: 1, - facts: - [{ keyPath: ['ansible_devices', 'sda'], - key: 'host', - value1: 'SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01)', - value2: '' - - }, - { keyPath: ['ansible_devices', 'sda'], - keyName: 'model', - value1: 'VMWare Virtual S', - value2: 'APPLE SSD SM256C' - }], - }, - { keyPath: ['ansible_devices', 'sda', 'partitions', 'sda1'], - displayKeyPath: 'partitions.sda1', - nestingLevel: 2, - facts: - // ... - }, - { keyPath: ['ansible_mounts'], - displayKeyPath: 'ansible_mounts', - nestingLevel: 1, - isArray: true, - facts: - [ [{ keyPath: ['ansible_mounts', '0'], - key: 'device', - leftValue: '/dev/sda5', - rightValue: '/dev/sda1' - }, - { keyPath: ['ansible_mounts', '0'], - key: 'fstype', - leftValue: 'ext4', - rightValue: 'btrfs' - }], - [{ keyPath: ['ansible_mounts', '1'], - key: 'device', - leftValue: 'absent', - rightValue: '/dev/sda5' - }] - ] - }] -``` diff --git a/awx/ui/static/js/system-tracking/search-date-range.js b/awx/ui/static/js/system-tracking/search-date-range.js new file mode 100644 index 0000000000..ed2a36e0e4 --- /dev/null +++ b/awx/ui/static/js/system-tracking/search-date-range.js @@ -0,0 +1,6 @@ +export function searchDateRange(date) { + return { + from: moment(date).startOf('day'), + to: moment(date).endOf('day') + }; +} diff --git a/awx/ui/static/js/system-tracking/string-or-date.filter.js b/awx/ui/static/js/system-tracking/string-or-date.filter.js index 275994a769..487af2190b 100644 --- a/awx/ui/static/js/system-tracking/string-or-date.filter.js +++ b/awx/ui/static/js/system-tracking/string-or-date.filter.js @@ -9,4 +9,4 @@ export default } }; } - ] + ]; diff --git a/awx/ui/static/js/system-tracking/system-tracking.controller.js b/awx/ui/static/js/system-tracking/system-tracking.controller.js index 817e5a4551..9cb44062ef 100644 --- a/awx/ui/static/js/system-tracking/system-tracking.controller.js +++ b/awx/ui/static/js/system-tracking/system-tracking.controller.js @@ -1,37 +1,41 @@ -function controller($rootScope, $scope, $routeParams, $location, $q, factDataServiceFactory, moment) { +import {searchDateRange} from './search-date-range'; +import {compareFacts} from './compare-facts'; - var service; - var inventoryId = $routeParams.id; +function controller($rootScope, + $scope, + $routeParams, + $location, + $q, + initialFactData, + getDataForComparison, + waitIndicator, + + _) { + // var inventoryId = $routeParams.id; var hostIds = $routeParams.hosts.split(','); - var moduleParam = $location.search().module || 'packages'; - var configReadyOff = - $rootScope.$on('ConfigReady', function() { - $(".date").systemTrackingDP({ - autoclose: true - }); - configReadyOff(); - }); - - $scope.leftFilterValue = hostIds[0]; - $scope.rightFilterValue = hostIds[1]; - - $scope.factModulePickersLabelLeft = "Fact collection date for host " + $scope.leftFilterValue; - $scope.factModulePickersLabelRight = "Fact collection date for host " + $scope.rightFilterValue; + $scope.factModulePickersLabelLeft = "Compare facts collected on"; + $scope.factModulePickersLabelRight = "To facts collected on"; $scope.modules = [{ name: 'packages', displayName: 'Packages', + compareKey: ['release', 'version'], + nameKey: 'name', isActive: true, displayType: 'flat' }, { name: 'services', + compareKey: ['state', 'source'], + nameKey: 'name', displayName: 'Services', isActive: false, displayType: 'flat' }, { name: 'files', displayName: 'Files', + nameKey: 'path', + compareKey: ['size', 'mode', 'md5', 'mtime', 'gid', 'uid'], isActive: false, displayType: 'flat' }, @@ -45,25 +49,57 @@ function controller($rootScope, $scope, $routeParams, $location, $q, factDataSer // Use this to determine how to orchestrate the services var viewType = hostIds.length > 1 ? 'multiHost' : 'singleHost'; - if (viewType === 'singleHost') { - var startDate = moment(); - $scope.leftFilterValue = startDate; - $scope.rightFilterValue = startDate.clone().subtract(1, 'days'); + var searchConfig = + { leftDate: initialFactData.leftDate, + rightDate: initialFactData.rightDate + }; + + $scope.leftDate = initialFactData.leftDate.from; + $scope.rightDate = initialFactData.rightDate.from; + + function setHeaderValues(viewType) { + if (viewType === 'singleHost') { + $scope.comparisonLeftHeader = $scope.leftDate; + $scope.comparisonRightHeader = $scope.rightDate; + } else { + $scope.comparisonLeftHeader = hostIds[0]; + $scope.comparisonRightHeader = hostIds[1]; + } } - service = factDataServiceFactory(viewType); + function reloadData(params, initialData) { + searchConfig = _.merge({}, searchConfig, params); - function reloadData(activeModule) { - activeModule.then(function(module) { - $scope.factData = - service.get(inventoryId, - module.name, - $scope.leftFilterValue, - $scope.rightFilterValue); - }); + var factData = initialData; + var leftDate = searchConfig.leftDate; + var rightDate = searchConfig.rightDate; + var activeModule = searchConfig.module; + + if (!factData) { + factData = getDataForComparison( + hostIds, + activeModule.name, + leftDate, + rightDate); + } + + waitIndicator('start'); + + _(factData) + .thenAll(_.partial(compareFacts, activeModule)) + .then(function(info) { + + $scope.factData = info; + + setHeaderValues(viewType); + + }).finally(function() { + waitIndicator('stop'); + }) + .value(); } - $scope.setActiveModule = function(newModuleName) { + $scope.setActiveModule = function(newModuleName, initialData) { var newModule = _.find($scope.modules, function(module) { return module.name === newModuleName; @@ -74,14 +110,40 @@ function controller($rootScope, $scope, $routeParams, $location, $q, factDataSer }); newModule.isActive = true; + + $location.replace(); $location.search('module', newModuleName); - reloadData($q.when(newModule)); - + reloadData( + { module: newModule + }, initialData); }; + function dateWatcher(dateProperty) { + return function(newValue, oldValue) { + // passing in `true` for the 3rd param to $watch should make + // angular use `angular.equals` for comparing these values; + // the watcher should not fire, but it still is. Therefore, + // using `moment.isSame` to keep from reloading data when the + // dates did not actually change + if (newValue.isSame(oldValue)) { + return; + } - $scope.setActiveModule(moduleParam); + var newDate = searchDateRange(newValue); + + var params = {}; + params[dateProperty] = newDate; + + reloadData(params); + }; + } + + $scope.$watch('leftDate', dateWatcher('leftDate'), true); + + $scope.$watch('rightDate', dateWatcher('rightDate'), true); + + $scope.setActiveModule(initialFactData.moduleName, initialFactData); } export default @@ -90,7 +152,9 @@ export default '$routeParams', '$location', '$q', - 'factDataServiceFactory', - 'moment', + 'factScanData', + 'getDataForComparison', + 'Wait', + 'lodashAsPromised', controller ]; diff --git a/awx/ui/static/js/system-tracking/system-tracking.partial.html b/awx/ui/static/js/system-tracking/system-tracking.partial.html index bb51f07ac6..a05967ef5d 100644 --- a/awx/ui/static/js/system-tracking/system-tracking.partial.html +++ b/awx/ui/static/js/system-tracking/system-tracking.partial.html @@ -1,21 +1,11 @@
-
-
-
+
{{ factModulePickersLabelLeft }} -
- - -
+
-
- - {{ factModulePickersLabelRight }} - -
- - -
+
+ {{ factModulePickersLabelRight }} +
@@ -33,19 +23,57 @@ - - - - - - - - - - - - - - - -
{{factData.leftFilterValue|stringOrDate:'L'}}{{factData.rightFilterValue|stringOrDate:'L'}}
{{fact.keyName}}{{fact.value1}}{{fact.value2}}
+
+

+ There were no facts collected for that module in the selected date range. Please pick a different range or module and try again. +

+
+
+
+

{{comparisonLeftHeader|stringOrDate:'L'}}

+

{{comparisonRightHeader|stringOrDate:'L'}}

+
+
+
+

+ {{group.displayKeyPath}} +

+

+ {{group.displayKeyPath}} +

+

+ {{group.displayKeyPath}} +

+
+ {{group.displayKeyPath}} +
+
+
+
+
+

+ {{fact.keyName}} +

+

+ {{fact.value1}} +

+

+ {{fact.value2}} +

+
+
+
+

+ {{fact.keyName}} +

+

+ {{fact.value1}} +

+

+ {{fact.value2}} +

+
+
+
+ +
diff --git a/awx/ui/static/js/system-tracking/system-tracking.route.js b/awx/ui/static/js/system-tracking/system-tracking.route.js index 02f231fc84..cb3eb0f5a6 100644 --- a/awx/ui/static/js/system-tracking/system-tracking.route.js +++ b/awx/ui/static/js/system-tracking/system-tracking.route.js @@ -1,5 +1,88 @@ +import {searchDateRange} from './search-date-range'; + export default { - route: '/inventories/:id/system-tracking/:hosts', + name: 'systemTracking', + route: '/inventories/:inventory/system-tracking/:hosts', controller: 'systemTracking', - templateUrl: '/static/js/system-tracking/system-tracking.partial.html' + templateUrl: '/static/js/system-tracking/system-tracking.partial.html', + resolve: { + factScanData: + [ 'getDataForComparison', + 'lodashAsPromised', + '$route', + '$location', + function(getDataForComparison, _, $route, $location) { + var hostIds = $route.current.params.hosts.split(','); + var moduleParam = $location.search().module || 'packages'; + + var leftDate = searchDateRange('2015-05-26'); + var rightDate = searchDateRange('2015-05-26'); + + if (hostIds.length === 1) { + hostIds = hostIds.concat(hostIds[0]); + } + + var data = + getDataForComparison(hostIds, moduleParam, leftDate, rightDate). + thenThru(function(factData) { + factData.leftDate = leftDate; + factData.rightDate = rightDate; + factData.moduleName = moduleParam; + return factData; + }) + .value(); + + return data; + + } + ], + inventory: + [ '$route', + '$q', + 'Rest', + 'GetBasePath', + function($route, $q, rest, getBasePath) { + if ($route.current.params.inventory) { + return $q.when(true); + } + + var inventoryId = $route.current.params.inventory; + + var url = getBasePath('inventory') + inventoryId + '/'; + rest.setUrl(url); + return rest.get() + .then(function(data) { + return data.data; + }); + } + ], + filters: + [ '$route', + '$q', + 'Rest', + 'GetBasePath', + function($route, $q, rest, getBasePath) { + if ($route.current.params.hosts) { + return $q.when(true); + } + + var hostIds = $route.current.params.filters.split(','); + + var hosts = + hostIds.map(function(hostId) { + var url = getBasePath('hosts') + + hostId + '/'; + + rest.setUrl(url); + return rest.get() + .then(function(data) { + return data.data; + }); + }); + + return $q.all(hosts); + } + + ] + } }; diff --git a/awx/ui/static/js/system-tracking/xor-objects.factory.js b/awx/ui/static/js/system-tracking/xor-objects.factory.js deleted file mode 100644 index a56d169abc..0000000000 --- a/awx/ui/static/js/system-tracking/xor-objects.factory.js +++ /dev/null @@ -1,28 +0,0 @@ -export default - function() { - return function xorObjects(key, thing1, thing2) { - var values1 = _.pluck(thing1, key); - var values2 = _.pluck(thing2, key); - - var valuesDiff = _.xor(values1, values2); - - return valuesDiff.reduce(function(arr, value) { - var searcher = {}; - searcher[key] = value; - - var valuePosition1 = _.find(thing1, searcher); - - if (valuePosition1) { - valuePosition1.position = 0; - } - - var valuePosition2 = _.find(thing2, searcher); - - if (valuePosition2) { - valuePosition2.position = 1; - } - - return _.compact(arr.concat(valuePosition1).concat(valuePosition2)); - }, []); - }; - } diff --git a/awx/ui/static/less/text-label.less b/awx/ui/static/less/text-label.less index cb3c6898a9..bb6bbd8242 100644 --- a/awx/ui/static/less/text-label.less +++ b/awx/ui/static/less/text-label.less @@ -1,19 +1,4 @@ -.include-text-label(@background-color; @color; @content) { - display: inline-block; - content: @content; - - border-radius: 3px; - background-color: @background-color; - color: @color; - text-transform: uppercase; - font-size: .7em; - font-weight: bold; - font-style: normal; - margin-left: 0.5em; - padding: 0.35em; - padding-bottom: 0.2em; - line-height: 1.1; -} +@import "../js/shared/text-label.less"; .host-disabled-label { &:after { diff --git a/awx/ui/tests/unit/system-tracking/single-host-data.service-test.js b/awx/ui/tests/unit/system-tracking/single-host-data.service-test.js index 322eaab9e3..7e9f88c626 100644 --- a/awx/ui/tests/unit/system-tracking/single-host-data.service-test.js +++ b/awx/ui/tests/unit/system-tracking/single-host-data.service-test.js @@ -2,7 +2,7 @@ import systemTracking from 'tower/system-tracking/main'; import {describeModule} from '../describe-module'; describeModule(systemTracking.name) - .testService('singleHostDataService', function(test, restStub) { + .testService('factScanDataService', function(test, restStub) { var service;