mirror of
https://github.com/ansible/awx.git
synced 2026-01-15 20:00:43 -03:30
[system_tracking] Support multiple versions of packages with same name
This commit is contained in:
parent
33b6da9bb6
commit
bda5a46729
@ -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|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
|
||||
* @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 {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
|
||||
@ -58,79 +61,124 @@ export default
|
||||
|
||||
|
||||
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 = {};
|
||||
searcher[nameKey] = basisFact[nameKey];
|
||||
|
||||
var matchingFact = _.where(comparatorFacts.facts, searcher);
|
||||
var containsValueArray = false;
|
||||
var matchingFacts = _.where(comparatorFacts.facts, searcher);
|
||||
var comparisonResults;
|
||||
var diffs;
|
||||
|
||||
// Perform comparison and get back comparisonResults; like:
|
||||
// { 'value':
|
||||
// { leftValue: 'blah',
|
||||
// rightValue: 'doo'
|
||||
// }
|
||||
// };
|
||||
// If this fact exists more than once in `basisFacts`, then
|
||||
// we need to process it differently
|
||||
//
|
||||
var comparisonResults =
|
||||
_.reduce(compareKeys, function(result, compareKey) {
|
||||
var otherBasisFacts = _.where(basisFacts.facts, searcher);
|
||||
if (renderOptions.supportsValueArray && otherBasisFacts.length > 1) {
|
||||
comparisonResults = processFactsForValueArray(basisFacts.position, otherBasisFacts, matchingFacts);
|
||||
} else {
|
||||
comparisonResults = processFactsForSingleValue(basisFact, matchingFacts[0] || {});
|
||||
}
|
||||
|
||||
var comparatorFact = matchingFact[0] || {};
|
||||
var isNestedDisplay = false;
|
||||
function processFactsForValueArray(basisPosition, basisFacts, comparatorFacts) {
|
||||
|
||||
var slottedValues = slotFactValues(basisFacts.position,
|
||||
basisFact[compareKey],
|
||||
comparatorFact[compareKey]);
|
||||
function renderFactValues(facts) {
|
||||
return facts.map(function(fact) {
|
||||
return factTemplate.render(fact);
|
||||
});
|
||||
}
|
||||
|
||||
if (_.isUndefined(slottedValues.left) && _.isUndefined(slottedValues.right)) {
|
||||
return result;
|
||||
}
|
||||
var basisFactValues = renderFactValues(basisFacts);
|
||||
var comparatorFactValues = renderFactValues(comparatorFacts);
|
||||
|
||||
var template = factTemplate;
|
||||
var slottedValues = slotFactValues(basisPosition, basisFactValues, comparatorFactValues);
|
||||
|
||||
if (_.isObject(template) && template.hasOwnProperty(compareKey)) {
|
||||
template = template[compareKey];
|
||||
if (!_.isEqual(slottedValues.left, slottedValues.right)) {
|
||||
slottedValues.isDivergent = true;
|
||||
containsValueArray = true;
|
||||
} else {
|
||||
slottedValues.isDivergent = false;
|
||||
}
|
||||
|
||||
// 'true' means render the key without formatting
|
||||
if (template === true) {
|
||||
return slottedValues;
|
||||
}
|
||||
|
||||
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 =
|
||||
{ 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;
|
||||
}
|
||||
|
||||
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 =
|
||||
_.any(comparisonResults, { isDivergent: true }) ||
|
||||
@ -167,6 +215,7 @@ export default
|
||||
var descriptor =
|
||||
{ displayKeyPath: basisFact[nameKey],
|
||||
nestingLevel: 0,
|
||||
containsValueArray: containsValueArray,
|
||||
facts: diffs
|
||||
};
|
||||
|
||||
|
||||
@ -3,7 +3,8 @@ var moduleConfig =
|
||||
{ compareKey: ['release', 'version'],
|
||||
nameKey: 'name',
|
||||
sortKey: 1,
|
||||
factTemplate: "{{epoch|append:':'}}{{version}}-{{release}}{{arch|prepend:'.'}}"
|
||||
factTemplate: "{{epoch|append:':'}}{{version}}-{{release}}{{arch|prepend:'.'}}",
|
||||
supportsValueArray: true
|
||||
},
|
||||
'services':
|
||||
{ compareKey: ['state', 'source'],
|
||||
|
||||
@ -15,6 +15,12 @@
|
||||
background-color: #ebebeb;
|
||||
border-color: #adadad;
|
||||
}
|
||||
|
||||
&--flexible {
|
||||
max-height: initial;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&-headingRow {
|
||||
@ -26,8 +32,21 @@
|
||||
padding: 8px;
|
||||
flex: 1 0 33%;
|
||||
white-space: nowrap;
|
||||
align-self: flex-start;
|
||||
&--offsetLeft {
|
||||
margin-left: 33%;
|
||||
}
|
||||
}
|
||||
|
||||
&-columnArray {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&-columnMember {
|
||||
margin-bottom: 16px;
|
||||
&:last-child {
|
||||
margin-bottom: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,10 +17,25 @@
|
||||
</h3>
|
||||
</div>
|
||||
<div ng-if="!isNestedDisplay">
|
||||
<div class="FactDataTable-row" ng-repeat="group in factData | orderBy: 'displayKeyPath'">
|
||||
<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 ng-repeat="group in factData | orderBy: 'displayKeyPath'">
|
||||
<div class="FactDataTable-row FactDataTable-row--flexible" ng-if="group.containsValueArray">
|
||||
<span class="FactDataTable-column">{{group.facts.keyName}}</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 ng-if="isNestedDisplay">
|
||||
@ -35,7 +50,7 @@
|
||||
<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-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}}
|
||||
</span>
|
||||
<span class="FactDatum-keyName FactDataTable-column" ng-if="fact.isArrayMember">
|
||||
|
||||
@ -105,6 +105,7 @@ describe('CompareFacts.Flat', function() {
|
||||
|
||||
expect(result).to.deep.equal(
|
||||
[{ displayKeyPath: 'foo',
|
||||
containsValueArray: false,
|
||||
nestingLevel: 0,
|
||||
facts:
|
||||
[{ keyName: 'value',
|
||||
@ -139,6 +140,7 @@ describe('CompareFacts.Flat', function() {
|
||||
|
||||
expect(result).to.deep.equal(
|
||||
[{ displayKeyPath: 'foo',
|
||||
containsValueArray: false,
|
||||
nestingLevel: 0,
|
||||
facts:
|
||||
[{ keyName: 'value',
|
||||
@ -334,6 +336,7 @@ describe('CompareFacts.Flat', function() {
|
||||
|
||||
expect(result).to.deep.equal(
|
||||
[{ displayKeyPath: 'foo',
|
||||
containsValueArray: false,
|
||||
nestingLevel: 0,
|
||||
facts:
|
||||
[{ keyName: 'value',
|
||||
@ -368,6 +371,7 @@ describe('CompareFacts.Flat', function() {
|
||||
|
||||
expect(result).to.deep.equal(
|
||||
[{ displayKeyPath: 'foo',
|
||||
containsValueArray: false,
|
||||
nestingLevel: 0,
|
||||
facts:
|
||||
{ keyName: 'foo',
|
||||
@ -389,6 +393,7 @@ describe('CompareFacts.Flat', function() {
|
||||
|
||||
expect(result).to.deep.equal(
|
||||
[{ displayKeyPath: 'foo',
|
||||
containsValueArray: false,
|
||||
nestingLevel: 0,
|
||||
facts:
|
||||
[{ 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() {
|
||||
var factData;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user