diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index f62b17e10d9..298cbccccd6 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -347,8 +347,8 @@ table th div.ui-resizable-handle { } .no-split tbody { - height: 570px; - padding-top: 30px; + height: 520px; + padding-top: 58px; } .horizontal-overflow tbody td, .horizontal-overflow thead th { @@ -359,6 +359,21 @@ table th div.ui-resizable-handle { overflow: auto; } +.groupable-header { + background: url(../images/bg-table-head.png); + border-left: 1px solid #C6C3C3; + border-right: 1px solid #C6C3C3; +} + +.groupable-header-columns th { + border: none; +} + +.groupable-header-border { + border-left: 1px solid #C6C3C3; + border-right: 1px solid #C6C3C3; +} + /** Header, misc*/ #template { display: none; diff --git a/ui/scripts/metrics.js b/ui/scripts/metrics.js index 6bf3fd40370..a5269b9df73 100644 --- a/ui/scripts/metrics.js +++ b/ui/scripts/metrics.js @@ -55,28 +55,52 @@ label: 'label.hosts' }, cpuused: { - label: 'Avg CPU Used' - }, - cpumaxdev: { - label: 'CPU Used Max Dev' + label: 'label.cpu.used', + collapsible: true, + columns: { + cpuusedavg: { + label: 'label.cpu.used.avg', + }, + cpumaxdev: { + label: 'label.cpu.max.dev' + } + } }, cpuallocated: { - label: 'CPU Allocated' - }, - cputotal: { - label: 'Total CPU Ghz' + label: 'label.cpu.allocated', + collapsible: true, + columns: { + cpuallocated: { + label: 'label.allocated' + }, + cputotal: { + label: 'label.cpu.total' + } + } }, memused: { - label: 'Avg Memory Used' - }, - memmaxdev: { - label: 'Memory Used Max Dev' + label: 'label.mem.used', + collapsible: true, + columns: { + memusedavg: { + label: 'label.mem.used.avg' + }, + memmaxdev: { + label: 'label.mem.max.dev' + } + } }, memallocated: { - label: 'Memory Allocated' - }, - memtotal: { - label: 'Total Memory GB' + label: 'label.mem.allocated', + collapsible: true, + columns: { + memallocated: { + label: 'label.allocated' + }, + memtotal: { + label: 'label.mem.total' + } + } } }, dataProvider: function(args) { @@ -93,18 +117,18 @@ data: {clusterid: cluster.id}, success: function(json) { items[idx].hosts = json.listhostsresponse.count; - items[idx].cpuused = 0.0; + items[idx].cpuusedavg = 0.0; items[idx].cpumaxdev = 0.0; items[idx].cpuallocated = 0.0; items[idx].cputotal = 0.0; - items[idx].memused = 0.0; + items[idx].memusedavg = 0.0; items[idx].memmaxdev = 0.0; items[idx].memallocated = 0.0; items[idx].memtotal = 0.0; var maxCpuUsed = 0.0; $.each(json.listhostsresponse.host, function(i, host) { if (host.hasOwnProperty('cpuused')) { - items[idx].cpuused += host.cpuused; + items[idx].cpuusedavg += host.cpuused; if (host.cpuused > maxCpuUsed) { maxCpuUsed = host.cpuused; } @@ -116,7 +140,7 @@ }); - items[idx].cpuused = 100.0 * items[idx].cpuused / items[idx].hosts; + items[idx].cpuusedavg = 100.0 * items[idx].cpuusedavg / items[idx].hosts; items[idx].cpuallocated = (items[idx].cpuallocated / items[idx].hosts).toFixed(2); }, async: false @@ -134,7 +158,8 @@ hideSearchBar: true, needsRefresh: true, noSplit: true, - horizontalOverflow: true + horizontalOverflow: true, + groupableColumns: true } }; diff --git a/ui/scripts/ui/widgets/dataTable.js b/ui/scripts/ui/widgets/dataTable.js index 7e02eca74e1..946ab076da2 100644 --- a/ui/scripts/ui/widgets/dataTable.js +++ b/ui/scripts/ui/widgets/dataTable.js @@ -143,12 +143,12 @@ var sortTable = function(columnIndex) { var direction = 'asc'; - if ($table.find('thead th').hasClass('sorted ' + direction)) { + if ($table.find('thead tr:last th').hasClass('sorted ' + direction)) { direction = 'desc'; } - $table.find('thead th').removeClass('sorted desc asc'); - $($table.find('thead th')[columnIndex]).addClass('sorted').addClass(direction); + $table.find('thead tr:last th').removeClass('sorted desc asc'); + $($table.find('thead tr:last th')[columnIndex]).addClass('sorted').addClass(direction); var $elems = $table.find('tbody td').filter(function() { return $(this).index() == columnIndex; @@ -242,7 +242,7 @@ $table.find('th:not(:has(input))').bind('mousemove mouseout', hoverResizableEvent); $table.find('th:not(:has(input))').bind('mousedown mousemove mouseup mouseout', resizeDragEvent); - $table.find('th:not(:has(input))').bind('click', function(event) { + $table.find('th:not(:has(input)):not(.collapsible-column)').bind('click', function(event) { if ($(this).hasClass('resizable')) { return false; } diff --git a/ui/scripts/ui/widgets/listView.js b/ui/scripts/ui/widgets/listView.js index c256d1c02fc..ce33eaf286a 100644 --- a/ui/scripts/ui/widgets/listView.js +++ b/ui/scripts/ui/widgets/listView.js @@ -765,10 +765,12 @@ var createHeader = function(preFilter, fields, $table, actions, options) { if (!options) options = {}; - var $thead = $('').prependTo($table).append($('')); + var $tr = $(''); + var $thead = $('').prependTo($table).append($tr); var reorder = options.reorder; var detailView = options.detailView; var multiSelect = options.multiSelect; + var groupableColumns = options.groupableColumns; var viewArgs = $table.closest('.list-view').data('view-args'); var uiCustom = viewArgs.uiCustom; var hiddenFields = []; @@ -776,8 +778,37 @@ if (preFilter != null) hiddenFields = preFilter(); + var addColumnToTr = function($tr, key, colspan, label) { + var $th = $('').addClass(key).attr('colspan', colspan).appendTo($tr); + if ($th.index()) $th.addClass('reduced-hide'); + if (colspan > 1) { + $th.css({'border-right': '1px solid #C6C3C3', 'border-left': '1px solid #C6C3C3'}); + $th.addClass('collapsible-column'); + $('').html(_l(label)).appendTo($th); + $('').html('»').css({'float': 'right'}).appendTo($th); + } else { + $th.html(_l(label)); + } + }; + + if (groupableColumns) { + $tr.addClass('groupable-header-columns').addClass('groupable-header'); + $.each(fields, function(key) { + var field = this; + if (field.columns) { + var colspan = Object.keys(field.columns).length; + addColumnToTr($tr, key, colspan, field.label); + } else { + addColumnToTr($tr, key, 1, ''); + } + return true; + }); + $tr = $('').appendTo($thead); + $tr.addClass('groupable-header'); + } + if (multiSelect) { - var $th = $('').addClass('multiselect').appendTo($thead.find('tr')); + var $th = $('').addClass('multiselect').appendTo($tr); var content = $('') .attr('type', 'checkbox') .addClass('multiSelectMasterCheckbox') @@ -794,18 +825,21 @@ if ($.inArray(key, hiddenFields) != -1) return true; var field = this; - var $th = $('').addClass(key).appendTo($thead.find('tr')); - - if ($th.index()) $th.addClass('reduced-hide'); - - $th.html(_l(field.label)); - + if (field.columns) { + $.each(field.columns, function(idx) { + var subfield = this; + addColumnToTr($tr, key, 1, subfield.label); + return true; + }); + } else { + addColumnToTr($tr, key, 1, field.label); + } return true; }); // Re-order row buttons if (reorder) { - $thead.find('tr').append( + $tr.append( $('').html(_l('label.order')).addClass('reorder-actions reduced-hide') ); } @@ -826,7 +860,7 @@ ); if (actions && !options.noActionCol && renderActionCol(actions) && actionsArray.length != headerActionsArray.length) { - $thead.find('tr').append( + $tr.append( $('') .html(_l('label.actions')) .addClass('actions reduced-hide') @@ -835,7 +869,7 @@ // Quick view if (detailView && !$.isFunction(detailView) && !detailView.noCompact && !uiCustom) { - $thead.find('tr').append( + $tr.append( $('') .html(_l('label.quickview')) .addClass('quick-view reduced-hide') @@ -1088,8 +1122,21 @@ ); } - // Add field data + var reducedFields = {}; $.each(fields, function(key) { + var field = this; + if (field.columns) { + $.each(field.columns, function(innerKey) { + reducedFields[innerKey] = this; + }); + } else { + reducedFields[key] = this; + } + return true; + }); + + // Add field data + $.each(reducedFields, function(key) { if ($.inArray(key, hiddenFields) != -1) return true; var field = this; @@ -1794,7 +1841,8 @@ reorder: reorder, detailView: listViewData.detailView, 'multiSelect': multiSelect, - noActionCol: listViewData.noActionCol + noActionCol: listViewData.noActionCol, + groupableColumns: listViewData.groupableColumns }); if (listViewData.noSplit == true) {