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 @@
+
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;