[CLOUDSTACK-10293] Single view network ACL rules listing

The ACL rules editing/addition page is not user-friendly. Users are not able to see in a single view all of the detail of the ACL rule (they need to use a scroll bar on the horizontal). The problem becomes worse when there are a considerable number of rules. Therefore, we are proposing the following changes:

1- Instead of using the table to create new ACL, we can create a button like the one presented in attached pictures, where users can click, and then a modal popup would appear and users would be able to create the new ACL there. This is similar to the workings of the ACL edit button.
2 - Remove the ability to add new ACL via table where they are presented. All ACLs should be entered via the “New ACL” button. Therefore, the section “Add ACL” would be removed as well;
3 - Move the action section of the list ACL table to the most left position;

These changes would reduce the information in the table and facilitate users to add new rules and easily edit them as well.
This commit is contained in:
Rafael Weingärtner 2018-02-14 14:39:28 -02:00
parent f96398c127
commit 689715504c
19 changed files with 397 additions and 288 deletions

View File

@ -8391,7 +8391,6 @@ div.container div.panel div#details-tab-addloadBalancer.detail-group div.loadBal
border-right: 1px solid #CFC9C9;
height: 15px;
overflow: auto;
padding-right: 0;
}
.multi-edit .data .data-body .data-item > table tbody tr td span {
@ -8426,8 +8425,44 @@ div.container div.panel div#details-tab-addloadBalancer.detail-group div.loadBal
color: #0000FF;
}
.multi-edit .data .data-body .data-item table tbody tr td.multi-actions {
border-right: none;
div#details-tab-aclRules table.multi-edit tr th.number,
div#details-tab-aclRules div.data-item table tr td.number {
width: 45px !important;
min-width: 45px !important;
max-width: 45px !important;
}
div#details-tab-aclRules div.multi-edit table tr th.action,
div#details-tab-aclRules div.multi-edit table tr td.action {
width: 40px !important;
min-width: 40px !important;
max-width: 40px !important;
}
div#details-tab-aclRules div.multi-edit table tr th.protocol,
div#details-tab-aclRules div.multi-edit table tr td.protocol {
width: 50px !important;
min-width: 50px !important;
max-width: 50px !important;
}
div#details-tab-aclRules div.multi-edit table tr th.protocolnumber,
div#details-tab-aclRules div.multi-edit table tr td.protocolnumber {
width: 60px !important;
min-width: 60px !important;
max-width: 60px !important;
}
div#details-tab-aclRules div.multi-edit table tr th.startport, div#details-tab-aclRules div.multi-edit table tr td.startport,
div#details-tab-aclRules div.multi-edit table tr th.endport, div#details-tab-aclRules div.multi-edit table tr td.endport {
width: 70px !important;
min-width: 70px !important;
max-width: 70px !important;
}
div#details-tab-aclRules td.cidrlist span {
text-align: center;
width: 100%;
}
.multi-edit .data .data-body .data-item table tbody tr td.multi-actions .action {
@ -8548,17 +8583,18 @@ div.container div.panel div#details-tab-addloadBalancer.detail-group div.loadBal
.detail-view .multi-edit table tr th,
.detail-view .multi-edit table tr td {
width: 87px !important;
min-width: 87px !important;
max-width: 87px !important;
width: 84px !important;
min-width: 84px !important;
max-width: 84px !important;
font-size: 10px;
}
/* special case for 'Source CIDR' column - make it wide enough to fit a CIDR without ellipsizing*/
.detail-view .multi-edit table tr th.cidrlist,
.detail-view .multi-edit table tr td.cidrlist {
min-width: 112px !important;
max-width: 112px !important;
min-width: 118px !important;
max-width: 118px !important;
padding: 0 0 0 0;
}
.detail-view .multi-edit td.cidrlist input {
width: 85%;
@ -8615,9 +8651,9 @@ div.container div.panel div#details-tab-addloadBalancer.detail-group div.loadBal
/*Sortable*/
.multi-edit table tbody tr td.reorder,
.multi-edit table thead tr th.reorder {
width: 30px !important;
min-width: 30px !important;
max-width: 30px !important;
width: 16px !important;
min-width: 16px !important;
max-width: 16px !important;
}
/*Security Rules*/
@ -13037,7 +13073,7 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it
-khtml-border-radius: 10px;
border-radius: 10px;
border-radius: 10px 10px 10px 10px;
background-position: -74px -162px;
background-position: -82px -162px;
}
.moveDrag:hover .icon {
@ -13357,4 +13393,3 @@ div.panel.copy-template-destination-list div.list-view div.fixed-header{
.multi-edit-add-list .ui-button.copytemplatecancel {
left: 310px;
}

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "المشاريع",
"label.protocol": "Protocol",
"label.protocol.number": "Protocol Number",
"label.protocol.number.short" : "#Protocol",
"label.provider": "Provider",
"label.providers": "Providers",
"label.public": "Public",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "Routing",
"label.routing.host": "Routing Host",
"label.rule": "Rule",
"label.rule.number.short": "#Rule",
"label.rule.number": "Rule Number",
"label.rules": "Rules",
"label.running.vms": "Running VMs",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "Projectes",
"label.protocol": "Protocol",
"label.protocol.number": "Protocol Number",
"label.protocol.number.short" : "#Protocol",
"label.provider": "Provider",
"label.providers": "Proveïdors",
"label.public": "Public",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "Routing",
"label.routing.host": "Routing Host",
"label.rule": "Rule",
"label.rule.number.short": "#Rule",
"label.rule.number": "Rule Number",
"label.rules": "Rules",
"label.running.vms": "Running VMs",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "Projekte",
"label.protocol": "Protokoll",
"label.protocol.number": "Protokollnummer",
"label.protocol.number.short" : "#Protokoll",
"label.provider": "Anbieter",
"label.providers": "Anbieter",
"label.public": "Öffentlich",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "Routing",
"label.routing.host": "Routing Host",
"label.rule": "Regel",
"label.rule.number.short": "#Regel",
"label.rule.number": "Regelnummer",
"label.rules": "Regeln",
"label.running.vms": "Laufende VMs",

View File

@ -1316,6 +1316,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
"label.promiscuous.mode":"Promiscuous Mode",
"label.protocol":"Protocol",
"label.protocol.number":"Protocol Number",
"label.protocol.number.short" : "#Protocol",
"label.provider":"Provider",
"label.providers":"Providers",
"label.public":"Public",
@ -1467,6 +1468,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
"label.routing.host":"Routing Host",
"label.rule":"Rule",
"label.rule.number":"Rule Number",
"label.rule.number.short": "#Rule",
"label.rules":"Rules",
"label.running.vms":"Running VMs",
"label.s3.access_key":"Access Key",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "Proyectos",
"label.protocol": "Protocolo",
"label.protocol.number": "Número de Protocolo",
"label.protocol.number.short" : "#Protocolo",
"label.provider": "Proveedor",
"label.providers": "Proveedores",
"label.public": "Pública",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "Enrutamiento",
"label.routing.host": "Servidor de Routeo",
"label.rule": "Regla",
"label.rule.number.short": "#Regla",
"label.rule.number": "Número de Regla",
"label.rules": "Reglas",
"label.running.vms": "MVs corriendo",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "Projets",
"label.protocol": "Protocole",
"label.protocol.number": "Numéro Protocole",
"label.protocol.number.short" : "#Protocole",
"label.provider": "Fournisseur",
"label.providers": "Fournisseurs",
"label.public": "Publique",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "Routage",
"label.routing.host": "Hôte de routage",
"label.rule": "Règle",
"label.rule.number.short": "#Règle",
"label.rule.number": "Numéro règle",
"label.rules": "Règles",
"label.running.vms": "VMs actives",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "Projektek",
"label.protocol": "Protokol",
"label.protocol.number": "Protokoll szám",
"label.protocol.number.short" : "#Protocol",
"label.provider": "Szolgáltató",
"label.providers": "Szolgáltatók",
"label.public": "Publikus",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "Útvonalválasztás",
"label.routing.host": "Routing kiszolgáló",
"label.rule": "Rule",
"label.rule.number.short": "#Rule",
"label.rule.number": "Szabály szám",
"label.rules": "Szabályok",
"label.running.vms": "Futó VM-ek",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "Progetti",
"label.protocol": "Protocol",
"label.protocol.number": "Protocol Number",
"label.protocol.number.short" : "#Protocol",
"label.provider": "Provider",
"label.providers": "Fornitori",
"label.public": "Public",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "Routing",
"label.routing.host": "Routing Host",
"label.rule": "Rule",
"label.rule.number.short": "#Rule",
"label.rule.number": "Rule Number",
"label.rules": "Regole",
"label.running.vms": "Running VMs",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "プロジェクト",
"label.protocol": "プロトコル",
"label.protocol.number": "プロトコル番号",
"label.protocol.number.short" : "#Protocol",
"label.provider": "プロバイダー",
"label.providers": "プロバイダー",
"label.public": "パブリック",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "ルーティング",
"label.routing.host": "ルーティング ホスト",
"label.rule": "Rule",
"label.rule.number.short": "#Rule",
"label.rule.number": "規則番号",
"label.rules": "規則",
"label.running.vms": "実行中の VM",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "프로젝트",
"label.protocol": "프로토콜",
"label.protocol.number": "Protocol Number",
"label.protocol.number.short" : "#Protocol",
"label.provider": "Provider",
"label.providers": "제공자",
"label.public": "공개",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "라우팅",
"label.routing.host": "Routing Host",
"label.rule": "Rule",
"label.rule.number.short": "#Rule",
"label.rule.number": "Rule Number",
"label.rules": "규칙",
"label.running.vms": "실행중 VM",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "Prosjekter",
"label.protocol": "Protokoll",
"label.protocol.number": "Protokollnummer",
"label.protocol.number.short" : "#Protocol",
"label.provider": "Tilbyder",
"label.providers": "Tilbydere",
"label.public": "Offentlig",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "Ruting",
"label.routing.host": "Ruter Vert",
"label.rule": "Rule",
"label.rule.number.short": "#Regel",
"label.rule.number": "Regelnummer",
"label.rules": "Regler",
"label.running.vms": "Kjørende VMer",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "Projecten",
"label.protocol": "Protocol",
"label.protocol.number": "protocol nummer",
"label.protocol.number.short" : "#Protocol",
"label.provider": "Provider",
"label.providers": "Providers",
"label.public": "Publiek",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "Routing",
"label.routing.host": "routeer machine",
"label.rule": "Rule",
"label.rule.number.short": "#Rule",
"label.rule.number": "Regel Nummer",
"label.rules": "Regels",
"label.running.vms": "Draaiende VMs",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "Projekty",
"label.protocol": "Protokół",
"label.protocol.number": "Protocol Number",
"label.protocol.number.short" : "#Protocol",
"label.provider": "Provider",
"label.providers": "Dostawcy",
"label.public": "Pobliczny",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "Routing",
"label.routing.host": "Routing Host",
"label.rule": "Rule",
"label.rule.number.short": "#Rule",
"label.rule.number": "Rule Number",
"label.rules": "Zasady",
"label.running.vms": "Running VMs",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "Projetos",
"label.protocol": "Protocolo",
"label.protocol.number": "Número do Protocolo",
"label.protocol.number.short" : "#Protocolo",
"label.provider": "Provedor",
"label.providers": "Providers",
"label.public": "Público",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "Roteamento",
"label.routing.host": "Host de Roteamento",
"label.rule": "Regra",
"label.rule.number.short": "#Regra",
"label.rule.number": "Regra Número",
"label.rules": "Regras",
"label.running.vms": "VMs Rodando",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "Проекты",
"label.protocol": "Протокол",
"label.protocol.number": "Protocol Number",
"label.protocol.number.short" : "#Protocol",
"label.provider": "Поставщики",
"label.providers": "Поставщики",
"label.public": "Публичный",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "Маршрутизация",
"label.routing.host": "Routing Host",
"label.rule": "Rule",
"label.rule.number.short": "#Rule",
"label.rule.number": "Номер правила",
"label.rules": "Правила",
"label.running.vms": "Запущенные ВМ",

View File

@ -1278,6 +1278,7 @@ var dictionary = {
"label.projects": "项目",
"label.protocol": "协议",
"label.protocol.number": "协议编号",
"label.protocol.number.short" : "#Protocol",
"label.provider": "提供程序",
"label.providers": "提供程序",
"label.public": "公用",
@ -1427,6 +1428,7 @@ var dictionary = {
"label.routing": "正在路由",
"label.routing.host": "正在路由主机",
"label.rule": "规则",
"label.rule.number.short": "#Rule",
"label.rule.number": "规则编号",
"label.rules": "规则",
"label.running.vms": "正在运行的 VM",

View File

@ -79,7 +79,10 @@
});
}
var $actions = undefined;
if(options.editOptionsFirst){
$actions = $('<td>').addClass('multi-actions').appendTo($item.find('tr'));
}
// Setup columns
$.each(fields, function(fieldName, field) {
if (!field || (options.ignoreEmptyFields && !data[fieldName])) {
@ -160,8 +163,9 @@
}
if (!field.isPassword) {
$td.attr('title', data[fieldName]);
if (field.edit) {
// Edit fields append value of data
// Edit fields append value of data
if (field.range) {
var start = _s(data[field.range[0]]);
var end = _s(data[field.range[1]]);
@ -177,7 +181,6 @@
} else {
$td.append($('<span>').html(_s(data[fieldName])));
}
$td.attr('title', data[fieldName]);
}
} else if (field.isBoolean) {
var $checkbox = $('<input>');
@ -324,9 +327,9 @@
return true;
});
// Actions column
var $actions = $('<td>').addClass('multi-actions').appendTo($item.find('tr'));
if(!options.editOptionsFirst){
var $actions = $('<td>').addClass('multi-actions').appendTo($item.find('tr'));
}
// Align action column width
$actions.width($multi.find('th.multi-actions').width() + 4);
@ -905,16 +908,20 @@
var $thead = $('<tr>').appendTo(
$('<thead>').appendTo($inputTable)
);
var $inputForm = $('<tr>').appendTo(
$('<tbody>').appendTo($inputTable)
);
if (!args.doNotShowInputTable){
var $inputForm = $('<tr>').appendTo(
$('<tbody>').appendTo($inputTable)
);
}
var $dataBody = $('<div>').addClass('data-body').appendTo($dataTable);
// Setup input table headers
if (reorder) {
$('<th>').addClass('reorder').appendTo($thead);
$('<td>').addClass('reorder').appendTo($inputForm);
if (!args.doNotShowInputTable){
$('<td>').addClass('reorder').appendTo($inputForm);
}
$multi.find('.data-body').sortable({
handle: '.action.moveDrag',
@ -946,6 +953,13 @@
});
}
if (args.editOptionsFirst && args.actions && !args.noHeaderActionsColumn) {
$thead.append($('<th></th>').html(_l('label.actions')).addClass('multi-actions'));
if (!args.doNotShowInputTable){
$inputForm.append($('<td></td>').addClass('multi-actions'));
}
}
$.each(args.fields, function(fieldName, field) {
if (!field) return true;
@ -954,7 +968,10 @@
$th.appendTo($thead);
var $td = $('<td>').addClass(fieldName);
$td.attr('rel', fieldName);
$td.appendTo($inputForm);
if (!args.doNotShowInputTable){
$td.appendTo($inputForm);
}
var isHidden = $.isFunction(field.isHidden) ?
field.isHidden({ context: context }) : field.isHidden;
@ -1071,7 +1088,10 @@
).appendTo($td);
}
if (field.desc) $input.attr('title', field.desc);
if (field.desc){
$input.attr('title', field.desc);
$th.attr('title', _l(field.desc));
}
});
// Setup header fields
@ -1093,134 +1113,137 @@
.prependTo($multi);
}
if (args.actions && !args.noHeaderActionsColumn) {
if (!args.editOptionsFirst && args.actions && !args.noHeaderActionsColumn) {
$thead.append($('<th></th>').html(_l('label.actions')).addClass('multi-actions'));
$inputForm.append($('<td></td>').addClass('multi-actions'));
if (!args.doNotShowInputTable){
$inputForm.append($('<td></td>').addClass('multi-actions'));
}
}
if($addVM){
$addVM.bind('click', function() {
// Validate form first
if (!$multiForm.valid()) {
if ($multiForm.find('input.error:visible').size()) {
return false;
}
}
var $dataList;
var addItem = function(itemData) {
var data = {};
$.each(getMultiData($multi), function(key, value) {
if (value != '') {
data[key] = value;
}
});
// Append custom data
var $customFields = $multi.find('tbody td').filter(function() {
return $(this).data('multi-custom-data');
});
$customFields.each(function() {
var $field = $(this);
var fieldID = $field.attr('rel');
var fieldData = $field.data('multi-custom-data');
data[fieldID] = fieldData;
});
// Loading appearance
var $loading = _medit.loadingItem($multi, _l('label.adding') + '...');
$dataBody.prepend($loading);
// Clear out fields
$multi.find('input').each(function() {
var $input = $(this);
if ($input.is(":checkbox")) {
$input.attr({
checked: false
});
} else if ($input.data('multi-default-value')) {
$input.val($input.data('multi-default-value'));
} else {
$input.val('');
}
});
$multi.find('tbody td').each(function() {
var $item = $(this);
if ($item.data('multi-custom-data')) {
$item.data('multi-custom-data', null);
}
});
// Apply action
args.add.action({
context: context,
data: data,
itemData: itemData,
$multi: $multi,
response: {
success: function(successArgs) {
var notification = successArgs ? successArgs.notification : null;
if (notification) {
$('.notifications').notifications('add', {
section: 'network',
desc: notification.label,
interval: 3000,
_custom: successArgs._custom,
poll: function(pollArgs) {
var complete = pollArgs.complete;
var error = pollArgs.error;
notification.poll({
_custom: pollArgs._custom,
complete: function(completeArgs) {
complete(args);
$loading.remove();
getData();
},
error: function(args) {
error(args);
$loading.remove();
return cloudStack.dialog.error(args);
}
});
}
});
} else {
$loading.remove();
getData();
}
},
error: cloudStack.dialog.error(function() {
$loading.remove();
})
}
});
};
if (args.noSelect) {
// Don't append instance data
addItem([]);
return true;
}
_medit.vmList($multi,
args.listView,
args.context,
multipleAdd, _l('label.add.vms'),
addItem);
return true;
});
}
$addVM.bind('click', function() {
// Validate form first
if (!$multiForm.valid()) {
if ($multiForm.find('input.error:visible').size()) {
return false;
}
}
var $dataList;
var addItem = function(itemData) {
var data = {};
$.each(getMultiData($multi), function(key, value) {
if (value != '') {
data[key] = value;
}
});
// Append custom data
var $customFields = $multi.find('tbody td').filter(function() {
return $(this).data('multi-custom-data');
});
$customFields.each(function() {
var $field = $(this);
var fieldID = $field.attr('rel');
var fieldData = $field.data('multi-custom-data');
data[fieldID] = fieldData;
});
// Loading appearance
var $loading = _medit.loadingItem($multi, _l('label.adding') + '...');
$dataBody.prepend($loading);
// Clear out fields
$multi.find('input').each(function() {
var $input = $(this);
if ($input.is(":checkbox")) {
$input.attr({
checked: false
});
} else if ($input.data('multi-default-value')) {
$input.val($input.data('multi-default-value'));
} else {
$input.val('');
}
});
$multi.find('tbody td').each(function() {
var $item = $(this);
if ($item.data('multi-custom-data')) {
$item.data('multi-custom-data', null);
}
});
// Apply action
args.add.action({
context: context,
data: data,
itemData: itemData,
$multi: $multi,
response: {
success: function(successArgs) {
var notification = successArgs ? successArgs.notification : null;
if (notification) {
$('.notifications').notifications('add', {
section: 'network',
desc: notification.label,
interval: 3000,
_custom: successArgs._custom,
poll: function(pollArgs) {
var complete = pollArgs.complete;
var error = pollArgs.error;
notification.poll({
_custom: pollArgs._custom,
complete: function(completeArgs) {
complete(args);
$loading.remove();
getData();
},
error: function(args) {
error(args);
$loading.remove();
return cloudStack.dialog.error(args);
}
});
}
});
} else {
$loading.remove();
getData();
}
},
error: cloudStack.dialog.error(function() {
$loading.remove();
})
}
});
};
if (args.noSelect) {
// Don't append instance data
addItem([]);
return true;
}
_medit.vmList($multi,
args.listView,
args.context,
multipleAdd, _l('label.add.vms'),
addItem);
return true;
});
var listView = args.listView;
var editOptionsFirst = args.editOptionsFirst;
var getData = function() {
dataProvider({
context: context,
@ -1247,7 +1270,8 @@
listView: listView,
tags: tags,
reorder: reorder,
selectPermission: selectPermission
selectPermission: selectPermission,
editOptionsFirst: editOptionsFirst
}
).appendTo($dataBody);
});

