mirror of
https://github.com/ansible/awx.git
synced 2026-05-07 17:37:37 -02:30
[system_tracking] Support multiple versions of packages with same name
This commit is contained in:
@@ -36,15 +36,18 @@ function slotFactValues(basisPosition, basisValue, comparatorValue) {
|
|||||||
* @property {string} nameKey - The name of the key that is used to locate facts from basisFacts in comparatorFacts
|
* @property {string} nameKey - The name of the key that is used to locate facts from basisFacts in comparatorFacts
|
||||||
* @property {string|string[]} compareKey - A single key or list of keys to compare in the two fact collections
|
* @property {string|string[]} compareKey - A single key or list of keys to compare in the two fact collections
|
||||||
* @property {Tower.SystemTracking.KeyNameMap} keyNameMap - An object mapping existing key names to new key names for display
|
* @property {Tower.SystemTracking.KeyNameMap} keyNameMap - An object mapping existing key names to new key names for display
|
||||||
* @prperty {Tower.SystemTracking.FactTemplate} factTemplate - An optional template used as the string for comparing and displaying a fact
|
* @property {Tower.SystemTracking.FactTemplate} factTemplate - An optional template used as the string for comparing and displaying a fact
|
||||||
|
* @property {boolean} supportsValueArray - Indicates that the module we're rendering supports values in an array of strings rather than just a string; iterim measure to make sure modules with multiple facts matching nameKey don't get evaluated because we won't know how to dipslay them
|
||||||
*
|
*
|
||||||
* @typedef {(string|boolean)} Tower.SystemTracking.KeyNameMapValue - The name you want to use for the display of a key or "true" to indicate a key should be displayed without changing its name (all keys are hidden by default)
|
* @typedef {(string|boolean)} Tower.SystemTracking.KeyNameMapValue - The name you want to use for the display of a key or "true" to indicate a key should be displayed without changing its name (all keys are hidden by default)
|
||||||
*
|
*
|
||||||
* @typedef {Object.<string, Tower.SystemTracking.KeyNameMapValue>} Tower.SystemTracking.KeyNameMap - An object whose keys are the names of keys that exist in a fact and whose values control how that key is displayed
|
* @typedef {Object.<string, Tower.SystemTracking.KeyNameMapValue>} Tower.SystemTracking.KeyNameMap - An object whose keys are the names of keys that exist in a fact and whose values control how that key is displayed
|
||||||
*
|
*
|
||||||
* @typedef {{displayKeyPath: string, nestingLevel: number, facts: Array.<Tower.SystemTracking.FactComparisonResult>}} Tower.SystemTracking.FactComparisonDescription
|
* @typedef {{displayKeyPath: string, nestingLevel: number, facts: Array.<Tower.SystemTracking.FactComparisonResult>}} Tower.SystemTracking.FactComparisonDescriptor
|
||||||
*
|
*
|
||||||
* @typedef {{keyName: string, value1, value2, isDivergent: bool}} Tower.SystemTracking.FactComparisonResult
|
* @typedef {{keyName: string, value1: Tower.SystemTracking.FactComparisonValue, value2: Tower.SystemTracking.FactComparisonValue, isDivergent: boolean}} Tower.SystemTracking.FactComparisonResult
|
||||||
|
*
|
||||||
|
* @typedef {(string|string[])} Tower.SystemTracking.FactComparisonValue
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export default
|
export default
|
||||||
@@ -58,79 +61,124 @@ export default
|
|||||||
|
|
||||||
|
|
||||||
return basisFacts.facts.reduce(function(arr, basisFact) {
|
return basisFacts.facts.reduce(function(arr, basisFact) {
|
||||||
|
|
||||||
|
// First, make sure this fact hasn't already been processed, if it
|
||||||
|
// has don't process it again
|
||||||
|
//
|
||||||
|
if (_.any(arr, { displayKeyPath: basisFact[nameKey] })) {
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
var searcher = {};
|
var searcher = {};
|
||||||
searcher[nameKey] = basisFact[nameKey];
|
searcher[nameKey] = basisFact[nameKey];
|
||||||
|
|
||||||
var matchingFact = _.where(comparatorFacts.facts, searcher);
|
var containsValueArray = false;
|
||||||
|
var matchingFacts = _.where(comparatorFacts.facts, searcher);
|
||||||
|
var comparisonResults;
|
||||||
var diffs;
|
var diffs;
|
||||||
|
|
||||||
// Perform comparison and get back comparisonResults; like:
|
// If this fact exists more than once in `basisFacts`, then
|
||||||
// { 'value':
|
// we need to process it differently
|
||||||
// { leftValue: 'blah',
|
|
||||||
// rightValue: 'doo'
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
//
|
//
|
||||||
var comparisonResults =
|
var otherBasisFacts = _.where(basisFacts.facts, searcher);
|
||||||
_.reduce(compareKeys, function(result, compareKey) {
|
if (renderOptions.supportsValueArray && otherBasisFacts.length > 1) {
|
||||||
|
comparisonResults = processFactsForValueArray(basisFacts.position, otherBasisFacts, matchingFacts);
|
||||||
|
} else {
|
||||||
|
comparisonResults = processFactsForSingleValue(basisFact, matchingFacts[0] || {});
|
||||||
|
}
|
||||||
|
|
||||||
var comparatorFact = matchingFact[0] || {};
|
function processFactsForValueArray(basisPosition, basisFacts, comparatorFacts) {
|
||||||
var isNestedDisplay = false;
|
|
||||||
|
|
||||||
var slottedValues = slotFactValues(basisFacts.position,
|
function renderFactValues(facts) {
|
||||||
basisFact[compareKey],
|
return facts.map(function(fact) {
|
||||||
comparatorFact[compareKey]);
|
return factTemplate.render(fact);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (_.isUndefined(slottedValues.left) && _.isUndefined(slottedValues.right)) {
|
var basisFactValues = renderFactValues(basisFacts);
|
||||||
return result;
|
var comparatorFactValues = renderFactValues(comparatorFacts);
|
||||||
}
|
|
||||||
|
|
||||||
var template = factTemplate;
|
var slottedValues = slotFactValues(basisPosition, basisFactValues, comparatorFactValues);
|
||||||
|
|
||||||
if (_.isObject(template) && template.hasOwnProperty(compareKey)) {
|
if (!_.isEqual(slottedValues.left, slottedValues.right)) {
|
||||||
template = template[compareKey];
|
slottedValues.isDivergent = true;
|
||||||
|
containsValueArray = true;
|
||||||
|
} else {
|
||||||
|
slottedValues.isDivergent = false;
|
||||||
|
}
|
||||||
|
|
||||||
// 'true' means render the key without formatting
|
return slottedValues;
|
||||||
if (template === true) {
|
}
|
||||||
|
|
||||||
|
function processFactsForSingleValue(basisFact, comparatorFact) {
|
||||||
|
// Perform comparison and get back comparisonResults; like:
|
||||||
|
// { 'value':
|
||||||
|
// { leftValue: 'blah',
|
||||||
|
// rightValue: 'doo'
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
return _.reduce(compareKeys, function(result, compareKey) {
|
||||||
|
|
||||||
|
var isNestedDisplay = false;
|
||||||
|
var basisFactValue = basisFact[compareKey];
|
||||||
|
var comparatorFactValue = comparatorFact[compareKey];
|
||||||
|
var slottedValues;
|
||||||
|
|
||||||
|
if (_.isUndefined(basisFactValue) && _.isUndefined(comparatorFactValue)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var template = factTemplate;
|
||||||
|
|
||||||
|
if (_.isObject(template) && template.hasOwnProperty(compareKey)) {
|
||||||
|
template = template[compareKey];
|
||||||
|
|
||||||
|
// 'true' means render the key without formatting
|
||||||
|
if (template === true) {
|
||||||
|
template =
|
||||||
|
{ render: function(fact) { return fact[compareKey]; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
isNestedDisplay = true;
|
||||||
|
} else if (typeof template.hasTemplate === 'function' && !template.hasTemplate()) {
|
||||||
template =
|
template =
|
||||||
{ render: function(fact) { return fact[compareKey]; }
|
{ render: function(fact) { return fact[compareKey]; }
|
||||||
};
|
};
|
||||||
|
isNestedDisplay = true;
|
||||||
|
} else if (typeof factTemplate.render === 'function') {
|
||||||
|
template = factTemplate;
|
||||||
|
} else if (!template.hasOwnProperty(compareKey)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (!renderOptions.supportsValueArray) {
|
||||||
|
// comparatorFact = comparatorFact[0];
|
||||||
|
// }
|
||||||
|
|
||||||
|
basisFactValue = template.render(basisFact);
|
||||||
|
comparatorFactValue = template.render(comparatorFact);
|
||||||
|
|
||||||
|
slottedValues = slotFactValues(basisFacts.position,
|
||||||
|
basisFactValue,
|
||||||
|
comparatorFactValue);
|
||||||
|
|
||||||
|
if (slottedValues.left !== slottedValues.right) {
|
||||||
|
slottedValues.isDivergent = true;
|
||||||
|
} else {
|
||||||
|
slottedValues.isDivergent = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNestedDisplay) {
|
||||||
|
result[compareKey] = slottedValues;
|
||||||
|
} else {
|
||||||
|
result = slottedValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
isNestedDisplay = true;
|
|
||||||
} else if (typeof template.hasTemplate === 'function' && !template.hasTemplate()) {
|
|
||||||
template =
|
|
||||||
{ render: function(fact) { return fact[compareKey]; }
|
|
||||||
};
|
|
||||||
isNestedDisplay = true;
|
|
||||||
} else if (typeof factTemplate.render === 'function') {
|
|
||||||
template = factTemplate;
|
|
||||||
} else if (!template.hasOwnProperty(compareKey)) {
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}, {});
|
||||||
|
}
|
||||||
if (basisFacts.position === 'left') {
|
|
||||||
slottedValues.left = template.render(basisFact);
|
|
||||||
slottedValues.right = template.render(comparatorFact);
|
|
||||||
} else {
|
|
||||||
slottedValues.left = template.render(comparatorFact);
|
|
||||||
slottedValues.right = template.render(basisFact);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slottedValues.left !== slottedValues.right) {
|
|
||||||
slottedValues.isDivergent = true;
|
|
||||||
} else {
|
|
||||||
slottedValues.isDivergent = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNestedDisplay) {
|
|
||||||
result[compareKey] = slottedValues;
|
|
||||||
} else {
|
|
||||||
result = slottedValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
var hasDiffs =
|
var hasDiffs =
|
||||||
_.any(comparisonResults, { isDivergent: true }) ||
|
_.any(comparisonResults, { isDivergent: true }) ||
|
||||||
@@ -167,6 +215,7 @@ export default
|
|||||||
var descriptor =
|
var descriptor =
|
||||||
{ displayKeyPath: basisFact[nameKey],
|
{ displayKeyPath: basisFact[nameKey],
|
||||||
nestingLevel: 0,
|
nestingLevel: 0,
|
||||||
|
containsValueArray: containsValueArray,
|
||||||
facts: diffs
|
facts: diffs
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ var moduleConfig =
|
|||||||
{ compareKey: ['release', 'version'],
|
{ compareKey: ['release', 'version'],
|
||||||
nameKey: 'name',
|
nameKey: 'name',
|
||||||
sortKey: 1,
|
sortKey: 1,
|
||||||
factTemplate: "{{epoch|append:':'}}{{version}}-{{release}}{{arch|prepend:'.'}}"
|
factTemplate: "{{epoch|append:':'}}{{version}}-{{release}}{{arch|prepend:'.'}}",
|
||||||
|
supportsValueArray: true
|
||||||
},
|
},
|
||||||
'services':
|
'services':
|
||||||
{ compareKey: ['state', 'source'],
|
{ compareKey: ['state', 'source'],
|
||||||
|
|||||||
@@ -15,6 +15,12 @@
|
|||||||
background-color: #ebebeb;
|
background-color: #ebebeb;
|
||||||
border-color: #adadad;
|
border-color: #adadad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--flexible {
|
||||||
|
max-height: initial;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&-headingRow {
|
&-headingRow {
|
||||||
@@ -26,8 +32,21 @@
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
flex: 1 0 33%;
|
flex: 1 0 33%;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
align-self: flex-start;
|
||||||
&--offsetLeft {
|
&--offsetLeft {
|
||||||
margin-left: 33%;
|
margin-left: 33%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-columnArray {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-columnMember {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,25 @@
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div ng-if="!isNestedDisplay">
|
<div ng-if="!isNestedDisplay">
|
||||||
<div class="FactDataTable-row" ng-repeat="group in factData | orderBy: 'displayKeyPath'">
|
<div ng-repeat="group in factData | orderBy: 'displayKeyPath'">
|
||||||
<span class="FactDataTable-column">{{group.facts.keyName}}</span>
|
<div class="FactDataTable-row FactDataTable-row--flexible" ng-if="group.containsValueArray">
|
||||||
<span class="FactDataTable-column">{{group.facts.value1}}</span>
|
<span class="FactDataTable-column">{{group.facts.keyName}}</span>
|
||||||
<span class="FactDataTable-column">{{group.facts.value2}}</span>
|
<span class="FactDataTable-column FactDataTable-columnArray">
|
||||||
|
<span class="FactDataTable-columnMember" ng-repeat="value in group.facts.value1">
|
||||||
|
{{value}}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span class="FactDataTable-column FactDataTable-columnArray">
|
||||||
|
<span class="FactDataTable-columnMember" ng-repeat="value in group.facts.value2">
|
||||||
|
{{value}}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="FactDataTable-row" ng-if="!group.containsValueArray">
|
||||||
|
<span class="FactDataTable-column">{{group.facts.keyName}}</span>
|
||||||
|
<span class="FactDataTable-column">{{group.facts.value1}}</span>
|
||||||
|
<span class="FactDataTable-column">{{group.facts.value2}}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ng-if="isNestedDisplay">
|
<div ng-if="isNestedDisplay">
|
||||||
@@ -35,7 +50,7 @@
|
|||||||
<div class="FactDataGroup-facts" data-facts="{{group.facts}}">
|
<div class="FactDataGroup-facts" data-facts="{{group.facts}}">
|
||||||
<div class="FactDataTable-arrayGroup" ng-if="group.isFactArray" ng-repeat="arrayGroup in group.facts" data-array-group="{{arrayGroup}}">
|
<div class="FactDataTable-arrayGroup" ng-if="group.isFactArray" ng-repeat="arrayGroup in group.facts" data-array-group="{{arrayGroup}}">
|
||||||
<div class="FactDataTable-row FactDatum" ng-class="{'FactDatum--divergent': fact.isDivergent }" ng-repeat="fact in arrayGroup" data-fact="{{fact}}">
|
<div class="FactDataTable-row FactDatum" ng-class="{'FactDatum--divergent': fact.isDivergent }" ng-repeat="fact in arrayGroup" data-fact="{{fact}}">
|
||||||
<span class="FactDatum-keyName FactDataTable-column" ng-unless="fact.isArrayMember">
|
<span class="FactDatum-keyName FactDataTable-column" ng-if="!fact.isArrayMember">
|
||||||
{{fact.keyName}}
|
{{fact.keyName}}
|
||||||
</span>
|
</span>
|
||||||
<span class="FactDatum-keyName FactDataTable-column" ng-if="fact.isArrayMember">
|
<span class="FactDatum-keyName FactDataTable-column" ng-if="fact.isArrayMember">
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ describe('CompareFacts.Flat', function() {
|
|||||||
|
|
||||||
expect(result).to.deep.equal(
|
expect(result).to.deep.equal(
|
||||||
[{ displayKeyPath: 'foo',
|
[{ displayKeyPath: 'foo',
|
||||||
|
containsValueArray: false,
|
||||||
nestingLevel: 0,
|
nestingLevel: 0,
|
||||||
facts:
|
facts:
|
||||||
[{ keyName: 'value',
|
[{ keyName: 'value',
|
||||||
@@ -139,6 +140,7 @@ describe('CompareFacts.Flat', function() {
|
|||||||
|
|
||||||
expect(result).to.deep.equal(
|
expect(result).to.deep.equal(
|
||||||
[{ displayKeyPath: 'foo',
|
[{ displayKeyPath: 'foo',
|
||||||
|
containsValueArray: false,
|
||||||
nestingLevel: 0,
|
nestingLevel: 0,
|
||||||
facts:
|
facts:
|
||||||
[{ keyName: 'value',
|
[{ keyName: 'value',
|
||||||
@@ -334,6 +336,7 @@ describe('CompareFacts.Flat', function() {
|
|||||||
|
|
||||||
expect(result).to.deep.equal(
|
expect(result).to.deep.equal(
|
||||||
[{ displayKeyPath: 'foo',
|
[{ displayKeyPath: 'foo',
|
||||||
|
containsValueArray: false,
|
||||||
nestingLevel: 0,
|
nestingLevel: 0,
|
||||||
facts:
|
facts:
|
||||||
[{ keyName: 'value',
|
[{ keyName: 'value',
|
||||||
@@ -368,6 +371,7 @@ describe('CompareFacts.Flat', function() {
|
|||||||
|
|
||||||
expect(result).to.deep.equal(
|
expect(result).to.deep.equal(
|
||||||
[{ displayKeyPath: 'foo',
|
[{ displayKeyPath: 'foo',
|
||||||
|
containsValueArray: false,
|
||||||
nestingLevel: 0,
|
nestingLevel: 0,
|
||||||
facts:
|
facts:
|
||||||
{ keyName: 'foo',
|
{ keyName: 'foo',
|
||||||
@@ -389,6 +393,7 @@ describe('CompareFacts.Flat', function() {
|
|||||||
|
|
||||||
expect(result).to.deep.equal(
|
expect(result).to.deep.equal(
|
||||||
[{ displayKeyPath: 'foo',
|
[{ displayKeyPath: 'foo',
|
||||||
|
containsValueArray: false,
|
||||||
nestingLevel: 0,
|
nestingLevel: 0,
|
||||||
facts:
|
facts:
|
||||||
[{ keyName: 'value',
|
[{ keyName: 'value',
|
||||||
@@ -407,6 +412,101 @@ describe('CompareFacts.Flat', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when value for nameKey exists multiple times in a single collection', function() {
|
||||||
|
|
||||||
|
context('with differences between any of the values', function() {
|
||||||
|
|
||||||
|
it('includes rendered values as array for value properties', function() {
|
||||||
|
|
||||||
|
var factTemplate =
|
||||||
|
{ hasTemplate:
|
||||||
|
function() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
render: function(fact) {
|
||||||
|
return fact.version;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = compareFacts(
|
||||||
|
{ position: 'left',
|
||||||
|
facts:
|
||||||
|
[{ 'name': 'some-package',
|
||||||
|
'version': 'abcd'
|
||||||
|
},
|
||||||
|
{ 'name': 'some-package',
|
||||||
|
'version': 'efgh'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{ position: 'right',
|
||||||
|
facts:
|
||||||
|
[{ 'name': 'some-package',
|
||||||
|
'version': 'abcd'
|
||||||
|
},
|
||||||
|
{ 'name': 'some-package',
|
||||||
|
'version': 'ijkl'
|
||||||
|
}]
|
||||||
|
|
||||||
|
}, options({ compareKey: ['value'],
|
||||||
|
factTemplate: factTemplate,
|
||||||
|
supportsValueArray: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
expect(result[0].containsValueArray).to.equal(true);
|
||||||
|
expect(result[0].facts).to.deep.equal(
|
||||||
|
{ keyName: 'some-package',
|
||||||
|
value1: ['abcd', 'efgh'],
|
||||||
|
value2: ['abcd', 'ijkl']
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
context('with no differences between any of the values', function() {
|
||||||
|
|
||||||
|
it('does not include the property at all', function() {
|
||||||
|
var expectation;
|
||||||
|
var factTemplate =
|
||||||
|
{ hasTemplate:
|
||||||
|
function() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
render: function(fact) {
|
||||||
|
return fact.version;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = compareFacts(
|
||||||
|
{ position: 'left',
|
||||||
|
facts:
|
||||||
|
[{ 'name': 'some-package',
|
||||||
|
'version': 'abcd'
|
||||||
|
},
|
||||||
|
{ 'name': 'some-package',
|
||||||
|
'version': 'efgh'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{ position: 'right',
|
||||||
|
facts:
|
||||||
|
[{ 'name': 'some-package',
|
||||||
|
'version': 'abcd'
|
||||||
|
},
|
||||||
|
{ 'name': 'some-package',
|
||||||
|
'version': 'efgh'
|
||||||
|
}]
|
||||||
|
|
||||||
|
}, options({ compareKey: ['value'],
|
||||||
|
factTemplate: factTemplate,
|
||||||
|
supportsValueArray: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Use assignment to avoid jshint warning
|
||||||
|
expectation = expect(result).to.be.empty;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
context('with factTemplate', function() {
|
context('with factTemplate', function() {
|
||||||
var factData;
|
var factData;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user