Skip to content

Commit

Permalink
[Discover] Add field types in-product help (#126657)
Browse files Browse the repository at this point in the history
* added base popover

* add field types popover

* replace callout

* fix anchor

* use another euifilterbutton

* clean up table and add more field types

* [Discover] add pagination

* [Discover] show field types which are present in current data view, sort them alphabetically

* renaming

* more progress

* remove _source

* fix mobile view

* update icon

* [Discover] improve unit tests

* Scrolling instead of pagination

* i18n feedback

* cleanup

* Update src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx

Co-authored-by: Matthias Wilhelm <[email protected]>

* Update discover_field_search.tsx

remove code that's unused

* add missing links

Co-authored-by: Kibana Machine <[email protected]>
Co-authored-by: Dzmitry Tamashevich <[email protected]>
Co-authored-by: Dmitry Tomashevich <[email protected]>
Co-authored-by: cchaos <[email protected]>
Co-authored-by: Matthias Wilhelm <[email protected]>
Co-authored-by: Matthias Wilhelm <[email protected]>
  • Loading branch information
7 people authored Apr 11, 2022
1 parent 9b7cde9 commit f032bbb
Show file tree
Hide file tree
Showing 7 changed files with 308 additions and 21 deletions.
3 changes: 3 additions & 0 deletions packages/kbn-doc-links/src/get_doc_links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => {
discover: {
guide: `${KIBANA_DOCS}discover.html`,
fieldStatistics: `${KIBANA_DOCS}show-field-statistics.html`,
fieldTypeHelp: `${ELASTICSEARCH_DOCS}mapping-types.html`,
dateFieldTypeDocs: `${ELASTICSEARCH_DOCS}date.html`,
dateFormatsDocs: `${ELASTICSEARCH_DOCS}mapping-date-format.html`,
documentExplorer: `${KIBANA_DOCS}document-explorer.html`,
},
filebeat: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
padding: $euiSizeM;
}

.dscFieldSearch__filterWrapper {
width: 100%;
.dscFieldTypesHelp__popover {
flex-grow: 0;
min-width: 0 !important; // Reduce width of icon-only button
}

.dscFieldTypesHelp__panel {
width: $euiSize * 22;
@include euiBreakpoint('xs', 's') {
width: $euiSize * 20;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,25 @@ import { findTestSubject } from '@elastic/eui/lib/test';
import { DiscoverFieldSearch, Props } from './discover_field_search';
import { EuiButtonGroupProps, EuiPopover } from '@elastic/eui';
import { ReactWrapper } from 'enzyme';
import { KibanaContextProvider } from '../../../../../../kibana_react/public';

describe('DiscoverFieldSearch', () => {
const defaultProps = {
onChange: jest.fn(),
value: 'test',
types: ['any', 'string', '_source'],
presentFieldTypes: ['string', 'date', 'boolean', 'number'],
};

function mountComponent(props?: Props) {
const compProps = props || defaultProps;
return mountWithIntl(<DiscoverFieldSearch {...compProps} />);
return mountWithIntl(
<KibanaContextProvider
services={{ docLinks: { links: { discover: { fieldTypeHelp: '' } } } }}
>
<DiscoverFieldSearch {...compProps} />
</KibanaContextProvider>
);
}

function findButtonGroup(component: ReactWrapper, id: string) {
Expand Down Expand Up @@ -131,9 +139,25 @@ describe('DiscoverFieldSearch', () => {
const btn = findTestSubject(component, 'toggleFieldFilterButton');
btn.simulate('click');
let popover = component.find(EuiPopover);
expect(popover.prop('isOpen')).toBe(true);
expect(popover.get(0).props.isOpen).toBe(true);
btn.simulate('click');
popover = component.find(EuiPopover);
expect(popover.prop('isOpen')).toBe(false);
expect(popover.get(0).props.isOpen).toBe(false);
});

test('click help button should open popover with types of field docs', () => {
const component = mountComponent();

const btn = findTestSubject(component, 'fieldTypesHelpButton');
btn.simulate('click');
let popover = component.find(EuiPopover);
expect(popover.get(1).props.isOpen).toBe(true);

const rows = component.find('.euiTableRow');
expect(rows.length).toBe(4);

btn.simulate('click');
popover = component.find(EuiPopover);
expect(popover.get(1).props.isOpen).toBe(false);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@

import './discover_field_search.scss';

import React, { OptionHTMLAttributes, ReactNode, useState } from 'react';
import React, { OptionHTMLAttributes, ReactNode, useMemo, useState } from 'react';
import { i18n } from '@kbn/i18n';
import {
EuiBasicTable,
EuiFieldSearch,
EuiFilterGroup,
EuiFlexGroup,
Expand All @@ -24,11 +25,18 @@ import {
EuiForm,
EuiFormRow,
EuiButtonGroup,
EuiOutsideClickDetector,
EuiFilterButton,
EuiSpacer,
EuiIcon,
EuiBasicTableColumn,
EuiLink,
EuiText,
EuiPanel,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { FieldIcon } from '@kbn/react-field';
import { GetFieldTypeDescription } from './lib/get_field_type_description';
import { useDiscoverServices } from '../../../../utils/use_discover_services';

export interface State {
searchable: string;
Expand All @@ -43,23 +51,31 @@ export interface Props {
* triggered on input of user into search field
*/
onChange: (field: string, value: string | boolean | undefined) => void;

/**
* types for the type filter
*/
types: string[];
/**
* types presented in current data view
*/
presentFieldTypes: string[];
/**
* the input value of the user
*/
value?: string;
}

/**
* types for the type filter
*/
types: string[];
interface FieldTypeTableItem {
id: number;
dataType: string;
description: string;
}

/**
* Component is Discover's side bar to search of available fields
* Additionally there's a button displayed that allows the user to show/hide more filter fields
*/
export function DiscoverFieldSearch({ onChange, value, types }: Props) {
export function DiscoverFieldSearch({ onChange, value, types, presentFieldTypes }: Props) {
const searchPlaceholder = i18n.translate('discover.fieldChooser.searchPlaceHolder', {
defaultMessage: 'Search field names',
});
Expand All @@ -80,13 +96,51 @@ export function DiscoverFieldSearch({ onChange, value, types }: Props) {

const [activeFiltersCount, setActiveFiltersCount] = useState(0);
const [isPopoverOpen, setPopoverOpen] = useState(false);
const [isHelpOpen, setIsHelpOpen] = useState(false);
const [values, setValues] = useState<State>({
searchable: 'any',
aggregatable: 'any',
type: 'any',
missing: true,
});

const { docLinks } = useDiscoverServices();

const items: FieldTypeTableItem[] = useMemo(() => {
return presentFieldTypes
.sort((one, another) => one.localeCompare(another))
.map((element, index) => ({
id: index,
dataType: element,
description: GetFieldTypeDescription(element),
}));
}, [presentFieldTypes]);

const onHelpClick = () => setIsHelpOpen((prevIsHelpOpen) => !prevIsHelpOpen);
const closeHelp = () => setIsHelpOpen(false);

const columnsSidebar: Array<EuiBasicTableColumn<FieldTypeTableItem>> = [
{
field: 'dataType',
name: 'Data type',
width: '110px',
render: (name: string) => (
<EuiFlexGroup alignItems="center" responsive={false} gutterSize="xs">
<EuiFlexItem grow={false}>
<FieldIcon type={name} />
</EuiFlexItem>
<EuiFlexItem>{name}</EuiFlexItem>
</EuiFlexGroup>
),
},
{
field: 'description',
name: 'Description',
// eslint-disable-next-line react/no-danger
render: (description: string) => <div dangerouslySetInnerHTML={{ __html: description }} />,
},
];

const filterBtnAriaLabel = isPopoverOpen
? i18n.translate('discover.fieldChooser.toggleFieldFilterButtonHideAriaLabel', {
defaultMessage: 'Hide field filter settings',
Expand Down Expand Up @@ -257,6 +311,26 @@ export function DiscoverFieldSearch({ onChange, value, types }: Props) {
</div>
);

const helpButton = (
<EuiFilterButton
grow={false}
onClick={onHelpClick}
data-test-subj="fieldTypesHelpButton"
className="dscFieldTypesHelp__button"
aria-label={i18n.translate('discover.fieldTypesPopover.buttonAriaLabel', {
defaultMessage: 'Filter type help',
})}
>
<EuiIcon
type="iInCircle"
color="primary"
title={i18n.translate('discover.fieldTypesPopover.iconTitle', {
defaultMessage: 'Filter type help',
})}
/>
</EuiFilterButton>
);

return (
<React.Fragment>
<EuiFlexGroup responsive={false} gutterSize={'s'}>
Expand All @@ -272,8 +346,8 @@ export function DiscoverFieldSearch({ onChange, value, types }: Props) {
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="xs" />
<EuiOutsideClickDetector onOutsideClick={() => {}} isDisabled={!isPopoverOpen}>
<EuiFilterGroup className="dscFieldSearch__filterWrapper">
<EuiFlexItem>
<EuiFilterGroup fullWidth>
<EuiPopover
id="dataPanelTypeFilter"
panelClassName="euiFilterGroup__popoverPanel"
Expand All @@ -294,8 +368,59 @@ export function DiscoverFieldSearch({ onChange, value, types }: Props) {
{selectionPanel}
{footer()}
</EuiPopover>
<EuiPopover
anchorPosition="rightUp"
display="block"
button={helpButton}
isOpen={isHelpOpen}
panelPaddingSize="none"
className="dscFieldTypesHelp__popover"
panelClassName="dscFieldTypesHelp__panel"
closePopover={closeHelp}
initialFocus="#dscFieldTypesHelpBasicTableId"
>
<EuiPopoverTitle paddingSize="s">
{i18n.translate('discover.fieldChooser.popoverTitle', {
defaultMessage: 'Field types',
})}
</EuiPopoverTitle>
<EuiPanel
className="eui-yScroll"
style={{ maxHeight: '50vh' }}
color="transparent"
paddingSize="s"
>
<EuiBasicTable
id="dscFieldTypesHelpBasicTableId"
tableCaption={i18n.translate('discover.fieldTypesPopover.tableTitle', {
defaultMessage: 'Description of field types',
})}
items={items}
compressed={true}
rowHeader="firstName"
columns={columnsSidebar}
responsive={false}
/>
</EuiPanel>
<EuiPanel color="transparent" paddingSize="s">
<EuiText color="subdued" size="xs">
<p>
{i18n.translate('discover.fieldTypesPopover.learnMoreText', {
defaultMessage: 'Learn more about',
})}
&nbsp;
<EuiLink href={docLinks.links.discover.fieldTypeHelp}>
<FormattedMessage
id="discover.fieldTypesPopover.learnMoreLink"
defaultMessage="field types."
/>
</EuiLink>
</p>
</EuiText>
</EuiPanel>
</EuiPopover>
</EuiFilterGroup>
</EuiOutsideClickDetector>
</EuiFlexItem>
</React.Fragment>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -196,16 +196,31 @@ export function DiscoverSidebarComponent({
}
}, [paginate, scrollContainer, unpopularFields]);

const fieldTypes = useMemo(() => {
const { fieldTypes, presentFieldTypes } = useMemo(() => {
const result = ['any'];
const dataViewFieldTypes = new Set<string>();
if (Array.isArray(fields)) {
for (const field of fields) {
if (result.indexOf(field.type) === -1) {
result.push(field.type);
if (field.type !== '_source') {
// If it's a string type, we want to distinguish between keyword and text
// For this purpose we need the ES type
const type =
field.type === 'string' &&
field.esTypes &&
['keyword', 'text'].includes(field.esTypes[0])
? field.esTypes?.[0]
: field.type;
// _id and _index would map to string, that's why we don't add the string type here
if (type && type !== 'string') {
dataViewFieldTypes.add(type);
}
if (result.indexOf(field.type) === -1) {
result.push(field.type);
}
}
}
}
return result;
return { fieldTypes: result, presentFieldTypes: Array.from(dataViewFieldTypes) };
}, [fields]);

const showFieldStats = useMemo(() => viewMode === VIEW_MODE.DOCUMENT_LEVEL, [viewMode]);
Expand Down Expand Up @@ -327,7 +342,7 @@ export function DiscoverSidebarComponent({
responsive={false}
>
<EuiFlexItem grow={false}>
<EuiFlexGroup direction="row" alignItems="center" gutterSize="s">
<EuiFlexGroup responsive={false} direction="row" alignItems="center" gutterSize="s">
<EuiFlexItem grow={true} className="dscSidebar__indexPatternSwitcher">
<DiscoverIndexPattern
selectedIndexPattern={selectedIndexPattern}
Expand All @@ -351,6 +366,7 @@ export function DiscoverSidebarComponent({
onChange={onChangeFieldSearch}
value={fieldFilter.name}
types={fieldTypes}
presentFieldTypes={presentFieldTypes}
/>
</form>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const mockServices = {
}
},
},
docLinks: { links: { discover: { fieldTypeHelp: '' } } },
} as unknown as DiscoverServices;

const mockfieldCounts: Record<string, number> = {};
Expand Down
Loading

0 comments on commit f032bbb

Please sign in to comment.