RefStack should allow associating specific guideline/target.
Since a user may have tested against a specific guideline version and target program, we should allow users to associate these specifics to their test results. Closes-Bug: #1477392 Co-Authored-By: Paul Van Eck <pvaneck@us.ibm.com> Change-Id: If0bf28f79e11b1ba83465d19e3d10953386d8864
This commit is contained in:
parent
3f08865327
commit
f41721e069
@ -188,3 +188,7 @@ h1, h2, h3, h4, h5, h6 {
|
||||
.test-detail ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
a.glyphicon {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
@ -34,9 +34,11 @@
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<strong>Capabilities Version:</strong>
|
||||
<select ng-model="ctrl.version" ng-change="ctrl.updateCapabilities()" class="form-control">
|
||||
<!-- Slicing the version file name here gets rid of the '.json' file extension -->
|
||||
<option ng-repeat="versionFile in ctrl.versionList" value="{{versionFile}}">{{versionFile.slice(0, -5)}}</option>
|
||||
<!-- Slicing the version file name here gets rid of the '.json' file extension -->
|
||||
<select ng-model="ctrl.version"
|
||||
ng-change="ctrl.updateCapabilities()"
|
||||
class="form-control"
|
||||
ng-options="versionFile.slice(0,-5) for versionFile in ctrl.versionList">
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
|
@ -89,7 +89,9 @@
|
||||
ctrl.versionsRequest =
|
||||
$http.get(content_url).success(function (data) {
|
||||
ctrl.versionList = data.sort().reverse();
|
||||
ctrl.version = ctrl.versionList[0];
|
||||
if (!ctrl.version) {
|
||||
ctrl.version = ctrl.versionList[0];
|
||||
}
|
||||
ctrl.updateCapabilities();
|
||||
}).error(function (error) {
|
||||
ctrl.showError = true;
|
||||
@ -109,6 +111,10 @@
|
||||
ctrl.resultsRequest =
|
||||
$http.get(content_url).success(function (data) {
|
||||
ctrl.resultsData = data;
|
||||
ctrl.version = ctrl.resultsData.meta.guideline;
|
||||
if (ctrl.resultsData.meta.target) {
|
||||
ctrl.target = ctrl.resultsData.meta.target;
|
||||
}
|
||||
getVersionList();
|
||||
}).error(function (error) {
|
||||
ctrl.showError = true;
|
||||
|
@ -38,12 +38,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div cg-busy="{promise:ctrl.authRequest,message:'Loading'}"></div>
|
||||
<div cg-busy="{promise:ctrl.resultsRequest,message:'Loading'}"></div>
|
||||
|
||||
<div ng-show="ctrl.data" class="results-table">
|
||||
<table ng-show="ctrl.data" class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th ng-if="ctrl.isUserResults"></th>
|
||||
<th>Upload Date</th>
|
||||
<th>Test Run ID</th>
|
||||
<th ng-if="ctrl.isUserResults">Shared</th>
|
||||
@ -51,10 +54,96 @@
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr ng-repeat="result in ctrl.data.results">
|
||||
<tr ng-repeat-start="(index, result) in ctrl.data.results">
|
||||
<td ng-if="ctrl.isUserResults">
|
||||
<a ng-if="!result.expanded"
|
||||
class="glyphicon glyphicon-plus"
|
||||
ng-click="result.expanded = true">
|
||||
</a>
|
||||
<a ng-if="result.expanded"
|
||||
class="glyphicon glyphicon-minus"
|
||||
ng-click="result.expanded = false">
|
||||
</a>
|
||||
</td>
|
||||
<td>{{result.created_at}}</td>
|
||||
<td><a ui-sref="resultsDetail({testID: result.id})">{{result.id}}</a></td>
|
||||
<td ng-if="ctrl.isUserResults"><span ng-show="result.meta.shared" class="glyphicon glyphicon-share"></span></td>
|
||||
<td ng-if="ctrl.isUserResults">
|
||||
<span ng-show="result.meta.shared" class="glyphicon glyphicon-share"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="result.expanded" ng-repeat-end>
|
||||
<td></td>
|
||||
<td colspan="3">
|
||||
<strong>Publicly Shared:</strong>
|
||||
<span ng-if="result.meta.shared == 'true' && !result.sharedEdit">Yes</span>
|
||||
<span ng-if="!result.meta.shared && !result.sharedEdit">
|
||||
<em>No</em>
|
||||
</span>
|
||||
<select ng-if="result.sharedEdit"
|
||||
ng-model="result.meta.shared"
|
||||
class="form-inline">
|
||||
<option value="true">Share</option>
|
||||
<option value="">Unshare</option>
|
||||
</select>
|
||||
<a ng-if="!result.sharedEdit"
|
||||
ng-click="result.sharedEdit = true"
|
||||
title="Edit"
|
||||
class="glyphicon glyphicon-pencil"></a>
|
||||
<a ng-if="result.sharedEdit"
|
||||
ng-click="ctrl.associateMeta(index,'shared',result.meta.shared)"
|
||||
title="Save"
|
||||
class="glyphicon glyphicon-floppy-disk"></a>
|
||||
<br />
|
||||
|
||||
<strong>Associated Guideline:</strong>
|
||||
<span ng-if="!result.meta.guideline && !result.guidelineEdit">
|
||||
<em>None</em>
|
||||
</span>
|
||||
<span ng-if="result.meta.guideline && !result.guidelineEdit">
|
||||
{{result.meta.guideline.slice(0, -5)}}
|
||||
</span>
|
||||
<select ng-if="result.guidelineEdit"
|
||||
ng-model="result.meta.guideline"
|
||||
ng-options="o as o.slice(0, -5) for o in ctrl.versionList"
|
||||
class="form-inline">
|
||||
<option value="">None</option>
|
||||
</select>
|
||||
<a ng-if="!result.guidelineEdit"
|
||||
ng-click="ctrl.getVersionList();result.guidelineEdit = true"
|
||||
title="Edit"
|
||||
class="glyphicon glyphicon-pencil"></a>
|
||||
<a ng-if="result.guidelineEdit"
|
||||
ng-click="ctrl.associateMeta(index, 'guideline', result.meta.guideline)"
|
||||
title="Save"
|
||||
class="glyphicon glyphicon-floppy-disk">
|
||||
</a>
|
||||
<br />
|
||||
|
||||
<strong>Associated Target Program:</strong>
|
||||
<span ng-if="!result.meta.target && !result.targetEdit">
|
||||
<em>None</em>
|
||||
</span>
|
||||
<span ng-if="result.meta.target && !result.targetEdit">
|
||||
{{ctrl.targetMappings[result.meta.target]}}</span>
|
||||
<select ng-if="result.targetEdit"
|
||||
ng-model="result.meta.target"
|
||||
class="form-inline">
|
||||
<option value="">None</option>
|
||||
<option value="platform">OpenStack Powered Platform</option>
|
||||
<option value="compute">OpenStack Powered Compute</option>
|
||||
<option value="object">OpenStack Powered Object Storage</option>
|
||||
</select>
|
||||
<a ng-if="!result.targetEdit"
|
||||
ng-click="result.targetEdit = true"
|
||||
title="Edit"
|
||||
class="glyphicon glyphicon-pencil">
|
||||
</a>
|
||||
<a ng-if="result.targetEdit"
|
||||
ng-click="ctrl.associateMeta(index, 'target', result.meta.target)"
|
||||
title="Save"
|
||||
class="glyphicon glyphicon-floppy-disk">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -79,4 +168,3 @@
|
||||
<span class="sr-only">Error:</span>
|
||||
{{ctrl.error}}
|
||||
</div>
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
.controller('ResultsController', ResultsController);
|
||||
|
||||
ResultsController.$inject = [
|
||||
'$scope', '$http', '$filter', '$state', 'refstackApiUrl'
|
||||
'$scope', '$http', '$filter', '$state', 'refstackApiUrl','raiseAlert'
|
||||
];
|
||||
|
||||
/**
|
||||
@ -28,12 +28,22 @@
|
||||
* This controller is for the '/results' page where a user can browse
|
||||
* a listing of community uploaded results.
|
||||
*/
|
||||
function ResultsController($scope, $http, $filter, $state, refstackApiUrl) {
|
||||
function ResultsController($scope, $http, $filter, $state, refstackApiUrl,
|
||||
raiseAlert) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.update = update;
|
||||
ctrl.open = open;
|
||||
ctrl.clearFilters = clearFilters;
|
||||
ctrl.associateMeta = associateMeta;
|
||||
ctrl.getVersionList = getVersionList;
|
||||
|
||||
/** Mappings of DefCore components to marketing program names. */
|
||||
ctrl.targetMappings = {
|
||||
'platform': 'Openstack Powered Platform',
|
||||
'compute': 'OpenStack Powered Compute',
|
||||
'object': 'OpenStack Powered Object Storage'
|
||||
};
|
||||
|
||||
/** Initial page to be on. */
|
||||
ctrl.currentPage = 1;
|
||||
@ -143,5 +153,58 @@
|
||||
ctrl.endDate = null;
|
||||
ctrl.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* This will send an API request in order to associate a metadata
|
||||
* key-value pair with the given testId
|
||||
* @param {Number} index - index of the test object in the results list
|
||||
* @param {String} key - metadata key
|
||||
* @param {String} value - metadata value
|
||||
*/
|
||||
function associateMeta(index, key, value) {
|
||||
var testId = ctrl.data.results[index].id;
|
||||
var metaUrl = [
|
||||
refstackApiUrl, '/results/', testId, '/meta/', key
|
||||
].join('');
|
||||
|
||||
var editFlag = key + 'Edit';
|
||||
if (value) {
|
||||
ctrl.associateRequest = $http.post(metaUrl, value)
|
||||
.success(function () {
|
||||
ctrl.data.results[index][editFlag] = false;
|
||||
}).error(function (error) {
|
||||
raiseAlert('danger', error.title, error.detail);
|
||||
});
|
||||
}
|
||||
else {
|
||||
ctrl.unassociateRequest = $http.delete(metaUrl)
|
||||
.success(function () {
|
||||
ctrl.data.results[index][editFlag] = false;
|
||||
}).error(function (error) {
|
||||
raiseAlert('danger', error.title, error.detail);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an array of available capability files from the Refstack
|
||||
* API server, sort this array reverse-alphabetically, and store it in
|
||||
* a scoped variable.
|
||||
* Sample API return array: ["2015.03.json", "2015.04.json"]
|
||||
*/
|
||||
function getVersionList() {
|
||||
if (ctrl.versionList) {
|
||||
return;
|
||||
}
|
||||
var content_url = refstackApiUrl + '/capabilities';
|
||||
ctrl.versionsRequest =
|
||||
$http.get(content_url).success(function (data) {
|
||||
ctrl.versionList = data.sort().reverse();
|
||||
}).error(function (error) {
|
||||
raiseAlert('danger', error.title,
|
||||
'Unable to retrieve version list');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
})();
|
||||
|
@ -160,7 +160,7 @@ describe('Refstack controllers', function () {
|
||||
'pagination': {'current_page': 1, 'total_pages': 2},
|
||||
'results': [{
|
||||
'created_at': '2015-03-09 01:23:45',
|
||||
'test_id': 'some-id',
|
||||
'id': 'some-id',
|
||||
'cpid': 'some-cpid'
|
||||
}]
|
||||
};
|
||||
@ -212,11 +212,56 @@ describe('Refstack controllers', function () {
|
||||
expect(ctrl.startDate).toBe(null);
|
||||
expect(ctrl.endDate).toBe(null);
|
||||
});
|
||||
|
||||
it('should have a function to associate metadata to a test run',
|
||||
function () {
|
||||
$httpBackend.expectGET(fakeApiUrl + '/results?page=1')
|
||||
.respond(fakeResponse);
|
||||
ctrl.data = fakeResponse;
|
||||
ctrl.data.results[0].targetEdit = true;
|
||||
ctrl.associateMeta(0, 'target', 'platform');
|
||||
$httpBackend.expectPOST(
|
||||
fakeApiUrl + '/results/some-id/meta/target',
|
||||
'platform')
|
||||
.respond(201, '');
|
||||
$httpBackend.flush();
|
||||
expect(ctrl.data.results[0].targetEdit).toBe(false);
|
||||
});
|
||||
|
||||
it('should have a function to delete metadata from a test run',
|
||||
function () {
|
||||
$httpBackend.expectGET(fakeApiUrl + '/results?page=1')
|
||||
.respond(fakeResponse);
|
||||
ctrl.data = fakeResponse;
|
||||
ctrl.data.results[0].targetEdit = true;
|
||||
ctrl.associateMeta(0, 'target', '');
|
||||
$httpBackend.expectDELETE(
|
||||
fakeApiUrl + '/results/some-id/meta/target')
|
||||
.respond(200, '');
|
||||
$httpBackend.flush();
|
||||
expect(ctrl.data.results[0].targetEdit).toBe(false);
|
||||
});
|
||||
|
||||
it('should have a function to get guideline versions',
|
||||
function () {
|
||||
$httpBackend.expectGET(fakeApiUrl + '/results?page=1')
|
||||
.respond(fakeResponse);
|
||||
$httpBackend.expectGET(fakeApiUrl +
|
||||
'/capabilities').respond(['2015.03.json', '2015.04.json']);
|
||||
ctrl.getVersionList();
|
||||
$httpBackend.flush();
|
||||
// Expect the list to have the latest guideline first.
|
||||
expect(ctrl.versionList).toEqual(['2015.04.json',
|
||||
'2015.03.json']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ResultsReportController', function () {
|
||||
var stateparams, ctrl;
|
||||
var fakeResultResponse = {'results': ['test_id_1']};
|
||||
var fakeResultResponse = {'results': ['test_id_1'], 'meta': {
|
||||
'public_key': 'ssh-rsa', 'guideline': '2015.04.json', 'target':
|
||||
'object'
|
||||
}};
|
||||
var fakeCapabilityResponse = {
|
||||
'platform': {'required': ['compute']},
|
||||
'schema': '1.2',
|
||||
|
@ -36,7 +36,7 @@ CONF = cfg.CONF
|
||||
class MetadataController(rest.RestController):
|
||||
"""/v1/results/<test_id>/meta handler."""
|
||||
|
||||
rw_access_keys = ('shared',)
|
||||
rw_access_keys = ('shared', 'guideline', 'target',)
|
||||
|
||||
@pecan.expose('json')
|
||||
def get(self, test_id):
|
||||
|
Loading…
Reference in New Issue
Block a user