mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
merge conflicts (#20522)
This commit is contained in:
parent
8e69c0d79d
commit
9e6c4bfba9
6 changed files with 664 additions and 810 deletions
File diff suppressed because it is too large
Load diff
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import _ from 'lodash';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
|
@ -26,6 +26,8 @@ import {
|
|||
EuiFieldSearch,
|
||||
EuiBasicTable,
|
||||
EuiPage,
|
||||
EuiPageBody,
|
||||
EuiPageContent,
|
||||
EuiLink,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
|
@ -36,6 +38,7 @@ import {
|
|||
EuiCallOut,
|
||||
EuiText,
|
||||
EuiTextColor,
|
||||
EuiEmptyPrompt,
|
||||
} from '@elastic/eui';
|
||||
import { DashboardConstants, createDashboardEditUrl } from '../dashboard_constants';
|
||||
|
||||
|
@ -52,6 +55,7 @@ export class DashboardListing extends React.Component {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
hasInitialFetchReturned: false,
|
||||
isFetchingItems: false,
|
||||
showDeleteModal: false,
|
||||
showLimitError: false,
|
||||
|
@ -87,6 +91,7 @@ export class DashboardListing extends React.Component {
|
|||
// order than they were sent out. Only load results for the most recent search.
|
||||
if (filter === this.state.filter) {
|
||||
this.setState({
|
||||
hasInitialFetchReturned: true,
|
||||
isFetchingItems: false,
|
||||
dashboards: response.hits,
|
||||
totalDashboards: response.total,
|
||||
|
@ -177,6 +182,14 @@ export class DashboardListing extends React.Component {
|
|||
return dashboardsCopy.slice(startIndex, lastIndex);
|
||||
}
|
||||
|
||||
hasNoDashboards() {
|
||||
if (!this.state.isFetchingItems && this.state.dashboards.length === 0 && !this.state.filter) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
renderConfirmDeleteModal() {
|
||||
return (
|
||||
<EuiOverlayMask>
|
||||
|
@ -215,46 +228,57 @@ export class DashboardListing extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
renderNoItemsMessage() {
|
||||
renderNoResultsMessage() {
|
||||
if (this.state.isFetchingItems) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!this.state.isFetchingItems && this.state.dashboards.length === 0 && !this.state.filter) {
|
||||
if (this.props.hideWriteControls) {
|
||||
return (
|
||||
<EuiText>
|
||||
<h2>
|
||||
<EuiTextColor color="subdued">
|
||||
{`Looks like you don't have any dashboards.`}
|
||||
</EuiTextColor>
|
||||
</h2>
|
||||
</EuiText>
|
||||
);
|
||||
}
|
||||
return 'No dashboards matched your search.';
|
||||
}
|
||||
|
||||
renderNoItemsMessage() {
|
||||
|
||||
if (this.props.hideWriteControls) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<EuiText>
|
||||
<h2>
|
||||
<EuiTextColor color="subdued">
|
||||
{`Looks like you don't have any dashboards. Let's create some!`}
|
||||
</EuiTextColor>
|
||||
</h2>
|
||||
</EuiText>
|
||||
<EuiButton
|
||||
href={`#${DashboardConstants.CREATE_NEW_DASHBOARD_URL}`}
|
||||
fill
|
||||
iconType="plusInCircle"
|
||||
data-test-subj="createDashboardPromptButton"
|
||||
>
|
||||
Create new dashboard
|
||||
</EuiButton>
|
||||
</React.Fragment>
|
||||
<EuiText>
|
||||
<h2>
|
||||
<EuiTextColor color="subdued">
|
||||
{`Looks like you don't have any dashboards.`}
|
||||
</EuiTextColor>
|
||||
</h2>
|
||||
</EuiText>
|
||||
);
|
||||
}
|
||||
|
||||
return 'No dashboards matched your search.';
|
||||
return (
|
||||
<div>
|
||||
<EuiEmptyPrompt
|
||||
iconType="dashboardApp"
|
||||
title={<h2>Create your first dashboard</h2>}
|
||||
body={
|
||||
<Fragment>
|
||||
<p>
|
||||
You can combine data views from any Kibana app into one dashboard and see everything in one place.
|
||||
</p>
|
||||
<p>
|
||||
New to Kibana? <EuiLink href="#/home/tutorial_directory/sampleData">Install some sample data</EuiLink> to take a test drive.
|
||||
</p>
|
||||
</Fragment>
|
||||
}
|
||||
actions={
|
||||
<EuiButton
|
||||
href={`#${DashboardConstants.CREATE_NEW_DASHBOARD_URL}`}
|
||||
fill
|
||||
iconType="plusInCircle"
|
||||
data-test-subj="createDashboardPromptButton"
|
||||
>
|
||||
Create new dashboard
|
||||
</EuiButton>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
renderSearchBar() {
|
||||
|
@ -356,6 +380,7 @@ export class DashboardListing extends React.Component {
|
|||
};
|
||||
}
|
||||
const items = this.state.dashboards.length === 0 ? [] : this.getPageOfItems();
|
||||
|
||||
return (
|
||||
<EuiBasicTable
|
||||
itemId={'id'}
|
||||
|
@ -363,7 +388,7 @@ export class DashboardListing extends React.Component {
|
|||
loading={this.state.isFetchingItems}
|
||||
columns={tableColumns}
|
||||
selection={selection}
|
||||
noItemsMessage={this.renderNoItemsMessage()}
|
||||
noItemsMessage={this.renderNoResultsMessage()}
|
||||
pagination={pagination}
|
||||
sorting={sorting}
|
||||
onChange={this.onTableChange}
|
||||
|
@ -371,7 +396,15 @@ export class DashboardListing extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
renderListingOrEmptyState() {
|
||||
if (this.hasNoDashboards()) {
|
||||
return this.renderNoItemsMessage();
|
||||
}
|
||||
|
||||
return this.renderListing();
|
||||
}
|
||||
|
||||
renderListing() {
|
||||
let createButton;
|
||||
if (!this.props.hideWriteControls) {
|
||||
createButton = (
|
||||
|
@ -386,15 +419,14 @@ export class DashboardListing extends React.Component {
|
|||
);
|
||||
}
|
||||
return (
|
||||
<EuiPage data-test-subj="dashboardLandingPage">
|
||||
|
||||
<div>
|
||||
{this.state.showDeleteModal && this.renderConfirmDeleteModal()}
|
||||
|
||||
<EuiFlexGroup justifyContent="spaceBetween" alignItems="flexEnd" data-test-subj="top-nav">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="l">
|
||||
<h1>
|
||||
Dashboard
|
||||
Dashboards
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
|
@ -409,8 +441,31 @@ export class DashboardListing extends React.Component {
|
|||
|
||||
{this.renderSearchBar()}
|
||||
|
||||
{this.renderTable()}
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
{this.renderTable()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderPageContent() {
|
||||
if (!this.state.hasInitialFetchReturned) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiPageContent verticalPosition="center" horizontalPosition="center" className="dashboardLandingPage__content">
|
||||
{this.renderListingOrEmptyState()}
|
||||
</EuiPageContent>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<EuiPage data-test-subj="dashboardLandingPage" className="dashboardLandingPage">
|
||||
<EuiPageBody>
|
||||
{this.renderPageContent()}
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ const find = (num) => {
|
|||
});
|
||||
};
|
||||
|
||||
test('renders table in loading state', () => {
|
||||
test('renders empty page in before initial fetch to avoid flickering', () => {
|
||||
const component = shallow(<DashboardListing
|
||||
find={find.bind(null, 2)}
|
||||
delete={() => {}}
|
||||
|
@ -67,18 +67,24 @@ test('renders table in loading state', () => {
|
|||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('initialFilter', () => {
|
||||
const component = shallow(<DashboardListing
|
||||
find={find.bind(null, 2)}
|
||||
delete={() => {}}
|
||||
listingLimit={1000}
|
||||
hideWriteControls={false}
|
||||
initialFilter="my dashboard"
|
||||
/>);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('after fetch', () => {
|
||||
test('initialFilter', async () => {
|
||||
const component = shallow(<DashboardListing
|
||||
find={find.bind(null, 2)}
|
||||
delete={() => {}}
|
||||
listingLimit={1000}
|
||||
hideWriteControls={false}
|
||||
initialFilter="my dashboard"
|
||||
/>);
|
||||
|
||||
// Ensure all promises resolve
|
||||
await new Promise(resolve => process.nextTick(resolve));
|
||||
// Ensure the state changes are reflected
|
||||
component.update();
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('renders table rows', async () => {
|
||||
const component = shallow(<DashboardListing
|
||||
find={find.bind(null, 2)}
|
||||
|
|
|
@ -432,3 +432,13 @@ dashboard-viewport-provider {
|
|||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboardLandingPage {
|
||||
min-height: 100vh;
|
||||
background: @globalColorLightestGray;
|
||||
}
|
||||
|
||||
.dashboardLandingPage__content {
|
||||
max-width: 1000px;
|
||||
margin: auto;
|
||||
}
|
||||
|
|
|
@ -187,7 +187,14 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
|
|||
}
|
||||
|
||||
async clickNewDashboard() {
|
||||
return await testSubjects.click('newDashboardLink');
|
||||
// newDashboardLink button is only visible when dashboard listing table is displayed (at least one dashboard).
|
||||
const exists = await testSubjects.exists('newDashboardLink');
|
||||
if (exists) {
|
||||
return await testSubjects.click('newDashboardLink');
|
||||
}
|
||||
|
||||
// no dashboards exist, click createDashboardPromptButton to create new dashboard
|
||||
return await this.clickCreateDashboardPrompt();
|
||||
}
|
||||
|
||||
async clickCreateDashboardPrompt() {
|
||||
|
|
|
@ -62,9 +62,14 @@ export function HeaderPageProvider({ getService, getPageObjects }) {
|
|||
async clickDashboard() {
|
||||
log.debug('click Dashboard tab');
|
||||
await this.clickSelector('a[href*=\'dashboard\']');
|
||||
await PageObjects.common.waitForTopNavToBeVisible();
|
||||
await retry.try(async () => {
|
||||
const isNavVisible = await testSubjects.exists('top-nav');
|
||||
const isLandingPageVisible = await testSubjects.exists('dashboardLandingPage');
|
||||
if (!isNavVisible && !isLandingPageVisible) {
|
||||
throw new Error('Dashboard application not loaded yet');
|
||||
}
|
||||
});
|
||||
await this.awaitGlobalLoadingIndicatorHidden();
|
||||
await this.confirmTopNavTextContains('dashboard');
|
||||
}
|
||||
|
||||
async clickManagement() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue