Add ability in UI to associate test to product/version

On the private results page, a user can now optionally associate
a test result to a specific product and version that they have
created or have access to.

Change-Id: I85112d999cd832d7ce1b8c14057a8301b5e5ed7d
This commit is contained in:
Paul Van Eck 2016-10-09 20:28:38 -07:00
parent 5ad18f067f
commit ade52043a6
4 changed files with 203 additions and 2 deletions

View File

@ -134,7 +134,7 @@
<option value="object">OpenStack Powered Object Storage</option>
</select>
<a ng-if="!result.targetEdit"
ng-click="result.targetEdit = true"
ng-click="result.targetEdit = true;"
title="Edit"
class="glyphicon glyphicon-pencil">
</a>
@ -143,6 +143,60 @@
title="Save"
class="glyphicon glyphicon-floppy-disk">
</a>
<br />
<strong>Associated Product:</strong>
<span ng-if="!result.product_version && !result.productEdit">
<em>None</em>
</span>
<span ng-if="result.product_version && !result.productEdit">
<span ng-if="ctrl.products[result.product_version.product_info.id].product_type == 0">
<a ui-sref="distro({id: result.product_version.product_info.id})">
{{ctrl.products[result.product_version.product_info.id].name}}
<small ng-if="result.product_version.version">
({{result.product_version.version}})
</small>
</a>
</span>
<span ng-if="ctrl.products[result.product_version.product_info.id].product_type != 0">
<a ui-sref="cloud({id: result.product_version.product_info.id})">
{{ctrl.products[result.product_version.product_info.id].name}}
<small ng-if="result.product_version.version">
({{result.product_version.version}})
</small>
</a>
</span>
</span>
<select ng-if="result.productEdit"
ng-options="product as product.name for product in ctrl.products | arrayConverter | orderBy: 'name' track by product.id"
ng-model="result.selectedProduct"
ng-change="ctrl.getProductVersions(result)">
<option value="">-- No Product --</option>
</select>
<span ng-if="result.productVersions.length && result.productEdit">
<span class="glyphicon glyphicon-arrow-right" style="padding-right:3px;color:#303030;"></span>
Version:
<select ng-options="version as version.version for version in result.productVersions | orderBy: 'version' track by version.id"
ng-model="result.selectedVersion">
</select>
</span>
<a ng-if="!result.productEdit"
ng-click="ctrl.prepVersionEdit(result)"
title="Edit"
class="glyphicon glyphicon-pencil">
</a>
<a ng-if="result.productEdit"
ng-click="ctrl.associateProductVersion(result)"
confirm="Once you associate this test to this product, ownership
will be transferred to the product's vendor admins.
Continue?"
title="Save"
class="glyphicon glyphicon-floppy-disk">
</a>
<br />
</td>
</tr>
</tbody>

View File

