mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Add a welcome screen for new Kibana instances (#21353)
Add a welcome screen to Kibana home if this is a new Kibana instance. New is determined by whether or not there are any index patterns defined. Local storage is used to retain the user's decision to hide the welcome screen.
This commit is contained in:
parent
4ecdad2ec7
commit
a73a928dea
12 changed files with 997 additions and 216 deletions
74
src/core_plugins/kibana/public/assets/bg_bottom_branded.svg
Normal file
74
src/core_plugins/kibana/public/assets/bg_bottom_branded.svg
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="1169px" height="880px" viewBox="0 0 1169 880" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: sketchtool 51.2 (57519) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>E2D4A2B4-5E17-4ADE-80E4-31B9CAF520F4</title>
|
||||
<desc>Created with sketchtool.</desc>
|
||||
<defs>
|
||||
<radialGradient cx="0%" cy="0%" fx="0%" fy="0%" r="155.5077%" gradientTransform="translate(0.000000,0.000000),scale(0.839695,1.000000),rotate(40.020000),translate(-0.000000,-0.000000)" id="radialGradient-1">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.5" offset="0%"></stop>
|
||||
<stop stop-color="#000000" stop-opacity="0.5" offset="100%"></stop>
|
||||
</radialGradient>
|
||||
<polygon id="path-2" points="0 0 1048 880 0 880"></polygon>
|
||||
<linearGradient x1="98.9240878%" y1="48.9240878%" x2="7.15652071%" y2="48.9240878%" id="linearGradient-3">
|
||||
<stop stop-color="#DFDDDD" stop-opacity="0.25" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.2" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="0%" y1="47.4208152%" x2="100%" y2="47.4208152%" id="linearGradient-4">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.6" offset="0%"></stop>
|
||||
<stop stop-color="#000000" stop-opacity="0.25" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<polygon id="path-5" points="560 364 1169 880 560 880"></polygon>
|
||||
<linearGradient x1="-3.33066907e-14%" y1="3.38788096e-14%" x2="100%" y2="100%" id="linearGradient-6">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.2" offset="0%"></stop>
|
||||
<stop stop-color="#000000" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<radialGradient cx="0%" cy="0%" fx="0%" fy="0%" r="127.620365%" gradientTransform="translate(0.000000,0.000000),scale(0.932203,1.000000),rotate(42.990446),translate(-0.000000,-0.000000)" id="radialGradient-7">
|
||||
<stop stop-color="#BBBBBB" stop-opacity="0.1" offset="0%"></stop>
|
||||
<stop stop-color="#000000" stop-opacity="0.5" offset="100%"></stop>
|
||||
</radialGradient>
|
||||
<polygon id="path-8" points="-12 538 342 868 -12 868"></polygon>
|
||||
<linearGradient x1="0%" y1="0%" x2="100%" y2="100%" id="linearGradient-9">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.4" offset="0%"></stop>
|
||||
<stop stop-color="#000000" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<radialGradient cx="0%" cy="0%" fx="0%" fy="0%" r="148.368294%" gradientTransform="translate(0.000000,0.000000),scale(1.000000,0.912371),rotate(47.623578),translate(-0.000000,-0.000000)" id="radialGradient-10">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.101024683" offset="0%"></stop>
|
||||
<stop stop-color="#000000" stop-opacity="0.15" offset="100%"></stop>
|
||||
</radialGradient>
|
||||
<path d="M197,880 L374,880 C365.385564,795.927984 296.005151,723.868711 197,686 L197,880 Z" id="path-11"></path>
|
||||
<radialGradient cx="0%" cy="0%" fx="0%" fy="0%" r="127.620365%" gradientTransform="translate(0.000000,0.000000),scale(1.000000,0.932203),rotate(47.009554),translate(-0.000000,-0.000000)" id="radialGradient-12">
|
||||
<stop stop-color="#BBBBBB" stop-opacity="0.1" offset="0%"></stop>
|
||||
<stop stop-color="#000000" stop-opacity="0.5" offset="100%"></stop>
|
||||
</radialGradient>
|
||||
<polygon id="path-13" points="165 703 330 880 165 880"></polygon>
|
||||
</defs>
|
||||
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="background/full/branded-alt" transform="translate(0.000000, -147.000000)">
|
||||
<g id="bg-bottom-branded" transform="translate(0.000000, 147.000000)">
|
||||
<g id="shape">
|
||||
<use fill="#F5F5F5" xlink:href="#path-2"></use>
|
||||
<use fill="url(#radialGradient-1)" style="mix-blend-mode: overlay;" xlink:href="#path-2"></use>
|
||||
</g>
|
||||
<g id="shape" opacity="0.1">
|
||||
<use fill="url(#linearGradient-3)" xlink:href="#path-5"></use>
|
||||
<use fill="url(#linearGradient-4)" style="mix-blend-mode: overlay;" xlink:href="#path-5"></use>
|
||||
</g>
|
||||
<g id="shape" opacity="0.65" transform="translate(165.000000, 703.000000) scale(-1, 1) rotate(-90.000000) translate(-165.000000, -703.000000) ">
|
||||
<use fill="#DD0A73" xlink:href="#path-8"></use>
|
||||
<use fill="url(#linearGradient-6)" style="mix-blend-mode: overlay;" xlink:href="#path-8"></use>
|
||||
<use fill="url(#radialGradient-7)" style="mix-blend-mode: overlay;" xlink:href="#path-8"></use>
|
||||
</g>
|
||||
<g id="shape" opacity="0.65" transform="translate(285.500000, 783.000000) scale(-1, -1) rotate(180.000000) translate(-285.500000, -783.000000) ">
|
||||
<use fill="#017F75" xlink:href="#path-11"></use>
|
||||
<use fill="url(#linearGradient-9)" style="mix-blend-mode: overlay;" xlink:href="#path-11"></use>
|
||||
<use fill="url(#radialGradient-10)" style="mix-blend-mode: overlay;" xlink:href="#path-11"></use>
|
||||
</g>
|
||||
<g id="shape" opacity="0.15">
|
||||
<use fill="#353535" xlink:href="#path-13"></use>
|
||||
<use fill="url(#linearGradient-6)" style="mix-blend-mode: overlay;" xlink:href="#path-13"></use>
|
||||
<use fill="url(#radialGradient-12)" style="mix-blend-mode: overlay;" xlink:href="#path-13"></use>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
41
src/core_plugins/kibana/public/assets/bg_top_branded.svg
Normal file
41
src/core_plugins/kibana/public/assets/bg_top_branded.svg
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="400px" height="373px" viewBox="0 0 400 373" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: sketchtool 51.2 (57519) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>7901612E-113D-4EE2-89F8-C5AEAD9876B6</title>
|
||||
<desc>Created with sketchtool.</desc>
|
||||
<defs>
|
||||
<linearGradient x1="10.7931708%" y1="50%" x2="100%" y2="50%" id="linearGradient-1">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.5" offset="0%"></stop>
|
||||
<stop stop-color="#E2E2E2" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<radialGradient cx="0%" cy="0%" fx="0%" fy="0%" r="146.629187%" gradientTransform="translate(0.000000,0.000000),scale(0.932500,1.000000),rotate(42.999538),translate(-0.000000,-0.000000)" id="radialGradient-2">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.5" offset="0%"></stop>
|
||||
<stop stop-color="#000000" stop-opacity="0.2" offset="100%"></stop>
|
||||
</radialGradient>
|
||||
<polygon id="path-3" points="400 373 0 0 400 4.61930179e-14"></polygon>
|
||||
<linearGradient x1="0%" y1="0%" x2="100%" y2="100%" id="linearGradient-4">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.6" offset="0%"></stop>
|
||||
<stop stop-color="#000000" stop-opacity="0" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<radialGradient cx="0%" cy="0%" fx="0%" fy="0%" r="146.09634%" gradientTransform="translate(0.000000,0.000000),scale(0.938889,1.000000),rotate(43.194713),translate(-0.000000,-0.000000)" id="radialGradient-5">
|
||||
<stop stop-color="#FFFFFF" stop-opacity="0.15" offset="0%"></stop>
|
||||
<stop stop-color="#000000" stop-opacity="0.5" offset="100%"></stop>
|
||||
</radialGradient>
|
||||
<polygon id="path-6" points="400 169 220 0 400 2.09292762e-14"></polygon>
|
||||
</defs>
|
||||
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="background/full/branded-alt" transform="translate(-1040.000000, 0.000000)">
|
||||
<g id="bg-top-branded" transform="translate(1040.000000, 0.000000)">
|
||||
<g id="shape" opacity="0.1">
|
||||
<use fill="url(#linearGradient-1)" xlink:href="#path-3"></use>
|
||||
<use fill="url(#radialGradient-2)" style="mix-blend-mode: overlay;" xlink:href="#path-3"></use>
|
||||
</g>
|
||||
<g id="shape" opacity="0.85">
|
||||
<use fill="#F5F5F5" xlink:href="#path-6"></use>
|
||||
<use fill="url(#linearGradient-4)" style="mix-blend-mode: overlay;" xlink:href="#path-6"></use>
|
||||
<use fill="url(#radialGradient-5)" style="mix-blend-mode: overlay;" xlink:href="#path-6"></use>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
BIN
src/core_plugins/kibana/public/assets/illo_dashboard.png
Normal file
BIN
src/core_plugins/kibana/public/assets/illo_dashboard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -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`] = `
|
||||
<EuiPage
|
||||
className="home"
|
||||
restrictWidth={false}
|
||||
|
@ -118,7 +118,7 @@ exports[`directories should not render directory entry when showOnHomePage is fa
|
|||
</EuiPage>
|
||||
`;
|
||||
|
||||
exports[`directories should render ADMIN directory entry in "Manage" panel 1`] = `
|
||||
exports[`home directories should render ADMIN directory entry in "Manage" panel 1`] = `
|
||||
<EuiPage
|
||||
className="home"
|
||||
restrictWidth={false}
|
||||
|
@ -255,7 +255,7 @@ exports[`directories should render ADMIN directory entry in "Manage" panel 1`] =
|
|||
</EuiPage>
|
||||
`;
|
||||
|
||||
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`] = `
|
||||
<EuiPage
|
||||
className="home"
|
||||
restrictWidth={false}
|
||||
|
@ -392,7 +392,7 @@ exports[`directories should render DATA directory entry in "Explore Data" panel
|
|||
</EuiPage>
|
||||
`;
|
||||
|
||||
exports[`isNewKibanaInstance should safely handle execeptions 1`] = `
|
||||
exports[`home isNewKibanaInstance should safely handle execeptions 1`] = `
|
||||
<EuiPage
|
||||
className="home"
|
||||
restrictWidth={false}
|
||||
|
@ -510,7 +510,7 @@ exports[`isNewKibanaInstance should safely handle execeptions 1`] = `
|
|||
</EuiPage>
|
||||
`;
|
||||
|
||||
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`] = `
|
||||
<EuiPage
|
||||
className="home"
|
||||
restrictWidth={false}
|
||||
|
@ -628,7 +628,7 @@ exports[`isNewKibanaInstance should set isNewKibanaInstance to false when there
|
|||
</EuiPage>
|
||||
`;
|
||||
|
||||
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`] = `
|
||||
<EuiPage
|
||||
className="home"
|
||||
restrictWidth={false}
|
||||
|
@ -746,7 +746,7 @@ exports[`isNewKibanaInstance should set isNewKibanaInstance to true when there a
|
|||
</EuiPage>
|
||||
`;
|
||||
|
||||
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`] = `
|
||||
<EuiPage
|
||||
className="home"
|
||||
restrictWidth={false}
|
||||
|
@ -864,7 +864,7 @@ exports[`should not contain RecentlyAccessed panel when there is no recentlyAcce
|
|||
</EuiPage>
|
||||
`;
|
||||
|
||||
exports[`should render home component 1`] = `
|
||||
exports[`home should render home component 1`] = `
|
||||
<EuiPage
|
||||
className="home"
|
||||
restrictWidth={false}
|
||||
|
@ -997,3 +997,364 @@ exports[`should render home component 1`] = `
|
|||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
`;
|
||||
|
||||
exports[`home welcome should show the normal home page if loading fails 1`] = `
|
||||
<EuiPage
|
||||
className="home"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<EuiPageBody
|
||||
restrictWidth={false}
|
||||
>
|
||||
<AddData
|
||||
apmUiEnabled={true}
|
||||
isNewKibanaInstance={false}
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="l"
|
||||
/>
|
||||
<EuiFlexGroup
|
||||
alignItems="stretch"
|
||||
component="div"
|
||||
direction="row"
|
||||
gutterSize="l"
|
||||
justifyContent="flexStart"
|
||||
responsive={true}
|
||||
wrap={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
component="div"
|
||||
grow={true}
|
||||
>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
paddingSize="l"
|
||||
>
|
||||
<EuiTitle
|
||||
size="m"
|
||||
>
|
||||
<h3>
|
||||
Visualize and Explore Data
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFlexGrid
|
||||
columns={2}
|
||||
gutterSize="l"
|
||||
responsive={true}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
component="div"
|
||||
grow={true}
|
||||
>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
paddingSize="l"
|
||||
>
|
||||
<EuiTitle
|
||||
size="m"
|
||||
>
|
||||
<h3>
|
||||
Manage and Administer the Elastic Stack
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFlexGrid
|
||||
columns={2}
|
||||
gutterSize="l"
|
||||
responsive={true}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer
|
||||
size="l"
|
||||
/>
|
||||
<EuiFlexGroup
|
||||
alignItems="stretch"
|
||||
component="div"
|
||||
direction="row"
|
||||
gutterSize="l"
|
||||
justifyContent="center"
|
||||
responsive={true}
|
||||
wrap={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
component="div"
|
||||
grow={false}
|
||||
>
|
||||
<EuiText
|
||||
grow={true}
|
||||
>
|
||||
<p>
|
||||
Didn’t find what you were looking for?
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiButton
|
||||
color="primary"
|
||||
fill={false}
|
||||
href="#/home/feature_directory"
|
||||
iconSide="left"
|
||||
type="button"
|
||||
>
|
||||
View full directory of Kibana plugins
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
`;
|
||||
|
||||
exports[`home welcome should show the normal home page if welcome screen is disabled locally 1`] = `
|
||||
<EuiPage
|
||||
className="home"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<EuiPageBody
|
||||
restrictWidth={false}
|
||||
>
|
||||
<AddData
|
||||
apmUiEnabled={true}
|
||||
isNewKibanaInstance={false}
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="l"
|
||||
/>
|
||||
<EuiFlexGroup
|
||||
alignItems="stretch"
|
||||
component="div"
|
||||
direction="row"
|
||||
gutterSize="l"
|
||||
justifyContent="flexStart"
|
||||
responsive={true}
|
||||
wrap={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
component="div"
|
||||
grow={true}
|
||||
>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
paddingSize="l"
|
||||
>
|
||||
<EuiTitle
|
||||
size="m"
|
||||
>
|
||||
<h3>
|
||||
Visualize and Explore Data
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFlexGrid
|
||||
columns={2}
|
||||
gutterSize="l"
|
||||
responsive={true}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
component="div"
|
||||
grow={true}
|
||||
>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
paddingSize="l"
|
||||
>
|
||||
<EuiTitle
|
||||
size="m"
|
||||
>
|
||||
<h3>
|
||||
Manage and Administer the Elastic Stack
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFlexGrid
|
||||
columns={2}
|
||||
gutterSize="l"
|
||||
responsive={true}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer
|
||||
size="l"
|
||||
/>
|
||||
<EuiFlexGroup
|
||||
alignItems="stretch"
|
||||
component="div"
|
||||
direction="row"
|
||||
gutterSize="l"
|
||||
justifyContent="center"
|
||||
responsive={true}
|
||||
wrap={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
component="div"
|
||||
grow={false}
|
||||
>
|
||||
<EuiText
|
||||
grow={true}
|
||||
>
|
||||
<p>
|
||||
Didn’t find what you were looking for?
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiButton
|
||||
color="primary"
|
||||
fill={false}
|
||||
href="#/home/feature_directory"
|
||||
iconSide="left"
|
||||
type="button"
|
||||
>
|
||||
View full directory of Kibana plugins
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
`;
|
||||
|
||||
exports[`home welcome should show the welcome screen if enabled, and there are no index patterns defined 1`] = `
|
||||
<Welcome
|
||||
onSkip={[Function]}
|
||||
urlBasePath="goober"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`home welcome stores skip welcome setting if skipped 1`] = `
|
||||
<EuiPage
|
||||
className="home"
|
||||
restrictWidth={false}
|
||||
>
|
||||
<EuiPageBody
|
||||
restrictWidth={false}
|
||||
>
|
||||
<AddData
|
||||
apmUiEnabled={true}
|
||||
isNewKibanaInstance={true}
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="l"
|
||||
/>
|
||||
<EuiFlexGroup
|
||||
alignItems="stretch"
|
||||
component="div"
|
||||
direction="row"
|
||||
gutterSize="l"
|
||||
justifyContent="flexStart"
|
||||
responsive={true}
|
||||
wrap={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
component="div"
|
||||
grow={true}
|
||||
>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
paddingSize="l"
|
||||
>
|
||||
<EuiTitle
|
||||
size="m"
|
||||
>
|
||||
<h3>
|
||||
Visualize and Explore Data
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFlexGrid
|
||||
columns={2}
|
||||
gutterSize="l"
|
||||
responsive={true}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
component="div"
|
||||
grow={true}
|
||||
>
|
||||
<EuiPanel
|
||||
grow={true}
|
||||
hasShadow={false}
|
||||
paddingSize="l"
|
||||
>
|
||||
<EuiTitle
|
||||
size="m"
|
||||
>
|
||||
<h3>
|
||||
Manage and Administer the Elastic Stack
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
size="m"
|
||||
/>
|
||||
<EuiFlexGrid
|
||||
columns={2}
|
||||
gutterSize="l"
|
||||
responsive={true}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer
|
||||
size="l"
|
||||
/>
|
||||
<EuiFlexGroup
|
||||
alignItems="stretch"
|
||||
component="div"
|
||||
direction="row"
|
||||
gutterSize="l"
|
||||
justifyContent="center"
|
||||
responsive={true}
|
||||
wrap={false}
|
||||
>
|
||||
<EuiFlexItem
|
||||
component="div"
|
||||
grow={false}
|
||||
>
|
||||
<EuiText
|
||||
grow={true}
|
||||
>
|
||||
<p>
|
||||
Didn’t find what you were looking for?
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiButton
|
||||
color="primary"
|
||||
fill={false}
|
||||
href="#/home/feature_directory"
|
||||
iconSide="left"
|
||||
type="button"
|
||||
>
|
||||
View full directory of Kibana plugins
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
`;
|
||||
|
|
|
@ -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 (
|
||||
<EuiFlexItem style={{ minHeight: 64 }} key={directory.id}>
|
||||
<Synopsis
|
||||
|
@ -98,17 +127,14 @@ export class Home extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
render() {
|
||||
renderNormal() {
|
||||
const { apmUiEnabled, recentlyAccessed } = this.props;
|
||||
|
||||
let recentlyAccessedPanel;
|
||||
if (recentlyAccessed.length > 0) {
|
||||
recentlyAccessedPanel = (
|
||||
<Fragment>
|
||||
<RecentlyAccessed
|
||||
recentlyAccessed={recentlyAccessed}
|
||||
/>
|
||||
<RecentlyAccessed recentlyAccessed={recentlyAccessed} />
|
||||
<EuiSpacer size="l" />
|
||||
</Fragment>
|
||||
);
|
||||
|
@ -117,7 +143,6 @@ export class Home extends Component {
|
|||
return (
|
||||
<EuiPage className="home">
|
||||
<EuiPageBody>
|
||||
|
||||
{recentlyAccessedPanel}
|
||||
|
||||
<AddData
|
||||
|
@ -131,26 +156,22 @@ export class Home extends Component {
|
|||
<EuiFlexItem>
|
||||
<EuiPanel paddingSize="l">
|
||||
<EuiTitle>
|
||||
<h3>
|
||||
Visualize and Explore Data
|
||||
</h3>
|
||||
<h3>Visualize and Explore Data</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m"/>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGrid columns={2}>
|
||||
{ this.renderDirectories(FeatureCatalogueCategory.DATA) }
|
||||
{this.renderDirectories(FeatureCatalogueCategory.DATA)}
|
||||
</EuiFlexGrid>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiPanel paddingSize="l">
|
||||
<EuiTitle>
|
||||
<h3>
|
||||
Manage and Administer the Elastic Stack
|
||||
</h3>
|
||||
<h3>Manage and Administer the Elastic Stack</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m"/>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGrid columns={2}>
|
||||
{ this.renderDirectories(FeatureCatalogueCategory.ADMIN) }
|
||||
{this.renderDirectories(FeatureCatalogueCategory.ADMIN)}
|
||||
</EuiFlexGrid>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
|
@ -161,14 +182,10 @@ export class Home extends Component {
|
|||
<EuiFlexGroup justifyContent="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText>
|
||||
<p>
|
||||
Didn’t find what you were looking for?
|
||||
</p>
|
||||
<p>Didn’t find what you were looking for?</p>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiButton
|
||||
href="#/home/feature_directory"
|
||||
>
|
||||
<EuiButton href="#/home/feature_directory">
|
||||
View full directory of Kibana plugins
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
|
@ -177,20 +194,54 @@ export class Home extends Component {
|
|||
</EuiPage>
|
||||
);
|
||||
}
|
||||
|
||||
// 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 (
|
||||
<Welcome
|
||||
onSkip={this.skipWelcome}
|
||||
urlBasePath={this.props.urlBasePath}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
|
|
@ -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 });
|
||||
};
|
||||
describe('home', () => {
|
||||
let defaultProps;
|
||||
|
||||
test('should render home component', () => {
|
||||
const recentlyAccessed = [
|
||||
{
|
||||
label: 'my vis',
|
||||
link: 'link_to_my_vis',
|
||||
id: '1'
|
||||
}
|
||||
];
|
||||
const component = shallow(<Home
|
||||
addBasePath={addBasePath}
|
||||
directories={[]}
|
||||
apmUiEnabled={true}
|
||||
recentlyAccessed={recentlyAccessed}
|
||||
find={findMock}
|
||||
/>);
|
||||
|
||||
expect(component).toMatchSnapshot(); // eslint-disable-line
|
||||
});
|
||||
|
||||
test('should not contain RecentlyAccessed panel when there is no recentlyAccessed history', () => {
|
||||
const component = shallow(<Home
|
||||
addBasePath={addBasePath}
|
||||
directories={[]}
|
||||
apmUiEnabled={true}
|
||||
recentlyAccessed={[]}
|
||||
find={findMock}
|
||||
/>);
|
||||
|
||||
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
|
||||
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',
|
||||
};
|
||||
|
||||
const component = shallow(<Home
|
||||
addBasePath={addBasePath}
|
||||
directories={[directoryEntry]}
|
||||
apmUiEnabled={true}
|
||||
recentlyAccessed={[]}
|
||||
find={findMock}
|
||||
/>);
|
||||
|
||||
expect(component).toMatchSnapshot(); // eslint-disable-line
|
||||
});
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
async function renderHome(props = {}) {
|
||||
const component = shallow(<Home
|
||||
addBasePath={addBasePath}
|
||||
directories={[directoryEntry]}
|
||||
apmUiEnabled={true}
|
||||
recentlyAccessed={[]}
|
||||
find={findMock}
|
||||
/>);
|
||||
|
||||
expect(component).toMatchSnapshot(); // eslint-disable-line
|
||||
});
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
const component = shallow(<Home
|
||||
addBasePath={addBasePath}
|
||||
directories={[directoryEntry]}
|
||||
apmUiEnabled={true}
|
||||
recentlyAccessed={[]}
|
||||
find={findMock}
|
||||
/>);
|
||||
|
||||
expect(component).toMatchSnapshot(); // eslint-disable-line
|
||||
});
|
||||
});
|
||||
|
||||
describe('isNewKibanaInstance', () => {
|
||||
test('should set isNewKibanaInstance to true when there are no index patterns', async () => {
|
||||
const component = shallow(<Home
|
||||
addBasePath={addBasePath}
|
||||
directories={[]}
|
||||
apmUiEnabled={true}
|
||||
recentlyAccessed={[]}
|
||||
find={
|
||||
() => {
|
||||
return Promise.resolve({ total: 0 });
|
||||
}
|
||||
}
|
||||
{...defaultProps}
|
||||
{...props}
|
||||
/>);
|
||||
|
||||
// Ensure all promises resolve
|
||||
await new Promise(resolve => process.nextTick(resolve));
|
||||
// Ensure the state changes are reflected
|
||||
component.update();
|
||||
|
||||
expect(component).toMatchSnapshot(); // eslint-disable-line
|
||||
});
|
||||
|
||||
test('should set isNewKibanaInstance to false when there are index patterns', async () => {
|
||||
const component = shallow(<Home
|
||||
addBasePath={addBasePath}
|
||||
directories={[]}
|
||||
apmUiEnabled={true}
|
||||
recentlyAccessed={[]}
|
||||
find={
|
||||
() => {
|
||||
return Promise.resolve({ total: 1 });
|
||||
}
|
||||
}
|
||||
/>);
|
||||
|
||||
// Ensure all promises resolve
|
||||
await new Promise(resolve => process.nextTick(resolve));
|
||||
// Ensure the state changes are reflected
|
||||
component.update();
|
||||
|
||||
expect(component).toMatchSnapshot(); // eslint-disable-line
|
||||
return component;
|
||||
}
|
||||
|
||||
test('should render home component', async () => {
|
||||
const component = await renderHome({
|
||||
recentlyAccessed: [
|
||||
{
|
||||
label: 'my vis',
|
||||
link: 'link_to_my_vis',
|
||||
id: '1'
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should safely handle execeptions', async () => {
|
||||
const component = shallow(<Home
|
||||
addBasePath={addBasePath}
|
||||
directories={[]}
|
||||
apmUiEnabled={true}
|
||||
recentlyAccessed={[]}
|
||||
find={
|
||||
() => {
|
||||
test('should not contain RecentlyAccessed panel when there is no recentlyAccessed history', async () => {
|
||||
const component = await renderHome({
|
||||
recentlyAccessed: [],
|
||||
});
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
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('welcome', () => {
|
||||
test('should show the welcome screen if enabled, and there are no index patterns defined', async () => {
|
||||
defaultProps.localStorage.getItem = sinon.spy(() => 'true');
|
||||
|
||||
const component = await renderHome({
|
||||
find: () => Promise.resolve({ total: 0 }),
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(defaultProps.localStorage.getItem);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
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');
|
||||
|
||||
const component = await renderHome();
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isNewKibanaInstance', () => {
|
||||
test('should set isNewKibanaInstance to true when there are no index patterns', async () => {
|
||||
const component = await renderHome({
|
||||
find: () => Promise.resolve({ total: 0 }),
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
test('should safely handle execeptions', async () => {
|
||||
const component = await renderHome({
|
||||
find: () => {
|
||||
throw new Error('simulated find error');
|
||||
}
|
||||
}
|
||||
/>);
|
||||
},
|
||||
});
|
||||
|
||||
// Ensure all promises resolve
|
||||
await new Promise(resolve => process.nextTick(resolve));
|
||||
// Ensure the state changes are reflected
|
||||
component.update();
|
||||
|
||||
expect(component).toMatchSnapshot(); // eslint-disable-line
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -100,6 +100,8 @@ export function HomeApp({
|
|||
apmUiEnabled={apmUiEnabled}
|
||||
recentlyAccessed={recentlyAccessed}
|
||||
find={savedObjectsClient.find}
|
||||
localStorage={localStorage}
|
||||
urlBasePath={chrome.getBasePath()}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
|
|
115
src/core_plugins/kibana/public/home/components/welcome.js
Normal file
115
src/core_plugins/kibana/public/home/components/welcome.js
Normal file
|
@ -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 (
|
||||
<div className="home-welcome">
|
||||
<header className="home-welcome-header">
|
||||
<div className="home-welcome-content eui-textCenter">
|
||||
<EuiSpacer size="xxl" />
|
||||
<span className="home-welcome-logo">
|
||||
<EuiIcon type="logoKibana" size="xxl" />
|
||||
</span>
|
||||
<EuiTitle size="l" className="home-welcome-title">
|
||||
<h1>Welcome to Kibana</h1>
|
||||
</EuiTitle>
|
||||
<EuiText size="s" className="welcome-subtitle">Your window into the Elastic Stack</EuiText>
|
||||
<EuiSpacer size="xl" />
|
||||
</div>
|
||||
</header>
|
||||
<div className="home-welcome-content home-welcome-body">
|
||||
<EuiFlexGroup gutterSize="l">
|
||||
<EuiFlexItem>
|
||||
<EuiCard
|
||||
image={`${urlBasePath}/plugins/kibana/assets/illo_dashboard.png`}
|
||||
textAlign="left"
|
||||
title="Let's get started"
|
||||
description="We noticed that you don't have any data in your cluster.
|
||||
You can try our sample data and dashboards or jump in with your own data."
|
||||
footer={(
|
||||
<footer>
|
||||
<EuiButton
|
||||
fill
|
||||
className="home-welcome-footer-action"
|
||||
href="#/home/tutorial_directory/sampleData"
|
||||
>
|
||||
Try our sample data
|
||||
</EuiButton>
|
||||
<EuiButtonEmpty
|
||||
className="home-welcome-footer-action"
|
||||
onClick={onSkip}
|
||||
data-test-subj="skipWelcomeScreen"
|
||||
>
|
||||
Explore on my own
|
||||
</EuiButtonEmpty>
|
||||
</footer>
|
||||
)}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Welcome.propTypes = {
|
||||
urlBasePath: PropTypes.string.isRequired,
|
||||
onSkip: PropTypes.func.isRequired,
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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 () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue