diff --git a/src/core_plugins/kibana/public/dashboard/dashboard.html b/src/core_plugins/kibana/public/dashboard/dashboard.html index 0549942b48582..7f3357c6ded70 100644 --- a/src/core_plugins/kibana/public/dashboard/dashboard.html +++ b/src/core_plugins/kibana/public/dashboard/dashboard.html @@ -70,6 +70,7 @@

This dashboard is empty. Let's fill it up!

toggle-expand="toggleExpandPanel" create-child-ui-state="createChildUiState" toggle-expand="toggleExpandPanel" + shared-items-count="{{panels.length}}" > @@ -40,6 +43,9 @@ search-source="savedObj.searchSource" sorting="panel.sort" columns="panel.columns" + shared-item + data-title="{{savedObj.title}}" + data-description="{{savedObj.description}}" render-counter class="panel-content" filter="filter"> diff --git a/src/core_plugins/kibana/public/discover/index.html b/src/core_plugins/kibana/public/discover/index.html index 3584ef747bcaf..a386ad6b0df86 100644 --- a/src/core_plugins/kibana/public/discover/index.html +++ b/src/core_plugins/kibana/public/discover/index.html @@ -126,6 +126,9 @@

Searching

columns="state.columns" infinite-scroll="true" filter="filterQuery" + shared-item + data-title="{{opts.savedSearch.lastSavedTitle}}" + data-description="{{opts.savedSearch.description}}" render-counter> diff --git a/src/core_plugins/kibana/public/visualize/editor/editor.html b/src/core_plugins/kibana/public/visualize/editor/editor.html index db4e89fcffec0..c94de8fa94c58 100644 --- a/src/core_plugins/kibana/public/visualize/editor/editor.html +++ b/src/core_plugins/kibana/public/visualize/editor/editor.html @@ -81,6 +81,9 @@
{ ngMock.module('kibana'); ngMock.inject(($compile, $rootScope) => { + scope = $rootScope.$new(); compile = () => { const $el = $(''); $el.data('$kbnTopNavController', {}); // Mock the kbnTopNav - $rootScope.$apply(); - $compile($el)($rootScope); + $compile($el)(scope); + scope.$apply(); return $el; }; }); @@ -22,4 +24,18 @@ describe('kbnGlobalTimepicker', function () { const $el = compile(); expect($el.attr('data-test-subj')).to.be('globalTimepicker'); }); + it('sets shared-timefilter to false when timefilter.enabled is false', function () { + scope.timefilter = { + enabled: false + }; + const $el = compile(); + expect($el.attr('shared-timefilter')).to.eql('false'); + }); + it('sets shared-timefilter to true when timefilter.enabled is true', function () { + scope.timefilter = { + enabled: true + }; + const $el = compile(); + expect($el.attr('shared-timefilter')).to.eql('true'); + }); }); diff --git a/src/ui/public/timepicker/kbn_global_timepicker.html b/src/ui/public/timepicker/kbn_global_timepicker.html index 970632bad56e5..681d5b5c6f5bb 100644 --- a/src/ui/public/timepicker/kbn_global_timepicker.html +++ b/src/ui/public/timepicker/kbn_global_timepicker.html @@ -1,4 +1,4 @@ -
+
PageObjects.dashboard.getSharedItemsCount()) + .then(function (count) { + PageObjects.common.log('shared-items-count = ' + count); + expect(count).to.eql(visualizations.length); + }); + }); + + bdd.it('should have panels with expected shared-item title and description', function checkTitles() { + const visualizations = PageObjects.dashboard.getTestVisualizations(); + return PageObjects.common.tryForTime(10000, function () { + return PageObjects.dashboard.getPanelSharedItemData() + .then(function (data) { + expect(data.map(item => item.title)).to.eql(visualizations.map(v => v.name)); + expect(data.map(item => item.description)).to.eql(visualizations.map(v => v.description)); + }); + }); + }); }); diff --git a/test/functional/apps/discover/_collapse_expand.js b/test/functional/apps/discover/_collapse_expand.js index ab471112932a6..0ba8c2c82fcfd 100644 --- a/test/functional/apps/discover/_collapse_expand.js +++ b/test/functional/apps/discover/_collapse_expand.js @@ -19,7 +19,7 @@ bdd.describe('discover tab', function describeIndexTests() { return esClient.deleteAndUpdateConfigDoc({ 'dateFormat:tz':'UTC', 'defaultIndex':'logstash-*' }) .then(function loadkibanaIndexPattern() { PageObjects.common.debug('load kibana index with default index pattern'); - return elasticDump.elasticLoad('visualize','.kibana'); + return elasticDump.elasticLoad('discover','.kibana'); }) // and load a set of makelogs data .then(function loadIfEmptyMakelogs() { diff --git a/test/functional/apps/discover/_discover.js b/test/functional/apps/discover/_discover.js index 1cad3e6a3a367..e1c62d24657bc 100644 --- a/test/functional/apps/discover/_discover.js +++ b/test/functional/apps/discover/_discover.js @@ -20,7 +20,7 @@ bdd.describe('discover app', function describeIndexTests() { // delete .kibana index and update configDoc await esClient.deleteAndUpdateConfigDoc({ 'dateFormat:tz':'UTC', 'defaultIndex':'logstash-*' }); PageObjects.common.debug('load kibana index with default index pattern'); - await elasticDump.elasticLoad('visualize','.kibana'); + await elasticDump.elasticLoad('discover','.kibana'); // and load a set of makelogs data await scenarioManager.loadIfEmpty('logstashFunctional'); @@ -32,6 +32,7 @@ bdd.describe('discover app', function describeIndexTests() { bdd.describe('query', function () { const queryName1 = 'Query # 1'; + const queryDescription1 = 'Query # 1 Description'; bdd.it('should show correct time range string by timepicker', async function () { const actualTimeString = await PageObjects.discover.getTimespanText(); @@ -226,4 +227,19 @@ bdd.describe('discover app', function describeIndexTests() { expect(await PageObjects.header.isTimepickerOpen()).to.be(false); }); }); + + + bdd.describe('shared-item', function () { + bdd.it('should have correct shared-item title and description', async () => { + const expected = { + title: 'A Saved Search', + description: 'A Saved Search Description' + }; + + await PageObjects.discover.loadSavedSearch(expected.title); + const { title, description } = await PageObjects.common.getSharedItemTitleAndDescription(); + expect(title).to.eql(expected.title); + expect(description).to.eql(expected.description); + }); + }); }); diff --git a/test/functional/apps/discover/_field_data.js b/test/functional/apps/discover/_field_data.js index e6bc583433329..7ea5aee146b17 100644 --- a/test/functional/apps/discover/_field_data.js +++ b/test/functional/apps/discover/_field_data.js @@ -19,7 +19,7 @@ bdd.describe('discover app', function describeIndexTests() { return esClient.deleteAndUpdateConfigDoc({ 'dateFormat:tz':'UTC', 'defaultIndex':'logstash-*' }) .then(function loadkibanaIndexPattern() { PageObjects.common.debug('load kibana index with default index pattern'); - return elasticDump.elasticLoad('visualize','.kibana'); + return elasticDump.elasticLoad('discover','.kibana'); }) // and load a set of makelogs data .then(function loadIfEmptyMakelogs() { diff --git a/test/functional/apps/discover/_shared_links.js b/test/functional/apps/discover/_shared_links.js index cca7965e5455b..3d2dc98e71d37 100644 --- a/test/functional/apps/discover/_shared_links.js +++ b/test/functional/apps/discover/_shared_links.js @@ -33,7 +33,7 @@ bdd.describe('shared links', function describeIndexTests() { return esClient.deleteAndUpdateConfigDoc({ 'dateFormat:tz':'UTC', 'defaultIndex':'logstash-*' }) .then(function loadkibanaIndexPattern() { PageObjects.common.debug('load kibana index with default index pattern'); - return elasticDump.elasticLoad('visualize','.kibana'); + return elasticDump.elasticLoad('discover','.kibana'); }) // and load a set of makelogs data .then(function loadIfEmptyMakelogs() { diff --git a/test/functional/apps/visualize/_shared_item.js b/test/functional/apps/visualize/_shared_item.js new file mode 100644 index 0000000000000..54a4a7899f347 --- /dev/null +++ b/test/functional/apps/visualize/_shared_item.js @@ -0,0 +1,31 @@ +import expect from 'expect.js'; + +import { + bdd +} from '../../../support'; + +import PageObjects from '../../../support/page_objects'; + +bdd.describe('visualize app', function describeIndexTests() { + + bdd.before(function () { + PageObjects.common.debug('navigateToApp visualize'); + return PageObjects.common.navigateToApp('visualize'); + }); + + bdd.describe('shared-item', function indexPatternCreation() { + + bdd.it('should have the correct shared-item title and description', function () { + const expected = { + title: 'Visualization AreaChart', + description: 'AreaChart' + }; + return PageObjects.visualize.clickVisualizationByName('Visualization AreaChart') + .then(() => PageObjects.common.getSharedItemTitleAndDescription()) + .then(({ title, description }) => { + expect(title).to.eql(expected.title); + expect(description).to.eql(expected.description); + }); + }); + }); +}); diff --git a/test/functional/apps/visualize/index.js b/test/functional/apps/visualize/index.js index 521d541620b26..046776ca69767 100644 --- a/test/functional/apps/visualize/index.js +++ b/test/functional/apps/visualize/index.js @@ -42,4 +42,5 @@ bdd.describe('visualize app', function () { require('./_vertical_bar_chart'); require('./_heatmap_chart'); require('./_point_series_options'); + require('./_shared_item'); }); diff --git a/test/support/page_objects/common.js b/test/support/page_objects/common.js index 0310375cd3981..1a6a74f2d91b5 100644 --- a/test/support/page_objects/common.js +++ b/test/support/page_objects/common.js @@ -330,4 +330,15 @@ export default class Common { this.debug(`Found ${elements.length} for selector ${selector}`); return elements; } + + async getSharedItemTitleAndDescription() { + const element = await this.remote + .setFindTimeout(defaultFindTimeout) + .findByCssSelector('[shared-item]'); + + return { + title: await element.getAttribute('data-title'), + description: await element.getAttribute('data-description') + }; + } } diff --git a/test/support/page_objects/dashboard_page.js b/test/support/page_objects/dashboard_page.js index 9b5df5383f5cd..61a5f4f490b25 100644 --- a/test/support/page_objects/dashboard_page.js +++ b/test/support/page_objects/dashboard_page.js @@ -94,7 +94,7 @@ export default class DashboardPage { clickVizNameLink(vizName) { return this.findTimeout - .findByLinkText(vizName) + .findByPartialLinkText(vizName) .click(); } @@ -200,8 +200,8 @@ export default class DashboardPage { }); } - getPanelData() { - PageObjects.common.debug('in getPanelData'); + getPanelSizeData() { + PageObjects.common.debug('in getPanelSizeData'); return this.findTimeout .findAllByCssSelector('li.gs-w') .then(function (titleObjects) { @@ -251,18 +251,22 @@ export default class DashboardPage { }); } - getTestVisualizationNames() { + getTestVisualizations() { return [ - 'Visualization PieChart', - 'Visualization☺ VerticalBarChart', - 'Visualization漢字 AreaChart', - 'Visualization☺漢字 DataTable', - 'Visualization漢字 LineChart', - 'Visualization TileMap', - 'Visualization MetricChart' + { name: 'Visualization PieChart', description: 'PieChart' }, + { name: 'Visualization☺ VerticalBarChart', description: 'VerticalBarChart' }, + { name: 'Visualization漢字 AreaChart', description: 'AreaChart' }, + { name: 'Visualization☺漢字 DataTable', description: 'DataTable' }, + { name: 'Visualization漢字 LineChart', description: 'LineChart' }, + { name: 'Visualization TileMap', description: 'TileMap' }, + { name: 'Visualization MetricChart', description: 'MetricChart' } ]; } + getTestVisualizationNames() { + return this.getTestVisualizations().map(visualization => visualization.name); + } + addVisualizations(visualizations) { return visualizations.reduce(function (promise, vizName) { return promise @@ -301,4 +305,33 @@ export default class DashboardPage { return slices[0].click(); } + getSharedItemsCount() { + PageObjects.common.debug('in getSharedItemsCount'); + const attributeName = 'shared-items-count'; + return this.findTimeout + .findByCssSelector(`[${attributeName}]`) + .then(function (element) { + if (element) { + return element.getAttribute(attributeName); + } + + return Promise.reject(); + }); + } + + getPanelSharedItemData() { + PageObjects.common.debug('in getPanelSharedItemData'); + return this.findTimeout + .findAllByCssSelector('li.gs-w') + .then(function (elements) { + return Promise.all(elements.map(async element => { + const sharedItem = await element.findByCssSelector('[shared-item]'); + return { + title: await sharedItem.getAttribute('data-title'), + description: await sharedItem.getAttribute('data-description') + }; + })); + }); + } + } diff --git a/test/support/page_objects/discover_page.js b/test/support/page_objects/discover_page.js index 71d63da1c9007..dc332fa858034 100644 --- a/test/support/page_objects/discover_page.js +++ b/test/support/page_objects/discover_page.js @@ -49,7 +49,7 @@ export default class DiscoverPage { loadSavedSearch(searchName) { return this.clickLoadSavedSearchButton() .then(() => { - this.findTimeout.findByLinkText(searchName).click(); + this.findTimeout.findByPartialLinkText(searchName).click(); }) .then(() => { return PageObjects.header.waitUntilLoadingHasFinished(); diff --git a/test/support/page_objects/header_page.js b/test/support/page_objects/header_page.js index 341519e0bec62..35dfe12136bbd 100644 --- a/test/support/page_objects/header_page.js +++ b/test/support/page_objects/header_page.js @@ -186,4 +186,12 @@ export default class HeaderPage { async getPrettyDuration() { return await PageObjects.common.findTestSubject('globalTimepickerRange').getVisibleText(); } + + async isSharedTimefilterEnabled() { + const element = await this.remote + .setFindTimeout(defaultFindTimeout) + .findByCssSelector(`[shared-timefilter=true]`); + + return new Boolean(element); + } } diff --git a/test/support/page_objects/visualize_page.js b/test/support/page_objects/visualize_page.js index a06115a9a3d38..90c967bfa0662 100644 --- a/test/support/page_objects/visualize_page.js +++ b/test/support/page_objects/visualize_page.js @@ -359,14 +359,14 @@ export default class VisualizePage { .type(vizName.replace('-',' ')); } - clickVisualizationByLinkText(vizName) { + clickVisualizationByName(vizName) { const self = this; PageObjects.common.debug('clickVisualizationByLinkText(' + vizName + ')'); return PageObjects.common.try(function tryingForTime() { return self.remote .setFindTimeout(defaultFindTimeout) - .findByLinkText(vizName) + .findByPartialLinkText(vizName) .click(); }); } @@ -382,7 +382,7 @@ export default class VisualizePage { } openSavedVisualization(vizName) { - return this.clickVisualizationByLinkText(vizName); + return this.clickVisualizationByName(vizName); } getXAxisLabels() {