Skip to content

Commit

Permalink
[Lens] Add IP support to Lens (elastic#46383)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisdavies authored Sep 24, 2019
1 parent f69e339 commit fee0699
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ const initialState: IndexPatternPrivateState = {
aggregatable: true,
searchable: true,
},
{
name: 'client',
type: 'ip',
aggregatable: true,
searchable: true,
},
],
},
'2': {
Expand Down Expand Up @@ -375,6 +381,10 @@ describe('IndexPattern Data Panel', () => {
name: 'source',
type: 'string',
},
{
name: 'client',
type: 'ip',
},
],
}),
});
Expand Down Expand Up @@ -423,6 +433,7 @@ describe('IndexPattern Data Panel', () => {

expect(wrapper.find(FieldItem).map(fieldItem => fieldItem.prop('field').name)).toEqual([
'bytes',
'client',
'memory',
'source',
'timestamp',
Expand Down Expand Up @@ -487,6 +498,7 @@ describe('IndexPattern Data Panel', () => {

expect(wrapper.find(FieldItem).map(fieldItem => fieldItem.prop('field').name)).toEqual([
'bytes',
'client',
'memory',
'source',
'timestamp',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,15 @@ function sortFields(fieldA: IndexPatternField, fieldB: IndexPatternField) {
return fieldA.name.localeCompare(fieldB.name, undefined, { sensitivity: 'base' });
}

const supportedFieldTypes = ['string', 'number', 'boolean', 'date'];
const supportedFieldTypes = new Set(['string', 'number', 'boolean', 'date', 'ip']);
const PAGINATION_SIZE = 50;

const fieldTypeNames: Record<DataType, string> = {
string: i18n.translate('xpack.lens.datatypes.string', { defaultMessage: 'string' }),
number: i18n.translate('xpack.lens.datatypes.number', { defaultMessage: 'number' }),
boolean: i18n.translate('xpack.lens.datatypes.boolean', { defaultMessage: 'boolean' }),
date: i18n.translate('xpack.lens.datatypes.date', { defaultMessage: 'date' }),
ip: i18n.translate('xpack.lens.datatypes.ipAddress', { defaultMessage: 'IP' }),
};

function isSingleEmptyLayer(layerMap: IndexPatternPrivateState['layers']) {
Expand Down Expand Up @@ -239,7 +240,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({
);

const displayedFields = allFields.filter(field => {
if (!supportedFieldTypes.includes(field.type)) {
if (!supportedFieldTypes.has(field.type)) {
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,40 @@ import React from 'react';
import { FieldIcon } from './field_icon';

describe('FieldIcon', () => {
it('should render numeric icons', () => {
it('should render icons', () => {
expect(shallow(<FieldIcon type="boolean" />)).toMatchInlineSnapshot(`
<EuiIcon
className="lnsFieldListPanel__fieldIcon lnsFieldListPanel__fieldIcon--boolean"
color="#F37020"
type="invert"
/>
`);
<EuiIcon
className="lnsFieldListPanel__fieldIcon lnsFieldListPanel__fieldIcon--boolean"
color="#F37020"
type="invert"
/>
`);
expect(shallow(<FieldIcon type="date" />)).toMatchInlineSnapshot(`
<EuiIcon
className="lnsFieldListPanel__fieldIcon lnsFieldListPanel__fieldIcon--date"
color="#B0916F"
type="calendar"
/>
`);
<EuiIcon
className="lnsFieldListPanel__fieldIcon lnsFieldListPanel__fieldIcon--date"
color="#B0916F"
type="calendar"
/>
`);
expect(shallow(<FieldIcon type="number" />)).toMatchInlineSnapshot(`
<EuiIcon
className="lnsFieldListPanel__fieldIcon lnsFieldListPanel__fieldIcon--number"
color="#1EA593"
type="number"
/>
`);
<EuiIcon
className="lnsFieldListPanel__fieldIcon lnsFieldListPanel__fieldIcon--number"
color="#1EA593"
type="number"
/>
`);
expect(shallow(<FieldIcon type="string" />)).toMatchInlineSnapshot(`
<EuiIcon
className="lnsFieldListPanel__fieldIcon lnsFieldListPanel__fieldIcon--string"
color="#FCA5D3"
type="string"
/>
`);
expect(shallow(<FieldIcon type="ip" />)).toMatchInlineSnapshot(`
<EuiIcon
className="lnsFieldListPanel__fieldIcon lnsFieldListPanel__fieldIcon--string"
color="#FCA5D3"
type="string"
className="lnsFieldListPanel__fieldIcon lnsFieldListPanel__fieldIcon--ip"
color="#7B000B"
type="storage"
/>
`);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ function getIconForDataType(dataType: string) {
const icons: Partial<Record<string, UnwrapArray<typeof ICON_TYPES>>> = {
boolean: 'invert',
date: 'calendar',
ip: 'storage',
};
return icons[dataType] || ICON_TYPES.find(t => t === dataType) || 'empty';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ export function FieldItem(props: FieldItemProps) {
(field.type !== 'number' &&
field.type !== 'string' &&
field.type !== 'date' &&
field.type !== 'boolean')
field.type !== 'boolean' &&
field.type !== 'ip')
) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,19 @@ describe('terms', () => {
isBucketed: true,
scale: 'ordinal',
});

expect(
termsOperation.getPossibleOperationForField({
aggregatable: true,
searchable: true,
name: 'test',
type: 'ip',
})
).toEqual({
dataType: 'ip',
isBucketed: true,
scale: 'ordinal',
});
});

it('should not return an operation if restrictions prevent terms', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ function isSortableByColumn(column: IndexPatternColumn) {
}

const DEFAULT_SIZE = 3;
const supportedTypes = new Set(['string', 'boolean', 'ip']);

export interface TermsIndexPatternColumn extends FieldBasedIndexPatternColumn {
operationType: 'terms';
Expand All @@ -54,19 +55,19 @@ export const termsOperation: OperationDefinition<TermsIndexPatternColumn> = {
}),
getPossibleOperationForField: ({ aggregationRestrictions, aggregatable, type }) => {
if (
(type === 'string' || type === 'boolean') &&
supportedTypes.has(type) &&
aggregatable &&
(!aggregationRestrictions || aggregationRestrictions.terms)
) {
return { dataType: type, isBucketed: true, scale: 'ordinal' };
return { dataType: type as DataType, isBucketed: true, scale: 'ordinal' };
}
},
isTransferable: (column, newIndexPattern) => {
const newField = newIndexPattern.fields.find(field => field.name === column.sourceField);

return Boolean(
newField &&
newField.type === 'string' &&
supportedTypes.has(newField.type) &&
newField.aggregatable &&
(!newField.aggregationRestrictions || newField.aggregationRestrictions.terms)
);
Expand Down
2 changes: 1 addition & 1 deletion x-pack/legacy/plugins/lens/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ export interface DatasourceLayerPanelProps {
layerId: string;
}

export type DataType = 'string' | 'number' | 'date' | 'boolean';
export type DataType = 'string' | 'number' | 'date' | 'boolean' | 'ip';

// An operation represents a column in a table, not any information
// about how the column was created such as whether it is a sum or average.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export function getScaleType(metadata: OperationMetadata | null, defaultScale: S
switch (metadata.dataType) {
case 'boolean':
case 'string':
case 'ip':
return ScaleType.Ordinal;
case 'date':
return ScaleType.Time;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,17 +117,17 @@ describe('xy_suggestions', () => {

expect(rest).toHaveLength(0);
expect(suggestionSubset(suggestion)).toMatchInlineSnapshot(`
Array [
Object {
"seriesType": "area_stacked",
"splitAccessor": "aaa",
"x": "date",
"y": Array [
"bytes",
],
},
]
`);
Array [
Object {
"seriesType": "area_stacked",
"splitAccessor": "aaa",
"x": "date",
"y": Array [
"bytes",
],
},
]
`);
});

test('does not suggest multiple splits', () => {
Expand Down Expand Up @@ -161,18 +161,18 @@ describe('xy_suggestions', () => {

expect(rest).toHaveLength(0);
expect(suggestionSubset(suggestion)).toMatchInlineSnapshot(`
Array [
Object {
"seriesType": "area_stacked",
"splitAccessor": "product",
"x": "date",
"y": Array [
"price",
"quantity",
],
},
]
`);
Array [
Object {
"seriesType": "area_stacked",
"splitAccessor": "product",
"x": "date",
"y": Array [
"price",
"quantity",
],
},
]
`);
});

test('uses datasource provided title if available', () => {
Expand Down Expand Up @@ -392,32 +392,33 @@ describe('xy_suggestions', () => {
});

expect(suggestionSubset(suggestion)).toMatchInlineSnapshot(`
Array [
Object {
"seriesType": "bar_stacked",
"splitAccessor": "ddd",
"x": "quantity",
"y": Array [
"price",
],
},
]
`);
Array [
Object {
"seriesType": "bar_stacked",
"splitAccessor": "ddd",
"x": "quantity",
"y": Array [
"price",
],
},
]
`);
});

test('handles unbucketed suggestions', () => {
(generateId as jest.Mock).mockReturnValueOnce('eee');
test('handles ip', () => {
(generateId as jest.Mock).mockReturnValueOnce('ddd');
const [suggestion] = getSuggestions({
table: {
isMultiRow: true,
columns: [
numCol('num votes'),
numCol('quantity'),
{
columnId: 'mybool',
columnId: 'myip',
operation: {
dataType: 'boolean',
isBucketed: false,
label: 'Yes / No',
dataType: 'ip',
label: 'Top 5 myip',
isBucketed: true,
scale: 'ordinal',
},
},
],
Expand All @@ -430,13 +431,48 @@ describe('xy_suggestions', () => {
Array [
Object {
"seriesType": "bar_stacked",
"splitAccessor": "eee",
"x": "mybool",
"splitAccessor": "ddd",
"x": "myip",
"y": Array [
"num votes",
"quantity",
],
},
]
`);
});

test('handles unbucketed suggestions', () => {
(generateId as jest.Mock).mockReturnValueOnce('eee');
const [suggestion] = getSuggestions({
table: {
isMultiRow: true,
columns: [
numCol('num votes'),
{
columnId: 'mybool',
operation: {
dataType: 'boolean',
isBucketed: false,
label: 'Yes / No',
},
},
],
layerId: 'first',
changeType: 'unchanged',
},
});

expect(suggestionSubset(suggestion)).toMatchInlineSnapshot(`
Array [
Object {
"seriesType": "bar_stacked",
"splitAccessor": "eee",
"x": "mybool",
"y": Array [
"num votes",
],
},
]
`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import { generateId } from '../id_generator';
const columnSortOrder = {
date: 0,
string: 1,
boolean: 2,
number: 3,
ip: 2,
boolean: 3,
number: 4,
};

function getIconForSeries(type: SeriesType): EuiIconType {
Expand Down

0 comments on commit fee0699

Please sign in to comment.