diff --git a/refstack-ui/app/components/results/results.html b/refstack-ui/app/components/results/results.html
index d75048a3..2552fba3 100644
--- a/refstack-ui/app/components/results/results.html
+++ b/refstack-ui/app/components/results/results.html
@@ -134,7 +134,7 @@
@@ -143,6 +143,60 @@
title="Save"
class="glyphicon glyphicon-floppy-disk">
+
+
+ Associated Product:
+
+ None
+
+
+
+
+ {{ctrl.products[result.product_version.product_info.id].name}}
+
+ ({{result.product_version.version}})
+
+
+
+
+
+ {{ctrl.products[result.product_version.product_info.id].name}}
+
+ ({{result.product_version.version}})
+
+
+
+
+
+
+
+
+
+ Version:
+
+
+
+
+
+
+
+
diff --git a/refstack-ui/app/components/results/resultsController.js b/refstack-ui/app/components/results/resultsController.js
index c3f14829..044b4232 100644
--- a/refstack-ui/app/components/results/resultsController.js
+++ b/refstack-ui/app/components/results/resultsController.js
@@ -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);
+ }
+
}
})();
diff --git a/refstack-ui/app/shared/filters.js b/refstack-ui/app/shared/filters.js
index 84b171b6..e38789f5 100644
--- a/refstack-ui/app/shared/filters.js
+++ b/refstack-ui/app/shared/filters.js
@@ -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;
diff --git a/refstack-ui/tests/unit/ControllerSpec.js b/refstack-ui/tests/unit/ControllerSpec.js
index fb941eb7..c8028e07 100644
--- a/refstack-ui/tests/unit/ControllerSpec.js
+++ b/refstack-ui/tests/unit/ControllerSpec.js
@@ -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 () {