Skip to content

Commit

Permalink
[Mappings editor] Add support for point field type (#77543)
Browse files Browse the repository at this point in the history
  • Loading branch information
alisonelizabeth committed Sep 22, 2020
1 parent 8d7aae0 commit 05df9ef
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { act } from 'react-dom/test-utils';

import { componentHelpers, MappingsEditorTestBed } from '../helpers';

const { setup, getMappingsEditorDataFactory } = componentHelpers.mappingsEditor;

// Parameters automatically added to the point datatype when saved (with the default values)
export const defaultPointParameters = {
type: 'point',
ignore_malformed: false,
ignore_z_value: true,
};

describe('Mappings editor: point datatype', () => {
/**
* Variable to store the mappings data forwarded to the consumer component
*/
let data: any;
let onChangeHandler: jest.Mock = jest.fn();
let getMappingsEditorData = getMappingsEditorDataFactory(onChangeHandler);
let testBed: MappingsEditorTestBed;

beforeAll(() => {
jest.useFakeTimers();
});

afterAll(() => {
jest.useRealTimers();
});

beforeEach(() => {
onChangeHandler = jest.fn();
getMappingsEditorData = getMappingsEditorDataFactory(onChangeHandler);
});

test('initial view and default parameters values', async () => {
const defaultMappings = {
properties: {
myField: {
type: 'point',
},
},
};

const updatedMappings = { ...defaultMappings };

await act(async () => {
testBed = setup({ value: defaultMappings, onChange: onChangeHandler });
});
testBed.component.update();

const {
component,
actions: { startEditField, updateFieldAndCloseFlyout },
} = testBed;

// Open the flyout to edit the field
await startEditField('myField');

// Save the field and close the flyout
await updateFieldAndCloseFlyout();

// It should have the default parameters values added
updatedMappings.properties.myField = defaultPointParameters;

({ data } = await getMappingsEditorData(component));
expect(data).toEqual(updatedMappings);
});

describe('meta parameter', () => {
const defaultMappings = {
properties: {
myField: {
type: 'point',
},
},
};

const updatedMappings = { ...defaultMappings };

const metaParameter = {
meta: {
my_metadata: 'foobar',
},
};

beforeEach(async () => {
await act(async () => {
testBed = setup({ value: defaultMappings, onChange: onChangeHandler });
});
testBed.component.update();
});

test('valid meta object', async () => {
const {
component,
actions: {
startEditField,
updateFieldAndCloseFlyout,
showAdvancedSettings,
toggleFormRow,
updateJsonEditor,
},
} = testBed;

// Open the flyout to edit the field
await startEditField('myField');
await showAdvancedSettings();

// Enable the meta parameter and add value
toggleFormRow('metaParameter');
await act(async () => {
updateJsonEditor('metaParameterEditor', metaParameter.meta);
});
component.update();

// Save the field and close the flyout
await updateFieldAndCloseFlyout();

// It should have the default parameters values added, plus metadata
updatedMappings.properties.myField = {
...defaultPointParameters,
...metaParameter,
};

({ data } = await getMappingsEditorData(component));
expect(data).toEqual(updatedMappings);
});

test('strip empty string', async () => {
const {
component,
actions: { startEditField, updateFieldAndCloseFlyout, showAdvancedSettings, toggleFormRow },
} = testBed;

// Open the flyout to edit the field
await startEditField('myField');
await showAdvancedSettings();

// Enable the meta parameter
toggleFormRow('metaParameter');

// Save the field and close the flyout without adding any values to meta parameter
await updateFieldAndCloseFlyout();

// It should have the default parameters values added
updatedMappings.properties.myField = defaultPointParameters;

({ data } = await getMappingsEditorData(component));
expect(data).toEqual(updatedMappings);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@ const createActions = (testBed: TestBed<TestSubjects>) => {
const getCheckboxValue = (testSubject: TestSubjects): boolean =>
find(testSubject).props().checked;

const toggleFormRow = (formRowName: string) => {
form.toggleEuiSwitch(`${formRowName}.formRowToggle`);
};

return {
selectTab,
getFieldAt,
Expand All @@ -252,6 +256,7 @@ const createActions = (testBed: TestBed<TestSubjects>) => {
getComboBoxValue,
getToggleValue,
getCheckboxValue,
toggleFormRow,
};
};

Expand Down Expand Up @@ -365,4 +370,6 @@ export type TestSubjects =
| 'searchQuoteAnalyzer-custom'
| 'searchQuoteAnalyzer-toggleCustomButton'
| 'searchQuoteAnalyzer-custom.input'
| 'useSameAnalyzerForSearchCheckBox.input';
| 'useSameAnalyzerForSearchCheckBox.input'
| 'metaParameterEditor'
| string;
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ import { i18n } from '@kbn/i18n';

import { EditFieldFormRow } from '../fields/edit_field';

export const IgnoreZValueParameter = () => (
export const IgnoreZValueParameter = ({ description }: { description?: string }) => (
<EditFieldFormRow
title={i18n.translate('xpack.idxMgmt.mappingsEditor.ignoreZValueFieldTitle', {
defaultMessage: 'Ignore Z value',
})}
description={i18n.translate('xpack.idxMgmt.mappingsEditor.ignoredZValueFieldDescription', {
defaultMessage:
'Three dimension points will be accepted, but only latitude and longitude values will be indexed; the third dimension is ignored.',
})}
description={
description ||
i18n.translate('xpack.idxMgmt.mappingsEditor.ignoredZValueFieldDescription', {
defaultMessage:
'Three dimension points will be accepted, but only latitude and longitude values will be indexed; the third dimension is ignored.',
})
}
formFieldPath="ignore_z_value"
/>
);
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ export const MetaParameter: FunctionComponent<Props> = ({ defaultToggleValue })
}),
href: documentationService.getMetaLink(),
}}
data-test-subj="metaParameter"
>
<UseField
path="meta"
config={getFieldConfig('meta')}
component={JsonEditorField}
componentProps={{
euiCodeEditorProps: {
['data-test-subj']: 'metaParameterEditor',
height: '300px',
'aria-label': i18n.translate('xpack.idxMgmt.mappingsEditor.metaParameterAriaLabel', {
defaultMessage: 'metadata field data editor',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { HistogramType } from './histogram_type';
import { ConstantKeywordType } from './constant_keyword_type';
import { RankFeatureType } from './rank_feature_type';
import { WildcardType } from './wildcard_type';
import { PointType } from './point_type';

const typeToParametersFormMap: { [key in DataType]?: ComponentType<any> } = {
alias: AliasType,
Expand Down Expand Up @@ -60,6 +61,7 @@ const typeToParametersFormMap: { [key in DataType]?: ComponentType<any> } = {
constant_keyword: ConstantKeywordType,
rank_feature: RankFeatureType,
wildcard: WildcardType,
point: PointType,
};

export const getParametersFormForType = (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { FunctionComponent } from 'react';

import { i18n } from '@kbn/i18n';

import { NormalizedField, Field as FieldType, ParameterName } from '../../../../types';
import { UseField, TextAreaField } from '../../../../shared_imports';
import { getFieldConfig } from '../../../../lib';
import {
IgnoreMalformedParameter,
IgnoreZValueParameter,
NullValueParameter,
MetaParameter,
} from '../../field_parameters';
import { AdvancedParametersSection, BasicParametersSection } from '../edit_field';

interface Props {
field: NormalizedField;
}

const getDefaultToggleValue = (param: ParameterName, field: FieldType) => {
return field[param] !== undefined && field[param] !== getFieldConfig(param).defaultValue;
};

export const PointType: FunctionComponent<Props> = ({ field }) => {
return (
<>
<BasicParametersSection>
<IgnoreMalformedParameter
description={i18n.translate(
'xpack.idxMgmt.mappingsEditor.point.ignoreMalformedFieldDescription',
{
defaultMessage:
'By default, documents that contain malformed points are not indexed. If enabled, these documents are indexed, but fields with malformed points are filtered out. Be careful: if too many documents are indexed this way, queries on the field become meaningless.',
}
)}
/>
</BasicParametersSection>

<AdvancedParametersSection>
<IgnoreZValueParameter
description={i18n.translate(
'xpack.idxMgmt.mappingsEditor.point.ignoreZValueFieldDescription',
{
defaultMessage:
'Three dimension points will be accepted, but only x and y values will be indexed; the third dimension is ignored.',
}
)}
/>

<NullValueParameter
defaultToggleValue={getDefaultToggleValue('null_value', field.source)}
description={i18n.translate(
'xpack.idxMgmt.mappingsEditor.point.nullValueFieldDescription',
{
defaultMessage:
'Replace explicit null values with a point value so that it can be indexed and searched.',
}
)}
>
<UseField
path="null_value"
component={TextAreaField}
config={getFieldConfig('null_value_point')}
/>
</NullValueParameter>

<MetaParameter defaultToggleValue={getDefaultToggleValue('meta', field.source)} />
</AdvancedParametersSection>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,26 @@ export const TYPE_DEFINITION: { [key in DataType]: DataTypeDefinition } = {
</p>
),
},
point: {
label: i18n.translate('xpack.idxMgmt.mappingsEditor.dataType.pointDescription', {
defaultMessage: 'Point',
}),
value: 'point',
documentation: {
main: '/point.html',
},
description: () => (
<p>
<FormattedMessage
id="xpack.idxMgmt.mappingsEditor.dataType.pointLongDescription"
defaultMessage="Point fields enable searching of {code} pairs that fall in a 2-dimensional planar coordinate system."
values={{
code: <EuiCode inline>{'x,y'}</EuiCode>,
}}
/>
</p>
),
},
wildcard: {
label: i18n.translate('xpack.idxMgmt.mappingsEditor.dataType.wildcardDescription', {
defaultMessage: 'Wildcard',
Expand Down Expand Up @@ -882,6 +902,7 @@ export const MAIN_TYPES: MainType[] = [
'token_count',
'histogram',
'wildcard',
'point',
'other',
];

Expand Down
Loading

0 comments on commit 05df9ef

Please sign in to comment.