diff --git a/src/core_plugins/kibana/public/assets/bg_bottom_branded.svg b/src/core_plugins/kibana/public/assets/bg_bottom_branded.svg new file mode 100644 index 0000000000000..9f6114fd5c502 --- /dev/null +++ b/src/core_plugins/kibana/public/assets/bg_bottom_branded.svg @@ -0,0 +1,74 @@ + + + + E2D4A2B4-5E17-4ADE-80E4-31B9CAF520F4 + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/kibana/public/assets/bg_top_branded.svg b/src/core_plugins/kibana/public/assets/bg_top_branded.svg new file mode 100644 index 0000000000000..f6e1965078462 --- /dev/null +++ b/src/core_plugins/kibana/public/assets/bg_top_branded.svg @@ -0,0 +1,41 @@ + + + + 7901612E-113D-4EE2-89F8-C5AEAD9876B6 + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/core_plugins/kibana/public/assets/illo_dashboard.png b/src/core_plugins/kibana/public/assets/illo_dashboard.png new file mode 100644 index 0000000000000..ef2dac5ca4144 Binary files /dev/null and b/src/core_plugins/kibana/public/assets/illo_dashboard.png differ diff --git a/src/core_plugins/kibana/public/home/components/__snapshots__/home.test.js.snap b/src/core_plugins/kibana/public/home/components/__snapshots__/home.test.js.snap index c400509856a1d..fca2261462277 100644 --- a/src/core_plugins/kibana/public/home/components/__snapshots__/home.test.js.snap +++ b/src/core_plugins/kibana/public/home/components/__snapshots__/home.test.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`directories should not render directory entry when showOnHomePage is false 1`] = ` +exports[`home directories should not render directory entry when showOnHomePage is false 1`] = ` `; -exports[`directories should render ADMIN directory entry in "Manage" panel 1`] = ` +exports[`home directories should render ADMIN directory entry in "Manage" panel 1`] = ` `; -exports[`directories should render DATA directory entry in "Explore Data" panel 1`] = ` +exports[`home directories should render DATA directory entry in "Explore Data" panel 1`] = ` `; -exports[`isNewKibanaInstance should safely handle execeptions 1`] = ` +exports[`home isNewKibanaInstance should safely handle execeptions 1`] = ` `; -exports[`isNewKibanaInstance should set isNewKibanaInstance to false when there are index patterns 1`] = ` +exports[`home isNewKibanaInstance should set isNewKibanaInstance to false when there are index patterns 1`] = ` `; -exports[`isNewKibanaInstance should set isNewKibanaInstance to true when there are no index patterns 1`] = ` +exports[`home isNewKibanaInstance should set isNewKibanaInstance to true when there are no index patterns 1`] = ` `; -exports[`should not contain RecentlyAccessed panel when there is no recentlyAccessed history 1`] = ` +exports[`home should not contain RecentlyAccessed panel when there is no recentlyAccessed history 1`] = ` `; -exports[`should render home component 1`] = ` +exports[`home should render home component 1`] = ` `; + +exports[`home welcome should show the normal home page if loading fails 1`] = ` + + + + + + + + +

+ Visualize and Explore Data +

+
+ + +
+
+ + + +

+ Manage and Administer the Elastic Stack +

+
+ + +
+
+
+ + + + +

+ Didn’t find what you were looking for? +

+
+ + + View full directory of Kibana plugins + +
+
+
+
+`; + +exports[`home welcome should show the normal home page if welcome screen is disabled locally 1`] = ` + + + + + + + + +

+ Visualize and Explore Data +

+
+ + +
+
+ + + +

+ Manage and Administer the Elastic Stack +

+
+ + +
+
+
+ + + + +

+ Didn’t find what you were looking for? +

+
+ + + View full directory of Kibana plugins + +
+
+
+
+`; + +exports[`home welcome should show the welcome screen if enabled, and there are no index patterns defined 1`] = ` + +`; + +exports[`home welcome stores skip welcome setting if skipped 1`] = ` + + + + + + + + +

+ Visualize and Explore Data +

+
+ + +
+
+ + + +

+ Manage and Administer the Elastic Stack +

+
+ + +
+
+
+ + + + +

+ Didn’t find what you were looking for? +

+
+ + + View full directory of Kibana plugins + +
+
+
+
+`; diff --git a/src/core_plugins/kibana/public/home/components/home.js b/src/core_plugins/kibana/public/home/components/home.js index a138983226a9f..1d3c195bdaf1d 100644 --- a/src/core_plugins/kibana/public/home/components/home.js +++ b/src/core_plugins/kibana/public/home/components/home.js @@ -36,12 +36,26 @@ import { EuiPageBody, } from '@elastic/eui'; +import { Welcome } from './welcome'; import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue'; -export class Home extends Component { +const KEY_ENABLE_WELCOME = 'home:welcome:show'; - state = { - isNewKibanaInstance: false, +export class Home extends Component { + constructor(props) { + super(props); + + const isWelcomeEnabled = props.localStorage.getItem(KEY_ENABLE_WELCOME) !== 'false'; + + this.state = { + // If welcome is enabled, we wait for loading to complete + // before rendering. This prevents an annoying flickering + // effect where home renders, and then a few ms after, the + // welcome screen fades in. + isLoading: isWelcomeEnabled, + isNewKibanaInstance: false, + isWelcomeEnabled, + }; } componentWillUnmount() { @@ -54,37 +68,52 @@ export class Home extends Component { } fetchIsNewKibanaInstance = async () => { - let resp; try { - resp = await this.props.find({ + // Set a max-time on this query so we don't hang the page too long... + // Worst case, we don't show the welcome screen when we should. + setTimeout(() => { + if (this.state.isLoading) { + this.setState({ isWelcomeEnabled: false }); + } + }, 500); + + const resp = await this.props.find({ type: 'index-pattern', fields: ['title'], search: `*`, search_fields: ['title'], - perPage: 1 + perPage: 1, }); - } catch (error) { - // ignore error - find is not critical for page functioning, - // just used to add some extra styling when there are no index-patterns - return; + + this.endLoading({ isNewKibanaInstance: resp.total === 0 }); + } catch (err) { + // An error here is relatively unimportant, as it only means we don't provide + // some UI niceties. + this.endLoading(); } + }; - if (!this._isMounted) { - return; + endLoading = (state = {}) => { + if (this._isMounted) { + this.setState({ + ...state, + isLoading: false, + }); } + }; - this.setState({ - isNewKibanaInstance: resp.total === 0 - }); - } + skipWelcome = () => { + this.props.localStorage.setItem(KEY_ENABLE_WELCOME, 'false'); + this._isMounted && this.setState({ isWelcomeEnabled: false }); + }; - renderDirectories = (category) => { + renderDirectories = category => { const { addBasePath, directories } = this.props; return directories - .filter((directory) => { + .filter(directory => { return directory.showOnHomePage && directory.category === category; }) - .map((directory) => { + .map(directory => { return ( 0) { recentlyAccessedPanel = ( - + ); @@ -117,7 +143,6 @@ export class Home extends Component { return ( - {recentlyAccessedPanel} -

