diff options
Diffstat (limited to 'testapi/opnfv_testapi')
-rw-r--r-- | testapi/opnfv_testapi/common/check.py | 6 | ||||
-rw-r--r-- | testapi/opnfv_testapi/handlers/pod_handlers.py | 23 | ||||
-rw-r--r-- | testapi/opnfv_testapi/ui/components/pods/modals/createModal.html | 35 | ||||
-rw-r--r-- | testapi/opnfv_testapi/ui/components/pods/pods.html | 145 | ||||
-rw-r--r-- | testapi/opnfv_testapi/ui/components/pods/podsController.js | 195 | ||||
-rw-r--r-- | testapi/opnfv_testapi/ui/index.html | 3 | ||||
-rw-r--r-- | testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js | 9 |
7 files changed, 295 insertions, 121 deletions
diff --git a/testapi/opnfv_testapi/common/check.py b/testapi/opnfv_testapi/common/check.py index 1155d24..db28e44 100644 --- a/testapi/opnfv_testapi/common/check.py +++ b/testapi/opnfv_testapi/common/check.py @@ -28,7 +28,7 @@ def is_authorized(method): user_info = yield dbapi.db_find_one('users', {'user': testapi_id}) if not user_info: raises.Unauthorized(message.not_lfid()) - if "owner" in kwargs: + if method.__name__ == "_create": kwargs['owner'] = testapi_id if self.table in ['projects']: query = kwargs.get('query') @@ -137,9 +137,9 @@ def new_not_exists(xstep): query_data = query() if self.table == 'pods': if query_data.get('name') is not None: - query_data['name'] = re.compile(query_data.get('name'), - re.IGNORECASE) + query_data['name'] = re.compile('\\b' + query_data.get('name') + '\\b', re.IGNORECASE) to_data = yield dbapi.db_find_one(self.table, query_data) + print to_data if to_data: raises.Forbidden(message.exist(self.table, query())) ret = yield gen.coroutine(xstep)(self, *args, **kwargs) diff --git a/testapi/opnfv_testapi/handlers/pod_handlers.py b/testapi/opnfv_testapi/handlers/pod_handlers.py index abf5bf9..9e52ca0 100644 --- a/testapi/opnfv_testapi/handlers/pod_handlers.py +++ b/testapi/opnfv_testapi/handlers/pod_handlers.py @@ -57,22 +57,11 @@ class PodGURHandler(GenericPodHandler): """ self._get_one(query={'name': pod_name}) + @swagger.operation(nickname='deletePodByName') def delete(self, pod_name): - """ Remove a POD - - # check for an existing pod to be deleted - mongo_dict = yield self.db.pods.find_one( - {'name': pod_name}) - pod = TestProject.pod(mongo_dict) - if pod is None: - raise HTTPError(HTTP_NOT_FOUND, - "{} could not be found as a pod to be deleted" - .format(pod_name)) - - # just delete it, or maybe save it elsewhere in a future - res = yield self.db.projects.remove( - {'name': pod_name}) - - self.finish_request(answer) """ - pass + @description: delete a pod by pod_name + @return 200: delete success + @raise 404: pods not exist + """ + self._delete(query={'name': pod_name}) diff --git a/testapi/opnfv_testapi/ui/components/pods/modals/createModal.html b/testapi/opnfv_testapi/ui/components/pods/modals/createModal.html new file mode 100644 index 0000000..9fe3c40 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/pods/modals/createModal.html @@ -0,0 +1,35 @@ +<div class="ball" style="padding:5px;"> + <div class="modal-body"> + <div class="form-horizontal"> + <fieldset> + <div class="form-group"> + <legend>Create Pod</legend> + <div class="row"> + <div ng-repeat="require in PodModalCtrl.createRequirements" style="margin-left:15px"> + <div class="update-project"> + <label for="cpid" class="control-label col-sm-2">{{require.label|capitalize}}: </label> + <div class="col-sm-9"> + <a ng-if="require.type == 'select'"> + <select class="form-control" dynamic-model="'PodModalCtrl.pod.' + require.label" ng-options="option for option in require.selects"></select> + </a> + <a ng-if="require.type == 'text'"> + <input type="text" class="form-control" dynamic-model="'PodModalCtrl.pod.' + require.label"/> + </a> + <a ng-if="require.type == 'textarea'"> + <textarea rows="2" class="form-control" cols="50" dynamic-model="'PodModalCtrl.pod.' + require.label"> + </textarea> + </a> + <p class="help-block"></p> + </div> + </div> + </div> + </div> + </div> + </fieldset> + </div> + </div> + <div class="modal-footer"> + <button class="btn btn-primary" ng-click="PodModalCtrl.confirm()">Ok</button> + <button class="btn btn-default" ng-click="PodModalCtrl.cancel()">Cancel</button> + </div> +</div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/pods/pods.html b/testapi/opnfv_testapi/ui/components/pods/pods.html index 72a9f6c..ca0458b 100644 --- a/testapi/opnfv_testapi/ui/components/pods/pods.html +++ b/testapi/opnfv_testapi/ui/components/pods/pods.html @@ -3,83 +3,88 @@ Querying pods is open to everybody.<br> But only login users are granted the privilege to create the new pod. </p> - <div class="row" style="margin-bottom:24px;"></div> - -<div class="pod-create" ng-class="{ 'hidden': ! auth.isAuthenticated }"> - <h4>Create</h4> - <div class="row"> - <div ng-repeat="require in ctrl.createRequirements"> - <div class="create-pod" style="margin-left:24px;"> - <p class="input-group"> - <label for="cpid">{{require.label|capitalize}}: </label> - <a ng-if="require.type == 'select'"> - <select dynamic-model="'ctrl.' + require.label" ng-options="option for option in require.selects"></select> - </a> - <a ng-if="require.type == 'text'"> - <input type="text" dynamic-model="'ctrl.' + require.label"/> - </a> - <a ng-if="require.type == 'textarea'"> - <textarea rows="2" cols="50" dynamic-model="'ctrl.' + require.label"> - </textarea> - </a> - </p> - </div> +<div cg-busy="{promise:ctrl.authRequest,message:'Loading'}"></div> +<div cg-busy="{promise:ctrl.podsRequest,message:'Loading'}"></div> +<br> +<div class="row podTable" style="vertical-align:middle"> + <div class="col-sm-1 pull-right" ng-class="{ 'hidden': !auth.isAuthenticated }" > + <button type="button" class="btn btn-danger" ng-click="ctrl.openBatchDeleteModal()"> + <i class="fa fa-minus"></i> Delete</button> </div> - - <div class="col-md-1" style="margin-top:12px;"> - <button type="submit" class="btn btn-primary" ng-click="ctrl.create()">Create</button> + <div class="col-sm-1 pull-right" ng-class="{ 'hidden': !auth.isAuthenticated }"> + <button type="button" class="btn btn-success" ng-click="ctrl.openCreateModal()"> + <i class="fa fa-plus"></i> Create</button> </div> - <div ng-show="ctrl.showError" class="col-md-11 alert alert-danger" role="alert"> - <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> - <span class="sr-only">Error:</span> - {{ctrl.error}} + <div class="col-sm-1 pull-right"> + <button type="button" class="btn btn-success" ng-click="ctrl.listPods()"> + <i class="fa fa-search"></i> Filter</button> </div> - <div ng-show="ctrl.showSuccess" class="col-md-11 alert alert-success" role="alert"> - <span class="glyphicon glyphicon-ok" aria-hidden="true"></span> - Create Success + <div class="col-sm-3 pull-right"> + <span style="margin-top:6px">Search: </span> + <input type="text" class="form-control search" ngModel="filter" placeholder="Search String"> + </div> + <div class="col-md-3 row pull-right"> + <span style="margin-top:6px">Filter: </span> + <select ng-model="ctrl.filter" class="form-control"> + <option value="name">Name</option> + <option value="owner">Owner</option> + </select> </div> - </div> </div> - -<div class="pods-filters" style="margin-top:36px;"> - <h4>Filters</h4> - <div class="row"> - <div class="col-md-3" style="margin-top:12px; margin-left:8px;"> - <button type="submit" class="btn btn-primary" ng-click="ctrl.update()">Filter</button> - <button type="submit" class="btn btn-primary btn-danger" ng-click="ctrl.clearFilters()">Clear</button> - </div> +<div class="col-md-12"> + <div ng-show="ctrl.showError" class="col-md-12 alert alert-danger" role="alert"> + <span class="pull-right"> {{ctrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <div ng-show="ctrl.showSuccess" class="col-md-12 alert alert-success" role="alert"> + <span class="pull-right"> {{ctrl.success}}</span> + <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> </div> </div> - -<div cg-busy="{promise:ctrl.authRequest,message:'Loading'}"></div> -<div cg-busy="{promise:ctrl.podsRequest,message:'Loading'}"></div> - -<div ng-show="ctrl.data" class="pods-table" style="margin-top:24px; margin-left:8px;"> - <table ng-data="ctrl.data.pods" ng-show="ctrl.data" class="table table-striped table-hover"> +<div class="col-md-12" style="padding-right:0px"> + <div class="table-responsive"> + <table class="table table-bordered table-hover" ng-data="ctrl.data.pods"> + <thead> + <tr style=" + text-align: center;"> + <th>Bulk Select</th> + <th>Name</th> + <th>Details</th> + <th>Role</th> + <th>Mode</th> + <th>CreatedAt</th> + <th>Operation</th> + </tr> + </thead> <tbody> - <tr ng-repeat-start="(index, pod) in ctrl.data.pods"> - <td> - <a href="#" ng-click="showPod = !showPod">{{pod.name}}</a> - <div class="show-pod" ng-class="{ 'hidden': ! showPod }" style="margin-left:24px;"> - <p> - owner: {{pod.owner}}<br> - role: {{pod.role}}<br> - mode: {{pod.mode}}<br> - create_date: {{pod.creation_date}}<br> - details: {{pod.details}} - </p> - </div> - </td> - </tr> - <tr ng-repeat-end=> - </tr> + <tr ng-repeat-start="(index, pod) in ctrl.data.pods" style="padding:9px"> + <td> + <div class="text-center"> + <input type="checkbox" value="{{pod.name}}" ng-model="ctrl.checkBox[index]" > + </div> + </td> + <td>{{pod.name}}</td> + <td style="width:20%;">{{pod.details}}</td> + <td>{{pod.role}}</td> + <td>{{pod.mode}}</td> + <td> + {{pod.creation_date}} + </td> + <td> + <span class="podTable-col"> + <a class="text-warning" title="Edit" ng-class="{ 'hidden': !auth.isAuthenticated }" > + <i class="fa fa-pencil-square-o"></i></a> + <a class="text-danger" ng-click="ctrl.openDeleteModal(pod.name)" title="Delete" ng-class="{ 'hidden': !auth.isAuthenticated }"> + <i class="fa fa-trash-o"></i></a> + <a class="text-info" ><i class="fa fa-eye"></i></a> + </span> + </td> + </tr> + <tr ng-repeat-end=> + </tr> </tbody> - </table> -</div> -<br> -<div ng-show="ctrl.showError" class="alert alert-danger" ng-class="{ 'hidden': auth.isAuthenticated }" role="alert"> - <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> - <span class="sr-only">Error:</span> - {{ctrl.error}} -</div> + </table> + </div> + </div> +</div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/pods/podsController.js b/testapi/opnfv_testapi/ui/components/pods/podsController.js index 9789cf2..fa60143 100644 --- a/testapi/opnfv_testapi/ui/components/pods/podsController.js +++ b/testapi/opnfv_testapi/ui/components/pods/podsController.js @@ -20,7 +20,8 @@ .controller('PodsController', PodsController); PodsController.$inject = [ - '$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert' + '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert', + 'confirmModal' ]; /** @@ -28,29 +29,23 @@ * This controller is for the '/pods' page where a user can browse * through pods declared in TestAPI. */ - function PodsController($scope, $http, $filter, $state, testapiApiUrl, - raiseAlert) { + function PodsController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, + raiseAlert, confirmModal) { var ctrl = this; ctrl.url = testapiApiUrl + '/pods'; + ctrl.checkBox = [] + ctrl.checkBoxList = []; ctrl.create = create; - ctrl.update = update; + ctrl.listPods = listPods; ctrl.open = open; + ctrl.filter = 'name' ctrl.clearFilters = clearFilters; - - ctrl.roles = ['community-ci', 'production-ci']; - ctrl.modes = ['metal', 'virtual']; - ctrl.createRequirements = [ - {label: 'name', type: 'text', required: true}, - {label: 'mode', type: 'select', selects: ctrl.modes}, - {label: 'role', type: 'select', selects: ctrl.roles}, - {label: 'details', type: 'textarea', required: false} - ]; - - ctrl.name = ''; - ctrl.role = 'community-ci'; - ctrl.mode = 'metal'; - ctrl.details = ''; + ctrl.openDeleteModal = openDeleteModal + ctrl.openBatchDeleteModal = openBatchDeleteModal + ctrl.openCreateModal = openCreateModal + ctrl.podDelete = podDelete + ctrl.batchDelete = batchDelete; /** * This is called when the date filter calendar is opened. It @@ -70,27 +65,29 @@ * listing. */ function clearFilters() { - ctrl.update(); + ctrl.listPods(); } /** * This will contact the TestAPI to create a new pod. */ - function create() { + function create(pod) { ctrl.showError = false; ctrl.showSuccess = false; - - if(ctrl.name != ""){ + console.log(pod); + if(pod.name != ""){ var pods_url = ctrl.url; var body = { - name: ctrl.name, - mode: ctrl.mode, - role: ctrl.role, - details: ctrl.details + name: pod.name, + mode: pod.mode, + role: pod.role, + details: pod.details }; ctrl.podsRequest = $http.post(pods_url, body).success(function (data) { ctrl.showSuccess = true ; + ctrl.success = "Create Success" + ctrl.listPods(); }).catch(function (data) { ctrl.showError = true; ctrl.error = "Error creating the new pod from server: " + data.statusText; @@ -105,11 +102,12 @@ /** * This will contact the TestAPI to get a listing of declared pods. */ - function update() { + function listPods() { ctrl.showError = false; ctrl.podsRequest = $http.get(ctrl.url).success(function (data) { ctrl.data = data; + // mapNametoRandom }).error(function (error) { ctrl.data = null; ctrl.showError = true; @@ -118,5 +116,148 @@ angular.toJson(error); }); } + + /** + * This will contact the TestAPI to delete a pod for given + * name. + */ + function podDelete(podName){ + var pods_url = ctrl.url + "/" + podName + $http.delete(pods_url).success(function(){ + ctrl.showSuccess = true ; + ctrl.success = "Delete Success" + ctrl.listPods(); + }).catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + /** + * This will delete list of pods. + */ + function batchDelete(){ + var index; + var checkedBox = []; + console.log(ctrl.checkBox) + for(index in ctrl.checkBox){ + if(!ctrl.showError){ + if(ctrl.checkBox[index]){ + podDelete(ctrl.data.pods[index].name); + } + } + } + ctrl.checkBox = [] + } + + /** + * This will open the modal that will show the batch delete confirm + * message + */ + function openBatchDeleteModal() { + confirmModal("Delete",ctrl.batchDelete); + } + + /** + * This will open the modal that will show the delete confirm + * message + */ + function openDeleteModal(name) { + console.log(name) + confirmModal("Delete", ctrl.podDelete, name); + } + + /** + * This will open the modal that will show the create + * view + */ + function openCreateModal(){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/pods/modals/createModal.html', + controller: 'PodModalCtrl as PodModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Create", + successHandler: ctrl.create, + }; + } + } + }); + } + + // function openUpdateModal(podName){ + // $uibModal.open({ + // templateUrl: 'testapi-ui/components/pods/modals/createModal.html', + // controller: 'PodModalCtrl as PodModalCtrl', + // size: 'md', + // resolve: { + // data: function () { + // return { + // text: "Update", + // successHandler: ctrl.update, + // // pod: ctrl. + // }; + // } + // } + // }); + // } + ctrl.listPods(); } + + + /** + * TestAPI Pod Modal Controller + * This controller is for the create modal where a user can create + * the project information and for the edit modal where user can + * edit the pods details + */ + angular.module('testapiApp').controller('PodModalCtrl', PodModalCtrl); + PodModalCtrl.$inject = ['$scope', '$uibModalInstance', 'data']; + function PodModalCtrl($scope, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + ctrl.roles = ['community-ci', 'production-ci']; + ctrl.modes = ['metal', 'virtual']; + ctrl.createRequirements = [ + {label: 'name', type: 'text', required: true}, + {label: 'mode', type: 'select', selects: ctrl.modes}, + {label: 'role', type: 'select', selects: ctrl.roles}, + {label: 'details', type: 'textarea', required: false} + ]; + ctrl.pod = { + name : '', + role : 'community-ci', + mode : 'metal', + details : '' + } + + if(ctrl.data.pod){ + ctrl.pod = ctrl.data.pod + } + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + $uibModalInstance.close(); + if (angular.isDefined(ctrl.data.successHandler)) { + ctrl.data.successHandler(ctrl.pod); + } + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + } + + })(); + diff --git a/testapi/opnfv_testapi/ui/index.html b/testapi/opnfv_testapi/ui/index.html index e15fff6..00c2b9c 100644 --- a/testapi/opnfv_testapi/ui/index.html +++ b/testapi/opnfv_testapi/ui/index.html @@ -27,7 +27,10 @@ <link rel="stylesheet" href="testapi-ui/assets/lib/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="testapi-ui/assets/lib/angular-busy/dist/angular-busy.min.css"> <link rel="stylesheet" href="testapi-ui/assets/css/style.css"> + <link rel="stylesheet" href="testapi-ui/assets/lib/font-awesome-4.7.0/css/font-awesome.min.css"> + <script src="testapi-ui/assets/lib/jquery/jquery-3.2.1.min.js"></script> + <script src="testapi-ui/assets/lib/bootstrap/dist/js/bootstrap.min.js"></script> <script src="testapi-ui/assets/lib/angular/angular.min.js"></script> <script src="testapi-ui/assets/lib/angular-ui-router/release/angular-ui-router.min.js"></script> <script src="testapi-ui/assets/lib/angular-resource/angular-resource.min.js"></script> diff --git a/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js b/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js index aba205e..fc0bfe6 100644 --- a/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js +++ b/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js @@ -11,7 +11,7 @@ * Opens confirm modal dialog with input textbox */ function confirmModal($uibModal) { - return function(text, successHandler) { + return function(text, successHandler, name) { $uibModal.open({ templateUrl: '/testapi-ui/shared/alerts/confirmModal.html', controller: 'CustomConfirmModalController as confirmModal', @@ -20,7 +20,8 @@ data: function () { return { text: text, - successHandler: successHandler + successHandler: successHandler, + name: name }; } } @@ -45,7 +46,7 @@ ctrl.cancel = cancel; ctrl.data = angular.copy(data); - + console.log(ctrl.data) /** * Initiate confirmation and call the success handler with the * input text. @@ -53,7 +54,7 @@ function confirm() { $uibModalInstance.close(); if (angular.isDefined(ctrl.data.successHandler)) { - ctrl.data.successHandler(ctrl.inputText); + ctrl.data.successHandler(ctrl.data.name); } } |