diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_cards.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_cards.tsx index b08e391f845e6..ba71549455409 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_cards.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_cards.tsx @@ -17,10 +17,10 @@ interface Props { }>; } export const AnalyticsCards: React.FC = ({ stats }) => ( - + {stats.map(({ text, stat, dataTestSubj }) => ( - + { @@ -23,4 +25,12 @@ describe('AnalyticsSection', () => { expect(wrapper.find('p').text()).toEqual('Dolor sit amet.'); expect(wrapper.find('[data-test-subj="HelloWorld"]')).toHaveLength(1); }); + + it('renders an optional icon', () => { + const wrapper = shallow( + + ); + + expect(wrapper.find(EuiIcon).prop('type')).toEqual('eye'); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_section.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_section.tsx index a068696fda0d3..065eecf76ad43 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_section.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_section.tsx @@ -7,18 +7,43 @@ import React from 'react'; -import { EuiPageContentBody, EuiTitle, EuiText, EuiSpacer } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiPageContentBody, + EuiSpacer, + EuiText, + EuiTitle, + IconType, +} from '@elastic/eui'; interface Props { title: string; subtitle: string; + iconType?: IconType; } -export const AnalyticsSection: React.FC = ({ title, subtitle, children }) => ( +export const AnalyticsSection: React.FC = ({ title, subtitle, iconType, children }) => (
- -

{title}

-
+ + {iconType && ( + + + + )} + + +

{title}

+
+
+
+

{subtitle}

diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.test.tsx index 593f70cda404c..a0b0e4402c1e4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.test.tsx @@ -69,6 +69,16 @@ describe('AnalyticsTable', () => { expect(tableContent).toContain('0'); }); + it('renders tag counts instead of tag names if isSmall is passed', () => { + const wrapper = mountWithIntl(); + const tableContent = wrapper.find(EuiBasicTable).text(); + + expect(tableContent).toContain('Analytics tags'); + expect(tableContent).toContain('1 tag'); + expect(tableContent).toContain('2 tags'); + expect(wrapper.find(EuiBadge)).toHaveLength(3); + }); + describe('renders an action column', () => { const wrapper = mountWithIntl(); runActionColumnTests(wrapper); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.tsx index a580047f1f635..737b87816ba46 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/analytics_table.tsx @@ -14,7 +14,8 @@ import { Query } from '../../types'; import { TERM_COLUMN_PROPS, - TAGS_COLUMN, + TAGS_LIST_COLUMN, + TAGS_COUNT_COLUMN, COUNT_COLUMN_PROPS, ACTIONS_COLUMN, } from './shared_columns'; @@ -22,15 +23,18 @@ import { interface Props { items: Query[]; hasClicks?: boolean; + isSmall?: boolean; } type Columns = Array>; -export const AnalyticsTable: React.FC = ({ items, hasClicks }) => { +export const AnalyticsTable: React.FC = ({ items, hasClicks, isSmall }) => { const TERM_COLUMN = { field: 'key', ...TERM_COLUMN_PROPS, }; + const TAGS_COLUMN = isSmall ? TAGS_COUNT_COLUMN : TAGS_LIST_COLUMN; + const COUNT_COLUMNS = [ { field: 'searches.doc_count', diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.test.tsx deleted file mode 100644 index 9204fa6e75fa7..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.test.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 { EuiBadge, EuiToolTip } from '@elastic/eui'; - -import { InlineTagsList } from './inline_tags_list'; - -describe('InlineTagsList', () => { - it('renders', () => { - const wrapper = shallow(); - - expect(wrapper.find(EuiBadge)).toHaveLength(1); - expect(wrapper.find(EuiBadge).prop('children')).toEqual('test'); - }); - - it('renders >2 badges in a tooltip list', () => { - const wrapper = shallow(); - - expect(wrapper.find(EuiBadge)).toHaveLength(3); - expect(wrapper.find(EuiToolTip)).toHaveLength(1); - - expect(wrapper.find(EuiBadge).at(0).prop('children')).toEqual('1'); - expect(wrapper.find(EuiBadge).at(1).prop('children')).toEqual('2'); - expect(wrapper.find(EuiBadge).at(2).prop('children')).toEqual('and 3 more'); - expect(wrapper.find(EuiToolTip).prop('content')).toEqual('3, 4, 5'); - }); - - it('does not render with no tags', () => { - const wrapper = shallow(); - - expect(wrapper.isEmptyRender()).toBe(true); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/query_clicks_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/query_clicks_table.tsx index 4a93724ff5245..ba8fd1f17f816 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/query_clicks_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/query_clicks_table.tsx @@ -17,7 +17,7 @@ import { generateEnginePath } from '../../../engine'; import { QueryClick } from '../../types'; -import { FIRST_COLUMN_PROPS, TAGS_COLUMN, COUNT_COLUMN_PROPS } from './shared_columns'; +import { FIRST_COLUMN_PROPS, TAGS_LIST_COLUMN, COUNT_COLUMN_PROPS } from './shared_columns'; interface Props { items: QueryClick[]; @@ -55,7 +55,7 @@ export const QueryClicksTable: React.FC = ({ items }) => { return ( = ({ items }) => { return ( { const { http } = HttpLogic.values; const { navigateToUrl } = KibanaLogic.values; @@ -101,13 +101,20 @@ export const ACTIONS_COLUMN = { ], }; -export const TAGS_COLUMN = { +export const TAGS_COLUMN_PROPS = { field: 'tags', name: i18n.translate('xpack.enterpriseSearch.appSearch.engine.analytics.table.tagsColumn', { defaultMessage: 'Analytics tags', }), truncateText: true, - render: (tags: Query['tags']) => , +}; +export const TAGS_LIST_COLUMN = { + ...TAGS_COLUMN_PROPS, + render: (tags: Query['tags']) => , +}; +export const TAGS_COUNT_COLUMN = { + ...TAGS_COLUMN_PROPS, + render: (tags: Query['tags']) => , }; export const COUNT_COLUMN_PROPS = { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/tags.scss b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/tags.scss new file mode 100644 index 0000000000000..4de1c5e6226fa --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/tags.scss @@ -0,0 +1,3 @@ +.tagsList .euiBadge { + max-width: $euiSize * 9; +} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/tags.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/tags.test.tsx new file mode 100644 index 0000000000000..9a42da7461e0c --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/tags.test.tsx @@ -0,0 +1,67 @@ +/* + * 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 { EuiBadge, EuiToolTip } from '@elastic/eui'; + +import { TagsList, TagsCount } from './tags'; + +describe('TagsList', () => { + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(EuiBadge)).toHaveLength(1); + expect(wrapper.find(EuiBadge).prop('children')).toEqual('test'); + }); + + it('renders >2 badges in a tooltip list', () => { + const wrapper = shallow(); + + expect(wrapper.find(EuiBadge)).toHaveLength(3); + expect(wrapper.find(EuiToolTip)).toHaveLength(1); + + expect(wrapper.find(EuiBadge).at(0).prop('children')).toEqual('1'); + expect(wrapper.find(EuiBadge).at(1).prop('children')).toEqual('2'); + expect(wrapper.find(EuiBadge).at(2).prop('children')).toEqual('and 3 more'); + expect(wrapper.find(EuiToolTip).prop('content')).toEqual('3, 4, 5'); + }); + + it('does not render if missing tags', () => { + const wrapper = shallow(); + + expect(wrapper.isEmptyRender()).toBe(true); + }); +}); + +describe('TagsCount', () => { + it('renders a count and all tags in a tooltip', () => { + const wrapper = shallow(); + + expect(wrapper.find(EuiToolTip)).toHaveLength(1); + expect(wrapper.find(EuiBadge)).toHaveLength(1); + expect(wrapper.find(EuiBadge).prop('children')).toEqual('3 tags'); + expect(wrapper.find(EuiToolTip).prop('content')).toEqual('1, 2, 3'); + }); + + it('handles pluralization correctly', () => { + const wrapper = shallow(); + + expect(wrapper.find(EuiToolTip)).toHaveLength(1); + expect(wrapper.find(EuiBadge)).toHaveLength(1); + expect(wrapper.find(EuiBadge).prop('children')).toEqual('1 tag'); + expect(wrapper.find(EuiToolTip).prop('content')).toEqual('1'); + }); + + it('does not render if missing tags', () => { + const wrapper = shallow(); + + expect(wrapper.isEmptyRender()).toBe(true); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/tags.tsx similarity index 67% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/tags.tsx index 908b096c80a9e..241abfabfab4c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/inline_tags_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/tags.tsx @@ -12,17 +12,35 @@ import { i18n } from '@kbn/i18n'; import { Query } from '../../types'; +import './tags.scss'; + interface Props { tags?: Query['tags']; } -export const InlineTagsList: React.FC = ({ tags }) => { + +export const TagsCount: React.FC = ({ tags }) => { + if (!tags?.length) return null; + + return ( + + + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.analytics.table.tagsCountBadge', { + defaultMessage: '{tagsCount, plural, one {# tag} other {# tags}}', + values: { tagsCount: tags.length }, + })} + + + ); +}; + +export const TagsList: React.FC = ({ tags }) => { if (!tags?.length) return null; const displayedTags = tags.slice(0, 2); const tooltipTags = tags.slice(2); return ( - + {displayedTags.map((tag: string) => ( {tag} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.scss b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.scss new file mode 100644 index 0000000000000..9b24a64390d4f --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.scss @@ -0,0 +1,5 @@ +.analyticsOverviewTables { + @include euiBreakpoint('xs', 's', 'm', 'l') { + flex-direction: column; // Force full width on table panels earlier to ensure content stays legible + } +} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.test.tsx index d8921ff0d3723..688d5dec1a958 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.test.tsx @@ -42,7 +42,7 @@ describe('Analytics overview', () => { expect(wrapper.find(AnalyticsCards)).toHaveLength(1); expect(wrapper.find(AnalyticsChart)).toHaveLength(1); - expect(wrapper.find(AnalyticsSection)).toHaveLength(3); + expect(wrapper.find(AnalyticsSection)).toHaveLength(2); expect(wrapper.find(AnalyticsTable)).toHaveLength(4); expect(wrapper.find(RecentQueriesTable)).toHaveLength(1); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.tsx index a4f0bc356ac78..82b0d9a318f1d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/views/analytics.tsx @@ -9,10 +9,12 @@ import React from 'react'; import { useValues } from 'kea'; -import { EuiSpacer, EuiTitle } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { EuiButtonTo } from '../../../../shared/react_router_helpers'; +import { EuiButtonEmptyTo } from '../../../../shared/react_router_helpers'; +import { CursorIcon } from '../../../icons'; + import { ENGINE_ANALYTICS_TOP_QUERIES_PATH, ENGINE_ANALYTICS_TOP_QUERIES_NO_RESULTS_PATH, @@ -20,6 +22,7 @@ import { ENGINE_ANALYTICS_TOP_QUERIES_WITH_CLICKS_PATH, ENGINE_ANALYTICS_RECENT_QUERIES_PATH, } from '../../../routes'; +import { DataPanel } from '../../data_panel'; import { generateEnginePath } from '../../engine'; import { AnalyticsLayout } from '../analytics_layout'; @@ -37,6 +40,8 @@ import { } from '../constants'; import { AnalyticsLogic, AnalyticsCards, AnalyticsChart, convertToChartData } from '../index'; +import './analytics.scss'; + export const Analytics: React.FC = () => { const { totalQueries, @@ -55,45 +60,54 @@ export const Analytics: React.FC = () => { return ( - + + + + + + {/* TODO: Update this panel to use the bordered version once available */} + + + + + - { 'Gain insight into the most frequent queries, and which queries returned no results.', } )} + iconType="search" > - -

{TOP_QUERIES}

-
- - - - -

{TOP_QUERIES_NO_RESULTS}

-
- - + + + {TOP_QUERIES}} + filled + action={} + > + + + + + {TOP_QUERIES_NO_RESULTS}} + filled + action={ + + } + > + + + +
@@ -134,39 +162,57 @@ export const Analytics: React.FC = () => { defaultMessage: 'Discover which queries generated the most and least amount of clicks.', } )} + iconType={CursorIcon} > - -

{TOP_QUERIES_WITH_CLICKS}

-
- - - - -

{TOP_QUERIES_NO_CLICKS}

-
- - + + + {TOP_QUERIES_WITH_CLICKS}} + filled + action={ + + } + > + + + + + {TOP_QUERIES_NO_CLICKS}} + filled + action={ + + } + > + + + + - {RECENT_QUERIES}} subtitle={i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.analytics.recentQueriesDescription', { defaultMessage: 'A view into queries happening right now.' } )} + action={} > - - +
); }; export const ViewAllButton: React.FC<{ to: string }> = ({ to }) => ( - + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.analytics.table.viewAllButtonLabel', { defaultMessage: 'View all', })} - + ); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.scss b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.scss new file mode 100644 index 0000000000000..f05e029ec8f8b --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.scss @@ -0,0 +1,8 @@ +.dataPanel { + // TODO: This CSS can be removed once EUI supports tables in `subdued` panels + &--filled { + .euiTable { + background-color: transparent; + } + } +} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.test.tsx new file mode 100644 index 0000000000000..e8f480bce9ee7 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.test.tsx @@ -0,0 +1,95 @@ +/* + * 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 { EuiIcon, EuiButton } from '@elastic/eui'; + +import { DataPanel } from './data_panel'; + +describe('DataPanel', () => { + it('renders with a title and children', () => { + const wrapper = shallow( + Tabula Rasa}> +
Look at this graph
+
+ ); + + expect(wrapper.find('[data-test-subj="title"]').text()).toEqual('Tabula Rasa'); + expect(wrapper.find('[data-test-subj="children"]').text()).toEqual('Look at this graph'); + }); + + describe('components', () => { + it('renders with an icon', () => { + const wrapper = shallow(The Smoke Monster} iconType="eye" />); + + expect(wrapper.find(EuiIcon).prop('type')).toEqual('eye'); + }); + + it('renders with a subtitle', () => { + const wrapper = shallow( + Hugo Reyes} subtitle="Hurley was typically happy-go-lucky" /> + ); + + expect(wrapper.find('p').text()).toEqual('Hurley was typically happy-go-lucky'); + }); + + it('renders with an icon and a subtitle', () => { + const wrapper = shallow( + Flight 815} + iconType="package" + subtitle="Oceanic Airlines Flight 815 was a scheduled flight from Sydney, Australia to Los Angeles, California" + /> + ); + + expect(wrapper.find(EuiIcon).prop('type')).toEqual('package'); + expect(wrapper.find('p').text()).toEqual( + 'Oceanic Airlines Flight 815 was a scheduled flight from Sydney, Australia to Los Angeles, California' + ); + }); + + it('renders with a button', () => { + const wrapper = shallow( + Board Flight 815} + action={Book flight} + /> + ); + + expect(wrapper.find('[data-test-subj="action"]')).toHaveLength(1); + }); + }); + + describe('props', () => { + it('renders panel color based on filled flag', () => { + const wrapper = shallow(Test} />); + + expect(wrapper.prop('color')).toEqual('plain'); + expect(wrapper.prop('className')).toEqual('dataPanel'); + + wrapper.setProps({ filled: true }); + + expect(wrapper.prop('color')).toEqual('subdued'); + expect(wrapper.prop('className')).toEqual('dataPanel dataPanel--filled'); + }); + + it('passes class names', () => { + const wrapper = shallow(Test} className="testing" />); + + expect(wrapper.prop('className')).toEqual('dataPanel testing'); + }); + + it('passes arbitrary props', () => { + const wrapper = shallow(Test} data-test-subj="testing" />); + + expect(wrapper.find('[data-test-subj="testing"]')).toHaveLength(1); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.tsx new file mode 100644 index 0000000000000..f6a474689b3af --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.tsx @@ -0,0 +1,73 @@ +/* + * 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 classNames from 'classnames'; + +import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiPanel, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; + +import './data_panel.scss'; + +interface Props { + title: React.ReactElement; // e.g., h2 tag + subtitle?: string; + iconType?: string; + action?: React.ReactNode; + filled?: boolean; + className?: string; +} + +export const DataPanel: React.FC = ({ + title, + subtitle, + iconType, + action, + filled, + className, + children, + ...props // e.g., data-test-subj +}) => { + const classes = classNames('dataPanel', className, { + 'dataPanel--filled': filled, + }); + + return ( + + + + + {iconType && ( + + + + )} + + {title} + {subtitle && ( + +

{subtitle}

+
+ )} +
+
+
+ {action && {action}} +
+ + {children} +
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/index.ts new file mode 100644 index 0000000000000..092a86180e95d --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { DataPanel } from './data_panel'; 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 index 42fa9777563db..ceda3ab92f589 100644 --- 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 @@ -11,8 +11,6 @@ import React from 'react'; import { shallow, ShallowWrapper } from 'enzyme'; -import { EuiButtonTo } from '../../../../shared/react_router_helpers'; - import { RecentApiLogs } from './recent_api_logs'; describe('RecentApiLogs', () => { @@ -24,8 +22,7 @@ describe('RecentApiLogs', () => { }); 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'); + expect(wrapper.prop('title')).toEqual(

Recent API events

); // 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 index 625ba2e905840..1c7f43a592536 100644 --- 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 @@ -7,40 +7,26 @@ import React from 'react'; -import { - EuiPageContent, - EuiPageContentHeader, - EuiPageContentHeaderSection, - EuiPageContentBody, - EuiTitle, -} from '@elastic/eui'; - -import { EuiButtonTo } from '../../../../shared/react_router_helpers'; +import { EuiButtonEmptyTo } from '../../../../shared/react_router_helpers'; import { ENGINE_API_LOGS_PATH } from '../../../routes'; import { RECENT_API_EVENTS } from '../../api_logs/constants'; +import { DataPanel } from '../../data_panel'; import { generateEnginePath } from '../../engine'; import { VIEW_API_LOGS } from '../constants'; export const RecentApiLogs: React.FC = () => { return ( - - - - -

{RECENT_API_EVENTS}

-
-
- - - {VIEW_API_LOGS} - - -
- - TODO: API Logs Table - {/* */} - -
+ {RECENT_API_EVENTS}} + action={ + + {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 index a2f35b4709939..74ce770205ffe 100644 --- 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 @@ -12,7 +12,6 @@ import React from 'react'; import { shallow, ShallowWrapper } from 'enzyme'; -import { EuiButtonTo } from '../../../../shared/react_router_helpers'; import { AnalyticsChart } from '../../analytics'; import { TotalCharts } from './total_charts'; @@ -31,18 +30,16 @@ describe('TotalCharts', () => { }); it('renders the total queries chart', () => { - const chart = wrapper.find('[data-test-subj="TotalQueriesChart"]'); + const panel = 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'); - expect(chart.find(AnalyticsChart)).toHaveLength(1); + expect(panel.prop('title')).toEqual(

Total queries

); + expect(panel.find(AnalyticsChart)).toHaveLength(1); }); it('renders the total API operations chart', () => { - const chart = wrapper.find('[data-test-subj="TotalApiOperationsChart"]'); + const panel = 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'); - expect(chart.find(AnalyticsChart)).toHaveLength(1); + expect(panel.prop('title')).toEqual(

Total API operations

); + expect(panel.find(AnalyticsChart)).toHaveLength(1); }); }); 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 index 6bd973ae142a8..77ba9ad0f9514 100644 --- 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 @@ -9,21 +9,13 @@ import React from 'react'; import { useValues } from 'kea'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiPageContent, - EuiPageContentHeader, - EuiPageContentHeaderSection, - EuiPageContentBody, - EuiTitle, - EuiText, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { EuiButtonTo } from '../../../../shared/react_router_helpers'; +import { EuiButtonEmptyTo } from '../../../../shared/react_router_helpers'; import { ENGINE_ANALYTICS_PATH, ENGINE_API_LOGS_PATH } from '../../../routes'; import { AnalyticsChart, convertToChartData } from '../../analytics'; import { TOTAL_QUERIES, TOTAL_API_OPERATIONS } from '../../analytics/constants'; +import { DataPanel } from '../../data_panel'; import { generateEnginePath } from '../../engine'; import { VIEW_ANALYTICS, VIEW_API_LOGS, LAST_7_DAYS } from '../constants'; @@ -35,62 +27,52 @@ export const TotalCharts: React.FC = () => { return ( - - - - -

{TOTAL_QUERIES}

-
- - {LAST_7_DAYS} - -
- - - {VIEW_ANALYTICS} - - -
- - - -
+ {TOTAL_QUERIES}} + subtitle={LAST_7_DAYS} + action={ + + {VIEW_ANALYTICS} + + } + > + +
- - - - -

{TOTAL_API_OPERATIONS}

-
- - {LAST_7_DAYS} - -
- - - {VIEW_API_LOGS} - - -
- - - -
+ {TOTAL_API_OPERATIONS}} + subtitle={LAST_7_DAYS} + action={ + + {VIEW_API_LOGS} + + } + > + +
); 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 index c33431354eafc..c60cf70f435c5 100644 --- 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 @@ -9,7 +9,7 @@ import React from 'react'; import { useValues } from 'kea'; -import { EuiPageHeader, EuiTitle, EuiSpacer } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiPageHeader, EuiTitle, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FlashMessages } from '../../../shared/flash_messages'; @@ -37,9 +37,14 @@ export const EngineOverviewMetrics: React.FC = () => { ) : ( <> - - - + + + + + + + + diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx index 4cfa5d9078162..ca70e323bd3e7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx @@ -25,10 +25,9 @@ import { LicensingLogic } from '../../../shared/licensing'; import { EuiButtonTo } from '../../../shared/react_router_helpers'; import { convertMetaToPagination, handlePageChange } from '../../../shared/table_pagination'; import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; +import { EngineIcon, MetaEngineIcon } from '../../icons'; import { ENGINE_CREATION_PATH, META_ENGINE_CREATION_PATH } from '../../routes'; -import { EngineIcon } from './assets/engine_icon'; -import { MetaEngineIcon } from './assets/meta_engine_icon'; import { EnginesOverviewHeader, LoadingState, EmptyState } from './components'; import { CREATE_AN_ENGINE_BUTTON_LABEL, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/icons/cursor_icon.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/icons/cursor_icon.tsx new file mode 100644 index 0000000000000..c874f135563ec --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/icons/cursor_icon.tsx @@ -0,0 +1,23 @@ +/* + * 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'; + +// TODO: This icon will be added to EUI soon - we should remove this custom SVG when once it's available in EUI +export const CursorIcon: React.FC = ({ ...props }) => ( + +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/engine_icon.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/icons/engine_icon.tsx similarity index 100% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/engine_icon.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/icons/engine_icon.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/icons.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/icons/icons.test.tsx similarity index 75% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/icons.test.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/icons/icons.test.tsx index 33ca5bd8248c9..7c4eaddda6c6f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/icons.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/icons/icons.test.tsx @@ -9,10 +9,16 @@ import React from 'react'; import { shallow } from 'enzyme'; +import { CursorIcon } from './cursor_icon'; import { EngineIcon } from './engine_icon'; import { MetaEngineIcon } from './meta_engine_icon'; -describe('Engines icons', () => { +describe('shared App Search icons', () => { + it('renders a cursor icon', () => { + const wrapper = shallow(); + expect(wrapper.hasClass('euiIcon')).toBe(true); + }); + it('renders an engine icon', () => { const wrapper = shallow(); expect(wrapper.hasClass('engineIcon')).toBe(true); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/icons/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/icons/index.ts new file mode 100644 index 0000000000000..1669fdab5ec4e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/icons/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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { CursorIcon } from './cursor_icon'; +export { EngineIcon } from './engine_icon'; +export { MetaEngineIcon } from './meta_engine_icon'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/meta_engine_icon.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/icons/meta_engine_icon.tsx similarity index 100% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/meta_engine_icon.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/icons/meta_engine_icon.tsx