From 652fe4064d369b743cc617fb6da6a49464f30ae6 Mon Sep 17 00:00:00 2001 From: Constance Date: Tue, 22 Jun 2021 11:40:10 -0700 Subject: [PATCH] [App Search] Convert API Logs page to new page template + empty state 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 --- .../components/api_logs/api_logs.test.tsx | 24 +++--- .../components/api_logs/api_logs.tsx | 73 ++++++++----------- .../components/api_logs_table.test.tsx | 10 +-- .../api_logs/components/api_logs_table.tsx | 20 ----- .../api_logs/components/empty_state.test.tsx | 27 +++++++ .../api_logs/components/empty_state.tsx | 45 ++++++++++++ .../components/api_logs/components/index.ts | 1 + .../components/engine/engine_router.tsx | 10 +-- 8 files changed, 124 insertions(+), 86 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/empty_state.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/empty_state.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs.test.tsx index c2a11ec06fa6a4..5b082ce8d26ba5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs.test.tsx @@ -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'; @@ -42,7 +39,7 @@ describe('ApiLogs', () => { it('renders', () => { const wrapper = shallow(); - 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); @@ -50,11 +47,20 @@ describe('ApiLogs', () => { expect(wrapper.find(LogRetentionTooltip).prop('type')).toEqual('api'); }); - it('renders a loading screen', () => { - setMockValues({ ...values, dataLoading: true, apiLogs: [] }); - const wrapper = shallow(); + 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(); + + 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(); - expect(wrapper.find(Loading)).toHaveLength(1); + expect(wrapper.prop('isLoading')).toEqual(false); + }); }); describe('effects', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs.tsx index b8179163c93f94..d3eef77db21f04 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/api_logs.tsx @@ -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 './'; @@ -44,38 +33,36 @@ export const ApiLogs: React.FC = () => { pollForApiLogs(); }, []); - if (dataLoading && !apiLogs.length) return ; - return ( - <> - - - - + } + > - - - - - -

{RECENT_API_EVENTS}

-
-
- - - - - - - -
- + + + + +

{RECENT_API_EVENTS}

+
+
+ + + + + + + +
+ - - -
-
- + + + +
); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.test.tsx index 2a00cc6eb42bb3..82d3d4715cbc56 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.test.tsx @@ -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'; @@ -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(); - 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(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.tsx index bb1327ce2da30b..1b5a8084f5b594 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/api_logs_table.tsx @@ -15,7 +15,6 @@ import { EuiBadge, EuiHealth, EuiButtonEmpty, - EuiEmptyPrompt, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedRelative } from '@kbn/i18n/react'; @@ -109,25 +108,6 @@ export const ApiLogsTable: React.FC = ({ hasPagination }) => { items={apiLogs} responsive loading={dataLoading} - noItemsMessage={ - - {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.emptyTitle', { - defaultMessage: 'Perform your first API call', - })} - - } - body={ -

- {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.emptyDescription', { - defaultMessage: "Check back after you've performed some API calls.", - })} -

- } - /> - } {...paginationProps} /> ); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/empty_state.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/empty_state.test.tsx new file mode 100644 index 00000000000000..3ad22ceac5840d --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/empty_state.test.tsx @@ -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() + .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') + ); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/empty_state.tsx new file mode 100644 index 00000000000000..3f6f44adefc71d --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/empty_state.tsx @@ -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 = () => ( + + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.emptyTitle', { + defaultMessage: 'Perform your first API call', + })} + + } + body={ +

+ {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.emptyDescription', { + defaultMessage: "Check back after you've performed some API calls.", + })} +

+ } + actions={ + + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.apiLogs.empty.buttonLabel', { + defaultMessage: 'View the API reference', + })} + + } + /> +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/index.ts index c0edc51d062283..863216554a540b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/components/index.ts @@ -7,3 +7,4 @@ export { ApiLogsTable } from './api_logs_table'; export { NewApiEventsPrompt } from './new_api_events_prompt'; +export { EmptyState } from './empty_state'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx index 3e18c9e680de22..fc057858426d2f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx @@ -114,6 +114,11 @@ export const EngineRouter: React.FC = () => { )} + {canViewEngineApiLogs && ( + + + + )} {/* TODO: Remove layout once page template migration is over */} }> {canViewEngineSchema && ( @@ -141,11 +146,6 @@ export const EngineRouter: React.FC = () => { )} - {canViewEngineApiLogs && ( - - - - )} {canViewMetaEngineSourceEngines && (