- Visualize and Explore Data -

+

Visualize and Explore Data

- + - { this.renderDirectories(FeatureCatalogueCategory.DATA) } + {this.renderDirectories(FeatureCatalogueCategory.DATA)}
-

- Manage and Administer the Elastic Stack -

+

Manage and Administer the Elastic Stack

- + - { this.renderDirectories(FeatureCatalogueCategory.ADMIN) } + {this.renderDirectories(FeatureCatalogueCategory.ADMIN)}
@@ -161,14 +182,10 @@ export class Home extends Component { -

- Didn’t find what you were looking for? -

+

Didn’t find what you were looking for?

- + View full directory of Kibana plugins
@@ -177,20 +194,54 @@ export class Home extends Component {
); } + + // For now, loading is just an empty page, as we'll show something + // in 250ms, no matter what, and a blank page prevents an odd flicker effect. + renderLoading() { + return ''; + } + + renderWelcome() { + return ( + + ); + } + + render() { + const { isLoading, isWelcomeEnabled, isNewKibanaInstance } = this.state; + + if (isWelcomeEnabled) { + if (isLoading) { + return this.renderLoading(); + } + if (isNewKibanaInstance) { + return this.renderWelcome(); + } + } + + return this.renderNormal(); + } } Home.propTypes = { addBasePath: PropTypes.func.isRequired, - directories: PropTypes.arrayOf(PropTypes.shape({ - id: PropTypes.string.isRequired, - title: PropTypes.string.isRequired, - description: PropTypes.string.isRequired, - icon: PropTypes.string.isRequired, - path: PropTypes.string.isRequired, - showOnHomePage: PropTypes.bool.isRequired, - category: PropTypes.string.isRequired - })), + directories: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + description: PropTypes.string.isRequired, + icon: PropTypes.string.isRequired, + path: PropTypes.string.isRequired, + showOnHomePage: PropTypes.bool.isRequired, + category: PropTypes.string.isRequired, + }) + ), apmUiEnabled: PropTypes.bool.isRequired, recentlyAccessed: PropTypes.arrayOf(recentlyAccessedShape).isRequired, find: PropTypes.func.isRequired, + localStorage: PropTypes.object.isRequired, + urlBasePath: PropTypes.string.isRequired, }; diff --git a/src/core_plugins/kibana/public/home/components/home.test.js b/src/core_plugins/kibana/public/home/components/home.test.js index 590a8727d3f25..8c901f34be1ac 100644 --- a/src/core_plugins/kibana/public/home/components/home.test.js +++ b/src/core_plugins/kibana/public/home/components/home.test.js @@ -18,175 +18,208 @@ */ import React from 'react'; +import sinon from 'sinon'; import { shallow } from 'enzyme'; import { Home } from './home'; import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue'; -const addBasePath = (url) => { return `base_path/${url}`; }; -const findMock = () => { - return Promise.resolve({ total: 1 }); -}; - -test('should render home component', () => { - const recentlyAccessed = [ - { - label: 'my vis', - link: 'link_to_my_vis', - id: '1' - } - ]; - const component = shallow(); - - expect(component).toMatchSnapshot(); // eslint-disable-line -}); - -test('should not contain RecentlyAccessed panel when there is no recentlyAccessed history', () => { - const component = shallow(); - - expect(component).toMatchSnapshot(); // eslint-disable-line -}); - -describe('directories', () => { - test('should render DATA directory entry in "Explore Data" panel', () => { - const directoryEntry = { - id: 'dashboard', - title: 'Dashboard', - description: 'Display and share a collection of visualizations and saved searches.', - icon: 'dashboardApp', - path: 'dashboard_landing_page', - showOnHomePage: true, - category: FeatureCatalogueCategory.DATA +describe('home', () => { + let defaultProps; + + beforeEach(() => { + defaultProps = { + recentlyAccessed: [], + directories: [], + apmUiEnabled: true, + kibanaVersion: '99.2.1', + addBasePath(url) { + return `base_path/${url}`; + }, + find() { + return Promise.resolve({ total: 1 }); + }, + loadingCount: { + increment: sinon.mock(), + decrement: sinon.mock(), + }, + localStorage: { + getItem: sinon.spy((path) => { + expect(path).toEqual('home:welcome:show'); + return 'false'; + }), + setItem: sinon.mock(), + }, + urlBasePath: 'goober', }; + }); + async function renderHome(props = {}) { const component = shallow(); - expect(component).toMatchSnapshot(); // eslint-disable-line - }); + // Ensure all promises resolve + await new Promise(resolve => process.nextTick(resolve)); + // Ensure the state changes are reflected + component.update(); + // Ensure all promises resolve + await new Promise(resolve => process.nextTick(resolve)); - test('should render ADMIN directory entry in "Manage" panel', () => { - const directoryEntry = { - id: 'index_patterns', - title: 'Index Patterns', - description: 'Manage the index patterns that help retrieve your data from Elasticsearch.', - icon: 'indexPatternApp', - path: 'index_management_landing_page', - showOnHomePage: true, - category: FeatureCatalogueCategory.ADMIN - }; + return component; + } - const component = shallow(); + test('should render home component', async () => { + const component = await renderHome({ + recentlyAccessed: [ + { + label: 'my vis', + link: 'link_to_my_vis', + id: '1' + } + ], + }); - expect(component).toMatchSnapshot(); // eslint-disable-line + expect(component).toMatchSnapshot(); }); - test('should not render directory entry when showOnHomePage is false', () => { - const directoryEntry = { - id: 'management', - title: 'Management', - description: 'Your center console for managing the Elastic Stack.', - icon: 'managementApp', - path: 'management_landing_page', - showOnHomePage: false, - category: FeatureCatalogueCategory.ADMIN - }; + test('should not contain RecentlyAccessed panel when there is no recentlyAccessed history', async () => { + const component = await renderHome({ + recentlyAccessed: [], + }); - const component = shallow(); + expect(component).toMatchSnapshot(); + }); - expect(component).toMatchSnapshot(); // eslint-disable-line + describe('directories', () => { + test('should render DATA directory entry in "Explore Data" panel', async () => { + const directoryEntry = { + id: 'dashboard', + title: 'Dashboard', + description: 'Display and share a collection of visualizations and saved searches.', + icon: 'dashboardApp', + path: 'dashboard_landing_page', + showOnHomePage: true, + category: FeatureCatalogueCategory.DATA + }; + + const component = await renderHome({ + directories: [directoryEntry], + }); + + expect(component).toMatchSnapshot(); + }); + + test('should render ADMIN directory entry in "Manage" panel', async () => { + const directoryEntry = { + id: 'index_patterns', + title: 'Index Patterns', + description: 'Manage the index patterns that help retrieve your data from Elasticsearch.', + icon: 'indexPatternApp', + path: 'index_management_landing_page', + showOnHomePage: true, + category: FeatureCatalogueCategory.ADMIN + }; + + const component = await renderHome({ + directories: [directoryEntry], + }); + + expect(component).toMatchSnapshot(); + }); + + test('should not render directory entry when showOnHomePage is false', async () => { + const directoryEntry = { + id: 'management', + title: 'Management', + description: 'Your center console for managing the Elastic Stack.', + icon: 'managementApp', + path: 'management_landing_page', + showOnHomePage: false, + category: FeatureCatalogueCategory.ADMIN + }; + + const component = await renderHome({ + directories: [directoryEntry], + }); + + expect(component).toMatchSnapshot(); + }); }); -}); -describe('isNewKibanaInstance', () => { - test('should set isNewKibanaInstance to true when there are no index patterns', async () => { - const component = shallow( { - return Promise.resolve({ total: 0 }); - } - } - />); + describe('welcome', () => { + test('should show the welcome screen if enabled, and there are no index patterns defined', async () => { + defaultProps.localStorage.getItem = sinon.spy(() => 'true'); - // Ensure all promises resolve - await new Promise(resolve => process.nextTick(resolve)); - // Ensure the state changes are reflected - component.update(); + const component = await renderHome({ + find: () => Promise.resolve({ total: 0 }), + }); - expect(component).toMatchSnapshot(); // eslint-disable-line - }); + sinon.assert.calledOnce(defaultProps.localStorage.getItem); - test('should set isNewKibanaInstance to false when there are index patterns', async () => { - const component = shallow( { - return Promise.resolve({ total: 1 }); - } - } - />); + expect(component).toMatchSnapshot(); + }); - // Ensure all promises resolve - await new Promise(resolve => process.nextTick(resolve)); - // Ensure the state changes are reflected - component.update(); + test('stores skip welcome setting if skipped', async () => { + defaultProps.localStorage.getItem = sinon.spy(() => 'true'); + + const component = await renderHome({ + find: () => Promise.resolve({ total: 0 }), + }); + + component.instance().skipWelcome(); + component.update(); + + sinon.assert.calledWith(defaultProps.localStorage.setItem, 'home:welcome:show', 'false'); + + expect(component).toMatchSnapshot(); + }); + + test('should show the normal home page if loading fails', async () => { + defaultProps.localStorage.getItem = sinon.spy(() => 'true'); + + const component = await renderHome({ + find: () => Promise.reject('Doh!'), + }); + + expect(component).toMatchSnapshot(); + }); + + test('should show the normal home page if welcome screen is disabled locally', async () => { + defaultProps.localStorage.getItem = sinon.spy(() => 'false'); - expect(component).toMatchSnapshot(); // eslint-disable-line + const component = await renderHome(); + + expect(component).toMatchSnapshot(); + }); }); - test('should safely handle execeptions', async () => { - const component = shallow( { - throw new Error('simulated find error'); - } - } - />); + describe('isNewKibanaInstance', () => { + test('should set isNewKibanaInstance to true when there are no index patterns', async () => { + const component = await renderHome({ + find: () => Promise.resolve({ total: 0 }), + }); - // Ensure all promises resolve - await new Promise(resolve => process.nextTick(resolve)); - // Ensure the state changes are reflected - component.update(); + expect(component).toMatchSnapshot(); + }); + + test('should set isNewKibanaInstance to false when there are index patterns', async () => { + const component = await renderHome({ + find: () => Promise.resolve({ total: 1 }), + }); + + expect(component).toMatchSnapshot(); + }); - expect(component).toMatchSnapshot(); // eslint-disable-line + test('should safely handle execeptions', async () => { + const component = await renderHome({ + find: () => { + throw new Error('simulated find error'); + }, + }); + + expect(component).toMatchSnapshot(); + }); }); }); + diff --git a/src/core_plugins/kibana/public/home/components/home_app.js b/src/core_plugins/kibana/public/home/components/home_app.js index e3b48c0e680ad..d277fd542f70d 100644 --- a/src/core_plugins/kibana/public/home/components/home_app.js +++ b/src/core_plugins/kibana/public/home/components/home_app.js @@ -100,6 +100,8 @@ export function HomeApp({ apmUiEnabled={apmUiEnabled} recentlyAccessed={recentlyAccessed} find={savedObjectsClient.find} + localStorage={localStorage} + urlBasePath={chrome.getBasePath()} /> diff --git a/src/core_plugins/kibana/public/home/components/welcome.js b/src/core_plugins/kibana/public/home/components/welcome.js new file mode 100644 index 0000000000000..aa10b551f4ca3 --- /dev/null +++ b/src/core_plugins/kibana/public/home/components/welcome.js @@ -0,0 +1,115 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * The UI and related logic for the welcome screen that *should* show only + * when it is enabled (the default) and there is no Kibana-consumed data + * in Elasticsearch. + */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import { + EuiCard, + EuiTitle, + EuiSpacer, + EuiFlexGroup, + EuiFlexItem, + EuiText, + EuiIcon, + EuiButton, + EuiButtonEmpty, +} from '@elastic/eui'; + +/** + * Shows a full-screen welcome page that gives helpful quick links to beginners. + */ +export class Welcome extends React.Component { + hideOnEsc = (e) => { + if (e.key === 'Escape') { + this.props.onSkip(); + } + }; + + componentDidMount() { + document.addEventListener('keydown', this.hideOnEsc); + } + + componentWillUnmount() { + document.removeEventListener('keydown', this.hideOnEsc); + } + + render() { + const { urlBasePath, onSkip } = this.props; + + return ( +
+
+
+ + + + + +

