From d1d3da7741fb32cc4536ce9c769da528cadf80d2 Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Fri, 3 Feb 2017 16:37:28 -0800 Subject: [PATCH] Add pager_controls directive and pager service. Add pagination to Dashboard and Visualize landing pages. Change Dashboard listing to use hrefs for each dashboard. --- .../dashboard/listing/dashboard_listing.html | 39 +++++++++--- .../dashboard/listing/dashboard_listing.js | 60 +++++++++++++------ .../visualize/listing/visualize_listing.html | 35 +++++++++-- .../visualize/listing/visualize_listing.js | 56 ++++++++++++----- src/ui/public/pager/index.js | 1 + src/ui/public/pager/pager_service.factory.js | 12 ++++ src/ui/public/pager/pager_service.js | 58 ++++++++++++++++++ .../tool_bar_pager_buttons.html | 16 +++++ .../tool_bar_pager_buttons.js | 29 +++++++++ .../tool_bar_pager_text.html | 3 + .../tool_bar_pager_text.js | 21 +++++++ src/ui/public/pager_control/index.js | 2 + 12 files changed, 284 insertions(+), 48 deletions(-) create mode 100644 src/ui/public/pager/index.js create mode 100644 src/ui/public/pager/pager_service.factory.js create mode 100644 src/ui/public/pager/pager_service.js create mode 100644 src/ui/public/pager_control/components/tool_bar_pager_buttons/tool_bar_pager_buttons.html create mode 100644 src/ui/public/pager_control/components/tool_bar_pager_buttons/tool_bar_pager_buttons.js create mode 100644 src/ui/public/pager_control/components/tool_bar_pager_text/tool_bar_pager_text.html create mode 100644 src/ui/public/pager_control/components/tool_bar_pager_text/tool_bar_pager_text.js create mode 100644 src/ui/public/pager_control/index.js diff --git a/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.html b/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.html index 45ce0f34fd1e5..943296d44c4c5 100644 --- a/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.html +++ b/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.html @@ -31,10 +31,6 @@ -
- -
-
+ +
+ + + +
@@ -118,7 +129,7 @@ @@ -132,7 +143,7 @@
- + {{ item.title }}
@@ -149,8 +160,20 @@ {{ listingController.getSelectedItemsCount() }} selected -
- + +
+ + +
diff --git a/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.js b/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.js index 3abec72de0128..e0b14fcf50d05 100644 --- a/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.js +++ b/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.js @@ -1,17 +1,22 @@ import SavedObjectRegistryProvider from 'ui/saved_objects/saved_object_registry'; +import 'ui/pager_control'; +import 'ui/pager'; import { DashboardConstants } from '../dashboard_constants'; import _ from 'lodash'; export function DashboardListingController( + $filter, $scope, + confirmModal, kbnUrl, Notifier, + pagerService, Private, - timefilter, - confirmModal + timefilter ) { timefilter.enabled = false; + const limitTo = $filter('limitTo'); // TODO: Extract this into an external service. const services = Private(SavedObjectRegistryProvider).byLoaderPropertiesName; const dashboardService = services.dashboards; @@ -19,17 +24,38 @@ export function DashboardListingController( let selectedItems = []; + /** + * Sorts hits either ascending or descending + * @param {Array} hits Array of saved finder object hits + * @return {Array} Array sorted either ascending or descending + */ + const sortItems = () => { + this.items = + this.isAscending + ? _.sortBy(this.items, 'title') + : _.sortBy(this.items, 'title').reverse(); + }; + + const calculateItemsOnPage = () => { + sortItems(); + this.pager.setTotalItems(this.items.length); + this.pageOfItems = limitTo(this.items, this.pager.pageSize, this.pager.startIndex); + }; + const fetchObjects = () => { dashboardService.find(this.filter) .then(result => { this.items = result.hits; - this.sortItems(); + calculateItemsOnPage(); }); }; this.items = []; + this.pageOfItems = []; this.filter = ''; + this.pager = pagerService.create(this.items.length, 20, 1); + /** * Boolean that keeps track of whether hits are sorted ascending (true) * or descending (false) by title @@ -37,21 +63,9 @@ export function DashboardListingController( */ this.isAscending = true; - /** - * Sorts hits either ascending or descending - * @param {Array} hits Array of saved finder object hits - * @return {Array} Array sorted either ascending or descending - */ - this.sortItems = function sortItems() { - this.items = - this.isAscending - ? _.sortBy(this.items, 'title') - : _.sortBy(this.items, 'title').reverse(); - }; - this.toggleSort = function toggleSort() { this.isAscending = !this.isAscending; - this.sortItems(); + calculateItemsOnPage(); }; this.toggleAll = function toggleAll() { @@ -102,8 +116,18 @@ export function DashboardListingController( }); }; - this.open = function open(item) { - kbnUrl.change(item.url.substr(1)); + this.onPageNext = () => { + this.pager.nextPage(); + calculateItemsOnPage(); + }; + + this.onPagePrevious = () => { + this.pager.previousPage(); + calculateItemsOnPage(); + }; + + this.getUrlForItem = function getUrlForItem(item) { + return `#/dashboard/${item.id}`; }; $scope.$watch(() => this.filter, () => { diff --git a/src/core_plugins/kibana/public/visualize/listing/visualize_listing.html b/src/core_plugins/kibana/public/visualize/listing/visualize_listing.html index 4b93cfb6cdd03..c77a324470b6c 100644 --- a/src/core_plugins/kibana/public/visualize/listing/visualize_listing.html +++ b/src/core_plugins/kibana/public/visualize/listing/visualize_listing.html @@ -30,10 +30,6 @@ -
- -
-
+ +
+ + + +
@@ -101,7 +112,7 @@ @@ -141,8 +152,20 @@ {{ listingController.getSelectedItemsCount() }} selected +
- + + +
diff --git a/src/core_plugins/kibana/public/visualize/listing/visualize_listing.js b/src/core_plugins/kibana/public/visualize/listing/visualize_listing.js index 273a672da9bce..0516f1a856d9e 100644 --- a/src/core_plugins/kibana/public/visualize/listing/visualize_listing.js +++ b/src/core_plugins/kibana/public/visualize/listing/visualize_listing.js @@ -1,16 +1,21 @@ import SavedObjectRegistryProvider from 'ui/saved_objects/saved_object_registry'; +import 'ui/pager_control'; +import 'ui/pager'; import _ from 'lodash'; export function VisualizeListingController( + $filter, $scope, confirmModal, kbnUrl, Notifier, + pagerService, Private, timefilter ) { timefilter.enabled = false; + const limitTo = $filter('limitTo'); // TODO: Extract this into an external service. const services = Private(SavedObjectRegistryProvider).byLoaderPropertiesName; const visualizationService = services.visualizations; @@ -18,17 +23,40 @@ export function VisualizeListingController( let selectedItems = []; + /** + * Sorts hits either ascending or descending + * @param {Array} hits Array of saved finder object hits + * @return {Array} Array sorted either ascending or descending + */ + const sortItems = () => { + const sortProperty = this.getSortProperty(); + + this.items = + sortProperty.isAscending + ? _.sortBy(this.items, sortProperty.getValue) + : _.sortBy(this.items, sortProperty.getValue).reverse(); + }; + + const calculateItemsOnPage = () => { + sortItems(); + this.pager.setTotalItems(this.items.length); + this.pageOfItems = limitTo(this.items, this.pager.pageSize, this.pager.startIndex); + }; + const fetchObjects = () => { visualizationService.find(this.filter) .then(result => { this.items = result.hits; - this.sortItems(); + calculateItemsOnPage(); }); }; this.items = []; + this.pageOfItems = []; this.filter = ''; + this.pager = pagerService.create(this.items.length, 20, 1); + /** * Remember sort direction per property. */ @@ -57,20 +85,6 @@ export function VisualizeListingController( return sortProperty.isAscending; }; - /** - * Sorts hits either ascending or descending - * @param {Array} hits Array of saved finder object hits - * @return {Array} Array sorted either ascending or descending - */ - this.sortItems = function sortItems() { - const sortProperty = this.getSortProperty(); - - this.items = - sortProperty.isAscending - ? _.sortBy(this.items, sortProperty.getValue) - : _.sortBy(this.items, sortProperty.getValue).reverse(); - }; - this.sortOn = function sortOn(propertyName) { const sortProperty = this.getSortProperty(); @@ -81,7 +95,7 @@ export function VisualizeListingController( this.getSortPropertyByName(propertyName).isSelected = true; } - this.sortItems(); + calculateItemsOnPage(); }; this.toggleAll = function toggleAll() { @@ -133,6 +147,16 @@ export function VisualizeListingController( }); }; + this.onPageNext = () => { + this.pager.nextPage(); + calculateItemsOnPage(); + }; + + this.onPagePrevious = () => { + this.pager.previousPage(); + calculateItemsOnPage(); + }; + this.getUrlForItem = function getUrlForItem(item) { return `#/visualize/edit/${item.id}`; }; diff --git a/src/ui/public/pager/index.js b/src/ui/public/pager/index.js new file mode 100644 index 0000000000000..74c9422c1d6f2 --- /dev/null +++ b/src/ui/public/pager/index.js @@ -0,0 +1 @@ +import './pager_service.factory'; diff --git a/src/ui/public/pager/pager_service.factory.js b/src/ui/public/pager/pager_service.factory.js new file mode 100644 index 0000000000000..93335891841db --- /dev/null +++ b/src/ui/public/pager/pager_service.factory.js @@ -0,0 +1,12 @@ +import uiModules from 'ui/modules'; +import { PagerService } from './pager_service'; + +const app = uiModules.get('kibana'); + +app.factory('pagerService', () => { + return { + create(...args) { + return new PagerService(...args); + } + }; +}); diff --git a/src/ui/public/pager/pager_service.js b/src/ui/public/pager/pager_service.js new file mode 100644 index 0000000000000..3ecf0b825e5aa --- /dev/null +++ b/src/ui/public/pager/pager_service.js @@ -0,0 +1,58 @@ +function clamp(val, min, max) { + return Math.min(Math.max(min, val), max); +} + +export class PagerService { + constructor(totalItems, pageSize, startingPage) { + this.currentPage = startingPage; + this.totalItems = totalItems; + this.pageSize = pageSize; + this.startIndex = 0; + this.updateMeta(); + } + + get pageCount() { + return Math.ceil(this.totalItems / this.pageSize); + } + + get hasNextPage() { + return this.currentPage < this.totalPages; + } + + get hasPreviousPage() { + return this.currentPage > 1; + } + + nextPage() { + this.currentPage += 1; + this.updateMeta(); + } + + previousPage() { + this.currentPage -= 1; + this.updateMeta(); + } + + setTotalItems(count) { + this.totalItems = count; + this.updateMeta(); + } + + setPageSize(count) { + this.pageSize = count; + this.updateMeta(); + } + + updateMeta() { + this.totalPages = Math.ceil(this.totalItems / this.pageSize); + this.currentPage = clamp(this.currentPage, 1, this.totalPages); + + this.startItem = ((this.currentPage - 1) * this.pageSize) + 1; + this.startItem = clamp(this.startItem, 0, this.totalItems); + + this.endItem = (this.startItem - 1) + this.pageSize; + this.endItem = clamp(this.endItem, 0, this.totalItems); + + this.startIndex = this.startItem - 1; + } +} diff --git a/src/ui/public/pager_control/components/tool_bar_pager_buttons/tool_bar_pager_buttons.html b/src/ui/public/pager_control/components/tool_bar_pager_buttons/tool_bar_pager_buttons.html new file mode 100644 index 0000000000000..361d67848e58e --- /dev/null +++ b/src/ui/public/pager_control/components/tool_bar_pager_buttons/tool_bar_pager_buttons.html @@ -0,0 +1,16 @@ +
+ + +
diff --git a/src/ui/public/pager_control/components/tool_bar_pager_buttons/tool_bar_pager_buttons.js b/src/ui/public/pager_control/components/tool_bar_pager_buttons/tool_bar_pager_buttons.js new file mode 100644 index 0000000000000..302f1382357af --- /dev/null +++ b/src/ui/public/pager_control/components/tool_bar_pager_buttons/tool_bar_pager_buttons.js @@ -0,0 +1,29 @@ +import uiModules from 'ui/modules'; +import template from './tool_bar_pager_buttons.html'; + +const app = uiModules.get('kibana'); + +app.directive('toolBarPagerButtons', function () { + return { + restrict: 'E', + replace: true, + template: template, + scope: { + hasNextPage: '=', + hasPreviousPage: '=', + onPageNext: '=', + onPagePrevious: '=', + }, + controllerAs: 'toolBarPagerButtons', + bindToController: true, + controller: class ToolBarPagerButtonsController { + nextPage = () => { + this.onPageNext(); + }; + + previousPage = () => { + this.onPagePrevious(); + }; + } + }; +}); diff --git a/src/ui/public/pager_control/components/tool_bar_pager_text/tool_bar_pager_text.html b/src/ui/public/pager_control/components/tool_bar_pager_text/tool_bar_pager_text.html new file mode 100644 index 0000000000000..36f7675b8db32 --- /dev/null +++ b/src/ui/public/pager_control/components/tool_bar_pager_text/tool_bar_pager_text.html @@ -0,0 +1,3 @@ +
+ {{ toolBarPagerText.startItem | number }}–{{ toolBarPagerText.endItem | number }} of {{ toolBarPagerText.totalItems | number }} +
\ No newline at end of file diff --git a/src/ui/public/pager_control/components/tool_bar_pager_text/tool_bar_pager_text.js b/src/ui/public/pager_control/components/tool_bar_pager_text/tool_bar_pager_text.js new file mode 100644 index 0000000000000..873bdb597d0fb --- /dev/null +++ b/src/ui/public/pager_control/components/tool_bar_pager_text/tool_bar_pager_text.js @@ -0,0 +1,21 @@ +import uiModules from 'ui/modules'; +import template from './tool_bar_pager_text.html'; + +const app = uiModules.get('kibana'); + +app.directive('toolBarPagerText', function () { + return { + restrict: 'E', + replace: true, + template: template, + scope: { + startItem: '=', + endItem: '=', + totalItems: '=', + }, + controllerAs: 'toolBarPagerText', + bindToController: true, + controller: class ToolBarPagerTextController { + } + }; +}); diff --git a/src/ui/public/pager_control/index.js b/src/ui/public/pager_control/index.js new file mode 100644 index 0000000000000..9f0f3b8ea66d5 --- /dev/null +++ b/src/ui/public/pager_control/index.js @@ -0,0 +1,2 @@ +import './components/tool_bar_pager_text/tool_bar_pager_text'; +import './components/tool_bar_pager_buttons/tool_bar_pager_buttons';