View File

@ -190,63 +190,14 @@
};
};
var aclMultiEdit = {
noSelect: true,
reorder: {
moveDrag: {
action: function(args) {
var rule = args.context.multiRule[0];
var number = 0;
var prevItem = args.prevItem ? args.prevItem.number : null;
var nextItem = args.nextItem ? args.nextItem.number : null;
if (!nextItem) { // Last item
number = prevItem + 100;
} else {
if (nextItem - prevItem <= 10) {
number = nextItem - parseInt(((nextItem - prevItem) / 2));
} else {
number = nextItem > 1 ? nextItem - 10 : 1;
}
}
$.ajax({
url: createURL('updateNetworkACLItem'),
data: {
id: rule.id,
number: number
},
success: function(json) {
var pollTimer = setInterval(function() {
pollAsyncJobResult({
_custom: {
jobId: json.createnetworkaclresponse.jobid
},
complete: function() {
clearInterval(pollTimer);
args.response.success();
},
error: function(errorMsg) {
clearInterval(pollTimer);
args.response.error(errorMsg);
}
});
}, 1000);
}
});
}
}
},
fields: {
var aclRuleFields = {
'number': {
label: 'label.rule.number',
label: 'label.rule.number.short',
desc: 'label.rule.number',
edit: true,
isEditable: true
},
'cidrlist': {
edit: true,
label: 'label.cidr',
@ -322,6 +273,13 @@
$portFields.hide();
} else if ($(this).val() == 'all') {
$portFields.hide();
$portFields.attr('disabled', 'disabled');
$icmpFields.hide();
$icmpFields.attr('disabled', 'disabled');
$protocolFields.attr('disabled', 'disabled');
$protocolFields.hide();
} else {
$otherFields.show();
$icmpFields.hide();
@ -378,8 +336,14 @@
$otherFields.hide();
$otherFields.parent().find('label.error').hide();
} else if ($(this).val() == 'all') {
$portFields.attr('disabled', 'disabled');
$portFields.hide();
$portFields.attr('disabled', 'disabled');
$icmpFields.hide();
$icmpFields.attr('disabled', 'disabled');
$protocolFields.hide();
$protocolFields.attr('disabled', 'disabled');
} else {
$otherFields.show();
$otherFields.parent().find('label.error').hide();
@ -420,7 +384,8 @@
},
'protocolnumber': {
label: 'label.protocol.number',
label: 'label.protocol.number.short',
desc: 'label.protocol.number',
edit: true,
isEditable: true
},
@ -436,6 +401,38 @@
isOptional: true,
isEditable: true
},
'icmptype': {
edit: true,
label: 'ICMP.type',
desc: 'Please specify -1 if you want to allow all ICMP types',
defaultValue: '-1',
isEditable: true
},
'icmpcode': {
edit: true,
label: 'ICMP.code',
desc: 'Please specify -1 if you want to allow all ICMP codes',
defaultValue: '-1',
isEditable: true
},
'traffictype': {
label: 'label.traffic.type',
isEditable: true,
select: function(args) {
args.response.success({
data: [{
name: 'Ingress',
description: 'Ingress'
}, {
name: 'Egress',
description: 'Egress'
}]
});
}
}
};
var aclRuleFieldsForMultiEdit = {
'networkid': {
label: 'label.select.tier',
select: function(args) {
@ -472,43 +469,60 @@
});
}
},
'icmptype': {
edit: true,
label: 'ICMP.type',
isDisabled: true,
desc: 'Please specify -1 if you want to allow all ICMP types',
defaultValue: '-1',
isEditable: true
},
'icmpcode': {
edit: true,
label: 'ICMP.code',
isDisabled: true,
desc: 'Please specify -1 if you want to allow all ICMP codes',
defaultValue: '-1',
isEditable: true
},
'traffictype': {
label: 'label.traffic.type',
isEditable: true,
select: function(args) {
args.response.success({
data: [{
name: 'Ingress',
description: 'Ingress'
}, {
name: 'Egress',
description: 'Egress'
}]
};
jQuery.extend(aclRuleFieldsForMultiEdit, aclRuleFields);
var aclMultiEdit = {
doNotShowInputTable: true,
editOptionsFirst: true,
noSelect: true,
reorder: {
moveDrag: {
action: function(args) {
var rule = args.context.multiRule[0];
var number = 0;
var prevItem = args.prevItem ? args.prevItem.number : null;
var nextItem = args.nextItem ? args.nextItem.number : null;
if (!nextItem) { // Last item
number = prevItem + 100;
} else {
if (nextItem - prevItem <= 10) {
number = nextItem - parseInt(((nextItem - prevItem) / 2));
} else {
number = nextItem > 1 ? nextItem - 10 : 1;
}
}
$.ajax({
url: createURL('updateNetworkACLItem'),
data: {
id: rule.id,
number: number
},
success: function(json) {
var pollTimer = setInterval(function() {
pollAsyncJobResult({
_custom: {
jobId: json.createnetworkaclresponse.jobid
},
complete: function() {
clearInterval(pollTimer);
args.response.success();
},
error: function(errorMsg) {
clearInterval(pollTimer);
args.response.error(errorMsg);
}
});
}, 1000);
}
});
}
},
'add-rule': {
label: 'label.add.rule',
addButton: true
}
},
fields: aclRuleFieldsForMultiEdit,
tags: cloudStack.api.tags({
resourceType: 'NetworkACL',
contextId: 'multiRule'
@ -983,32 +997,6 @@
});
}
},
/*
rules: {
title: 'label.rules',
multiple: true,
fields: [
{
sourceport: { label: 'Source Port' },
instanceport: { label: 'Instance Port' }
}
],
dataProvider: function(args) {
$.ajax({
url: createURL('listLoadBalancers'),
data: {
id: args.context.internalLoadBalancers[0].id
},
success: function(json) {
var item = json.listloadbalancersresponse.loadbalancer[0];
args.response.success({ data: item.loadbalancerrule });
}
});
}
},
*/
assignedVms: {
title: 'label.assigned.vms',
listView: {
@ -1333,35 +1321,65 @@
$.ajax({
url: createURL('listNetworkACLs&aclid=' + args.context.aclLists[0].id),
success: function(json) {
var items = json.listnetworkaclsresponse.networkacl.sort(function(a, b) {
return a.number >= b.number;
}).map(function(acl) {
if (parseInt(acl.protocol)) { // protocol number
acl.protocolnumber = acl.protocol;
acl.protocol = "protocolnumber";
}
var items = json.listnetworkaclsresponse.networkacl;
return acl;
});
if(items){
items.sort(function(a, b) {
return a.number >= b.number;
}).map(function(acl) {
if (parseInt(acl.protocol)) { // protocol number
acl.protocolnumber = acl.protocol;
acl.protocol = "protocolnumber";
}
return acl;
});
}
args.response.success({
data: items
/* {
cidrlist: '10.1.1.0/24',
protocol: 'TCP',
startport: 22, endport: 22,
networkid: 0,
traffictype: 'Egress'
},
{
cidrlist: '10.2.1.0/24',
protocol: 'UDP',
startport: 56, endport: 72,
networkid: 0,
trafficType: 'Ingress'
}
]*/
});
if(jQuery('#details-tab-aclRules').siblings('div.toolbar').children('div.add').size() === 0){
var $addAclRuleDivButton = jQuery('<div>').addClass('button add');
var $spanAddAclRuleButtonMessage = jQuery('<span>').html(_l('label.add.ACL'));
$addAclRuleDivButton.html($spanAddAclRuleButtonMessage);
$addAclRuleDivButton.click(function(){
cloudStack.dialog.createForm({
form: {
title: 'label.add.rule',
desc: 'Create a new ACL rule',
fields: aclRuleFields
},
after: function(argsLocal) {
var data = argsLocal.data;
data.aclid = argsLocal.context.aclLists[0].id;
if(data.protocol != 'icmp'){
data.icmpcode = undefined;
data.icmptype = undefined;
}
if(data.protocol != 'protocolnumber'){
data.protocolnumber = undefined;
}
if(data.protocol === 'all'){
data.startport = undefined;
data.endport = undefined;
}
$.ajax({
url: createURL('createNetworkACL'),
data: argsLocal.data,
type: "POST",
success: function(json) {
jQuery('button.cancel:visible').click();
jQuery('div.toolbar:visible div.refresh').click();
}
});
},
context: args.context
});
});
jQuery('#details-tab-aclRules').siblings('div.toolbar').append($addAclRuleDivButton);
}
}
});
}