diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/constants.ts new file mode 100644 index 0000000000000..51ae11ad2ab82 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/constants.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const TOTAL_DOCUMENTS = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.analytics.totalDocuments', + { defaultMessage: 'Total documents' } +); + +export const TOTAL_API_OPERATIONS = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.analytics.totalApiOperations', + { defaultMessage: 'Total API operations' } +); + +export const TOTAL_QUERIES = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.analytics.totalQueries', + { defaultMessage: 'Total queries' } +); + +export const TOTAL_CLICKS = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.analytics.totalClicks', + { defaultMessage: 'Total clicks' } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/constants.ts new file mode 100644 index 0000000000000..6fd60b7a34ebc --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/api_logs/constants.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const RECENT_API_EVENTS = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.apiLogs.recent', + { defaultMessage: 'Recent API events' } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/constants.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/constants.tsx new file mode 100644 index 0000000000000..736ef09fa6cf3 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/constants.tsx @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; + +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCode, EuiLink } from '@elastic/eui'; + +import { DOCS_PREFIX } from '../../routes'; + +export const DOCUMENT_CREATION_DESCRIPTION = ( + .json, + postCode: POST, + documentsApiLink: ( + + documents API + + ), + apiStrong: Indexing by API, + }} + /> +); + +export const DOCUMENT_API_INDEXING_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.documentCreation.api.title', + { defaultMessage: 'Indexing by API' } +); + +export const DOCUMENT_API_INDEXING_DESCRIPTION = ( + + documents API + + ), + clientLibrariesLink: ( + + client libraries + + ), + }} + /> +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts index 3c963e415f33b..9ce524038075b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts @@ -9,10 +9,6 @@ import { i18n } from '@kbn/i18n'; // TODO: It's very likely that we'll move these i18n constants to their respective component // folders once those are migrated over. This is a temporary way of DRYing them out for now. -export const OVERVIEW_TITLE = i18n.translate( - 'xpack.enterpriseSearch.appSearch.engine.overview.title', - { defaultMessage: 'Overview' } -); export const ANALYTICS_TITLE = i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.analytics.title', { defaultMessage: 'Analytics' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx index 77aca8a71994d..a7ac6f203b1f7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx @@ -28,8 +28,8 @@ import { } from '../../routes'; import { getAppSearchUrl } from '../../../shared/enterprise_search_url'; import { ENGINES_TITLE } from '../engines'; +import { OVERVIEW_TITLE } from '../engine_overview'; import { - OVERVIEW_TITLE, ANALYTICS_TITLE, DOCUMENTS_TITLE, SCHEMA_TITLE, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx index 8f067754c48a0..e8609c169855b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx @@ -18,6 +18,7 @@ jest.mock('../../../shared/flash_messages', () => ({ import { setQueuedErrorMessage } from '../../../shared/flash_messages'; import { Loading } from '../../../shared/loading'; +import { EngineOverview } from '../engine_overview'; import { EngineRouter } from './'; @@ -71,7 +72,7 @@ describe('EngineRouter', () => { const wrapper = shallow(); expect(wrapper.find(Switch)).toHaveLength(1); - expect(wrapper.find('[data-test-subj="EngineOverviewTODO"]')).toHaveLength(1); + expect(wrapper.find(EngineOverview)).toHaveLength(1); }); it('renders an analytics view', () => { 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 9833305c438c1..f586106924f2c 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 @@ -31,8 +31,8 @@ import { // ENGINE_API_LOGS_PATH, } from '../../routes'; import { ENGINES_TITLE } from '../engines'; +import { OVERVIEW_TITLE } from '../engine_overview'; import { - OVERVIEW_TITLE, ANALYTICS_TITLE, // DOCUMENTS_TITLE, // SCHEMA_TITLE, @@ -46,6 +46,7 @@ import { } from './constants'; import { Loading } from '../../../shared/loading'; +import { EngineOverview } from '../engine_overview'; import { EngineLogic } from './'; @@ -100,7 +101,7 @@ export const EngineRouter: React.FC = () => { )} -
Overview
+
); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/index.ts new file mode 100644 index 0000000000000..11e7b2a5fba97 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { UnavailablePrompt } from './unavailable_prompt'; +export { TotalStats } from './total_stats'; +export { TotalCharts } from './total_charts'; +export { RecentApiLogs } from './recent_api_logs'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.test.tsx new file mode 100644 index 0000000000000..fb34682e3c7ec --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.test.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { setMockValues } from '../../../../__mocks__/kea.mock'; + +import React from 'react'; +import { shallow, ShallowWrapper } from 'enzyme'; + +import { EuiButtonTo } from '../../../../shared/react_router_helpers'; + +import { RecentApiLogs } from './recent_api_logs'; + +describe('RecentApiLogs', () => { + let wrapper: ShallowWrapper; + + beforeAll(() => { + jest.clearAllMocks(); + setMockValues({ + engineName: 'some-engine', + }); + wrapper = shallow(); + }); + + it('renders the recent API logs table', () => { + expect(wrapper.find('h2').text()).toEqual('Recent API events'); + expect(wrapper.find(EuiButtonTo).prop('to')).toEqual('/engines/some-engine/api-logs'); + // TODO: expect(wrapper.find(ApiLogsTable)).toHaveLength(1) + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.tsx new file mode 100644 index 0000000000000..3f42419252d28 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/recent_api_logs.tsx @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { useValues } from 'kea'; + +import { + EuiPageContent, + EuiPageContentHeader, + EuiPageContentHeaderSection, + EuiPageContentBody, + EuiTitle, +} from '@elastic/eui'; + +import { EuiButtonTo } from '../../../../shared/react_router_helpers'; + +import { ENGINE_API_LOGS_PATH, getEngineRoute } from '../../../routes'; +import { RECENT_API_EVENTS } from '../../api_logs/constants'; +import { VIEW_API_LOGS } from '../constants'; + +import { EngineLogic } from '../../engine'; + +export const RecentApiLogs: React.FC = () => { + const { engineName } = useValues(EngineLogic); + const engineRoute = getEngineRoute(engineName); + + return ( + + + + +

{RECENT_API_EVENTS}

+
+
+ + + {VIEW_API_LOGS} + + +
+ + TODO: API Logs Table + {/* */} + +
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.test.tsx new file mode 100644 index 0000000000000..775a74921d0d4 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.test.tsx @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { setMockValues } from '../../../../__mocks__/kea.mock'; + +import React from 'react'; +import { shallow, ShallowWrapper } from 'enzyme'; + +import { EuiButtonTo } from '../../../../shared/react_router_helpers'; + +import { TotalCharts } from './total_charts'; + +describe('TotalCharts', () => { + let wrapper: ShallowWrapper; + + beforeAll(() => { + jest.clearAllMocks(); + setMockValues({ + engineName: 'some-engine', + startDate: '1970-01-01', + endDate: '1970-01-08', + queriesPerDay: [0, 1, 2, 3, 5, 10, 50], + operationsPerDay: [0, 0, 0, 0, 0, 0, 0], + }); + wrapper = shallow(); + }); + + it('renders the total queries chart', () => { + const chart = wrapper.find('[data-test-subj="TotalQueriesChart"]'); + + expect(chart.find('h2').text()).toEqual('Total queries'); + expect(chart.find(EuiButtonTo).prop('to')).toEqual('/engines/some-engine/analytics'); + // TODO: find chart component + }); + + it('renders the total API operations chart', () => { + const chart = wrapper.find('[data-test-subj="TotalApiOperationsChart"]'); + + expect(chart.find('h2').text()).toEqual('Total API operations'); + expect(chart.find(EuiButtonTo).prop('to')).toEqual('/engines/some-engine/api-logs'); + // TODO: find chart component + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.tsx new file mode 100644 index 0000000000000..214a6bd74aab2 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_charts.tsx @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { useValues } from 'kea'; + +import { + EuiFlexGroup, + EuiFlexItem, + EuiPageContent, + EuiPageContentHeader, + EuiPageContentHeaderSection, + EuiPageContentBody, + EuiTitle, + EuiText, +} from '@elastic/eui'; + +import { EuiButtonTo } from '../../../../shared/react_router_helpers'; + +import { ENGINE_ANALYTICS_PATH, ENGINE_API_LOGS_PATH, getEngineRoute } from '../../../routes'; +import { TOTAL_QUERIES, TOTAL_API_OPERATIONS } from '../../analytics/constants'; +import { VIEW_ANALYTICS, VIEW_API_LOGS, LAST_7_DAYS } from '../constants'; + +import { EngineLogic } from '../../engine'; +import { EngineOverviewLogic } from '../'; + +export const TotalCharts: React.FC = () => { + const { engineName } = useValues(EngineLogic); + const engineRoute = getEngineRoute(engineName); + + const { + // startDate, + // endDate, + // queriesPerDay, + // operationsPerDay, + } = useValues(EngineOverviewLogic); + + return ( + + + + + + +

{TOTAL_QUERIES}

+
+ + {LAST_7_DAYS} + +
+ + + {VIEW_ANALYTICS} + + +
+ + TODO: Analytics chart + {/* */} + +
+
+ + + + + +

{TOTAL_API_OPERATIONS}

+
+ + {LAST_7_DAYS} + +
+ + + {VIEW_API_LOGS} + + +
+ + TODO: API Logs chart + {/* */} + +
+
+
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.test.tsx new file mode 100644 index 0000000000000..6cb47e8b419f3 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.test.tsx @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { setMockValues } from '../../../../__mocks__/kea.mock'; + +import React from 'react'; +import { shallow, ShallowWrapper } from 'enzyme'; +import { EuiStat } from '@elastic/eui'; + +import { TotalStats } from './total_stats'; + +describe('TotalStats', () => { + let wrapper: ShallowWrapper; + + beforeAll(() => { + jest.clearAllMocks(); + setMockValues({ + totalQueries: 11, + documentCount: 22, + totalClicks: 33, + }); + wrapper = shallow(); + }); + + it('renders the total queries stat', () => { + expect(wrapper.find('[data-test-subj="TotalQueriesCard"]')).toHaveLength(1); + + const card = wrapper.find(EuiStat).at(0); + expect(card.prop('title')).toEqual(11); + expect(card.prop('description')).toEqual('Total queries'); + }); + + it('renders the total documents stat', () => { + expect(wrapper.find('[data-test-subj="TotalDocumentsCard"]')).toHaveLength(1); + + const card = wrapper.find(EuiStat).at(1); + expect(card.prop('title')).toEqual(22); + expect(card.prop('description')).toEqual('Total documents'); + }); + + it('renders the total clicks stat', () => { + expect(wrapper.find('[data-test-subj="TotalClicksCard"]')).toHaveLength(1); + + const card = wrapper.find(EuiStat).at(2); + expect(card.prop('title')).toEqual(33); + expect(card.prop('description')).toEqual('Total clicks'); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.tsx new file mode 100644 index 0000000000000..a27142938f558 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/total_stats.tsx @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { useValues } from 'kea'; +import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiStat } from '@elastic/eui'; + +import { TOTAL_QUERIES, TOTAL_DOCUMENTS, TOTAL_CLICKS } from '../../analytics/constants'; + +import { EngineOverviewLogic } from '../'; + +export const TotalStats: React.FC = () => { + const { totalQueries, documentCount, totalClicks } = useValues(EngineOverviewLogic); + + return ( + + + + + + + + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.test.tsx new file mode 100644 index 0000000000000..3ddfd14b0eb0c --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.test.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { EuiEmptyPrompt } from '@elastic/eui'; + +import { UnavailablePrompt } from './unavailable_prompt'; + +describe('UnavailablePrompt', () => { + it('renders', () => { + const wrapper = shallow(); + expect(wrapper.find(EuiEmptyPrompt)).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.tsx new file mode 100644 index 0000000000000..e9cc6e2f05bf3 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/unavailable_prompt.tsx @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; + +import { i18n } from '@kbn/i18n'; +import { EuiEmptyPrompt } from '@elastic/eui'; + +export const UnavailablePrompt: React.FC = () => ( + + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.overview.unavailableTitle', { + defaultMessage: 'Dashboard metrics are currently unavailable', + })} + + } + body={ +

+ {i18n.translate('xpack.enterpriseSearch.appSearch.engine.overview.unavailableBody', { + defaultMessage: 'Please try again in a few minutes.', + })} +

+ } + /> +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/constants.ts new file mode 100644 index 0000000000000..797811ec6cde8 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/constants.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const OVERVIEW_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.overview.title', + { defaultMessage: 'Overview' } +); + +export const VIEW_ANALYTICS = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.overview.analyticsLink', + { defaultMessage: 'View analytics' } +); + +export const VIEW_API_LOGS = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.overview.apiLogsLink', + { defaultMessage: 'View API logs' } +); + +export const LAST_7_DAYS = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.overview.chartDuration', + { defaultMessage: 'Last 7 days' } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx new file mode 100644 index 0000000000000..196fb2ca2bf13 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import '../../../__mocks__/shallow_useeffect.mock'; +import { setMockValues, setMockActions } from '../../../__mocks__/kea.mock'; + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { Loading } from '../../../shared/loading'; +import { EmptyEngineOverview } from './engine_overview_empty'; +import { EngineOverviewMetrics } from './engine_overview_metrics'; +import { EngineOverview } from './'; + +describe('EngineOverview', () => { + const values = { + dataLoading: false, + documentCount: 0, + myRole: {}, + isMetaEngine: false, + }; + const actions = { + pollForOverviewMetrics: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(values); + setMockActions(actions); + }); + + it('renders', () => { + const wrapper = shallow(); + expect(wrapper.find('[data-test-subj="EngineOverview"]')).toHaveLength(1); + }); + + it('initializes data on mount', () => { + shallow(); + expect(actions.pollForOverviewMetrics).toHaveBeenCalledTimes(1); + }); + + it('renders a loading component if async data is still loading', () => { + setMockValues({ ...values, dataLoading: true }); + const wrapper = shallow(); + expect(wrapper.find(Loading)).toHaveLength(1); + }); + + describe('EmptyEngineOverview', () => { + it('renders when the engine has no documents & the user can add documents', () => { + const myRole = { canManageEngineDocuments: true, canViewEngineCredentials: true }; + setMockValues({ ...values, myRole, documentCount: 0 }); + const wrapper = shallow(); + expect(wrapper.find(EmptyEngineOverview)).toHaveLength(1); + }); + }); + + describe('EngineOverviewMetrics', () => { + it('renders when the engine has documents', () => { + setMockValues({ ...values, documentCount: 1 }); + const wrapper = shallow(); + expect(wrapper.find(EngineOverviewMetrics)).toHaveLength(1); + }); + + it('renders when the user does not have the ability to add documents', () => { + const myRole = { canManageEngineDocuments: false, canViewEngineCredentials: false }; + setMockValues({ ...values, myRole }); + const wrapper = shallow(); + expect(wrapper.find(EngineOverviewMetrics)).toHaveLength(1); + }); + + it('always renders for meta engines', () => { + setMockValues({ ...values, isMetaEngine: true }); + const wrapper = shallow(); + expect(wrapper.find(EngineOverviewMetrics)).toHaveLength(1); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx new file mode 100644 index 0000000000000..dd43bc67b3e88 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useEffect } from 'react'; +import { useActions, useValues } from 'kea'; + +import { AppLogic } from '../../app_logic'; +import { EngineLogic } from '../engine'; +import { Loading } from '../../../shared/loading'; + +import { EngineOverviewLogic } from './'; +import { EmptyEngineOverview } from './engine_overview_empty'; +import { EngineOverviewMetrics } from './engine_overview_metrics'; + +export const EngineOverview: React.FC = () => { + const { + myRole: { canManageEngineDocuments, canViewEngineCredentials }, + } = useValues(AppLogic); + const { isMetaEngine } = useValues(EngineLogic); + + const { pollForOverviewMetrics } = useActions(EngineOverviewLogic); + const { dataLoading, documentCount } = useValues(EngineOverviewLogic); + + useEffect(() => { + pollForOverviewMetrics(); + }, []); + + if (dataLoading) { + return ; + } + + const engineHasDocuments = documentCount > 0; + const canAddDocuments = canManageEngineDocuments && canViewEngineCredentials; + const showEngineOverview = engineHasDocuments || !canAddDocuments || isMetaEngine; + + return ( +
+ {showEngineOverview ? : } +
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.test.tsx new file mode 100644 index 0000000000000..8ebe09820a67e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.test.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import '../../../__mocks__/enterprise_search_url.mock'; +import { setMockValues } from '../../../__mocks__/kea.mock'; + +import React from 'react'; +import { shallow, ShallowWrapper } from 'enzyme'; +import { EuiButton } from '@elastic/eui'; + +import { CURRENT_MAJOR_VERSION } from '../../../../../common/version'; + +import { EmptyEngineOverview } from './engine_overview_empty'; + +describe('EmptyEngineOverview', () => { + let wrapper: ShallowWrapper; + + beforeAll(() => { + jest.clearAllMocks(); + setMockValues({ + engineName: 'empty-engine', + }); + wrapper = shallow(); + }); + + it('renders', () => { + expect(wrapper.find('h1').text()).toEqual('Engine setup'); + expect(wrapper.find('h2').text()).toEqual('Setting up the “empty-engine” engine'); + expect(wrapper.find('h3').text()).toEqual('Indexing by API'); + }); + + it('renders correctly versioned documentation URLs', () => { + expect(wrapper.find(EuiButton).prop('href')).toEqual( + `https://www.elastic.co/guide/en/app-search/${CURRENT_MAJOR_VERSION}/index.html` + ); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.tsx new file mode 100644 index 0000000000000..f2bf5a54f810c --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_empty.tsx @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { useValues } from 'kea'; + +import { i18n } from '@kbn/i18n'; +import { + EuiPageHeader, + EuiPageHeaderSection, + EuiPageContent, + EuiPageContentHeader, + EuiPageContentBody, + EuiTitle, + EuiText, + EuiButton, + EuiSpacer, +} from '@elastic/eui'; + +import { EngineLogic } from '../engine'; + +import { DOCS_PREFIX } from '../../routes'; +import { + DOCUMENT_CREATION_DESCRIPTION, + DOCUMENT_API_INDEXING_TITLE, + DOCUMENT_API_INDEXING_DESCRIPTION, +} from '../document_creation/constants'; +// TODO +// import { DocumentCreationButtons, CodeExample } from '../document_creation' + +export const EmptyEngineOverview: React.FC = () => { + const { engineName } = useValues(EngineLogic); + + return ( + <> + + + +

+ {i18n.translate('xpack.enterpriseSearch.appSearch.engine.overview.empty.heading', { + defaultMessage: 'Engine setup', + })} +

+
+
+ + + {i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.overview.empty.headingAction', + { defaultMessage: 'View documentation' } + )} + + +
+ + + +

+ {i18n.translate('xpack.enterpriseSearch.appSearch.engine.overview.empty.subheading', { + defaultMessage: 'Setting up the “{engineName}” engine', + values: { engineName }, + })} +

+
+
+ + +

{DOCUMENT_CREATION_DESCRIPTION}

+
+ + {/* TODO: */} +
+ + + +

{DOCUMENT_API_INDEXING_TITLE}

+
+
+ + +

{DOCUMENT_API_INDEXING_DESCRIPTION}

+

+ {i18n.translate('xpack.enterpriseSearch.appSearch.engine.overview.empty.apiExample', { + defaultMessage: + 'To see the API in action, you can experiment with the example request below using a command line or a client library.', + })} +

+
+ + {/* */} +
+
+ + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.test.tsx new file mode 100644 index 0000000000000..8250446e231b3 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.test.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { setMockValues } from '../../../__mocks__/kea.mock'; + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { UnavailablePrompt, TotalStats, TotalCharts, RecentApiLogs } from './components'; +import { EngineOverviewMetrics } from './engine_overview_metrics'; + +describe('EngineOverviewMetrics', () => { + it('renders', () => { + const wrapper = shallow(); + expect(wrapper.find('h1').text()).toEqual('Engine overview'); + }); + + it('renders an unavailable prompt if engine data is still indexing', () => { + setMockValues({ apiLogsUnavailable: true }); + const wrapper = shallow(); + expect(wrapper.find(UnavailablePrompt)).toHaveLength(1); + }); + + it('renders total stats, charts, and recent logs when metrics are available', () => { + setMockValues({ apiLogsUnavailable: false }); + const wrapper = shallow(); + expect(wrapper.find(TotalStats)).toHaveLength(1); + expect(wrapper.find(TotalCharts)).toHaveLength(1); + expect(wrapper.find(RecentApiLogs)).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.tsx new file mode 100644 index 0000000000000..9630f6fa2f81d --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview_metrics.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { useValues } from 'kea'; + +import { i18n } from '@kbn/i18n'; +import { EuiPageHeader, EuiTitle, EuiSpacer } from '@elastic/eui'; + +import { EngineOverviewLogic } from './'; + +import { UnavailablePrompt, TotalStats, TotalCharts, RecentApiLogs } from './components'; + +export const EngineOverviewMetrics: React.FC = () => { + const { apiLogsUnavailable } = useValues(EngineOverviewLogic); + + return ( + <> + + +

+ {i18n.translate('xpack.enterpriseSearch.appSearch.engine.overview.heading', { + defaultMessage: 'Engine overview', + })} +

+
+
+ {apiLogsUnavailable ? ( + + ) : ( + <> + + + + + + + )} + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/index.ts index fcd92ba6a338c..82c5d7dc8e60a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/index.ts @@ -5,3 +5,5 @@ */ export { EngineOverviewLogic } from './engine_overview_logic'; +export { EngineOverview } from './engine_overview'; +export { OVERVIEW_TITLE } from './constants';