From 3e365ad8c2e13a66fb5c74da11bc6ac8709bf021 Mon Sep 17 00:00:00 2001 From: bfederle Date: Fri, 20 Jan 2012 14:30:24 -0800 Subject: [PATCH] bug 11798 (WIP) -Add UI for sticky policy -Create sticky policy functionality --- ui/css/cloudstack3.css | 28 ++++ ui/scripts-test/network.js | 138 +++++++++++++++++++- ui/scripts/network.js | 199 ++++++++++++++++++++++++++++- ui/scripts/sharedFunctions.js | 2 +- ui/scripts/ui/dialog.js | 68 +++++----- ui/scripts/ui/widgets/multiEdit.js | 48 +++++++ 6 files changed, 444 insertions(+), 39 deletions(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index d291e0bb6e4..eab5c3e3c39 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -5646,6 +5646,8 @@ div.panel.ui-dialog div.list-view div.fixed-header { -webkit-border-radius: 5px; -khtml-border-radius: 5px; border-radius: 5px 5px 5px 5px; + width: 74px; + text-align: center; padding: 6px 9px 4px 0px; background: url(../images/bg-gradients.png) repeat-x 0px -220px; /*+placement:shift 4px 0px;*/ @@ -5663,6 +5665,28 @@ div.panel.ui-dialog div.list-view div.fixed-header { box-shadow: inset 0px 1px 1px #000000; } +.multi-edit .button.custom-action { + background: url(../images/bg-gradients.png) 0px -271px; + border: 1px solid #B7B7B7; + color: #485867; + font-size: 11px; + /*+text-shadow:0px 1px #FFFFFF;*/ + -moz-text-shadow: 0px 1px #FFFFFF; + -webkit-text-shadow: 0px 1px #FFFFFF; + -o-text-shadow: 0px 1px #FFFFFF; + text-shadow: 0px 1px #FFFFFF; +} + +.multi-edit .button.custom-action:hover { + background: #808080 url(../images/bg-gradients.png); + color: #FFFFFF; + /*+text-shadow:0px 1px 1px #000000;*/ + -moz-text-shadow: 0px 1px 1px #000000; + -webkit-text-shadow: 0px 1px 1px #000000; + -o-text-shadow: 0px 1px 1px #000000; + text-shadow: 0px 1px 1px #000000; +} + .multi-edit-add-list .ui-button.ok, .multi-edit-add-list .ui-button.cancel { float: right; @@ -5791,6 +5815,10 @@ div.panel.ui-dialog div.list-view div.fixed-header { cursor: pointer; } +.multi-edit .data .data-body .data-item tr td .custom-action { + margin: -6px 0 0 -1px; +} + .multi-edit .data .data-body .data-item tr td.add-vm:hover { color: #0060FF; font-weight: bold; diff --git a/ui/scripts-test/network.js b/ui/scripts-test/network.js index 7613713f843..32cfca82e5b 100644 --- a/ui/scripts-test/network.js +++ b/ui/scripts-test/network.js @@ -21,7 +21,7 @@ vlan: { label: 'VLAN' } }, dataProvider: testData.dataProvider.listView('networks'), - + detailView: { name: 'Network details', viewAll: { path: 'network.ipAddresses', label: 'IP Addresses' }, @@ -513,6 +513,124 @@ }); } }, + 'sticky': { + label: 'Sticky Policy', + custom: { + buttonLabel: 'Configure', + action: function(args) { + var success = args.response.success; + var fields = { + method: { + label: 'Stickiness method', + select: function(args) { + var $select = args.$select; + var $form = $select.closest('form'); + + args.response.success({ + data: [ + { + id: 'none', + description: 'None' + }, + { + id: 'lb', + description: 'LB-based' + }, + { + id: 'cookie', + description: 'Cookie-based' + }, + { + id: 'source', + description: 'Source-based' + } + ] + }, 500); + + $select.change(function() { + var value = $select.val(); + var showFields = []; + + switch (value) { + case 'none': + showFields = []; + break; + case 'lb': + showFields = ['name', 'mode', 'nocache', 'indirect', 'postonly', 'domain']; + break; + case 'cookie': + showFields = ['name', 'length', 'holdtime', 'request-learn', 'prefix', 'mode']; + break; + case 'source': + showFields = ['tablesize', 'expire']; + break; + } + + $select.closest('.form-item').siblings('.form-item').each(function() { + var $field = $(this); + var id = $field.attr('rel'); + + if ($.inArray(id, showFields) > -1) { + $field.css('display', 'inline-block'); + } else { + $field.hide(); + } + }); + + $select.closest(':ui-dialog').dialog('option', 'position', 'center'); + }); + } + }, + name: { label: 'Name', validation: { required: true }, isHidden: true }, + mode: { label: 'Mode', isHidden: true }, + length: { label: 'Length', validation: { required: true }, isHidden: true }, + holdtime: { label: 'Hold Time', validation: { required: true }, isHidden: true }, + tablesize: { label: 'Table size', isHidden: true }, + expire: { label: 'Expire', isHidden: true }, + requestlearn: { label: 'Request-Learn', isBoolean: true, isHidden: true }, + prefix: { label: 'Prefix', isBoolean: true, isHidden: true }, + nocache: { label: 'No cache', isBoolean: true, isHidden: true }, + indirect: { label: 'Indirect', isBoolean: true, isHidden: true }, + postonly: { label: 'Is post-only', isBoolean: true, isHidden: true }, + domain: { label: 'Domain', isBoolean: true, isHidden: true } + }; + + if (args.data) { + var populatedFields = $.map(fields, function(field, id) { + return id; + }); + + $(populatedFields).each(function() { + var id = this; + var field = fields[id]; + var dataItem = args.data[id]; + + if (field.isBoolean) { + field.isChecked = dataItem ? true : false; + } else { + field.defaultValue = dataItem; + } + }); + } + + cloudStack.dialog.createForm({ + form: { + title: 'Configure Sticky Policy', + desc: 'Please complete the following fields', + fields: fields + }, + after: function(args) { + var data = cloudStack.serializeForm(args.$form); + success({ + data: $.extend(data, { + _buttonLabel: data.method.toUpperCase() + }) + }); + } + }); + } + } + }, 'add-vm': { label: 'Add VMs', addButton: true @@ -569,7 +687,17 @@ testData.data.instances[1], testData.data.instances[2], testData.data.instances[3] - ] + ], + sticky: { + _buttonLabel: 'lb'.toUpperCase(), + method: 'lb', + name: 'StickyTest', + mode: '123', + nocache: true, + indirect: false, + postonly: true, + domain: false + } } ] }); @@ -864,9 +992,9 @@ 'icmptype': { edit: true, label: 'ICMP Type', isHidden: true }, 'icmpcode': { edit: true, label: 'ICMP Code', isHidden: true }, 'cidr': { edit: true, label: 'CIDR', isHidden: true }, - 'accountname': { - edit: true, - label: 'Account, Security Group', + 'accountname': { + edit: true, + label: 'Account, Security Group', isHidden: true, range: ['accountname', 'securitygroupname'] }, diff --git a/ui/scripts/network.js b/ui/scripts/network.js index b0ef0852a14..a78a6adc015 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -1507,6 +1507,124 @@ }); } }, + 'sticky': { + label: 'Sticky Policy', + custom: { + buttonLabel: 'Configure', + action: function(args) { + var success = args.response.success; + var fields = { + methodname: { + label: 'Stickiness method', + select: function(args) { + var $select = args.$select; + var $form = $select.closest('form'); + + args.response.success({ + data: [ + { + id: 'none', + description: 'None' + }, + { + id: 'LbCookie', + description: 'LB-based' + }, + { + id: 'AppCookie', + description: 'Cookie-based' + }, + { + id: 'SourceBased', + description: 'Source-based' + } + ] + }, 500); + + $select.change(function() { + var value = $select.val(); + var showFields = []; + + switch (value) { + case 'none': + showFields = []; + break; + case 'LbCookie': + showFields = ['name', 'mode', 'nocache', 'indirect', 'postonly', 'domain']; + break; + case 'AppCookie': + showFields = ['name', 'length', 'holdtime', 'request-learn', 'prefix', 'mode']; + break; + case 'SourceBased': + showFields = ['tablesize', 'expire']; + break; + } + + $select.closest('.form-item').siblings('.form-item').each(function() { + var $field = $(this); + var id = $field.attr('rel'); + + if ($.inArray(id, showFields) > -1) { + $field.css('display', 'inline-block'); + } else { + $field.hide(); + } + }); + + $select.closest(':ui-dialog').dialog('option', 'position', 'center'); + }); + } + }, + name: { label: 'Name', validation: { required: true }, isHidden: true }, + mode: { label: 'Mode', isHidden: true }, + length: { label: 'Length', validation: { required: true }, isHidden: true }, + holdtime: { label: 'Hold Time', validation: { required: true }, isHidden: true }, + tablesize: { label: 'Table size', isHidden: true }, + expire: { label: 'Expire', isHidden: true }, + requestlearn: { label: 'Request-Learn', isBoolean: true, isHidden: true }, + prefix: { label: 'Prefix', isBoolean: true, isHidden: true }, + nocache: { label: 'No cache', isBoolean: true, isHidden: true }, + indirect: { label: 'Indirect', isBoolean: true, isHidden: true }, + postonly: { label: 'Is post-only', isBoolean: true, isHidden: true }, + domain: { label: 'Domain', isBoolean: true, isHidden: true } + }; + + if (args.data) { + var populatedFields = $.map(fields, function(field, id) { + return id; + }); + + $(populatedFields).each(function() { + var id = this; + var field = fields[id]; + var dataItem = args.data[id]; + + if (field.isBoolean) { + field.isChecked = dataItem ? true : false; + } else { + field.defaultValue = dataItem; + } + }); + } + + cloudStack.dialog.createForm({ + form: { + title: 'Configure Sticky Policy', + desc: 'Please complete the following fields', + fields: fields + }, + after: function(args) { + var data = cloudStack.serializeForm(args.$form); + success({ + data: $.extend(data, { + _buttonLabel: data.methodname.toUpperCase() + }) + }); + } + }); + } + } + }, 'add-vm': { label: 'Add VMs', addButton: true @@ -1516,13 +1634,20 @@ label: 'Add VMs', action: function(args) { var openFirewall = g_firewallRuleUiEnabled == "true" ? false : true; + var data = { + algorithm: args.data.algorithm, + name: args.data.name, + privateport: args.data.privateport, + publicport: args.data.publicport + }; + var stickyData = $.extend(true, {}, args.data.sticky); $.ajax({ url: createURL('createLoadBalancerRule'), - - data: $.extend(args.data, { + data: $.extend(data, { openfirewall: openFirewall, - publicipid: args.context.ipAddresses[0].id + publicipid: args.context.ipAddresses[0].id, + networkid: args.context.networks[0].id }), dataType: 'json', async: true, @@ -1547,7 +1672,73 @@ }, notification: { label: 'Add load balancer rule', - poll: pollAsyncJobResult + poll: function(args) { + var complete = args.complete; + var error = args.error; + + pollAsyncJobResult({ + _custom: args._custom, + complete: function(args) { + // Create stickiness policy + if (stickyData && stickyData.methodname != 'none') { + var stickyURLData = ''; + var stickyParams; + + switch (stickyData.methodname) { + case 'LbCookie': + stickyParams = ['name', 'mode', 'nocache', 'indirect', 'postonly', 'domain']; + break; + case 'AppCookie': + stickyParams = ['name', 'length', 'holdtime', 'request-learn', 'prefix', 'mode']; + break; + case 'SourceBased': + stickyParams = ['tablesize', 'expire']; + break; + } + + $(stickyParams).each(function(index) { + var param = '¶m[' + index + ']'; + var name = this; + var value = stickyData[name]; + + if (!value) return true; + if (value == 'on') value = true; + + stickyURLData += param + '.name=' + name + param + '.value=' + value; + }); + + $.ajax({ + url: createURL('createLBStickinessPolicy' + stickyURLData), + data: { + lbruleid: args.data.loadbalancer.id, + name: stickyData.name, + methodname: stickyData.methodname + }, + success: function(json) { + var addStickyCheck = setInterval(function() { + pollAsyncJobResult({ + _custom: { + jobId: json.createLBStickinessPolicy.jobid, + }, + complete: function(args) { + clearInterval(addStickyCheck); + complete(); + }, + error: function(args) { + clearInterval(addStickyCheck); + } + }); + }, 1000); + }, + error: error + }); + } else { + complete(); + } + }, + error: error + }); + } } }); }, diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index f6f5e5ce69e..4098615c5c9 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -56,7 +56,7 @@ var pollAsyncJobResult = function(args) { }); } else { - args.complete(); + args.complete({ data: json.queryasyncjobresultresponse.jobresult }); } } else if (result.jobstatus == 2) { // Failed diff --git a/ui/scripts/ui/dialog.js b/ui/scripts/ui/dialog.js index 9f32f732480..60b68401c91 100644 --- a/ui/scripts/ui/dialog.js +++ b/ui/scripts/ui/dialog.js @@ -36,30 +36,36 @@ .appendTo($form); // Render fields and events - $.each(args.form.fields, function(key, field) { + var fields = $.map(args.form.fields, function(value, key) { + return key; + }) + $(fields).each(function() { + var key = this; + var field = args.form.fields[key]; + var $formItem = $('
') - .addClass('form-item') - .attr({ rel: key }); + .addClass('form-item') + .attr({ rel: key }); - if (this.hidden || this.isHidden) $formItem.hide(); + if (field.hidden || field.isHidden) $formItem.hide(); $formItem.appendTo($form); // Label field var $name = $('
').addClass('name') - .appendTo($formItem) - .append( - $('