Merge "add web portal framework for TestAPI"
[releng.git] / utils / test / testapi / 3rd_party / static / testapi-ui / components / guidelines / guidelinesController.js
1 /*
2  * Licensed under the Apache License, Version 2.0 (the "License");
3  * you may not use this file except in compliance with the License.
4  * You may obtain a copy of the License at
5  *
6  * http://www.apache.org/licenses/LICENSE-2.0
7  *
8  * Unless required by applicable law or agreed to in writing, software
9  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14
15 (function () {
16     'use strict';
17
18     angular
19         .module('testapiApp')
20         .controller('GuidelinesController', GuidelinesController);
21
22     GuidelinesController.$inject = ['$http', '$uibModal', 'testapiApiUrl'];
23
24     /**
25      * TestAPI Guidelines Controller
26      * This controller is for the '/guidelines' page where a user can browse
27      * through tests belonging to Interop WG defined capabilities.
28      */
29     function GuidelinesController($http, $uibModal, testapiApiUrl) {
30         var ctrl = this;
31
32         ctrl.getVersionList = getVersionList;
33         ctrl.update = update;
34         ctrl.updateTargetCapabilities = updateTargetCapabilities;
35         ctrl.filterStatus = filterStatus;
36         ctrl.getObjectLength = getObjectLength;
37         ctrl.openTestListModal = openTestListModal;
38
39         /** The target OpenStack marketing program to show capabilities for. */
40         ctrl.target = 'platform';
41
42         /** The various possible capability statuses. */
43         ctrl.status = {
44             required: true,
45             advisory: false,
46             deprecated: false,
47             removed: false
48         };
49
50         /**
51          * The template to load for displaying capability details.
52          */
53         ctrl.detailsTemplate = 'components/guidelines/partials/' +
54                                'guidelineDetails.html';
55
56         /**
57          * Retrieve an array of available guideline files from the TestAPI
58          * API server, sort this array reverse-alphabetically, and store it in
59          * a scoped variable. The scope's selected version is initialized to
60          * the latest (i.e. first) version here as well. After a successful API
61          * call, the function to update the capabilities is called.
62          * Sample API return array: ["2015.03.json", "2015.04.json"]
63          */
64         function getVersionList() {
65             var content_url = testapiApiUrl + '/guidelines';
66             ctrl.versionsRequest =
67                 $http.get(content_url).success(function (data) {
68                     ctrl.versionList = data.sort().reverse();
69                     // Default to the first approved guideline which is expected
70                     // to be at index 1.
71                     ctrl.version = ctrl.versionList[1];
72                     ctrl.update();
73                 }).error(function (error) {
74                     ctrl.showError = true;
75                     ctrl.error = 'Error retrieving version list: ' +
76                         angular.toJson(error);
77                 });
78         }
79
80         /**
81          * This will contact the TestAPI API server to retrieve the JSON
82          * content of the guideline file corresponding to the selected
83          * version.
84          */
85         function update() {
86             var content_url = testapiApiUrl + '/guidelines/' + ctrl.version;
87             ctrl.capsRequest =
88                 $http.get(content_url).success(function (data) {
89                     ctrl.guidelines = data;
90                     ctrl.updateTargetCapabilities();
91                 }).error(function (error) {
92                     ctrl.showError = true;
93                     ctrl.guidelines = null;
94                     ctrl.error = 'Error retrieving guideline content: ' +
95                         angular.toJson(error);
96                 });
97         }
98
99         /**
100          * This will update the scope's 'targetCapabilities' object with
101          * capabilities belonging to the selected OpenStack marketing program
102          * (programs typically correspond to 'components' in the Interop WG
103          * schema). Each capability will have its status mapped to it.
104          */
105         function updateTargetCapabilities() {
106             ctrl.targetCapabilities = {};
107             var components = ctrl.guidelines.components;
108             var targetCaps = ctrl.targetCapabilities;
109
110             // The 'platform' target is comprised of multiple components, so
111             // we need to get the capabilities belonging to each of its
112             // components.
113             if (ctrl.target === 'platform') {
114                 var platform_components = ctrl.guidelines.platform.required;
115
116                 // This will contain status priority values, where lower
117                 // values mean higher priorities.
118                 var statusMap = {
119                     required: 1,
120                     advisory: 2,
121                     deprecated: 3,
122                     removed: 4
123                 };
124
125                 // For each component required for the platform program.
126                 angular.forEach(platform_components, function (component) {
127                     // Get each capability list belonging to each status.
128                     angular.forEach(components[component],
129                         function (caps, status) {
130                             // For each capability.
131                             angular.forEach(caps, function(cap) {
132                                 // If the capability has already been added.
133                                 if (cap in targetCaps) {
134                                     // If the status priority value is less
135                                     // than the saved priority value, update
136                                     // the value.
137                                     if (statusMap[status] <
138                                         statusMap[targetCaps[cap]]) {
139                                         targetCaps[cap] = status;
140                                     }
141                                 }
142                                 else {
143                                     targetCaps[cap] = status;
144                                 }
145                             });
146                         });
147                 });
148             }
149             else {
150                 angular.forEach(components[ctrl.target],
151                     function (caps, status) {
152                         angular.forEach(caps, function(cap) {
153                             targetCaps[cap] = status;
154                         });
155                     });
156             }
157         }
158
159         /**
160          * This filter will check if a capability's status corresponds
161          * to a status that is checked/selected in the UI. This filter
162          * is meant to be used with the ng-repeat directive.
163          * @param {Object} capability
164          * @returns {Boolean} True if capability's status is selected
165          */
166         function filterStatus(capability) {
167             var caps = ctrl.targetCapabilities;
168             return (ctrl.status.required &&
169                 caps[capability.id] === 'required') ||
170                 (ctrl.status.advisory &&
171                 caps[capability.id] === 'advisory') ||
172                 (ctrl.status.deprecated &&
173                 caps[capability.id] === 'deprecated') ||
174                 (ctrl.status.removed &&
175                 caps[capability.id] === 'removed');
176         }
177
178         /**
179          * This function will get the length of an Object/dict based on
180          * the number of keys it has.
181          * @param {Object} object
182          * @returns {Number} length of object
183          */
184         function getObjectLength(object) {
185             return Object.keys(object).length;
186         }
187
188         /**
189          * This will open the modal that will show a list of all tests
190          * belonging to capabilities with the selected status(es).
191          */
192         function openTestListModal() {
193             $uibModal.open({
194                 templateUrl: '/components/guidelines/partials' +
195                         '/testListModal.html',
196                 backdrop: true,
197                 windowClass: 'modal',
198                 animation: true,
199                 controller: 'TestListModalController as modal',
200                 size: 'lg',
201                 resolve: {
202                     version: function () {
203                         return ctrl.version.slice(0, -5);
204                     },
205                     target: function () {
206                         return ctrl.target;
207                     },
208                     status: function () {
209                         return ctrl.status;
210                     }
211                 }
212             });
213         }
214
215         ctrl.getVersionList();
216     }
217
218     angular
219         .module('testapiApp')
220         .controller('TestListModalController', TestListModalController);
221
222     TestListModalController.$inject = [
223         '$uibModalInstance', '$http', 'version',
224         'target', 'status', 'testapiApiUrl'
225     ];
226
227     /**
228      * Test List Modal Controller
229      * This controller is for the modal that appears if a user wants to see the
230      * test list corresponding to Interop WG capabilities with the selected
231      * statuses.
232      */
233     function TestListModalController($uibModalInstance, $http, version,
234         target, status, testapiApiUrl) {
235
236         var ctrl = this;
237
238         ctrl.version = version;
239         ctrl.target = target;
240         ctrl.status = status;
241         ctrl.close = close;
242         ctrl.updateTestListString = updateTestListString;
243
244         ctrl.aliases = true;
245         ctrl.flagged = false;
246
247         // Check if the API URL is absolute or relative.
248         if (testapiApiUrl.indexOf('http') > -1) {
249             ctrl.url = testapiApiUrl;
250         }
251         else {
252             ctrl.url = location.protocol + '//' + location.host +
253                 testapiApiUrl;
254         }
255
256         /**
257          * This function will close/dismiss the modal.
258          */
259         function close() {
260             $uibModalInstance.dismiss('exit');
261         }
262
263         /**
264          * This function will return a list of statuses based on which ones
265          * are selected.
266          */
267         function getStatusList() {
268             var statusList = [];
269             angular.forEach(ctrl.status, function(value, key) {
270                 if (value) {
271                     statusList.push(key);
272                 }
273             });
274             return statusList;
275         }
276
277         /**
278          * This will get the list of tests from the API and update the
279          * controller's test list string variable.
280          */
281         function updateTestListString() {
282             var statuses = getStatusList();
283             if (!statuses.length) {
284                 ctrl.error = 'No tests matching selected criteria.';
285                 return;
286             }
287             ctrl.testListUrl = [
288                 ctrl.url, '/guidelines/', ctrl.version, '/tests?',
289                 'target=', ctrl.target, '&',
290                 'type=', statuses.join(','), '&',
291                 'alias=', ctrl.aliases.toString(), '&',
292                 'flag=', ctrl.flagged.toString()
293             ].join('');
294             ctrl.testListRequest =
295                 $http.get(ctrl.testListUrl).
296                     then(function successCallback(response) {
297                         ctrl.error = null;
298                         ctrl.testListString = response.data;
299                         if (!ctrl.testListString) {
300                             ctrl.testListCount = 0;
301                         }
302                         else {
303                             ctrl.testListCount =
304                                 ctrl.testListString.split('\n').length;
305                         }
306                     }, function errorCallback(response) {
307                         ctrl.testListString = null;
308                         ctrl.testListCount = null;
309                         if (angular.isObject(response.data) &&
310                             response.data.message) {
311                             ctrl.error = 'Error retrieving test list: ' +
312                                 response.data.message;
313                         }
314                         else {
315                             ctrl.error = 'Unknown error retrieving test list.';
316                         }
317                     });
318         }
319
320         updateTestListString();
321     }
322 })();