Add "add template" and "delete template" buttons to vitrage template

view.

Story: 2002701
Task: 22536

Depends-On: I156ec1665d98f247f01a1b0a5adaf26ab1eb09ce
Change-Id: If0cb54d7dfabda57491652c13ff203f6da982dba
This commit is contained in:
Niv Oppenhaim 2018-07-29 09:54:05 +00:00
parent 470ae7d22d
commit 4ae81c30d4
10 changed files with 225 additions and 8 deletions

View File

@ -0,0 +1,3 @@
---
features:
- Added buttons for adding and removing templates in the template view.

View File

@ -22,11 +22,12 @@ https://docs.openstack.org/horizon/latest/contributor/tutorials/plugin.html
While interactions with the service can be handled in the views.py,
isolating the logic is an established pattern in Horizon.
"""
from horizon.utils.memoized import memoized # noqa
import json
from keystoneauth1.identity.generic.token import Token
from keystoneauth1.session import Session
from openstack_dashboard.api import base
import tempfile
from vitrageclient import client as vitrage_client
import logging
@ -77,7 +78,22 @@ def rca(request, alarm_id, all_tenants='false'):
all_tenants=all_tenants)
def templates(request, template_id='all'):
def template_show(request, template_id='all'):
if template_id == 'all':
return vitrageclient(request).template.list()
return vitrageclient(request).template.show(template_id)
def template_delete(request, template_id):
return vitrageclient(request).template.delete(template_id)
def template_add(request):
template = json.loads(request.body)
type = template.get('type')
with tempfile.NamedTemporaryFile(suffix='.yaml') as temp:
temp.write(template.get('template'))
temp.flush()
temp.seek(0)
response = vitrageclient(request).template.add(temp.name, type)
return response

View File

@ -135,5 +135,24 @@ class Templates(generic.View):
The result is a template object.
"""
return vitrage.template_show(request, template_id)
return vitrage.templates(request, template_id)
@rest_utils.ajax()
def delete(self, request, template_id):
"""Delete a single template with the vitrage id.
:param template_id the id of the vitrage template
"""
return vitrage.template_delete(request, template_id)
@rest_utils.ajax()
def post(self, request, **kwargs):
"""Add a single template.
request.body holds template in format:
{template: template_string
type: template_type}
"""
return vitrage.template_add(request)

View File

@ -17,7 +17,9 @@
getTopology: getTopology,
getAlarms: getAlarms,
getRca: getRca,
getTemplates: getTemplates
getTemplates: getTemplates,
deleteTemplate: deleteTemplate,
addTemplate: addTemplate
};
return service;
@ -74,6 +76,21 @@
});
}
function deleteTemplate(template_id) {
return apiService.delete('/api/vitrage/template/'+template_id)
.catch(function () {
toastService.add('error', gettext('Unable to fetch the Vitrage Templates service.'));
});
}
function addTemplate(template, type) {
var temp = { 'template' : template, 'type': type }
return apiService.post('/api/vitrage/template/default/', temp)
.catch(function () {
toastService.add('error', gettext('Unable to fetch the Vitrage Templates service.'));
});
}
}
}());

View File

@ -0,0 +1,22 @@
<div class="template-container">
<div class="controls">
<i title="Close" class="fa fa-times" ng-click="templateList.closeModal()"></i>
</div>
<div style="margin:15px">
<h2>Select template type:</h2>
</div>
<form>
<div style="margin: 15px">
<select class="form-control form-control-lg" id="typeSelect">
<option selected="selected">Standard</option>
<option>Definition</option>
<option>Equivalence</option>
</select>
</div>
<div style="margin: 15px">
<button type="button" class="btn btn-primary" ng-click="templateList.submitModal()">
Submit
</button>
</div>
</form>
</div>

View File

@ -12,8 +12,10 @@
function show(modalOptions) {
modalInstance = $uibModal.open(modalOptions);
return modalInstance;
}
//resolves the promise modalInstance.result
function close() {
if(modalInstance) {
modalInstance.close();
@ -21,9 +23,18 @@
}
}
//rejects the promise modalInstance.result
function dismiss() {
if(modalInstance) {
modalInstance.dismiss();
modalInstance = null;
}
}
return {
show: show,
close: close
close: close,
dismiss: dismiss
}
}
})();

View File

