Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use EuiTokens for ES field types #57911

Merged
merged 17 commits into from
Feb 21, 2020
Original file line number Diff line number Diff line change
@@ -206,7 +206,7 @@ discover-app {
background-color: transparent;
}

.dscField--noResults {
.dscFieldName--noResults {
color: $euiColorDarkShade;
}

Original file line number Diff line number Diff line change
@@ -18,7 +18,9 @@
*/
import React from 'react';
import classNames from 'classnames';
import { FieldIcon } from '../../../../../../../../../plugins/kibana_react/public';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';

import { FieldIcon, FieldIconProps } from '../../../../../../../../../plugins/kibana_react/public';
import { shortenDottedString } from '../../../../../../../../../plugins/data/common/utils';
import { getFieldTypeName } from './field_type_name';

@@ -35,25 +37,35 @@ interface Props {
fieldName?: string;
fieldType?: string;
useShortDots?: boolean;
fieldIconProps?: Omit<FieldIconProps, 'type'>;
}

export function FieldName({ field, fieldName, fieldType, useShortDots }: Props) {
export function FieldName({ field, fieldName, fieldType, useShortDots, fieldIconProps }: Props) {
const type = field ? String(field.type) : String(fieldType);
const typeName = getFieldTypeName(type);

const name = field ? String(field.name) : String(fieldName);
const displayName = useShortDots ? shortenDottedString(name) : name;

const className = classNames({
'dscField--noResults': field ? !field.rowCount && !field.scripted : false,
// this is currently not styled, should display an icon
scripted: field ? field.scripted : false,
const noResults = field ? !field.rowCount && !field.scripted : false;

const className = classNames('dscFieldName', {
'dscFieldName--noResults': noResults,
});

return (
<span className={className} title={typeName}>
<FieldIcon type={type} label={typeName} />
<span className="dscFieldName">{displayName}</span>
</span>
<EuiFlexGroup className={className} alignItems="center" gutterSize="s" responsive={false}>
<EuiFlexItem grow={false}>
<FieldIcon
type={type}
label={typeName}
scripted={field ? field.scripted : false}
{...fieldIconProps}
/>
</EuiFlexItem>
<EuiFlexItem className="eui-textTruncate">
<span className="dscFieldName__displayName eui-textTruncate">{displayName}</span>
</EuiFlexItem>
</EuiFlexGroup>
);
}
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@

.dscFieldName {
color: $euiColorDarkShade;
padding-left: $euiSizeS;
}


Original file line number Diff line number Diff line change
@@ -87,7 +87,12 @@ export function DocViewTableRow({
</td>
)}
<td className="kbnDocViewer__field">
<FieldName field={fieldMapping} fieldName={field} fieldType={fieldType} />
<FieldName
field={fieldMapping}
fieldName={field}
fieldType={fieldType}
fieldIconProps={{ fill: 'none', color: 'gray' }}
/>
</td>
<td>
{isCollapsible && (

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 28 additions & 8 deletions src/plugins/kibana_react/public/field_icon/field_icon.test.tsx
Original file line number Diff line number Diff line change
@@ -18,24 +18,44 @@
*/
import React from 'react';
import { shallow } from 'enzyme';
import { FieldIcon } from './field_icon';
import { FieldIcon, typeToEuiIconMap } from './field_icon';

test('FieldIcon renders a blackwhite icon for a string', () => {
const component = shallow(<FieldIcon type="string" />);
const availableTypes = Object.keys(typeToEuiIconMap);

describe('FieldIcon renders known field types', () => {
availableTypes.forEach(type => {
test(`${type} is rendered`, () => {
const component = shallow(<FieldIcon type={type} />);
expect(component).toMatchSnapshot();
});
});
});

test('FieldIcon renders an icon for an unknown type', () => {
const component = shallow(<FieldIcon type="sdfsdf" label="test" />);
expect(component).toMatchSnapshot();
});

test('FieldIcon renders a colored icon for a number', () => {
const component = shallow(<FieldIcon type="number" label="test" useColor />);
test('FieldIcon supports same props as EuiToken', () => {
const component = shallow(
<FieldIcon
type="number"
label="test"
color="euiColorVis0"
size="l"
shape="circle"
fill="none"
/>
);
expect(component).toMatchSnapshot();
});

test('FieldIcon renders an icon for an unknown type', () => {
const component = shallow(<FieldIcon type="sdfsdf" label="test" useColor />);
test('FieldIcon changes fill when scripted is true', () => {
const component = shallow(<FieldIcon type="number" label="test" scripted={true} />);
expect(component).toMatchSnapshot();
});

test('FieldIcon renders with className if provided', () => {
const component = shallow(<FieldIcon type="sdfsdf" label="test" className="myClass" useColor />);
const component = shallow(<FieldIcon type="sdfsdf" label="test" className="myClass" />);
expect(component).toMatchSnapshot();
});
63 changes: 29 additions & 34 deletions src/plugins/kibana_react/public/field_icon/field_icon.tsx
Original file line number Diff line number Diff line change
@@ -17,14 +17,10 @@
* under the License.
*/
import React from 'react';
import { euiPaletteColorBlind, EuiIcon } from '@elastic/eui';
import { IconSize } from '@elastic/eui/src/components/icon/icon';
import classNames from 'classnames';
import { EuiToken, EuiTokenProps } from '@elastic/eui';

interface IconMapEntry {
icon: string;
color: string;
}
interface FieldIconProps {
export interface FieldIconProps extends Omit<EuiTokenProps, 'iconType'> {
type:
| 'boolean'
| 'conflict'
@@ -39,51 +35,50 @@ interface FieldIconProps {
| string
| 'nested';
label?: string;
size?: IconSize;
useColor?: boolean;
className?: string;
scripted?: boolean;
}

const colors = euiPaletteColorBlind();

// defaultIcon => a unknown datatype
const defaultIcon = { icon: 'questionInCircle', color: colors[0] };
const defaultIcon = { iconType: 'questionInCircle', color: 'gray' };

export const typeToEuiIconMap: Partial<Record<string, IconMapEntry>> = {
boolean: { icon: 'invert', color: colors[5] },
export const typeToEuiIconMap: Partial<Record<string, EuiTokenProps>> = {
boolean: { iconType: 'tokenBoolean' },
// icon for an index pattern mapping conflict in discover
conflict: { icon: 'alert', color: colors[8] },
date: { icon: 'calendar', color: colors[7] },
geo_point: { icon: 'globe', color: colors[2] },
geo_shape: { icon: 'globe', color: colors[2] },
ip: { icon: 'storage', color: colors[8] },
conflict: { iconType: 'alert', color: 'euiVisColor9' },
date: { iconType: 'tokenDate' },
geo_point: { iconType: 'tokenGeo', color: 'euiColorVis5' },
geo_shape: { iconType: 'tokenGeo', color: 'euiColorVis5' },
ip: { iconType: 'tokenIP' },
// is a plugin's data type https://www.elastic.co/guide/en/elasticsearch/plugins/current/mapper-murmur3-usage.html
murmur3: { icon: 'document', color: colors[1] },
number: { icon: 'number', color: colors[0] },
_source: { icon: 'editorCodeBlock', color: colors[3] },
string: { icon: 'string', color: colors[4] },
nested: { icon: 'nested', color: colors[2] },
murmur3: { iconType: 'tokenFile' },
number: { iconType: 'tokenNumber' },
_source: { iconType: 'editorCodeBlock', color: 'gray' },
string: { iconType: 'tokenString' },
nested: { iconType: 'tokenNested' },
};

/**
* Field icon used across the app
* Field token icon used across the app
*/
export function FieldIcon({
type,
label,
size = 's',
useColor = false,
className = undefined,
scripted,
className,
...rest
}: FieldIconProps) {
const euiIcon = typeToEuiIconMap[type] || defaultIcon;
const token = typeToEuiIconMap[type] || defaultIcon;

return (
<EuiIcon
type={euiIcon.icon}
<EuiToken
{...token}
className={classNames('kbnFieldIcon', className)}
aria-label={label || type}
size={size as IconSize}
color={useColor || type === 'conflict' ? euiIcon.color : undefined}
className={className}
title={label || type}
size={size as EuiTokenProps['size']}
fill={scripted ? 'dark' : undefined}
{...rest}
/>
);
}
Loading