Skip to content

Commit

Permalink
[App Search] Convert API Logs page to new page template + empty state…
Browse files Browse the repository at this point in the history
… polish (#102820)

* Convert API Logs noItemsMessage to its own empty state prompt

- Will be used by new page template

* Convert API Logs view to new page template

+ use new empty state
+ add tests clarifying loading UX

* Update router

* Fix i18n ID
  • Loading branch information
Constance committed Jun 22, 2021
1 parent 00a6bdd commit f422cbd
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ import React from 'react';

import { shallow } from 'enzyme';

import { EuiPageHeader } from '@elastic/eui';

import { Loading } from '../../../shared/loading';
import { rerender } from '../../../test_helpers';
import { rerender, getPageTitle } from '../../../test_helpers';
import { LogRetentionCallout, LogRetentionTooltip } from '../log_retention';

import { ApiLogsTable, NewApiEventsPrompt } from './components';
Expand All @@ -42,19 +39,28 @@ describe('ApiLogs', () => {

it('renders', () => {
const wrapper = shallow(<ApiLogs />);
expect(wrapper.find(EuiPageHeader).prop('pageTitle')).toEqual('API Logs');
expect(getPageTitle(wrapper)).toEqual('API Logs');
expect(wrapper.find(ApiLogsTable)).toHaveLength(1);
expect(wrapper.find(NewApiEventsPrompt)).toHaveLength(1);

expect(wrapper.find(LogRetentionCallout).prop('type')).toEqual('api');
expect(wrapper.find(LogRetentionTooltip).prop('type')).toEqual('api');
});

it('renders a loading screen', () => {
setMockValues({ ...values, dataLoading: true, apiLogs: [] });
const wrapper = shallow(<ApiLogs />);
describe('loading state', () => {
it('renders a full-page loading state on initial page load (no logs exist yet)', () => {
setMockValues({ ...values, dataLoading: true, apiLogs: [] });
const wrapper = shallow(<ApiLogs />);

expect(wrapper.prop('isLoading')).toEqual(true);
});

it('does not re-render a full-page loading state after initial page load (uses component-level loading state instead)', () => {
setMockValues({ ...values, dataLoading: true, apiLogs: [{}] });
const wrapper = shallow(<ApiLogs />);

expect(wrapper.find(Loading)).toHaveLength(1);
expect(wrapper.prop('isLoading')).toEqual(false);
});
});

describe('effects', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,14 @@ import React, { useEffect } from 'react';

import { useValues, useActions } from 'kea';

import {
EuiPageHeader,
EuiTitle,
EuiPageContent,
EuiPageContentBody,
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
} from '@elastic/eui';

import { FlashMessages } from '../../../shared/flash_messages';
import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
import { Loading } from '../../../shared/loading';
import { EuiTitle, EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer } from '@elastic/eui';

import { getEngineBreadcrumbs } from '../engine';
import { AppSearchPageTemplate } from '../layout';
import { LogRetentionCallout, LogRetentionTooltip, LogRetentionOptions } from '../log_retention';

import { ApiLogFlyout } from './api_log';
import { ApiLogsTable, NewApiEventsPrompt } from './components';
import { ApiLogsTable, NewApiEventsPrompt, EmptyState } from './components';
import { API_LOGS_TITLE, RECENT_API_EVENTS } from './constants';

import { ApiLogsLogic } from './';
Expand All @@ -44,38 +33,36 @@ export const ApiLogs: React.FC = () => {
pollForApiLogs();
}, []);

if (dataLoading && !apiLogs.length) return <Loading />;

return (
<>
<SetPageChrome trail={getEngineBreadcrumbs([API_LOGS_TITLE])} />
<EuiPageHeader pageTitle={API_LOGS_TITLE} />

<FlashMessages />
<AppSearchPageTemplate
pageChrome={getEngineBreadcrumbs([API_LOGS_TITLE])}
pageHeader={{ pageTitle: API_LOGS_TITLE }}
isLoading={dataLoading && !apiLogs.length}
isEmptyState={!apiLogs.length}
emptyState={<EmptyState />}
>
<LogRetentionCallout type={LogRetentionOptions.API} />

<EuiPageContent hasBorder>
<EuiPageContentBody>
<EuiFlexGroup gutterSize="m" alignItems="center" responsive={false} wrap>
<EuiFlexItem grow={false}>
<EuiTitle size="s">
<h2>{RECENT_API_EVENTS}</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<LogRetentionTooltip type={LogRetentionOptions.API} />
</EuiFlexItem>
<EuiFlexItem />
<EuiFlexItem grow={false}>
<NewApiEventsPrompt />
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="m" />
<EuiPanel hasBorder>
<EuiFlexGroup gutterSize="m" alignItems="center" responsive={false} wrap>
<EuiFlexItem grow={false}>
<EuiTitle size="s">
<h2>{RECENT_API_EVENTS}</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<LogRetentionTooltip type={LogRetentionOptions.API} />
</EuiFlexItem>
<EuiFlexItem />
<EuiFlexItem grow={false}>
<NewApiEventsPrompt />
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="m" />

<ApiLogsTable hasPagination />
<ApiLogFlyout />
</EuiPageContentBody>
</EuiPageContent>
</>
<ApiLogsTable hasPagination />
<ApiLogFlyout />
</EuiPanel>
</AppSearchPageTemplate>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import React from 'react';

import { shallow } from 'enzyme';

import { EuiBasicTable, EuiBadge, EuiHealth, EuiButtonEmpty, EuiEmptyPrompt } from '@elastic/eui';
import { EuiBasicTable, EuiBadge, EuiHealth, EuiButtonEmpty } from '@elastic/eui';

import { DEFAULT_META } from '../../../../shared/constants';
import { mountWithIntl } from '../../../../test_helpers';
Expand Down Expand Up @@ -91,14 +91,6 @@ describe('ApiLogsTable', () => {
expect(actions.openFlyout).toHaveBeenCalled();
});

it('renders an empty prompt if no items are passed', () => {
setMockValues({ ...values, apiLogs: [] });
const wrapper = mountWithIntl(<ApiLogsTable />);
const promptContent = wrapper.find(EuiEmptyPrompt).text();

expect(promptContent).toContain('Perform your first API call');
});

describe('hasPagination', () => {
it('does not render with pagination by default', () => {
const wrapper = shallow(<ApiLogsTable />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
EuiBadge,
EuiHealth,
EuiButtonEmpty,
EuiEmptyPrompt,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedRelative } from '@kbn/i18n/react';
Expand Down Expand Up @@ -109,25 +108,6 @@ export const ApiLogsTable: React.FC<Props> = ({ hasPagination }) => {
items={apiLogs}
responsive
loading={dataLoading}
noItemsMessage={
<EuiEmptyPrompt
iconType="clock"
title={
<h3>
{i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.emptyTitle', {
defaultMessage: 'Perform your first API call',
})}
</h3>
}
body={
<p>
{i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.emptyDescription', {
defaultMessage: "Check back after you've performed some API calls.",
})}
</p>
}
/>
}
{...paginationProps}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';

import { shallow } from 'enzyme';

import { EuiEmptyPrompt, EuiButton } from '@elastic/eui';

import { EmptyState } from './';

describe('EmptyState', () => {
it('renders', () => {
const wrapper = shallow(<EmptyState />)
.find(EuiEmptyPrompt)
.dive();

expect(wrapper.find('h2').text()).toEqual('Perform your first API call');
expect(wrapper.find(EuiButton).prop('href')).toEqual(
expect.stringContaining('/api-reference.html')
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';

import { EuiButton, EuiEmptyPrompt } from '@elastic/eui';
import { i18n } from '@kbn/i18n';

import { DOCS_PREFIX } from '../../../routes';

export const EmptyState: React.FC = () => (
<EuiEmptyPrompt
iconType="clock"
title={
<h2>
{i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.emptyTitle', {
defaultMessage: 'Perform your first API call',
})}
</h2>
}
body={
<p>
{i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.emptyDescription', {
defaultMessage: "Check back after you've performed some API calls.",
})}
</p>
}
actions={
<EuiButton
size="s"
target="_blank"
iconType="popout"
href={`${DOCS_PREFIX}/api-reference.html`}
>
{i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.empty.buttonLabel', {
defaultMessage: 'View the API reference',
})}
</EuiButton>
}
/>
);
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@

export { ApiLogsTable } from './api_logs_table';
export { NewApiEventsPrompt } from './new_api_events_prompt';
export { EmptyState } from './empty_state';
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ export const EngineRouter: React.FC = () => {
<SearchUI />
</Route>
)}
{canViewEngineApiLogs && (
<Route path={ENGINE_API_LOGS_PATH}>
<ApiLogs />
</Route>
)}
{/* TODO: Remove layout once page template migration is over */}
<Layout navigation={<AppSearchNav />}>
{canViewEngineSchema && (
Expand Down Expand Up @@ -141,11 +146,6 @@ export const EngineRouter: React.FC = () => {
<ResultSettings />
</Route>
)}
{canViewEngineApiLogs && (
<Route path={ENGINE_API_LOGS_PATH}>
<ApiLogs />
</Route>
)}
{canViewMetaEngineSourceEngines && (
<Route path={META_ENGINE_SOURCE_ENGINES_PATH}>
<SourceEngines />
Expand Down

0 comments on commit f422cbd

Please sign in to comment.