@ -57,6 +57,34 @@
}
}
function deleteTemplate(template_id) {
if (vitrageAPI) {
return vitrageAPI.deleteTemplate(template_id)
.then(function (data) {
return data;
})
.catch(function (err) {
console.error(err);
}
);
}
}
function addTemplate(template, type) {
if (vitrageAPI) {
return vitrageAPI.addTemplate(template, type)
.then(function (data) {
return data;
})
.catch(function (err) {
console.error(err);
}
);
}
}
function getRootCauseAnalysis(alarm_id, adminState) {
if (vitrageAPI) {
@ -75,7 +103,9 @@
getTopology: getTopology,
getAlarms: getAlarms,
getRootCauseAnalysis: getRootCauseAnalysis,
getTemplates: getTemplates
getTemplates: getTemplates,
deleteTemplate: deleteTemplate,
addTemplate: addTemplate
};
}
})();

View File

@ -7,13 +7,85 @@
TemplateListController.$inject = ['$scope', 'modalSrv', 'vitrageTopologySrv'];
function TemplateListController($scope, modalSrv, vitrageTopologySrv) {
function TemplateListController($scope, modalSrv, vitrageTopologySrv)
{
var templateList = this;
templateList.templates = [];
templateList.itemplates = [];
$scope.STATIC_URL = STATIC_URL;
templateList.templates = [];
templateList.closeModal = function() {
if(templateList.file){
delete templateList.file.name;
}
modalSrv.dismiss();
}
templateList.submitModal = function() {
modalSrv.close();
}
templateList.uploadFile = function(file, errFile) {
if (file) {
var ending = file.name.split('.').pop();
if(ending !== 'yml' && ending !== 'yaml') {
horizon.toast.add("error", gettext("Invalid file type. Templates should be YAML files"));
delete file.name;
return;
}
var modalOptions = {
animation: true,
templateUrl: STATIC_URL + 'dashboard/project/components/templateAdd/templateAddOptions.html',
controller: 'TemplateListController',
controllerAs: 'templateList',
windowClass: 'modal-dialog-metadata',
resolve: {file: function() {
return file;
}}
};
templateList.file = file;
modalSrv.show(modalOptions).result.then(() => templateList.chooseType())
}
}
templateList.chooseType = function() {
var e = document.getElementById("typeSelect");
var type = e.options[e.selectedIndex].text.toLowerCase();
var file = templateList.file;
templateList.type = type;
if (type !== "standard" && type !== "definition" && type !== "equivalence") {
horizon.toast.add("error", gettext("Invalid type entered. Type is one of: standard, definition, equivalence"));
delete file.name;
return;
}
var r = new FileReader();
r.onload = function(e) {
var content = e.target.result;
vitrageTopologySrv.addTemplate(content, type).then(function(result){
getData();
})
.catch(function(){
horizon.toast.add("error",gettext("Unable to add template"));
return;
});
}
r.catch = function() {
horizon.toast.add("error",gettext("Unable to read file"));
delete file.name;
}
try{
r.readAsText(file);
}
catch(error){
horizon.toast.add("error",gettext("Unable to read file"));
delete file.name;
return;
}
}
getData();
function getData() {
@ -34,6 +106,15 @@
modalSrv.show(modalOptions);
}
templateList.onDeleteClick = function(template) {
vitrageTopologySrv.deleteTemplate(template.uuid).then(function(result){
getData();
})
.catch(function(){
horizon.toast.add("error", gettext("Unable to delete template"));
});
}
}
}

View File

@ -1,4 +1,16 @@
<div class="template-list" ng-controller="TemplateListController as templateList">
<div class="add-btn">
<button class="btn btn-primary"
type="file"
id="add-template"
ngf-select="templateList.uploadFile($file, $invalidFiles)"
ngf-max-height="1000"
accept="*"
ngf-max-size="1MB">
Add Template
</button>
</div>
<div class="panel panel-default">
<table st-table='templateList.itemplates' st-safe-src="templateList.templates" class="table-striped table-rsp table-detail modern"
@ -11,6 +23,7 @@
<th st-sort="details">{$ 'Details' | translate $}</th>
<th st-sort="timestamp">{$ 'Timestamp' | translate $}</th>
<th>{$ 'Show' | translate $}</th>
<th>{$ 'Delete' | translate $}</th>
</tr>
<tr>
<th colspan="5">
@ -26,8 +39,9 @@
<td>{$template.status$}</td>
<td>{$template.type$}</td>
<td>{$template["status details"]$}</td>
<td><i class="fa fa-clock-o"></i> {$template.date | date:"yyyy-MM-dd HH:mm:ss"$}</td>
<td><i class="fa fa-clock-o"></i> {$template.date | date:"yyyy-MM-dd hh:mm:ss"$}</td>
<td ng-click="templateList.onShowClick(template)"><i class="fa fa-list"></i></td>
<td ng-click="templateList.onDeleteClick(template)"><i class="fa fa-trash"></i></td>
</tr>
</tbody>
</table>

View File

@ -7,4 +7,8 @@
padding-left: 20px;
}
.add-btn{
padding-bottom: 15px;
}
}