@ -37,6 +37,10 @@
ctrl.clearFilters = clearFilters;
ctrl.associateMeta = associateMeta;
ctrl.getVersionList = getVersionList;
ctrl.getUserProducts = getUserProducts;
ctrl.associateProductVersion = associateProductVersion;
ctrl.getProductVersions = getProductVersions;
ctrl.prepVersionEdit = prepVersionEdit;
/** Mappings of DefCore components to marketing program names. */
ctrl.targetMappings = {
@ -90,6 +94,7 @@
if (ctrl.isUserResults) {
ctrl.authRequest = $scope.auth.doSignCheck()
.then(ctrl.update);
ctrl.getUserProducts();
} else {
ctrl.update();
}
@ -206,5 +211,98 @@
});
}
/**
* Get products user has management rights to or all products depending
* on the passed in parameter value.
*/
function getUserProducts() {
if (ctrl.products) {
return;
}
var contentUrl = refstackApiUrl + '/products';
ctrl.productsRequest =
$http.get(contentUrl).success(function (data) {
ctrl.products = {};
angular.forEach(data.products, function(prod) {
if (prod.can_manage) {
ctrl.products[prod.id] = prod;
}
});
}).error(function (error) {
ctrl.products = null;
ctrl.showError = true;
ctrl.error =
'Error retrieving Products listing from server: ' +
angular.toJson(error);
});
}
/**
* Send a PUT request to the API server to associate a product with
* a test result.
*/
function associateProductVersion(result) {
var verId = (result.selectedVersion ?
result.selectedVersion.id : null);
var testId = result.id;
var url = refstackApiUrl + '/results/' + testId;
ctrl.associateRequest = $http.put(url, {'product_version_id':
verId})
.success(function (data) {
result.product_version = result.selectedVersion;
if (result.selectedVersion) {
result.product_version.product_info =
result.selectedProduct;
}
result.productEdit = false;
}).error(function (error) {
raiseAlert('danger', error.title, error.detail);
});
}
/**
* Get all versions for a product.
*/
function getProductVersions(result) {
if (!result.selectedProduct) {
result.productVersions = [];
result.selectedVersion = null;
return;
}
var url = refstackApiUrl + '/products/' +
result.selectedProduct.id + '/versions';
ctrl.getVersionsRequest = $http.get(url)
.success(function (data) {
result.productVersions = data;
// If the test result isn't already associated to a
// version, default it to the null version.
if (!result.product_version) {
angular.forEach(data, function(ver) {
if (!ver.version) {
result.selectedVersion = ver;
}
});
}
}).error(function (error) {
raiseAlert('danger', error.title, error.detail);
});
}
/**
* Instantiate variables needed for editing product/version
* associations.
*/
function prepVersionEdit(result) {
result.productEdit = true;
if (result.product_version) {
result.selectedProduct =
ctrl.products[result.product_version.product_info.id];
}
result.selectedVersion = result.product_version;
ctrl.getProductVersions(result);
}
}
})();

View File

@ -31,7 +31,9 @@
return function (objects) {
var array = [];
angular.forEach(objects, function (object, key) {
object.id = key;
if (!('id' in object)) {
object.id = key;
}
array.push(object);
});
return array;

View File

@ -215,6 +215,8 @@ describe('Refstack controllers', function () {
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
ctrl = $controller('ResultsController', {$scope: scope});
$httpBackend.when('GET', fakeApiUrl +
'/results?page=1').respond(fakeResponse);
}));
it('should fetch the first page of results with proper URL args',
@ -301,6 +303,51 @@ describe('Refstack controllers', function () {
expect(ctrl.versionList).toEqual(['2015.04.json',
'2015.03.json']);
});
it('should have a function to get products manageable by a user',
function () {
var prodResp = {'products': [{'id': 'abc',
'can_manage': true},
{'id': 'foo',
'can_manage': false}]};
ctrl.products = null;
$httpBackend.expectGET(fakeApiUrl + '/products')
.respond(200, prodResp);
ctrl.getUserProducts();
$httpBackend.flush();
var expected = {'abc': {'id': 'abc', 'can_manage': true}};
expect(ctrl.products).toEqual(expected);
});
it('should have a function to associate a product version to a test',
function () {
var result = {'id': 'bar',
'selectedVersion': {'id': 'foo'},
'selectedProduct': {'id': 'prod'}};
ctrl.products = null;
$httpBackend.expectPUT(fakeApiUrl + '/results/bar')
.respond(201);
ctrl.associateProductVersion(result);
$httpBackend.flush();
var expected = {'id': 'foo', 'product_info': {'id': 'prod'}};
expect(result.product_version).toEqual(expected);
});
it('should have a function to get product versions',
function () {
var result = {'id': 'bar',
'selectedProduct': {'id': 'prod'}};
var verResp = [{'id': 'ver1', 'version': '1.0'},
{'id': 'ver2', 'version': null}];
ctrl.products = null;
$httpBackend.expectGET(fakeApiUrl + '/products/prod/versions')
.respond(200, verResp);
ctrl.getProductVersions(result);
$httpBackend.flush();
expect(result.productVersions).toEqual(verResp);
var expected = {'id': 'ver2', 'version': null};
expect(result.selectedVersion).toEqual(expected);
});
});
describe('ResultsReportController', function () {