From 689715504c84dce65e3f9d5f834cd01e5284bad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Weing=C3=A4rtner?= Date: Wed, 14 Feb 2018 14:39:28 -0200 Subject: [PATCH] [CLOUDSTACK-10293] Single view network ACL rules listing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- ui/css/cloudstack3.css | 61 ++++-- ui/l10n/ar.js | 2 + ui/l10n/ca.js | 2 + ui/l10n/de_DE.js | 2 + ui/l10n/en.js | 2 + ui/l10n/es.js | 2 + ui/l10n/fr_FR.js | 2 + ui/l10n/hu.js | 2 + ui/l10n/it_IT.js | 2 + ui/l10n/ja_JP.js | 2 + ui/l10n/ko_KR.js | 2 + ui/l10n/nb_NO.js | 2 + ui/l10n/nl_NL.js | 2 + ui/l10n/pl.js | 2 + ui/l10n/pt_BR.js | 2 + ui/l10n/ru_RU.js | 2 + ui/l10n/zh_CN.js | 2 + ui/scripts/ui/widgets/multiEdit.js | 300 ++++++++++++++++------------- ui/scripts/vpc.js | 292 +++++++++++++++------------- 19 files changed, 397 insertions(+), 288 deletions(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 519778ba59b..9b4e7638001 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -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; } - diff --git a/ui/l10n/ar.js b/ui/l10n/ar.js index 3b560a86e72..8bd2d031215 100644 --- a/ui/l10n/ar.js +++ b/ui/l10n/ar.js @@ -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", diff --git a/ui/l10n/ca.js b/ui/l10n/ca.js index f6ae80f81f3..3ee21729151 100644 --- a/ui/l10n/ca.js +++ b/ui/l10n/ca.js @@ -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", diff --git a/ui/l10n/de_DE.js b/ui/l10n/de_DE.js index 934f8f98c09..7ae796fe499 100644 --- a/ui/l10n/de_DE.js +++ b/ui/l10n/de_DE.js @@ -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", diff --git a/ui/l10n/en.js b/ui/l10n/en.js index 7b19946b1ed..02b8c79acbf 100644 --- a/ui/l10n/en.js +++ b/ui/l10n/en.js @@ -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", diff --git a/ui/l10n/es.js b/ui/l10n/es.js index 35257d47989..d125ad2af48 100644 --- a/ui/l10n/es.js +++ b/ui/l10n/es.js @@ -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", diff --git a/ui/l10n/fr_FR.js b/ui/l10n/fr_FR.js index 9935a818021..99ec18bd795 100644 --- a/ui/l10n/fr_FR.js +++ b/ui/l10n/fr_FR.js @@ -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", diff --git a/ui/l10n/hu.js b/ui/l10n/hu.js index 912ecf9a49d..e84800da55c 100644 --- a/ui/l10n/hu.js +++ b/ui/l10n/hu.js @@ -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", diff --git a/ui/l10n/it_IT.js b/ui/l10n/it_IT.js index f725584e08b..3dd7f35a5f5 100644 --- a/ui/l10n/it_IT.js +++ b/ui/l10n/it_IT.js @@ -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", diff --git a/ui/l10n/ja_JP.js b/ui/l10n/ja_JP.js index 40cf38fd857..ce8967298b6 100644 --- a/ui/l10n/ja_JP.js +++ b/ui/l10n/ja_JP.js @@ -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", diff --git a/ui/l10n/ko_KR.js b/ui/l10n/ko_KR.js index f6980bc067e..e60e0a95b7f 100644 --- a/ui/l10n/ko_KR.js +++ b/ui/l10n/ko_KR.js @@ -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", diff --git a/ui/l10n/nb_NO.js b/ui/l10n/nb_NO.js index 28cd09c3b9a..08a077c8e99 100644 --- a/ui/l10n/nb_NO.js +++ b/ui/l10n/nb_NO.js @@ -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", diff --git a/ui/l10n/nl_NL.js b/ui/l10n/nl_NL.js index 4508241ad30..0481297711d 100644 --- a/ui/l10n/nl_NL.js +++ b/ui/l10n/nl_NL.js @@ -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", diff --git a/ui/l10n/pl.js b/ui/l10n/pl.js index 30c04b9ff75..55b1b72b33d 100644 --- a/ui/l10n/pl.js +++ b/ui/l10n/pl.js @@ -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", diff --git a/ui/l10n/pt_BR.js b/ui/l10n/pt_BR.js index ccfa59ae7d3..42051e20755 100644 --- a/ui/l10n/pt_BR.js +++ b/ui/l10n/pt_BR.js @@ -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", diff --git a/ui/l10n/ru_RU.js b/ui/l10n/ru_RU.js index 6a11b38a0f7..8ced34c3e06 100644 --- a/ui/l10n/ru_RU.js +++ b/ui/l10n/ru_RU.js @@ -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": "Запущенные ВМ", diff --git a/ui/l10n/zh_CN.js b/ui/l10n/zh_CN.js index dc44fdb9a96..b755356115e 100644 --- a/ui/l10n/zh_CN.js +++ b/ui/l10n/zh_CN.js @@ -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", diff --git a/ui/scripts/ui/widgets/multiEdit.js b/ui/scripts/ui/widgets/multiEdit.js index c3fa97c8fc1..36e3ffb4c90 100755 --- a/ui/scripts/ui/widgets/multiEdit.js +++ b/ui/scripts/ui/widgets/multiEdit.js @@ -79,7 +79,10 @@ }); } - + var $actions = undefined; + if(options.editOptionsFirst){ + $actions = $('').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($('').html(_s(data[fieldName]))); } - $td.attr('title', data[fieldName]); } } else if (field.isBoolean) { var $checkbox = $(''); @@ -324,9 +327,9 @@ return true; }); - // Actions column - var $actions = $('').addClass('multi-actions').appendTo($item.find('tr')); - + if(!options.editOptionsFirst){ + var $actions = $('').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 = $('').appendTo( $('').appendTo($inputTable) ); - var $inputForm = $('').appendTo( - $('').appendTo($inputTable) - ); + if (!args.doNotShowInputTable){ + var $inputForm = $('').appendTo( + $('').appendTo($inputTable) + ); + } var $dataBody = $('
').addClass('data-body').appendTo($dataTable); // Setup input table headers if (reorder) { $('').addClass('reorder').appendTo($thead); - $('').addClass('reorder').appendTo($inputForm); + if (!args.doNotShowInputTable){ + $('').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($('').html(_l('label.actions')).addClass('multi-actions')); + if (!args.doNotShowInputTable){ + $inputForm.append($('').addClass('multi-actions')); + } + } + $.each(args.fields, function(fieldName, field) { if (!field) return true; @@ -954,7 +968,10 @@ $th.appendTo($thead); var $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($('').html(_l('label.actions')).addClass('multi-actions')); - $inputForm.append($('').addClass('multi-actions')); + if (!args.doNotShowInputTable){ + $inputForm.append($('').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); }); diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index 14e41af2b23..40c954f5d00 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -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('
').addClass('button add'); + var $spanAddAclRuleButtonMessage = jQuery('').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); + } } }); }