Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ interface Props {
}>;
}
export const AnalyticsCards: React.FC<Props> = ({ stats }) => (
<EuiFlexGroup>
<EuiFlexGroup direction="column">
{stats.map(({ text, stat, dataTestSubj }) => (
<EuiFlexItem key={text}>
<EuiPanel>
<EuiPanel color="subdued" hasShadow={false}>
<EuiStat
title={stat}
description={text}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import React from 'react';

import { shallow } from 'enzyme';

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

import { AnalyticsSection } from './';

describe('AnalyticsSection', () => {
Expand All @@ -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(
<AnalyticsSection title="Lorem ipsum" subtitle="Dolor sit amet." iconType="eye" />
);

expect(wrapper.find(EuiIcon).prop('type')).toEqual('eye');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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<Props> = ({ title, subtitle, children }) => (
export const AnalyticsSection: React.FC<Props> = ({ title, subtitle, iconType, children }) => (
<section>
<header>
<EuiTitle size="m">
<h2>{title}</h2>
</EuiTitle>
<EuiFlexGroup
gutterSize="xs"
alignItems="center"
justifyContent="flexStart"
responsive={false}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before (no responsive={false}):

After:

>
{iconType && (
<EuiFlexItem grow={false}>
<EuiIcon type={iconType} size="l" />
</EuiFlexItem>
)}
<EuiFlexItem>
<EuiTitle size="s">
<h2>{title}</h2>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="xs" />
<EuiText size="s" color="subdued">
<p>{subtitle}</p>
</EuiText>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(<AnalyticsTable items={items} isSmall />);
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(<AnalyticsTable items={items} />);
runActionColumnTests(wrapper);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,27 @@ import { Query } from '../../types';

import {
TERM_COLUMN_PROPS,
TAGS_COLUMN,
TAGS_LIST_COLUMN,
TAGS_COUNT_COLUMN,
COUNT_COLUMN_PROPS,
ACTIONS_COLUMN,
} from './shared_columns';

interface Props {
items: Query[];
hasClicks?: boolean;
isSmall?: boolean;
}
type Columns = Array<EuiBasicTableColumn<Query>>;

export const AnalyticsTable: React.FC<Props> = ({ items, hasClicks }) => {
export const AnalyticsTable: React.FC<Props> = ({ 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',
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down Expand Up @@ -55,7 +55,7 @@ export const QueryClicksTable: React.FC<Props> = ({ items }) => {

return (
<EuiBasicTable
columns={[DOCUMENT_COLUMN, TAGS_COLUMN, CLICKS_COLUMN] as Columns}
columns={[DOCUMENT_COLUMN, TAGS_LIST_COLUMN, CLICKS_COLUMN] as Columns}
items={items}
responsive
noItemsMessage={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { RecentQuery } from '../../types';

import {
TERM_COLUMN_PROPS,
TAGS_COLUMN,
TAGS_LIST_COLUMN,
COUNT_COLUMN_PROPS,
ACTIONS_COLUMN,
} from './shared_columns';
Expand Down Expand Up @@ -53,7 +53,9 @@ export const RecentQueriesTable: React.FC<Props> = ({ items }) => {

return (
<EuiBasicTable
columns={[TERM_COLUMN, TIME_COLUMN, TAGS_COLUMN, RESULTS_COLUMN, ACTIONS_COLUMN] as Columns}
columns={
[TERM_COLUMN, TIME_COLUMN, TAGS_LIST_COLUMN, RESULTS_COLUMN, ACTIONS_COLUMN] as Columns
}
items={items}
responsive
hasActions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { ENGINE_ANALYTICS_QUERY_DETAIL_PATH, ENGINE_CURATION_PATH } from '../../
import { generateEnginePath, EngineLogic } from '../../../engine';
import { Query, RecentQuery } from '../../types';

import { InlineTagsList } from './inline_tags_list';
import { TagsList, TagsCount } from './tags';

/**
* Shared columns / column properties between separate analytics tables
Expand Down Expand Up @@ -49,7 +49,7 @@ export const TERM_COLUMN_PROPS = {
};

export const ACTIONS_COLUMN = {
width: '120px',
width: '90px',
actions: [
{
name: i18n.translate('xpack.enterpriseSearch.appSearch.engine.analytics.table.viewAction', {
Expand All @@ -76,10 +76,10 @@ export const ACTIONS_COLUMN = {
}),
description: i18n.translate(
'xpack.enterpriseSearch.appSearch.engine.analytics.table.editTooltip',
{ defaultMessage: 'Edit query' }
{ defaultMessage: 'Manage curation' }
),
type: 'icon',
icon: 'pencil',
icon: 'package',
onClick: async (item: Query | RecentQuery) => {
const { http } = HttpLogic.values;
const { navigateToUrl } = KibanaLogic.values;
Expand All @@ -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']) => <InlineTagsList tags={tags} />,
};
export const TAGS_LIST_COLUMN = {
...TAGS_COLUMN_PROPS,
render: (tags: Query['tags']) => <TagsList tags={tags} />,
};
export const TAGS_COUNT_COLUMN = {
...TAGS_COLUMN_PROPS,
render: (tags: Query['tags']) => <TagsCount tags={tags} />,
};

export const COUNT_COLUMN_PROPS = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.tagsList .euiBadge {
max-width: $euiSize * 9;
}
Original file line number Diff line number Diff line change
@@ -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(<TagsList tags={['test']} />);

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(<TagsList tags={['1', '2', '3', '4', '5']} />);

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(<TagsList tags={[]} />);

expect(wrapper.isEmptyRender()).toBe(true);
});
});

describe('TagsCount', () => {
it('renders a count and all tags in a tooltip', () => {
const wrapper = shallow(<TagsCount tags={['1', '2', '3']} />);

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(<TagsCount tags={['1']} />);

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(<TagsCount tags={[]} />);

expect(wrapper.isEmptyRender()).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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<Props> = ({ tags }) => {

export const TagsCount: React.FC<Props> = ({ tags }) => {
if (!tags?.length) return null;

return (
<EuiToolTip position="bottom" content={tags.join(', ')}>
<EuiBadge color={'hollow'}>
{i18n.translate('xpack.enterpriseSearch.appSearch.engine.analytics.table.tagsCountBadge', {
defaultMessage: '{tagsCount, plural, one {# tag} other {# tags}}',
values: { tagsCount: tags.length },
})}
</EuiBadge>
</EuiToolTip>
);
};

export const TagsList: React.FC<Props> = ({ tags }) => {
if (!tags?.length) return null;

const displayedTags = tags.slice(0, 2);
const tooltipTags = tags.slice(2);

return (
<EuiBadgeGroup>
<EuiBadgeGroup className="tagsList">
{displayedTags.map((tag: string) => (
<EuiBadge color="hollow" key={tag}>
{tag}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
}
Comment on lines +1 to +5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before:

After:
responsive

Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
Expand Down
Loading