Skip to content

Commit

Permalink
[Ingest pipelines] add extract_device_type to user agent processor (e…
Browse files Browse the repository at this point in the history
…lastic#100986)

* testing layouts

* fix copy for beta badge

* replace hardcoded text with i18n strings

* avoid updating types and just replace label

* Small cr changes

* get rid of style prop and just use a smaller badge
  • Loading branch information
sabarasaba committed Jun 24, 2021
1 parent ad1dd21 commit eda1dfb
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ type TestSubject =
| 'separatorValueField.input'
| 'quoteValueField.input'
| 'emptyValueField.input'
| 'extractDeviceTypeSwitch.input'
| 'propertiesValueField'
| 'regexFileField.input'
| 'valueFieldInput'
| 'mediaTypeSelectorField'
| 'ignoreEmptyField.input'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* 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 { act } from 'react-dom/test-utils';
import { setup, SetupResult, getProcessorValue } from './processor.helpers';

// Default parameter values automatically added to the user agent processor when saved
const defaultUserAgentParameters = {
if: undefined,
regex_file: undefined,
properties: undefined,
description: undefined,
ignore_missing: undefined,
ignore_failure: undefined,
extract_device_type: undefined,
};

const USER_AGENT_TYPE = 'user_agent';

describe('Processor: User Agent', () => {
let onUpdate: jest.Mock;
let testBed: SetupResult;

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

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

beforeEach(async () => {
onUpdate = jest.fn();

await act(async () => {
testBed = await setup({
value: {
processors: [],
},
onFlyoutOpen: jest.fn(),
onUpdate,
});
});

testBed.component.update();

// Open flyout to add new processor
testBed.actions.addProcessor();
// Add type (the other fields are not visible until a type is selected)
await testBed.actions.addProcessorType(USER_AGENT_TYPE);
});

test('prevents form submission if required fields are not provided', async () => {
const {
actions: { saveNewProcessor },
form,
} = testBed;

// Click submit button with only the processor type defined
await saveNewProcessor();

// Expect form error as "field" is required parameter
expect(form.getErrorsMessages()).toEqual(['A field value is required.']);
});

test('saves with just the default parameter value', async () => {
const {
actions: { saveNewProcessor },
form,
} = testBed;

// Add "field" value (required)
form.setInputValue('fieldNameField.input', 'field_1');
// Save the field
await saveNewProcessor();

const processors = getProcessorValue(onUpdate, USER_AGENT_TYPE);
expect(processors[0][USER_AGENT_TYPE]).toEqual({
...defaultUserAgentParameters,
field: 'field_1',
});
});

test('allows optional parameters to be set', async () => {
const {
actions: { saveNewProcessor },
form,
find,
component,
} = testBed;

// Add "field" value (required)
form.setInputValue('fieldNameField.input', 'field_1');

// Set optional parameteres
form.setInputValue('targetField.input', 'target_field');
form.setInputValue('regexFileField.input', 'hello*');
form.toggleEuiSwitch('ignoreMissingSwitch.input');
form.toggleEuiSwitch('ignoreFailureSwitch.input');
form.toggleEuiSwitch('extractDeviceTypeSwitch.input');
await act(async () => {
find('propertiesValueField').simulate('change', [{ label: 'os' }]);
});
component.update();

// Save the field with new changes
await saveNewProcessor();

const processors = getProcessorValue(onUpdate, USER_AGENT_TYPE);
expect(processors[0][USER_AGENT_TYPE]).toEqual({
...defaultUserAgentParameters,
field: 'field_1',
target_field: 'target_field',
properties: ['os'],
regex_file: 'hello*',
extract_device_type: true,
ignore_missing: true,
ignore_failure: true,
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
*/

import React, { FunctionComponent } from 'react';
import { EuiComboBoxProps } from '@elastic/eui';
import { i18n } from '@kbn/i18n';

import { EuiComboBoxOptionOption } from '@elastic/eui';
import { ComboBoxField, FIELD_TYPES, UseField } from '../../../../../../../shared_imports';

import { FieldsConfig, to } from '../shared';
Expand All @@ -29,10 +29,10 @@ const fieldsConfig: FieldsConfig = {

interface Props {
helpText?: React.ReactNode;
propertyOptions?: EuiComboBoxOptionOption[];
euiFieldProps?: EuiComboBoxProps<string>;
}

export const PropertiesField: FunctionComponent<Props> = ({ helpText, propertyOptions }) => {
export const PropertiesField: FunctionComponent<Props> = ({ helpText, euiFieldProps }) => {
return (
<UseField
config={{
Expand All @@ -41,12 +41,7 @@ export const PropertiesField: FunctionComponent<Props> = ({ helpText, propertyOp
}}
component={ComboBoxField}
path="fields.properties"
componentProps={{
euiFieldProps: {
options: propertyOptions || [],
noSuggestions: !propertyOptions,
},
}}
componentProps={{ euiFieldProps }}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@
*/

import React, { FunctionComponent } from 'react';
import { EuiCode } from '@elastic/eui';
import { EuiCode, EuiBetaBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';

import { EuiComboBoxOptionOption } from '@elastic/eui';
import { FIELD_TYPES, UseField, Field } from '../../../../../../shared_imports';
import { FIELD_TYPES, ToggleField, UseField, Field } from '../../../../../../shared_imports';

import { FieldsConfig, from } from './shared';
import { FieldsConfig, from, to } from './shared';
import { IgnoreMissingField } from './common_fields/ignore_missing_field';
import { FieldNameField } from './common_fields/field_name_field';
import { TargetField } from './common_fields/target_field';
import { PropertiesField } from './common_fields/properties_field';

const propertyOptions: EuiComboBoxOptionOption[] = [
const propertyOptions: Array<EuiComboBoxOptionOption<string>> = [
{ label: 'name' },
{ label: 'os' },
{ label: 'device' },
Expand Down Expand Up @@ -47,6 +47,18 @@ const fieldsConfig: FieldsConfig = {
}
),
},
extract_device_type: {
type: FIELD_TYPES.TOGGLE,
defaultValue: false,
deserializer: to.booleanOrUndef,
serializer: from.undefinedIfValue(false),
helpText: i18n.translate(
'xpack.ingestPipelines.pipelineEditor.userAgentForm.extractDeviceTypeFieldHelpText',
{
defaultMessage: 'Extracts device type from the user agent string.',
}
),
},
};

export const UserAgent: FunctionComponent = () => {
Expand All @@ -59,7 +71,12 @@ export const UserAgent: FunctionComponent = () => {
)}
/>

<UseField config={fieldsConfig.regex_file} component={Field} path="fields.regex_file" />
<UseField
config={fieldsConfig.regex_file}
component={Field}
path="fields.regex_file"
data-test-subj="regexFileField"
/>

<TargetField
helpText={
Expand All @@ -78,7 +95,40 @@ export const UserAgent: FunctionComponent = () => {
'xpack.ingestPipelines.pipelineEditor.userAgentForm.propertiesFieldHelpText',
{ defaultMessage: 'Properties added to the target field.' }
)}
propertyOptions={propertyOptions}
euiFieldProps={{
options: propertyOptions,
noSuggestions: false,
'data-test-subj': 'propertiesValueField',
}}
/>

<UseField
config={fieldsConfig.extract_device_type}
component={ToggleField}
path="fields.extract_device_type"
data-test-subj="extractDeviceTypeSwitch"
euiFieldProps={{
label: (
<EuiFlexGroup gutterSize="xs">
<EuiFlexItem grow={false}>
<FormattedMessage
id="xpack.ingestPipelines.pipelineEditor.userAgentForm.extractDeviceNameFieldText"
defaultMessage="Extract device type"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiBetaBadge
size="s"
label="Beta"
tooltipContent={i18n.translate(
'xpack.ingestPipelines.pipelineEditor.userAgentForm.extractDeviceNameTooltipText',
{ defaultMessage: 'This functionality is in beta and is subject to change.' }
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
),
}}
/>

<IgnoreMissingField />
Expand Down

0 comments on commit eda1dfb

Please sign in to comment.