From 74c395d556e1b56bfd77125c521d4beaa2d75cd7 Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Mon, 7 Jun 2021 10:54:32 +0200 Subject: [PATCH 01/18] initial form setup --- .../processor_form/processors/index.ts | 1 + .../processors/network_direction.tsx | 198 ++++++++++++++++++ .../shared/map_processor_type_to_form.tsx | 18 ++ .../ingest_pipelines/public/shared_imports.ts | 1 + 4 files changed, 218 insertions(+) create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/index.ts index 5e3e5f82478bd6..f5eb1ab3ec59be 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/index.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/index.ts @@ -28,6 +28,7 @@ export { Join } from './join'; export { Json } from './json'; export { Kv } from './kv'; export { Lowercase } from './lowercase'; +export { NetworkDirection } from './network_direction'; export { Pipeline } from './pipeline'; export { RegisteredDomain } from './registered_domain'; export { Remove } from './remove'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx new file mode 100644 index 00000000000000..3c6e59aae6f81c --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -0,0 +1,198 @@ +/* + * 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 React, { FunctionComponent, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiCode, EuiButtonGroup, EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { FieldsConfig, from, to } from './shared'; +import { TargetField } from './common_fields/target_field'; +import { SerializerFunc } from '../../../../../../shared_imports'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; +import { FIELD_TYPES, UseField, useFormData, Field, ComboBoxField, fieldValidators } from '../../../../../../shared_imports'; + +const fieldsConfig: FieldsConfig = { + /* Optional fields config */ + source_ip: { + type: FIELD_TYPES.TEXT, + serializer: from.emptyStringToUndefined, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.networkDirection.sourceIpLabel', + { + defaultMessage: 'Source IP (optional)', + } + ), + helpText: ( + {'source.ip'}, + }} + /> + ), + }, + destination_ip: { + type: FIELD_TYPES.TEXT, + serializer: from.emptyStringToUndefined, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.networkDirection.destinationIpLabel', + { + defaultMessage: 'Destination IP (optional)', + } + ), + helpText: ( + {'destination.ip'}, + }} + /> + ), + }, + internal_networks: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: to.arrayOfStrings, + serializer: from.optionalArrayOfStrings, + validations: [ + { + validator: fieldValidators.emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksRequiredError', { + defaultMessage: 'A value is required.', + }) + ), + }, + ], + helpText: ( + + ), + }, + internal_networks_field: { + type: FIELD_TYPES.TEXT, + serializer: from.emptyStringToUndefined, + validations: [ + { + validator: fieldValidators.emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksFieldRequiredError', { + defaultMessage: 'A value is required.', + }) + ), + }, + ], + helpText: ( + {'internal_networks'}, + }} + /> + ), + }, +}; + +const internalNetworkValues: string[] = [ + 'loopback', + 'unicast', + 'global_unicast', + 'multicast', + 'interface_local_multicast', + 'link_local_unicast', + 'link_local_multicast', + 'link_local_multicast', + 'private', + 'public', + 'unspecified', +]; + +// TODO: when loading the form, setup correct default in EuiButtonGroup +// TODO: When switching the EuiButtonGroup, clear both values for required fields +export const NetworkDirection: FunctionComponent = () => { + const [{ fields }] = useFormData(); + const defaultInternalNetwork = fields?.internal_networks_field !== '' ? 'internal_networks_field' : 'internal_networks'; + const [internalNetworkType, setInternalNetworkType] = useState(defaultInternalNetwork); + + console.log(fields); + + return ( + <> + + + + + {'network.direction'}, + }} + /> + } + /> + + + setInternalNetworkType(id)} + /> + + + ({ label })) + }, + }} + config={fieldsConfig.internal_networks} + component={ComboBoxField} + path="fields.internal_networks" + style={{ display: internalNetworkType === 'internal_networks' ? 'block' : 'none' }} + /> + + + + } + /> + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx index 983fb0ea67bb0f..4fc3e6552fc7f8 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx @@ -34,6 +34,7 @@ import { Json, Kv, Lowercase, + NetworkDirection, Pipeline, RegisteredDomain, Remove, @@ -517,6 +518,23 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { }, }), }, + network_direction: { + FieldsComponent: NetworkDirection, + docLinkPath: '/network-direction-processor.html', + label: i18n.translate('xpack.ingestPipelines.processors.label.networkDirection', { + defaultMessage: 'Network Direction', + }), + typeDescription: i18n.translate('xpack.ingestPipelines.processors.description.networkDirection', { + defaultMessage: 'Calculates the network direction given a source IP address.', + }), + getDefaultDescription: ({ name }) => + i18n.translate('xpack.ingestPipelines.processors.defaultDescription.networkDirection', { + defaultMessage: 'Runs the "{name}" ingest pipeline', + values: { + name, + }, + }), + }, pipeline: { FieldsComponent: Pipeline, docLinkPath: '/pipeline-processor.html', diff --git a/x-pack/plugins/ingest_pipelines/public/shared_imports.ts b/x-pack/plugins/ingest_pipelines/public/shared_imports.ts index 8ed57221a13956..29be11430bf646 100644 --- a/x-pack/plugins/ingest_pipelines/public/shared_imports.ts +++ b/x-pack/plugins/ingest_pipelines/public/shared_imports.ts @@ -43,6 +43,7 @@ export { ArrayItem, FormHook, useFormContext, + UseMultiFields, FormDataProvider, OnFormUpdateArg, FieldConfig, From 3ceffc33b1224936684bb28ecb1aba3c58134292 Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Wed, 9 Jun 2021 16:33:12 +0200 Subject: [PATCH 02/18] custom solution with usemultifields --- .../processors/network_direction.tsx | 193 ++++++++++-------- .../context/processors_context.tsx | 3 +- 2 files changed, 110 insertions(+), 86 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx index 3c6e59aae6f81c..fa605eb251e9e6 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -7,14 +7,23 @@ import React, { FunctionComponent, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiCode, EuiButtonGroup, EuiSpacer } from '@elastic/eui'; +import { EuiButtonEmpty, EuiCode } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { FieldsConfig, from, to } from './shared'; import { TargetField } from './common_fields/target_field'; import { SerializerFunc } from '../../../../../../shared_imports'; import { IgnoreMissingField } from './common_fields/ignore_missing_field'; -import { FIELD_TYPES, UseField, useFormData, Field, ComboBoxField, fieldValidators } from '../../../../../../shared_imports'; +import { FIELD_TYPES, UseField, UseMultiFields, useFormData, Field, FieldHook, FieldConfig, fieldValidators } from '../../../../../../shared_imports'; + +interface InternalNetworkTypes { + internal_networks: string[]; + internal_networks_field: string; +} + +type InternalNetworkFields = { + [K in keyof InternalNetworkTypes]: FieldHook; +}; const fieldsConfig: FieldsConfig = { /* Optional fields config */ @@ -56,48 +65,6 @@ const fieldsConfig: FieldsConfig = { /> ), }, - internal_networks: { - type: FIELD_TYPES.COMBO_BOX, - deserializer: to.arrayOfStrings, - serializer: from.optionalArrayOfStrings, - validations: [ - { - validator: fieldValidators.emptyField( - i18n.translate('xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksRequiredError', { - defaultMessage: 'A value is required.', - }) - ), - }, - ], - helpText: ( - - ), - }, - internal_networks_field: { - type: FIELD_TYPES.TEXT, - serializer: from.emptyStringToUndefined, - validations: [ - { - validator: fieldValidators.emptyField( - i18n.translate('xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksFieldRequiredError', { - defaultMessage: 'A value is required.', - }) - ), - }, - ], - helpText: ( - {'internal_networks'}, - }} - /> - ), - }, }; const internalNetworkValues: string[] = [ @@ -114,14 +81,81 @@ const internalNetworkValues: string[] = [ 'unspecified', ]; +const internalNetworkConfig: Record< + keyof InternalNetworkFields, + { path: string; config?: FieldConfig, euiFieldProps?: Record } +> = { + internal_networks: { + path: 'fields.internal_networks', + euiFieldProps: { + noSuggestions: false, + options: internalNetworkValues.map(label => ({ label })) + }, + config: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: to.arrayOfStrings, + serializer: from.optionalArrayOfStrings, + validations: [ + { + validator: fieldValidators.emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksRequiredError', { + defaultMessage: 'A value is required.', + }) + ), + }, + ], + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksLabel', + { + defaultMessage: 'Internal networks', + } + ), + helpText: ( + + ), + } + }, + internal_networks_field: { + path: 'fields.internal_networks_field', + config: { + type: FIELD_TYPES.TEXT, + serializer: from.emptyStringToUndefined, + validations: [ + { + validator: fieldValidators.emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksFieldRequiredError', { + defaultMessage: 'A value is required.', + }) + ), + }, + ], + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksFieldLabel', + { + defaultMessage: 'Internal networks field', + } + ), + helpText: ( + {'internal_networks'}, + }} + /> + ), + } + }, +}; + // TODO: when loading the form, setup correct default in EuiButtonGroup // TODO: When switching the EuiButtonGroup, clear both values for required fields export const NetworkDirection: FunctionComponent = () => { const [{ fields }] = useFormData(); - const defaultInternalNetwork = fields?.internal_networks_field !== '' ? 'internal_networks_field' : 'internal_networks'; - const [internalNetworkType, setInternalNetworkType] = useState(defaultInternalNetwork); - - console.log(fields); + const [isCustom, setIsCustom] = useState(fields?.internal_networks_field !== ''); return ( <> @@ -149,45 +183,34 @@ export const NetworkDirection: FunctionComponent = () => { } /> - - setInternalNetworkType(id)} - /> - + + {({ internal_networks, internal_networks_field }) => { + // The fields need to be optionally rendered for this custom solution to work + const field = isCustom ? internal_networks_field : internal_networks; + const configKey: keyof InternalNetworkTypes = isCustom ? 'internal_networks_field' : 'internal_networks'; - ({ label })) - }, + return ( + setIsCustom(!isCustom)} + > + {isCustom + ? i18n.translate('xpack.idxMgmt.mappingsEditor.predefinedButtonLabel', { + defaultMessage: 'Use preset fields', + }) + : i18n.translate('xpack.idxMgmt.mappingsEditor.customButtonLabel', { + defaultMessage: 'Use custom field', + })} + + )} + /> + ); }} - config={fieldsConfig.internal_networks} - component={ComboBoxField} - path="fields.internal_networks" - style={{ display: internalNetworkType === 'internal_networks' ? 'block' : 'none' }} - /> - - + = ({ }); break; case 'managingProcessor': + const whitelistFields = ['internal_networks_field', 'internal_networks']; // These are the option names we get back from our UI - const knownOptionNames = Object.keys(processorTypeAndOptions.options); + const knownOptionNames = [...Object.keys(processorTypeAndOptions.options), ...whitelistFields]; // The processor that we are updating may have options configured the UI does not know about const unknownOptions = omit(mode.arg.processor.options, knownOptionNames); // In order to keep the options we don't get back from our UI, we merge the known and unknown options From 1984240316a0797e372f67361a729030497eb78b Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Mon, 28 Jun 2021 14:17:38 +0300 Subject: [PATCH 03/18] wip: sort of working now --- .../processors/network_direction.tsx | 209 +++++++++--------- 1 file changed, 102 insertions(+), 107 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx index fa605eb251e9e6..93e0a81b5c06b4 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -7,23 +7,15 @@ import React, { FunctionComponent, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiButtonEmpty, EuiCode } from '@elastic/eui'; +import { EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiButtonEmpty, EuiCode } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { FieldsConfig, from, to } from './shared'; + import { TargetField } from './common_fields/target_field'; import { SerializerFunc } from '../../../../../../shared_imports'; import { IgnoreMissingField } from './common_fields/ignore_missing_field'; -import { FIELD_TYPES, UseField, UseMultiFields, useFormData, Field, FieldHook, FieldConfig, fieldValidators } from '../../../../../../shared_imports'; - -interface InternalNetworkTypes { - internal_networks: string[]; - internal_networks_field: string; -} - -type InternalNetworkFields = { - [K in keyof InternalNetworkTypes]: FieldHook; -}; +import { FIELD_TYPES, UseField, TextField, ComboBoxField, useFormData, Field, FieldHook } from '../../../../../../shared_imports'; const fieldsConfig: FieldsConfig = { /* Optional fields config */ @@ -65,6 +57,42 @@ const fieldsConfig: FieldsConfig = { /> ), }, + internal_networks: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: to.arrayOfStrings, + serializer: from.optionalArrayOfStrings, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksLabel', + { + defaultMessage: 'Internal networks', + } + ), + helpText: ( + + ), + }, + internal_networks_field: { + type: FIELD_TYPES.TEXT, + serializer: from.emptyStringToUndefined, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksFieldLabel', + { + defaultMessage: 'Internal networks field', + } + ), + helpText: ( + {'internal_networks'}, + }} + /> + ), + }, }; const internalNetworkValues: string[] = [ @@ -81,81 +109,36 @@ const internalNetworkValues: string[] = [ 'unspecified', ]; -const internalNetworkConfig: Record< - keyof InternalNetworkFields, - { path: string; config?: FieldConfig, euiFieldProps?: Record } -> = { - internal_networks: { - path: 'fields.internal_networks', - euiFieldProps: { - noSuggestions: false, - options: internalNetworkValues.map(label => ({ label })) - }, - config: { - type: FIELD_TYPES.COMBO_BOX, - deserializer: to.arrayOfStrings, - serializer: from.optionalArrayOfStrings, - validations: [ - { - validator: fieldValidators.emptyField( - i18n.translate('xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksRequiredError', { - defaultMessage: 'A value is required.', - }) - ), - }, - ], - label: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksLabel', - { - defaultMessage: 'Internal networks', - } - ), - helpText: ( - - ), - } - }, - internal_networks_field: { - path: 'fields.internal_networks_field', - config: { - type: FIELD_TYPES.TEXT, - serializer: from.emptyStringToUndefined, - validations: [ - { - validator: fieldValidators.emptyField( - i18n.translate('xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksFieldRequiredError', { - defaultMessage: 'A value is required.', - }) - ), - }, - ], - label: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksFieldLabel', - { - defaultMessage: 'Internal networks field', - } - ), - helpText: ( - {'internal_networks'}, - }} - /> - ), - } - }, -}; +const getCustomPath = (isCustom: boolean) => + isCustom + ? 'fields.internal_networks_field' + : 'fields.internal_networks'; + +const getCustomConfig = (isCustom: boolean) => + isCustom + ? fieldsConfig.internal_networks_field + : fieldsConfig.internal_networks; + // TODO: when loading the form, setup correct default in EuiButtonGroup // TODO: When switching the EuiButtonGroup, clear both values for required fields export const NetworkDirection: FunctionComponent = () => { const [{ fields }] = useFormData(); - const [isCustom, setIsCustom] = useState(fields?.internal_networks_field !== ''); + const [isCustom, setIsCustom] = useState(fields?.internal_networks_field?.length > 0); + + console.log(fields); + + const toggleCustom = (field: FieldHook) => () => { + if (isCustom) { + field.setValue([]); + } else { + field.setValue(''); + } + + field.reset({ resetValue: false }); + + setIsCustom(!isCustom); + }; return ( <> @@ -183,34 +166,46 @@ export const NetworkDirection: FunctionComponent = () => { } /> - - {({ internal_networks, internal_networks_field }) => { - // The fields need to be optionally rendered for this custom solution to work - const field = isCustom ? internal_networks_field : internal_networks; - const configKey: keyof InternalNetworkTypes = isCustom ? 'internal_networks_field' : 'internal_networks'; - - return ( - setIsCustom(!isCustom)} - > - {isCustom - ? i18n.translate('xpack.idxMgmt.mappingsEditor.predefinedButtonLabel', { - defaultMessage: 'Use preset fields', + + + + {(field) => ( +
+ + {isCustom + ? i18n.translate('xpack.ingestPipelines.networkDirection.builtInLabel', { + defaultMessage: 'Use built-in internal network type', }) - : i18n.translate('xpack.idxMgmt.mappingsEditor.customButtonLabel', { - defaultMessage: 'Use custom field', + : i18n.translate('xpack.ingestPipelines.networkDirection.customLabel', { + defaultMessage: 'Use custom internal network', })} - - )} - /> - ); - }} - + + + {/* Wrap inside a flex item to maintain the same padding around the field. */} + + + {isCustom ? ( + + ) : ( + ({ label })) + }} + /> + )} + + +
+ )} +
+ + Date: Mon, 28 Jun 2021 15:12:36 +0300 Subject: [PATCH 04/18] fix bootstraping of initial state --- .../processors/network_direction.tsx | 218 +++++++++--------- 1 file changed, 112 insertions(+), 106 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx index 93e0a81b5c06b4..6368730a061084 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -5,17 +5,25 @@ * 2.0. */ -import React, { FunctionComponent, useState } from 'react'; +import React, { FunctionComponent, useState, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiButtonEmpty, EuiCode } from '@elastic/eui'; +import { EuiButtonEmpty, EuiCode } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { FieldsConfig, from, to } from './shared'; - import { TargetField } from './common_fields/target_field'; import { SerializerFunc } from '../../../../../../shared_imports'; import { IgnoreMissingField } from './common_fields/ignore_missing_field'; -import { FIELD_TYPES, UseField, TextField, ComboBoxField, useFormData, Field, FieldHook } from '../../../../../../shared_imports'; +import { FIELD_TYPES, UseField, UseMultiFields, useFormData, Field, FieldHook, FieldConfig, fieldValidators } from '../../../../../../shared_imports'; + +interface InternalNetworkTypes { + internal_networks: string[]; + internal_networks_field: string; +} + +type InternalNetworkFields = { + [K in keyof InternalNetworkTypes]: FieldHook; +}; const fieldsConfig: FieldsConfig = { /* Optional fields config */ @@ -57,42 +65,6 @@ const fieldsConfig: FieldsConfig = { /> ), }, - internal_networks: { - type: FIELD_TYPES.COMBO_BOX, - deserializer: to.arrayOfStrings, - serializer: from.optionalArrayOfStrings, - label: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksLabel', - { - defaultMessage: 'Internal networks', - } - ), - helpText: ( - - ), - }, - internal_networks_field: { - type: FIELD_TYPES.TEXT, - serializer: from.emptyStringToUndefined, - label: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksFieldLabel', - { - defaultMessage: 'Internal networks field', - } - ), - helpText: ( - {'internal_networks'}, - }} - /> - ), - }, }; const internalNetworkValues: string[] = [ @@ -109,37 +81,61 @@ const internalNetworkValues: string[] = [ 'unspecified', ]; -const getCustomPath = (isCustom: boolean) => - isCustom - ? 'fields.internal_networks_field' - : 'fields.internal_networks'; - -const getCustomConfig = (isCustom: boolean) => - isCustom - ? fieldsConfig.internal_networks_field - : fieldsConfig.internal_networks; - +const internalNetworkConfig: Record< + keyof InternalNetworkFields, + { path: string; config?: FieldConfig, euiFieldProps?: Record } +> = { + internal_networks: { + path: 'fields.internal_networks', + euiFieldProps: { + noSuggestions: false, + options: internalNetworkValues.map(label => ({ label })) + }, + config: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: to.arrayOfStrings, + serializer: from.optionalArrayOfStrings, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksLabel', + { + defaultMessage: 'Internal networks', + } + ), + helpText: ( + + ), + } + }, + internal_networks_field: { + path: 'fields.internal_networks_field', + config: { + type: FIELD_TYPES.TEXT, + serializer: from.emptyStringToUndefined, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksFieldLabel', + { + defaultMessage: 'Internal networks field', + } + ), + helpText: ( + {'internal_networks'}, + }} + /> + ), + } + }, +}; // TODO: when loading the form, setup correct default in EuiButtonGroup // TODO: When switching the EuiButtonGroup, clear both values for required fields export const NetworkDirection: FunctionComponent = () => { - const [{ fields }] = useFormData(); - const [isCustom, setIsCustom] = useState(fields?.internal_networks_field?.length > 0); - - console.log(fields); - - const toggleCustom = (field: FieldHook) => () => { - if (isCustom) { - field.setValue([]); - } else { - field.setValue(''); - } - - field.reset({ resetValue: false }); - - setIsCustom(!isCustom); - }; - return ( <> { } /> - - - - {(field) => ( -
- - {isCustom - ? i18n.translate('xpack.ingestPipelines.networkDirection.builtInLabel', { - defaultMessage: 'Use built-in internal network type', - }) - : i18n.translate('xpack.ingestPipelines.networkDirection.customLabel', { - defaultMessage: 'Use custom internal network', + + {({ internal_networks, internal_networks_field }) => { + // The fields need to be optionally rendered for this custom solution to work + const [{ fields }] = useFormData(); + const [isCustom, setIsCustom] = useState(); + const field = isCustom ? internal_networks_field : internal_networks; + const configKey: keyof InternalNetworkTypes = isCustom ? 'internal_networks_field' : 'internal_networks'; + + console.log(fields); + + useEffect(() => { + if (fields !== undefined && isCustom === undefined) { + setIsCustom(fields?.internal_networks_field?.length > 0); + } + }, [fields]); + + const toggleCustom = (field: FieldHook) => () => { + if (isCustom) { + field.setValue(''); + } else { + field.setValue([]); + } + + field.reset({ resetValue: false }); + + setIsCustom(!isCustom); + }; + + return ( + + {isCustom + ? i18n.translate('xpack.idxMgmt.mappingsEditor.predefinedButtonLabel', { + defaultMessage: 'Use preset fields', + }) + : i18n.translate('xpack.idxMgmt.mappingsEditor.customButtonLabel', { + defaultMessage: 'Use custom field', })} - - - {/* Wrap inside a flex item to maintain the same padding around the field. */} - - - {isCustom ? ( - - ) : ( - ({ label })) - }} - /> - )} - - -
- )} -
- - + + )} + /> + ); + }} +
Date: Tue, 29 Jun 2021 12:00:06 +0300 Subject: [PATCH 05/18] fix field validation --- .../processors/network_direction.tsx | 67 +++++++++++++------ 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx index 6368730a061084..3c8ab1cbedaca7 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -14,7 +14,7 @@ import { FieldsConfig, from, to } from './shared'; import { TargetField } from './common_fields/target_field'; import { SerializerFunc } from '../../../../../../shared_imports'; import { IgnoreMissingField } from './common_fields/ignore_missing_field'; -import { FIELD_TYPES, UseField, UseMultiFields, useFormData, Field, FieldHook, FieldConfig, fieldValidators } from '../../../../../../shared_imports'; +import { FIELD_TYPES, UseField, UseMultiFields, useFormData, Field, FieldHook, FieldConfig } from '../../../../../../shared_imports'; interface InternalNetworkTypes { internal_networks: string[]; @@ -25,6 +25,20 @@ type InternalNetworkFields = { [K in keyof InternalNetworkTypes]: FieldHook; }; +const internalNetworkValues: string[] = [ + 'loopback', + 'unicast', + 'global_unicast', + 'multicast', + 'interface_local_multicast', + 'link_local_unicast', + 'link_local_multicast', + 'link_local_multicast', + 'private', + 'public', + 'unspecified', +]; + const fieldsConfig: FieldsConfig = { /* Optional fields config */ source_ip: { @@ -67,20 +81,6 @@ const fieldsConfig: FieldsConfig = { }, }; -const internalNetworkValues: string[] = [ - 'loopback', - 'unicast', - 'global_unicast', - 'multicast', - 'interface_local_multicast', - 'link_local_unicast', - 'link_local_multicast', - 'link_local_multicast', - 'private', - 'public', - 'unspecified', -]; - const internalNetworkConfig: Record< keyof InternalNetworkFields, { path: string; config?: FieldConfig, euiFieldProps?: Record } @@ -95,6 +95,20 @@ const internalNetworkConfig: Record< type: FIELD_TYPES.COMBO_BOX, deserializer: to.arrayOfStrings, serializer: from.optionalArrayOfStrings, + fieldsToValidateOnChange: ['fields.internal_networks', 'fields.internal_networks_field'], + validations: [ + { + validator: ({ value, path, formData }) => { + if (value.length === 0 && formData['fields.internal_networks_field'].length === 0) { + return { + err: 'ERR_FIELD_MISSING', + path, + message: 'Cannot be empty' + }; + } + } + } + ], label: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksLabel', { @@ -114,6 +128,20 @@ const internalNetworkConfig: Record< config: { type: FIELD_TYPES.TEXT, serializer: from.emptyStringToUndefined, + fieldsToValidateOnChange: ['fields.internal_networks', 'fields.internal_networks_field'], + validations: [ + { + validator: ({ value, path, formData }) => { + if (value.length === 0 && formData['fields.internal_networks'].length === 0) { + return { + err: 'ERR_FIELD_MISSING', + path, + message: 'Cannot be empty' + }; + } + } + } + ], label: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksFieldLabel', { @@ -133,8 +161,6 @@ const internalNetworkConfig: Record< }, }; -// TODO: when loading the form, setup correct default in EuiButtonGroup -// TODO: When switching the EuiButtonGroup, clear both values for required fields export const NetworkDirection: FunctionComponent = () => { return ( <> @@ -164,16 +190,13 @@ export const NetworkDirection: FunctionComponent = () => { {({ internal_networks, internal_networks_field }) => { - // The fields need to be optionally rendered for this custom solution to work const [{ fields }] = useFormData(); - const [isCustom, setIsCustom] = useState(); + const [isCustom, setIsCustom] = useState(); const field = isCustom ? internal_networks_field : internal_networks; const configKey: keyof InternalNetworkTypes = isCustom ? 'internal_networks_field' : 'internal_networks'; - console.log(fields); - useEffect(() => { - if (fields !== undefined && isCustom === undefined) { + if (fields && isCustom === undefined) { setIsCustom(fields?.internal_networks_field?.length > 0); } }, [fields]); From f6b04c56bf9452d7ac956fbc2e0caba79fdeff85 Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Tue, 29 Jun 2021 12:34:10 +0300 Subject: [PATCH 06/18] add tests --- .../processors/network_direction.test.tsx | 181 ++++++++++++++++++ .../__jest__/processors/processor.helpers.tsx | 4 + .../processors/network_direction.tsx | 8 +- 3 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx new file mode 100644 index 00000000000000..7c4c25409659bf --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx @@ -0,0 +1,181 @@ +/* + * 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 network direction processor when saved +const defaultNetworkDirectionParameters = { + if: undefined, + tag: undefined, + source_ip: undefined, + description: undefined, + target_field: undefined, + ignore_missing: undefined, + ignore_failure: undefined, + destination_ip: undefined, + internal_networks_field: undefined, +}; + +const NETWORK_DIRECTION_TYPE = 'network_direction'; + +describe('Processor: Network Direction', () => { + 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(NETWORK_DIRECTION_TYPE); + }); + + test('prevents form submission if required fields are not provided', async () => { + const { + actions: { saveNewProcessor }, + form, + } = testBed; + + // Click submit button with only the type defined + await saveNewProcessor(); + + // Expect form error as "field" is required parameter + expect(form.getErrorsMessages()).toEqual(['A field value is required.']); + }); + + test('saves with default parameter values', async () => { + const { + actions: { saveNewProcessor }, + find, + component, + } = testBed; + + // Add "networkDirectionField" value (required) + await act(async () => { + find('networkDirectionField.input').simulate('change', [{ label: 'loopback' }]); + }); + component.update(); + + // Save the field + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, NETWORK_DIRECTION_TYPE); + expect(processors[0][NETWORK_DIRECTION_TYPE]).toEqual({ + ...defaultNetworkDirectionParameters, + 'internal_networks': ['loopback'], + }); + }); + + test('allows to set internal_networks_field', async () => { + const { + actions: { saveNewProcessor }, + form, + find, + } = testBed; + + + find('toggleCustomField').simulate('click'); + + form.setInputValue('networkDirectionField.input', 'internal_networks_field'); + + // Save the field with new changes + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, NETWORK_DIRECTION_TYPE); + expect(processors[0][NETWORK_DIRECTION_TYPE]).toEqual({ + ...defaultNetworkDirectionParameters, + 'internal_networks_field': 'internal_networks_field', + }); + }); + + test('allows to set just internal_networks_field or internal_networks', async () => { + const { + actions: { saveNewProcessor }, + form, + find, + component, + } = testBed; + + + // Set internal_networks field + await act(async () => { + find('networkDirectionField.input').simulate('change', [{ label: 'loopback' }]); + }); + component.update(); + + // Toggle to internal_networks_field and set a random value + find('toggleCustomField').simulate('click'); + form.setInputValue('networkDirectionField.input', 'internal_networks_field'); + + // Save the field with new changes + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, NETWORK_DIRECTION_TYPE); + expect(processors[0][NETWORK_DIRECTION_TYPE]).toEqual({ + ...defaultNetworkDirectionParameters, + 'internal_networks_field': 'internal_networks_field', + }); + }); + + test('allows optional parameters to be set', async () => { + const { + actions: { saveNewProcessor }, + form, + find, + component, + } = testBed; + + // Add "networkDirectionField" value (required) + await act(async () => { + find('networkDirectionField.input').simulate('change', [{ label: 'loopback' }]); + }); + component.update(); + + // Set optional parameteres + form.toggleEuiSwitch('ignoreMissingSwitch.input'); + form.toggleEuiSwitch('ignoreFailureSwitch.input'); + form.setInputValue('sourceIpField.input', 'source.ip'); + form.setInputValue('targetField.input', 'target_field'); + form.setInputValue('destinationIpField.input', 'destination.ip'); + + // Save the field with new changes + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, NETWORK_DIRECTION_TYPE); + expect(processors[0][NETWORK_DIRECTION_TYPE]).toEqual({ + ...defaultNetworkDirectionParameters, + ignore_failure: true, + ignore_missing: false, + source_ip: 'source.ip', + target_field: 'target_field', + destination_ip: 'destination.ip', + 'internal_networks': ['loopback'], + }); + }); +}); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx index 5f6ace20694104..7a21d15a123cc0 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx @@ -161,6 +161,10 @@ type TestSubject = | 'regexFileField.input' | 'valueFieldInput' | 'mediaTypeSelectorField' + | 'networkDirectionField.input' + | 'sourceIpField.input' + | 'destinationIpField.input' + | 'toggleCustomField' | 'ignoreEmptyField.input' | 'overrideField.input' | 'fieldsValueField.input' diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx index 3c8ab1cbedaca7..53320f801465d5 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -103,7 +103,7 @@ const internalNetworkConfig: Record< return { err: 'ERR_FIELD_MISSING', path, - message: 'Cannot be empty' + message: 'A field value is required.' }; } } @@ -136,7 +136,7 @@ const internalNetworkConfig: Record< return { err: 'ERR_FIELD_MISSING', path, - message: 'Cannot be empty' + message: 'A field value is required.' }; } } @@ -168,12 +168,14 @@ export const NetworkDirection: FunctionComponent = () => { config={fieldsConfig.source_ip} component={Field} path="fields.source_ip" + data-test-subj="sourceIpField" /> { {isCustom ? i18n.translate('xpack.idxMgmt.mappingsEditor.predefinedButtonLabel', { From d5541748112e4d4be6c7c09452455d07ce71391d Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Tue, 29 Jun 2021 12:45:07 +0300 Subject: [PATCH 07/18] fix linter errors --- .../processors/network_direction.test.tsx | 10 +-- .../processors/network_direction.tsx | 87 +++++++++++-------- .../shared/map_processor_type_to_form.tsx | 9 +- .../context/processors_context.tsx | 5 +- 4 files changed, 63 insertions(+), 48 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx index 7c4c25409659bf..8b3b7933ba8a3d 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx @@ -88,7 +88,7 @@ describe('Processor: Network Direction', () => { const processors = getProcessorValue(onUpdate, NETWORK_DIRECTION_TYPE); expect(processors[0][NETWORK_DIRECTION_TYPE]).toEqual({ ...defaultNetworkDirectionParameters, - 'internal_networks': ['loopback'], + internal_networks: ['loopback'], }); }); @@ -99,7 +99,6 @@ describe('Processor: Network Direction', () => { find, } = testBed; - find('toggleCustomField').simulate('click'); form.setInputValue('networkDirectionField.input', 'internal_networks_field'); @@ -110,7 +109,7 @@ describe('Processor: Network Direction', () => { const processors = getProcessorValue(onUpdate, NETWORK_DIRECTION_TYPE); expect(processors[0][NETWORK_DIRECTION_TYPE]).toEqual({ ...defaultNetworkDirectionParameters, - 'internal_networks_field': 'internal_networks_field', + internal_networks_field: 'internal_networks_field', }); }); @@ -122,7 +121,6 @@ describe('Processor: Network Direction', () => { component, } = testBed; - // Set internal_networks field await act(async () => { find('networkDirectionField.input').simulate('change', [{ label: 'loopback' }]); @@ -139,7 +137,7 @@ describe('Processor: Network Direction', () => { const processors = getProcessorValue(onUpdate, NETWORK_DIRECTION_TYPE); expect(processors[0][NETWORK_DIRECTION_TYPE]).toEqual({ ...defaultNetworkDirectionParameters, - 'internal_networks_field': 'internal_networks_field', + internal_networks_field: 'internal_networks_field', }); }); @@ -175,7 +173,7 @@ describe('Processor: Network Direction', () => { source_ip: 'source.ip', target_field: 'target_field', destination_ip: 'destination.ip', - 'internal_networks': ['loopback'], + internal_networks: ['loopback'], }); }); }); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx index 53320f801465d5..d294526c6a56d1 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -14,7 +14,15 @@ import { FieldsConfig, from, to } from './shared'; import { TargetField } from './common_fields/target_field'; import { SerializerFunc } from '../../../../../../shared_imports'; import { IgnoreMissingField } from './common_fields/ignore_missing_field'; -import { FIELD_TYPES, UseField, UseMultiFields, useFormData, Field, FieldHook, FieldConfig } from '../../../../../../shared_imports'; +import { + FIELD_TYPES, + UseField, + UseMultiFields, + useFormData, + Field, + FieldHook, + FieldConfig, +} from '../../../../../../shared_imports'; interface InternalNetworkTypes { internal_networks: string[]; @@ -44,12 +52,9 @@ const fieldsConfig: FieldsConfig = { source_ip: { type: FIELD_TYPES.TEXT, serializer: from.emptyStringToUndefined, - label: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.networkDirection.sourceIpLabel', - { - defaultMessage: 'Source IP (optional)', - } - ), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.networkDirection.sourceIpLabel', { + defaultMessage: 'Source IP (optional)', + }), helpText: ( , euiFieldProps?: Record } + { path: string; config?: FieldConfig; euiFieldProps?: Record } > = { internal_networks: { path: 'fields.internal_networks', euiFieldProps: { noSuggestions: false, - options: internalNetworkValues.map(label => ({ label })) + options: internalNetworkValues.map((label) => ({ label })), }, config: { type: FIELD_TYPES.COMBO_BOX, @@ -103,11 +108,11 @@ const internalNetworkConfig: Record< return { err: 'ERR_FIELD_MISSING', path, - message: 'A field value is required.' + message: 'A field value is required.', }; } - } - } + }, + }, ], label: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksLabel', @@ -121,7 +126,7 @@ const internalNetworkConfig: Record< defaultMessage="List of internal networks." /> ), - } + }, }, internal_networks_field: { path: 'fields.internal_networks_field', @@ -136,11 +141,11 @@ const internalNetworkConfig: Record< return { err: 'ERR_FIELD_MISSING', path, - message: 'A field value is required.' + message: 'A field value is required.', }; } - } - } + }, + }, ], label: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.networkDirection.internalNetworksFieldLabel', @@ -157,11 +162,20 @@ const internalNetworkConfig: Record< }} /> ), - } + }, }, }; export const NetworkDirection: FunctionComponent = () => { + const [{ fields }] = useFormData(); + const [isCustom, setIsCustom] = useState(); + + useEffect(() => { + if (fields && isCustom === undefined) { + setIsCustom(fields?.internal_networks_field?.length > 0); + } + }, [fields, isCustom]); + return ( <> { /> - {({ internal_networks, internal_networks_field }) => { - const [{ fields }] = useFormData(); - const [isCustom, setIsCustom] = useState(); - const field = isCustom ? internal_networks_field : internal_networks; - const configKey: keyof InternalNetworkTypes = isCustom ? 'internal_networks_field' : 'internal_networks'; - - useEffect(() => { - if (fields && isCustom === undefined) { - setIsCustom(fields?.internal_networks_field?.length > 0); - } - }, [fields]); + {({ + internal_networks: internalNetworks, + internal_networks_field: internalNetworksField, + }) => { + const field = isCustom ? internalNetworksField : internalNetworks; + const configKey: keyof InternalNetworkTypes = isCustom + ? 'internal_networks_field' + : 'internal_networks'; - const toggleCustom = (field: FieldHook) => () => { + const toggleCustom = (currentField: FieldHook) => () => { if (isCustom) { - field.setValue(''); + currentField.setValue(''); } else { - field.setValue([]); + currentField.setValue([]); } - field.reset({ resetValue: false }); + currentField.reset({ resetValue: false }); setIsCustom(!isCustom); }; @@ -220,7 +231,7 @@ export const NetworkDirection: FunctionComponent = () => { field={field} euiFieldProps={internalNetworkConfig[configKey].euiFieldProps} data-test-subj="networkDirectionField" - labelAppend={( + labelAppend={ { > {isCustom ? i18n.translate('xpack.idxMgmt.mappingsEditor.predefinedButtonLabel', { - defaultMessage: 'Use preset fields', - }) + defaultMessage: 'Use preset fields', + }) : i18n.translate('xpack.idxMgmt.mappingsEditor.customButtonLabel', { - defaultMessage: 'Use custom field', - })} + defaultMessage: 'Use custom field', + })} - )} + } /> ); }} diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx index 4fc3e6552fc7f8..9a4714928e744f 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx @@ -524,9 +524,12 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { label: i18n.translate('xpack.ingestPipelines.processors.label.networkDirection', { defaultMessage: 'Network Direction', }), - typeDescription: i18n.translate('xpack.ingestPipelines.processors.description.networkDirection', { - defaultMessage: 'Calculates the network direction given a source IP address.', - }), + typeDescription: i18n.translate( + 'xpack.ingestPipelines.processors.description.networkDirection', + { + defaultMessage: 'Calculates the network direction given a source IP address.', + } + ), getDefaultDescription: ({ name }) => i18n.translate('xpack.ingestPipelines.processors.defaultDescription.networkDirection', { defaultMessage: 'Runs the "{name}" ingest pipeline', diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/context/processors_context.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/context/processors_context.tsx index 15a71ce017eb3e..ad9fd4298ac73d 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/context/processors_context.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/context/processors_context.tsx @@ -152,7 +152,10 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ case 'managingProcessor': const whitelistFields = ['internal_networks_field', 'internal_networks']; // These are the option names we get back from our UI - const knownOptionNames = [...Object.keys(processorTypeAndOptions.options), ...whitelistFields]; + const knownOptionNames = [ + ...Object.keys(processorTypeAndOptions.options), + ...whitelistFields, + ]; // The processor that we are updating may have options configured the UI does not know about const unknownOptions = omit(mode.arg.processor.options, knownOptionNames); // In order to keep the options we don't get back from our UI, we merge the known and unknown options From 72beda242e7948f682eb7532ab6c31f8046c0544 Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Tue, 29 Jun 2021 13:18:51 +0300 Subject: [PATCH 08/18] Fix i18 namespace --- .../processor_form/processors/network_direction.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx index d294526c6a56d1..ddc3905ba1800d 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -238,10 +238,10 @@ export const NetworkDirection: FunctionComponent = () => { data-test-subj="toggleCustomField" > {isCustom - ? i18n.translate('xpack.idxMgmt.mappingsEditor.predefinedButtonLabel', { - defaultMessage: 'Use preset fields', + ? i18n.translate('xpack.ingestPipelines.pipelineEditor.internalNetworkPredefinedLabel', { + defaultMessage: 'Use preset field', }) - : i18n.translate('xpack.idxMgmt.mappingsEditor.customButtonLabel', { + : i18n.translate('xpack.ingestPipelines.pipelineEditor.internalNetworkCustomLabel', { defaultMessage: 'Use custom field', })} From fc859474426a7dfd192ceaaf1cf45085db3392af Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Tue, 29 Jun 2021 13:28:38 +0300 Subject: [PATCH 09/18] Fix linter problems and remove unused whitelisting --- .../processors/network_direction.tsx | 18 ++++++++++++------ .../context/processors_context.tsx | 6 +----- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx index ddc3905ba1800d..5bcd2cdb012e44 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -238,12 +238,18 @@ export const NetworkDirection: FunctionComponent = () => { data-test-subj="toggleCustomField" > {isCustom - ? i18n.translate('xpack.ingestPipelines.pipelineEditor.internalNetworkPredefinedLabel', { - defaultMessage: 'Use preset field', - }) - : i18n.translate('xpack.ingestPipelines.pipelineEditor.internalNetworkCustomLabel', { - defaultMessage: 'Use custom field', - })} + ? i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.internalNetworkPredefinedLabel', + { + defaultMessage: 'Use preset field', + } + ) + : i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.internalNetworkCustomLabel', + { + defaultMessage: 'Use custom field', + } + )} } /> diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/context/processors_context.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/context/processors_context.tsx index ad9fd4298ac73d..0c43297e811d3c 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/context/processors_context.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/context/processors_context.tsx @@ -150,12 +150,8 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ }); break; case 'managingProcessor': - const whitelistFields = ['internal_networks_field', 'internal_networks']; // These are the option names we get back from our UI - const knownOptionNames = [ - ...Object.keys(processorTypeAndOptions.options), - ...whitelistFields, - ]; + const knownOptionNames = Object.keys(processorTypeAndOptions.options); // The processor that we are updating may have options configured the UI does not know about const unknownOptions = omit(mode.arg.processor.options, knownOptionNames); // In order to keep the options we don't get back from our UI, we merge the known and unknown options From 152ecaf4a318bb6721f2771252ce2e36acd69c8f Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Tue, 29 Jun 2021 13:57:32 +0300 Subject: [PATCH 10/18] Fix copy for description --- .../components/shared/map_processor_type_to_form.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx index 9a4714928e744f..e9fb78422c6fc4 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx @@ -530,13 +530,10 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { defaultMessage: 'Calculates the network direction given a source IP address.', } ), - getDefaultDescription: ({ name }) => + getDefaultDescription: () => i18n.translate('xpack.ingestPipelines.processors.defaultDescription.networkDirection', { - defaultMessage: 'Runs the "{name}" ingest pipeline', - values: { - name, - }, - }), + defaultMessage: 'Calculates the network direction given a source IP address.', + }) }, pipeline: { FieldsComponent: Pipeline, From 07e70d870fd0e7c61f7c3b1849544e103d80919a Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Tue, 29 Jun 2021 14:22:08 +0300 Subject: [PATCH 11/18] lil prettier fix --- .../components/shared/map_processor_type_to_form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx index e9fb78422c6fc4..e6ca465bf1a022 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/shared/map_processor_type_to_form.tsx @@ -533,7 +533,7 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { getDefaultDescription: () => i18n.translate('xpack.ingestPipelines.processors.defaultDescription.networkDirection', { defaultMessage: 'Calculates the network direction given a source IP address.', - }) + }), }, pipeline: { FieldsComponent: Pipeline, From ece91ce30a4c416c2f79022d09cb9cec62d1b387 Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Wed, 30 Jun 2021 08:22:14 +0300 Subject: [PATCH 12/18] add docs and tweak copy --- .../processors/network_direction.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx index 5bcd2cdb012e44..242b836e11ecbd 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -156,7 +156,7 @@ const internalNetworkConfig: Record< helpText: ( {'internal_networks'}, }} @@ -167,14 +167,19 @@ const internalNetworkConfig: Record< }; export const NetworkDirection: FunctionComponent = () => { - const [{ fields }] = useFormData(); + const [{ fields }] = useFormData({ watch: 'fields.internal_networks_field' }); const [isCustom, setIsCustom] = useState(); + // On initial render the fields variable is undefined and eventually get loaded + // with data as the form-lib fields get rendered. Since the state of the UI for the + // `NetworksFields` depends on that, we need to have an effect that runs only once + // when the `fields` have been loaded and when the isCustom hasnt been yet set. + const internalNetworksFieldValue = fields?.internal_networks_field; useEffect(() => { - if (fields && isCustom === undefined) { - setIsCustom(fields?.internal_networks_field?.length > 0); + if (internalNetworksFieldValue && isCustom === undefined) { + setIsCustom(internalNetworksFieldValue?.length > 0); } - }, [fields, isCustom]); + }, [internalNetworksFieldValue, isCustom]); return ( <> From 7e9b740cbab881f0c594035afe4959211a66565b Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Wed, 30 Jun 2021 08:48:02 +0300 Subject: [PATCH 13/18] small tweaks --- .../processors/network_direction.test.tsx | 3 ++- .../processors/network_direction.tsx | 17 +++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx index 8b3b7933ba8a3d..7a4c55d6f5e027 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/network_direction.test.tsx @@ -18,6 +18,7 @@ const defaultNetworkDirectionParameters = { ignore_missing: undefined, ignore_failure: undefined, destination_ip: undefined, + internal_networks: undefined, internal_networks_field: undefined, }; @@ -56,7 +57,7 @@ describe('Processor: Network Direction', () => { await testBed.actions.addProcessorType(NETWORK_DIRECTION_TYPE); }); - test('prevents form submission if required fields are not provided', async () => { + test('prevents form submission if internal_network field is not provided', async () => { const { actions: { saveNewProcessor }, form, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx index 242b836e11ecbd..43a2c7ec601d38 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -7,6 +7,7 @@ import React, { FunctionComponent, useState, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; +import { isEmpty } from 'lodash'; import { EuiButtonEmpty, EuiCode } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -104,12 +105,8 @@ const internalNetworkConfig: Record< validations: [ { validator: ({ value, path, formData }) => { - if (value.length === 0 && formData['fields.internal_networks_field'].length === 0) { - return { - err: 'ERR_FIELD_MISSING', - path, - message: 'A field value is required.', - }; + if (isEmpty(value) && isEmpty(formData['fields.internal_networks_field'])) { + return { path, message: 'A field value is required.' }; } }, }, @@ -137,12 +134,8 @@ const internalNetworkConfig: Record< validations: [ { validator: ({ value, path, formData }) => { - if (value.length === 0 && formData['fields.internal_networks'].length === 0) { - return { - err: 'ERR_FIELD_MISSING', - path, - message: 'A field value is required.', - }; + if (isEmpty(value) && isEmpty(formData['fields.internal_networks'])) { + return { path, message: 'A field value is required.' }; } }, }, From 704aa59c854cf3fa6d327a5ea126c25c8a7ed164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Thu, 1 Jul 2021 15:40:29 +0100 Subject: [PATCH 14/18] [Form lib] expose handler to access field defaultValue --- .../forms/hook_form_lib/components/use_array.ts | 12 +++--------- .../forms/hook_form_lib/components/use_field.tsx | 3 +-- .../static/forms/hook_form_lib/hooks/use_form.ts | 12 ++++++------ .../es_ui_shared/static/forms/hook_form_lib/types.ts | 3 ++- 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.ts index 1152290f7d553c..0a6f2cc2c2b181 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.ts @@ -62,7 +62,7 @@ export const UseArray = ({ const uniqueId = useRef(0); const form = useFormContext(); - const { __getFieldDefaultValue } = form; + const { getFieldDefaultValue } = form; const getNewItemAtIndex = useCallback( (index: number): ArrayItem => ({ @@ -75,7 +75,7 @@ export const UseArray = ({ const fieldDefaultValue = useMemo(() => { const defaultValues = readDefaultValueOnForm - ? (__getFieldDefaultValue(path) as any[]) + ? (getFieldDefaultValue(path) as any[]) : undefined; const getInitialItemsFromValues = (values: any[]): ArrayItem[] => @@ -88,13 +88,7 @@ export const UseArray = ({ return defaultValues ? getInitialItemsFromValues(defaultValues) : new Array(initialNumberOfItems).fill('').map((_, i) => getNewItemAtIndex(i)); - }, [ - path, - initialNumberOfItems, - readDefaultValueOnForm, - __getFieldDefaultValue, - getNewItemAtIndex, - ]); + }, [path, initialNumberOfItems, readDefaultValueOnForm, getFieldDefaultValue, getNewItemAtIndex]); // Create a new hook field with the "isIncludedInOutput" set to false so we don't use its value to build the final form data. // Apart from that the field behaves like a normal field and is hooked into the form validation lifecycle. diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.tsx index 3a5fbaba8f3b88..45fa2e977a6c7f 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_field.tsx @@ -59,8 +59,7 @@ function UseFieldComp(props: Props( [getFormData$, updateFormData$, fieldsToArray] ); - const getFieldDefaultValue: FormHook['__getFieldDefaultValue'] = useCallback( - (fieldName) => get(defaultValueDeserialized.current, fieldName), - [] - ); - const readFieldConfigFromSchema: FormHook['__readFieldConfigFromSchema'] = useCallback( (fieldName) => { const config = (get(schema ?? {}, fieldName) as FieldConfig) || {}; @@ -338,6 +333,11 @@ export function useForm( const getFields: FormHook['getFields'] = useCallback(() => fieldsRefs.current, []); + const getFieldDefaultValue: FormHook['getFieldDefaultValue'] = useCallback( + (fieldName) => get(defaultValueDeserialized.current, fieldName), + [] + ); + const submit: FormHook['submit'] = useCallback( async (e) => { if (e) { @@ -430,6 +430,7 @@ export function useForm( setFieldValue, setFieldErrors, getFields, + getFieldDefaultValue, getFormData, getErrors, reset, @@ -438,7 +439,6 @@ export function useForm( __updateFormDataAt: updateFormDataAt, __updateDefaultValueAt: updateDefaultValueAt, __readFieldConfigFromSchema: readFieldConfigFromSchema, - __getFieldDefaultValue: getFieldDefaultValue, __addField: addField, __removeField: removeField, __validateFields: validateFields, diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts index 75c918d4340f2f..b08cba79e98773 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts @@ -36,6 +36,8 @@ export interface FormHook setFieldErrors: (fieldName: string, errors: ValidationError[]) => void; /** Access the fields on the form. */ getFields: () => FieldsMap; + /** Access the defaultValue for a specific field */ + getFieldDefaultValue: (path: string) => unknown; /** * Return the form data. It accepts an optional options object with an `unflatten` parameter (defaults to `true`). * If you are only interested in the raw form data, pass `unflatten: false` to the handler @@ -58,7 +60,6 @@ export interface FormHook __updateFormDataAt: (field: string, value: unknown) => void; __updateDefaultValueAt: (field: string, value: unknown) => void; __readFieldConfigFromSchema: (field: string) => FieldConfig; - __getFieldDefaultValue: (path: string) => unknown; } export type FormSchema = { From 2da09413e1f3453dc772acc36b1144da622dd92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20Loix?= Date: Thu, 1 Jul 2021 15:41:52 +0100 Subject: [PATCH 15/18] Refactor --- .../processors/network_direction.tsx | 122 +++++++----------- .../context/processors_context.tsx | 8 +- 2 files changed, 57 insertions(+), 73 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx index 43a2c7ec601d38..36dd89cca7ef14 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FunctionComponent, useState, useEffect } from 'react'; +import React, { FunctionComponent, useState, useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { isEmpty } from 'lodash'; import { EuiButtonEmpty, EuiCode } from '@elastic/eui'; @@ -18,8 +18,7 @@ import { IgnoreMissingField } from './common_fields/ignore_missing_field'; import { FIELD_TYPES, UseField, - UseMultiFields, - useFormData, + useFormContext, Field, FieldHook, FieldConfig, @@ -87,10 +86,17 @@ const fieldsConfig: FieldsConfig = { }, }; -const internalNetworkConfig: Record< +const getInternalNetworkConfig: ( + toggleCustom: () => void +) => Record< keyof InternalNetworkFields, - { path: string; config?: FieldConfig; euiFieldProps?: Record } -> = { + { + path: string; + config?: FieldConfig; + euiFieldProps?: Record; + labelAppend: JSX.Element; + } +> = (toggleCustom: () => void) => ({ internal_networks: { path: 'fields.internal_networks', euiFieldProps: { @@ -124,6 +130,14 @@ const internalNetworkConfig: Record< /> ), }, + labelAppend: ( + + {i18n.translate('xpack.ingestPipelines.pipelineEditor.internalNetworkCustomLabel', { + defaultMessage: 'Use custom field', + })} + + ), + key: 'preset', }, internal_networks_field: { path: 'fields.internal_networks_field', @@ -156,23 +170,34 @@ const internalNetworkConfig: Record< /> ), }, + labelAppend: ( + + {i18n.translate('xpack.ingestPipelines.pipelineEditor.internalNetworkPredefinedLabel', { + defaultMessage: 'Use preset field', + })} + + ), + key: 'custom', }, -}; +}); export const NetworkDirection: FunctionComponent = () => { - const [{ fields }] = useFormData({ watch: 'fields.internal_networks_field' }); - const [isCustom, setIsCustom] = useState(); - - // On initial render the fields variable is undefined and eventually get loaded - // with data as the form-lib fields get rendered. Since the state of the UI for the - // `NetworksFields` depends on that, we need to have an effect that runs only once - // when the `fields` have been loaded and when the isCustom hasnt been yet set. - const internalNetworksFieldValue = fields?.internal_networks_field; - useEffect(() => { - if (internalNetworksFieldValue && isCustom === undefined) { - setIsCustom(internalNetworksFieldValue?.length > 0); - } - }, [internalNetworksFieldValue, isCustom]); + const { getFieldDefaultValue } = useFormContext(); + const isInternalNetowrksFieldDefined = + getFieldDefaultValue('fields.internal_networks_field') !== undefined; + const [isCustom, setIsCustom] = useState(isInternalNetowrksFieldDefined); + + const toggleCustom = useCallback(() => { + setIsCustom((prev) => !prev); + }, []); + + const internalNetworkFieldProps = useMemo( + () => + isCustom + ? getInternalNetworkConfig(toggleCustom).internal_networks_field + : getInternalNetworkConfig(toggleCustom).internal_networks, + [isCustom, toggleCustom] + ); return ( <> @@ -202,58 +227,11 @@ export const NetworkDirection: FunctionComponent = () => { } /> - - {({ - internal_networks: internalNetworks, - internal_networks_field: internalNetworksField, - }) => { - const field = isCustom ? internalNetworksField : internalNetworks; - const configKey: keyof InternalNetworkTypes = isCustom - ? 'internal_networks_field' - : 'internal_networks'; - - const toggleCustom = (currentField: FieldHook) => () => { - if (isCustom) { - currentField.setValue(''); - } else { - currentField.setValue([]); - } - - currentField.reset({ resetValue: false }); - - setIsCustom(!isCustom); - }; - - return ( - - {isCustom - ? i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.internalNetworkPredefinedLabel', - { - defaultMessage: 'Use preset field', - } - ) - : i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.internalNetworkCustomLabel', - { - defaultMessage: 'Use custom field', - } - )} - - } - /> - ); - }} - + = ({ break; case 'managingProcessor': // These are the option names we get back from our UI - const knownOptionNames = Object.keys(processorTypeAndOptions.options); + const knownOptionNames = [ + ...Object.keys(processorTypeAndOptions.options), + // We manually add fields that we **don't** want to be treated as "unknownOptions" + 'internal_networks', + 'internal_networks_field', + ]; + // The processor that we are updating may have options configured the UI does not know about const unknownOptions = omit(mode.arg.processor.options, knownOptionNames); // In order to keep the options we don't get back from our UI, we merge the known and unknown options From 1ba0a83490625ed9293c3ab33eaa8f8b2ef1e4ed Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Mon, 5 Jul 2021 09:16:03 +0300 Subject: [PATCH 16/18] fix up import orders --- .../processor_form/processors/network_direction.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx index 36dd89cca7ef14..2026a77bc6566e 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/network_direction.tsx @@ -8,13 +8,9 @@ import React, { FunctionComponent, useState, useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { isEmpty } from 'lodash'; -import { EuiButtonEmpty, EuiCode } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiButtonEmpty, EuiCode } from '@elastic/eui'; -import { FieldsConfig, from, to } from './shared'; -import { TargetField } from './common_fields/target_field'; -import { SerializerFunc } from '../../../../../../shared_imports'; -import { IgnoreMissingField } from './common_fields/ignore_missing_field'; import { FIELD_TYPES, UseField, @@ -22,7 +18,11 @@ import { Field, FieldHook, FieldConfig, + SerializerFunc, } from '../../../../../../shared_imports'; +import { FieldsConfig, from, to } from './shared'; +import { TargetField } from './common_fields/target_field'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; interface InternalNetworkTypes { internal_networks: string[]; From dab5d11a572744fc9a2cec42da190cd299242c79 Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Mon, 5 Jul 2021 12:22:35 +0300 Subject: [PATCH 17/18] Fix test mocks --- x-pack/plugins/cases/public/components/__mock__/form.ts | 2 +- .../security_solution/public/cases/components/__mock__/form.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/cases/public/components/__mock__/form.ts b/x-pack/plugins/cases/public/components/__mock__/form.ts index 6d3e8353e630ae..0964453da484f7 100644 --- a/x-pack/plugins/cases/public/components/__mock__/form.ts +++ b/x-pack/plugins/cases/public/components/__mock__/form.ts @@ -33,7 +33,7 @@ export const mockFormHook = { __validateFields: jest.fn(), __updateFormDataAt: jest.fn(), __readFieldConfigFromSchema: jest.fn(), - __getFieldDefaultValue: jest.fn(), + getFieldDefaultValue: jest.fn(), }; export const getFormMock = (sampleData: any) => ({ diff --git a/x-pack/plugins/security_solution/public/cases/components/__mock__/form.ts b/x-pack/plugins/security_solution/public/cases/components/__mock__/form.ts index 9ec356f70f9a41..6f224df40ea5ad 100644 --- a/x-pack/plugins/security_solution/public/cases/components/__mock__/form.ts +++ b/x-pack/plugins/security_solution/public/cases/components/__mock__/form.ts @@ -35,7 +35,7 @@ export const mockFormHook = { __validateFields: jest.fn(), __updateFormDataAt: jest.fn(), __readFieldConfigFromSchema: jest.fn(), - __getFieldDefaultValue: jest.fn(), + getFieldDefaultValue: jest.fn(), }; // eslint-disable-next-line @typescript-eslint/no-explicit-any export const getFormMock = (sampleData: any) => ({ From fb4444d69aa8f482854f493693715594412e478a Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Mon, 5 Jul 2021 12:25:23 +0300 Subject: [PATCH 18/18] Move up mocks a bit --- x-pack/plugins/cases/public/components/__mock__/form.ts | 2 +- .../security_solution/public/cases/components/__mock__/form.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/cases/public/components/__mock__/form.ts b/x-pack/plugins/cases/public/components/__mock__/form.ts index 0964453da484f7..aa40ea0421b4c3 100644 --- a/x-pack/plugins/cases/public/components/__mock__/form.ts +++ b/x-pack/plugins/cases/public/components/__mock__/form.ts @@ -23,6 +23,7 @@ export const mockFormHook = { setFieldErrors: jest.fn(), getFields: jest.fn(), getFormData: jest.fn(), + getFieldDefaultValue: jest.fn(), /* Returns a list of all errors in the form */ getErrors: jest.fn(), reset: jest.fn(), @@ -33,7 +34,6 @@ export const mockFormHook = { __validateFields: jest.fn(), __updateFormDataAt: jest.fn(), __readFieldConfigFromSchema: jest.fn(), - getFieldDefaultValue: jest.fn(), }; export const getFormMock = (sampleData: any) => ({ diff --git a/x-pack/plugins/security_solution/public/cases/components/__mock__/form.ts b/x-pack/plugins/security_solution/public/cases/components/__mock__/form.ts index 6f224df40ea5ad..3ba7aa616f1c11 100644 --- a/x-pack/plugins/security_solution/public/cases/components/__mock__/form.ts +++ b/x-pack/plugins/security_solution/public/cases/components/__mock__/form.ts @@ -25,6 +25,7 @@ export const mockFormHook = { setFieldErrors: jest.fn(), getFields: jest.fn(), getFormData: jest.fn(), + getFieldDefaultValue: jest.fn(), /* Returns a list of all errors in the form */ getErrors: jest.fn(), reset: jest.fn(), @@ -35,7 +36,6 @@ export const mockFormHook = { __validateFields: jest.fn(), __updateFormDataAt: jest.fn(), __readFieldConfigFromSchema: jest.fn(), - getFieldDefaultValue: jest.fn(), }; // eslint-disable-next-line @typescript-eslint/no-explicit-any export const getFormMock = (sampleData: any) => ({