diff --git a/app/assets/javascripts/controllers/live_metrics/ad_hoc_metrics_controller.js b/app/assets/javascripts/controllers/live_metrics/ad_hoc_metrics_controller.js index e7f52bab366..a5f8601ea05 100644 --- a/app/assets/javascripts/controllers/live_metrics/ad_hoc_metrics_controller.js +++ b/app/assets/javascripts/controllers/live_metrics/ad_hoc_metrics_controller.js @@ -22,6 +22,9 @@ dash.tags = {}; dash.chartData = {}; + dash.page = 1; + dash.pages = 1; + dash.filterConfig = { fields: [], appliedFilters: [], @@ -52,6 +55,8 @@ if (dash.filterConfig.appliedFilters.length === 0) { dash.applied = false; dash.items = []; + dash.page = 1; + dash.pages = 1; dash.filterConfig.resultsCount = 0; return; } @@ -66,6 +71,8 @@ // when change filter we automatically apply changes if (!addOnly) { dash.items = []; + dash.page = 1; + dash.pages = 1; dash.filterChanged = false; dash.filterConfig.resultsCount = 0; dash.applyFilters(); @@ -111,6 +118,7 @@ dash.getTenants = httpUtils.getTenants; dash.refreshList = httpUtils.refreshList; dash.refreshGraph = httpUtils.refreshGraph; + dash.setPage = httpUtils.setPage; // try to parse config variables from page url // and set page config variables diff --git a/app/assets/javascripts/controllers/live_metrics/util/metrics-http-factory.js b/app/assets/javascripts/controllers/live_metrics/util/metrics-http-factory.js index ee5120ac683..30011db3410 100644 --- a/app/assets/javascripts/controllers/live_metrics/util/metrics-http-factory.js +++ b/app/assets/javascripts/controllers/live_metrics/util/metrics-http-factory.js @@ -27,11 +27,8 @@ angular.module('miq.util').factory('metricsHttpFactory', function() { angular.forEach(dash.items, getLatestData); - if (dash.items.length > dash.max_metrics) { - dash.filterConfig.resultsCount = __("Showing first") + " " + dash.max_metrics; - } else { - dash.filterConfig.resultsCount = dash.items.length; - } + dash.pages = (data.pages > 0) ? data.pages : 1; + dash.filterConfig.resultsCount = __("Page ") + data.page + __(" Of ") + dash.pages + __(", Found ") + data.items; } function refreshOneGraph(metricId, metricType, currentItem) { @@ -85,7 +82,9 @@ angular.module('miq.util').factory('metricsHttpFactory', function() { dash.itemSelected = false; dash.loadingMetrics = true; var _tags = dash.tags !== {} ? '&tags=' + JSON.stringify(dash.tags) : ''; - $http.get(dash.url + '&limit=' + dash.max_metrics +'&query=metric_definitions' + _tags) + var pagination = '&page=' + dash.page + '&items_per_page=' + dash.items_per_page; + + $http.get(dash.url + '&limit=' + dash.max_metrics +'&query=metric_definitions' + _tags + pagination) .then(getMetricDefinitionsData) .catch(miqService.handleFailure); }; @@ -111,11 +110,23 @@ angular.module('miq.util').factory('metricsHttpFactory', function() { } }; + var setPage = function(page) { + var _page = page || 1; + if (_page < 1) _page = 1; + if (_page > dash.pages) _page = dash.pages; + + if (dash.page !== _page) { + dash.page = _page; + refreshList(); + } + }; + return { getMetricTags: getMetricTags, getTenants: getTenants, refreshList: refreshList, - refreshGraph: refreshGraph + refreshGraph: refreshGraph, + setPage: setPage } } }); diff --git a/app/assets/javascripts/controllers/live_metrics/util/metrics-parse-url-factroy.js b/app/assets/javascripts/controllers/live_metrics/util/metrics-parse-url-factroy.js index 71d8f2a6f43..1b14dd55084 100644 --- a/app/assets/javascripts/controllers/live_metrics/util/metrics-parse-url-factroy.js +++ b/app/assets/javascripts/controllers/live_metrics/util/metrics-parse-url-factroy.js @@ -8,5 +8,6 @@ angular.module('miq.util').factory('metricsParseUrlFactory', function() { dash.tenant = '_system'; dash.minBucketDurationInSecondes = 20 * 60; dash.max_metrics = 1000; + dash.items_per_page = 10; }; }); diff --git a/app/assets/stylesheets/metrics.scss b/app/assets/stylesheets/metrics.scss index 7ce65a2b9bb..ed0b6cd5d20 100644 --- a/app/assets/stylesheets/metrics.scss +++ b/app/assets/stylesheets/metrics.scss @@ -19,9 +19,37 @@ } } + .form-group.toolbar-actions.ng-scope { + width: calc(100% - 295px); + } + + .toolbar-pf-include-actions.ng-scope { + width: 100%; + } + + .pagination, .pagination-div, .form-group.pagination-div.ng-scope { + display: flex; + float: right; + margin: 0px; + margin-bottom: 0px; + + .page-input { + width: 40px; + margin-left: 10px; + margin-right: 10px; + text-align: right; + } + } + + .form-group.toolbar-pf-filter, + .form-group.toolbar-actions.ng-scope, + .toolbar-pf-actions.ng-pristine.ng-valid.no-filter-results { + margin-bottom: 5px; + } + .list-view-container, .line-chart, .blank-slate-pf { margin-bottom: 0; - min-height: calc(100vh - 362px); + min-height: calc(100vh - 357px); margin-left: 20px; margin-right: 20px; } diff --git a/app/services/hawkular_proxy_service.rb b/app/services/hawkular_proxy_service.rb index a0d6cadfdd7..1d8fa9512aa 100644 --- a/app/services/hawkular_proxy_service.rb +++ b/app/services/hawkular_proxy_service.rb @@ -25,6 +25,8 @@ def data(query) :type => @params['type'], :metric_id => @params['metric_id'], :tags => _tags, + :page => @params['page'] || 1, + :items_per_page => @params['items_per_page'] || 15, :limit => @params['limit'] || 10_000, :ends => @params['ends'] || (DateTime.now.to_i * 1000), :starts => @params['starts'], @@ -36,16 +38,33 @@ def data(query) case query when 'metric_definitions' + data = metric_definitions(params[:tags], params[:limit].to_i, params[:type]) + + items = data.count + page = params[:page].to_i + items_per_page = params[:items_per_page].to_i + pages = (items.to_f / items_per_page.to_f).ceil + start_index = items_per_page * (page - 1) + end_index = start_index + items_per_page + { - :metric_definitions => metric_definitions(params[:tags], params[:limit].to_i, params[:type]) + :page => page, + :items => items, + :items_per_page => items_per_page, + :pages => pages, + :limit => params[:limit].to_i, + :metric_definitions => data[start_index...end_index] } when 'metric_tags' { :metric_tags => metric_tags(params[:tags], params[:limit].to_i, params[:type]) } when 'get_data' + data = get_data(params[:metric_id], params).compact + limit = params[:limit].to_i + { - :data => get_data(params[:metric_id], params).compact + :data => data[0..limit] } when 'get_tenants' { @@ -66,11 +85,12 @@ def data(query) def metric_definitions(tags, limit, type) list = _metric_definitions(tags, type).map { |m| m.json if m.json } - list.sort { |a, b| a["id"].downcase <=> b["id"].downcase }[0..limit] + list.sort { |a, b| a["id"].downcase <=> b["id"].downcase }[0...limit] end def metric_tags(tags, limit, type) - tags = metric_definitions(tags, limit, type).map do |x| + definitions = metric_definitions(tags, limit, type) + tags = definitions.map do |x| x["tags"].keys if x["tags"] end @@ -78,14 +98,12 @@ def metric_tags(tags, limit, type) end def get_data(id, params) - data = client.get_data(id, - :limit => params[:limit].to_i, - :starts => params[:starts].to_i, - :ends => params[:ends].to_i, - :bucketDuration => params[:bucketDuration] || nil, - :order => params[:order] || 'ASC') - - data[0..params[:limit].to_i] + client.get_data(id, + :limit => params[:limit].to_i, + :starts => params[:starts].to_i, + :ends => params[:ends].to_i, + :bucketDuration => params[:bucketDuration] || nil, + :order => params[:order] || 'ASC') end def tenants(limit) @@ -97,7 +115,7 @@ def tenants(limit) tenants.map! { |x| x["id"] if x["id"].include?(@params['include']) } end - tenants.compact[0..limit] + tenants.compact[0...limit] end private diff --git a/app/views/ems_container/ad_hoc/_chart_view_form.html.haml b/app/views/ems_container/ad_hoc/_chart_view_form.html.haml index 9740f1334a1..13a89dff8e1 100644 --- a/app/views/ems_container/ad_hoc/_chart_view_form.html.haml +++ b/app/views/ems_container/ad_hoc/_chart_view_form.html.haml @@ -26,17 +26,17 @@ "options" => "dash.dateOptions", "date" => "dash.timeFilter.date"} - %dropdown.dropdown-kebab-pf + %button.btn.btn-primary.pull-left{"type" => "button", "ng-click" => "dash.refreshGraph()"} + = _("Refresh") + + %dropdown.dropdown-kebab-pf.pull-left %button.btn.btn-link.dropdown-toggle{"type" => "button", "data-toggle" => "dropdown", "aria-haspopup" => "true", "aria-expanded" => "true"} - %span.fa.fa-fw.fa-ellipsis-v + %span.fa.fa-ellipsis-v %ul.dropdown-menu{"aria-labelledby" => "dropdownKebab"} %li{"ng-repeat" => "range in dash.timeIntervals"} %a{"href" => "#", "ng-click" => "dash.minBucketDurationInSecondes = range.value; dash.refreshGraph()"} {{range.title}} - - %button.btn.btn-primary.pull-left{"type" => "button", "ng-click" => "dash.refreshGraph()"} - = _("Refresh") diff --git a/app/views/ems_container/ad_hoc/_list_view_form.html.haml b/app/views/ems_container/ad_hoc/_list_view_form.html.haml index a9b62b846e5..6c8523a7b31 100644 --- a/app/views/ems_container/ad_hoc/_list_view_form.html.haml +++ b/app/views/ems_container/ad_hoc/_list_view_form.html.haml @@ -29,3 +29,33 @@ "ng-click" => "dash.viewGraph()", "ng-disabled" => "!dash.itemSelected"} = _("View Graph") + + = # TODO: pagination should move inside the #paging-div element once #592 is complete + .form-group.pagination-div + %ul.pagination.pagination-pf-back + %li + %a{"href" => "#", + "ng-click" => "dash.setPage(1)", + "title" => _("First Page")} + %span.i.fa.fa-angle-double-left + %li + %a{"href" => "#", + "ng-click" => "dash.setPage(dash.page - 1)", + "title" => _("Previous Page")} + %span.i.fa.fa-angle-left + + %input.page-input.form-control{"ng-model" => "dash.page", + "readonly" => "readonly", + "type" => "text"} + + %ul.pagination.pagination-pf-forward + %li + %a{"href" => "#", + "ng-click" => "dash.setPage(dash.page + 1)", + "title" => _("Next Page")} + %span.i.fa.fa-angle-right + %li + %a{"href" => "#", + "ng-click" => "dash.setPage(dash.pages)", + "title" => _("Last Page")} + %span.i.fa.fa-angle-double-right diff --git a/spec/javascripts/controllers/container_live_dashboard/container_live_dashboard_controller_spec.js b/spec/javascripts/controllers/container_live_dashboard/container_live_dashboard_controller_spec.js index 56f081b7dfe..6f618c34219 100644 --- a/spec/javascripts/controllers/container_live_dashboard/container_live_dashboard_controller_spec.js +++ b/spec/javascripts/controllers/container_live_dashboard/container_live_dashboard_controller_spec.js @@ -17,7 +17,7 @@ describe('adHocMetricsController', function() { beforeEach(inject(function(_$httpBackend_, $rootScope, _$controller_) { $httpBackend = _$httpBackend_; $httpBackend.when('GET','/container_dashboard/data/42/?live=true&tenant=_system&query=metric_tags&limit=250').respond(mock_data); - $httpBackend.when('GET','/container_dashboard/data/42/?live=true&tenant=_system&limit=1000&query=metric_definitions&tags={}').respond(mock_metrics_data); + $httpBackend.when('GET','/container_dashboard/data/42/?live=true&tenant=_system&limit=1000&query=metric_definitions&tags={}&page=1&items_per_page=10').respond(mock_metrics_data); $httpBackend.when('GET','/container_dashboard/data/42/?live=true&type=gauge&tenant=_system&query=get_data&metric_id=hello1&limit=5&order=DESC').respond(mock_data1_data); $httpBackend.when('GET','/container_dashboard/data/42/?live=true&type=gauge&tenant=_system&query=get_data&metric_id=hello2&limit=5&order=DESC').respond(mock_data2_data); $controller = _$controller_('adHocMetricsController');