diff --git a/src/core_plugins/kibana/public/dashboard/__tests__/dashboard_panels.js b/src/core_plugins/kibana/public/dashboard/__tests__/dashboard_panels.js new file mode 100644 index 0000000000000..0611c8eba587a --- /dev/null +++ b/src/core_plugins/kibana/public/dashboard/__tests__/dashboard_panels.js @@ -0,0 +1,86 @@ +import angular from 'angular'; +import expect from 'expect.js'; +import ngMock from 'ng_mock'; +import 'plugins/kibana/dashboard/services/_saved_dashboard'; + +describe('dashboard panels', function () { + let $scope; + let $el; + + const compile = (dashboard) => { + ngMock.inject(($rootScope, $controller, $compile, $route) => { + $scope = $rootScope.$new(); + $route.current = { + locals: { + dash: dashboard + } + }; + + $el = angular.element(` + + + `); + $compile($el)($scope); + $scope.$digest(); + }); + }; + + beforeEach(() => { + ngMock.module('kibana'); + }); + + afterEach(() => { + $scope.$destroy(); + $el.remove(); + }); + + it('loads with no vizualizations', function () { + ngMock.inject((SavedDashboard) => { + let dash = new SavedDashboard(); + dash.init(); + compile(dash); + }); + expect($scope.state.panels.length).to.be(0); + }); + + it('loads one vizualization', function () { + ngMock.inject((SavedDashboard) => { + let dash = new SavedDashboard(); + dash.init(); + dash.panelsJSON = `[{"col":3,"id":"foo1","row":1,"size_x":2,"size_y":2,"type":"visualization"}]`; + compile(dash); + }); + expect($scope.state.panels.length).to.be(1); + }); + + it('loads vizualizations in correct order', function () { + ngMock.inject((SavedDashboard) => { + let dash = new SavedDashboard(); + dash.init(); + dash.panelsJSON = `[ + {"col":3,"id":"foo1","row":1,"size_x":2,"size_y":2,"type":"visualization"}, + {"col":5,"id":"foo2","row":1,"size_x":2,"size_y":2,"type":"visualization"}, + {"col":9,"id":"foo3","row":1,"size_x":2,"size_y":2,"type":"visualization"}, + {"col":11,"id":"foo4","row":1,"size_x":2,"size_y":2,"type":"visualization"}, + {"col":1,"id":"foo5","row":1,"size_x":2,"size_y":2,"type":"visualization"}, + {"col":7,"id":"foo6","row":1,"size_x":2,"size_y":2,"type":"visualization"}, + {"col":4,"id":"foo7","row":6,"size_x":3,"size_y":2,"type":"visualization"}, + {"col":1,"id":"foo8","row":8,"size_x":3,"size_y":2,"type":"visualization"}, + {"col":10,"id":"foo9","row":8,"size_x":3,"size_y":2,"type":"visualization"}, + {"col":10,"id":"foo10","row":6,"size_x":3,"size_y":2,"type":"visualization"}, + {"col":4,"id":"foo11","row":8,"size_x":3,"size_y":2,"type":"visualization"}, + {"col":7,"id":"foo12","row":8,"size_x":3,"size_y":2,"type":"visualization"}, + {"col":1,"id":"foo13","row":6,"size_x":3,"size_y":2,"type":"visualization"}, + {"col":7,"id":"foo14","row":6,"size_x":3,"size_y":2,"type":"visualization"}, + {"col":5,"id":"foo15","row":3,"size_x":6,"size_y":3,"type":"visualization"}, + {"col":1,"id":"foo17","row":3,"size_x":4,"size_y":3,"type":"visualization"}]`; + compile(dash); + }); + expect($scope.state.panels.length).to.be(16); + const foo8Panel = $scope.state.panels.find( + (panel) => { return panel.id === 'foo8'; }); + expect(foo8Panel).to.not.be(null); + expect(foo8Panel.row).to.be(8); + expect(foo8Panel.col).to.be(1); + }); +}); diff --git a/src/core_plugins/kibana/public/dashboard/directives/grid.js b/src/core_plugins/kibana/public/dashboard/directives/grid.js index afff8d497bc38..ef4ea724aab88 100644 --- a/src/core_plugins/kibana/public/dashboard/directives/grid.js +++ b/src/core_plugins/kibana/public/dashboard/directives/grid.js @@ -37,6 +37,20 @@ app.directive('dashboardGrid', function ($compile, Notifier) { function init() { $el.addClass('gridster'); + // See issue https://github.com/elastic/kibana/issues/2138 and the + // subsequent fix for why we need to sort here. Short story is that + // gridster can fail to render widgets in the correct order, depending + // on the specific order of the panels. + // See https://github.com/ducksboard/gridster.js/issues/147 + // for some additional back story. + $state.panels.sort((a, b) => { + if (a.row === b.row) { + return a.col - b.col; + } else { + return a.row - b.row; + } + }); + gridster = $el.gridster({ max_cols: COLS, min_cols: COLS,