Welcome to Kibana

+
+ Your window into the Elastic Stack + +
+
+
+ + + + + Try our sample data + + + Explore on my own + + + )} + /> + + +
+
+ ); + } +} + +Welcome.propTypes = { + urlBasePath: PropTypes.string.isRequired, + onSkip: PropTypes.func.isRequired, +}; diff --git a/src/core_plugins/kibana/public/home/home.less b/src/core_plugins/kibana/public/home/home.less index b8ce68b98a699..f2c4764a2b58b 100644 --- a/src/core_plugins/kibana/public/home/home.less +++ b/src/core_plugins/kibana/public/home/home.less @@ -26,3 +26,83 @@ home-app { .sampleDataSetCard { flex-grow: 0; } + +.home-welcome { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 100000; + background: inherit; + // When sassified, should pull in EUI colors: $euiColorLightestShade, $euiColorEmptyShade + background-image: linear-gradient(0deg, @globalColorLightestGray 0%, white 100%); + color: inherit; + opacity: 0; + overflow: auto; + animation: homeFadeIn 0.5s ease-in 0s forwards; +} + +.home-welcome::before { + content: url(../assets/bg_top_branded.svg); + position: absolute; + top: 0; + right: 0; + z-index: 1; +} + +.home-welcome::after { + content: url(../assets/bg_bottom_branded.svg); + position: fixed; + bottom: -2px; // Hides an odd space at the bottom of the svg + left: 0; + z-index: 1; +} + +.home-welcome-header { + position: relative; + padding: 32px; + z-index: 10; +} + +.home-welcome-logo { + display: inline-block; + margin-bottom: 24px; + background-color: white; + border-radius: 100%; + padding: 16px; + box-shadow: 0 4px 16px -6px rgba(0, 0, 0, 0.75); +} + +.home-welcome-title { + color: inherit; + font-weight: 400; +} + +.home-welcome-footer-action { + margin-right: 8px; +} + +.welcome-subtitle { + opacity: 0.75; +} + +.home-welcome-content { + position: relative; + margin: auto; + max-width: 512px; + padding-left: 32px; + padding-right: 32px; + z-index: 10; +} + +@keyframes homeFadeIn { + from { + opacity: 0; + transform: translateY(200px), scale(0.75); + } + to { + opacity: 1; + transform: translateY(0), scale(1); + } +} diff --git a/src/core_plugins/kibana/public/management/sections/settings/lib/get_category_name.js b/src/core_plugins/kibana/public/management/sections/settings/lib/get_category_name.js index cad3f28a5ad16..d41c4bce089ca 100644 --- a/src/core_plugins/kibana/public/management/sections/settings/lib/get_category_name.js +++ b/src/core_plugins/kibana/public/management/sections/settings/lib/get_category_name.js @@ -20,14 +20,14 @@ import { StringUtils } from 'ui/utils/string_utils'; const names = { - 'general': 'General', - 'timelion': 'Timelion', - 'notifications': 'Notifications', - 'visualizations': 'Visualizations', - 'discover': 'Discover', - 'dashboard': 'Dashboard', - 'reporting': 'Reporting', - 'search': 'Search', + general: 'General', + timelion: 'Timelion', + notifications: 'Notifications', + visualizations: 'Visualizations', + discover: 'Discover', + dashboard: 'Dashboard', + reporting: 'Reporting', + search: 'Search', }; export function getCategoryName(category) { diff --git a/test/functional/page_objects/home_page.js b/test/functional/page_objects/home_page.js index 9b1c3d6a5c741..77205e7bc3323 100644 --- a/test/functional/page_objects/home_page.js +++ b/test/functional/page_objects/home_page.js @@ -63,6 +63,18 @@ export function HomePageProvider({ getService }) { await testSubjects.click(`launchSampleDataSet${id}`); } + // When logging into a brand new Kibana instance, the welcome screen + // may pop up. It may not, depending on the speed of the test, so it + // pays to check for the welcome screen and hide it in any test that + // hits the Kibana home page. + isWelcomeShowing() { + return testSubjects.exists('skipWelcomeScreen'); + } + + async hideWelcomeScreen() { + await testSubjects.click('skipWelcomeScreen'); + } + async loadSavedObjects() { await retry.try(async () => { await testSubjects.click('loadSavedObjects'); diff --git a/x-pack/test/functional/page_objects/security_page.js b/x-pack/test/functional/page_objects/security_page.js index c41323f3962ec..96e30e152689f 100644 --- a/x-pack/test/functional/page_objects/security_page.js +++ b/x-pack/test/functional/page_objects/security_page.js @@ -16,7 +16,7 @@ export function SecurityPageProvider({ getService, getPageObjects }) { const testSubjects = getService('testSubjects'); const esArchiver = getService('esArchiver'); const defaultFindTimeout = config.get('timeouts.find'); - const PageObjects = getPageObjects(['common', 'header', 'settings']); + const PageObjects = getPageObjects(['common', 'header', 'settings', 'home']); class LoginPage { async login(username, password) { @@ -72,12 +72,24 @@ export function SecurityPageProvider({ getService, getPageObjects }) { async logout() { log.debug('SecurityPage.logout'); - const logoutLinkExists = await find.existsByLinkText('Logout'); + const [isWelcomeShowing, logoutLinkExists] = await Promise.all([ + PageObjects.home.isWelcomeShowing(), + find.existsByLinkText('Logout'), + ]); + if (!logoutLinkExists) { log.debug('Logout not found'); return; } + // This sometimes happens when hitting the home screen on a brand new / empty + // Kibana instance. It may not *always* happen, depending on how + // long it takes the home screen to query Elastic to see if it's a + // new Kibana instance. + if (isWelcomeShowing) { + await PageObjects.home.hideWelcomeScreen(); + } + await find.clickByLinkText('Logout'); await retry.try(async () => {