From b0ef005bd8a27b24af8beeaa0c71613cf55fff60 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 20 Aug 2020 19:04:42 +0200 Subject: [PATCH] [Ingest Pipelines] Processor forms for processors E-J (#75054) * Added the enrich processor form (big one) * added fail processor form * Added foreach processor form * Added geoip processor form and refactored some deserialization * added grok processor form and updated comments and some i18n ids * updated existing gsub processor form to be in line with other forms * added html_strip processor form * refactored some serialize and deserialize functions and added inference processor form * fix copy-pasta mistake in inference form and add join processor form * Added JSON processor field - Also factored out target_field field to common field (still have to update the all instances) - Built out special logic for handling add_to_root and target_field combo on JSON processor form - Created another serializer, for default boolean -> undefined. * remove unused variable * Refactor to use new shared target_field component, and fix JSON serializer bug * fix i18n * address pr feedback * Fix enrich max fields help text copy * add link to enrich policy docs in help text * fix error validation message in enrich policy form and replace space with horizontal rule * address copy feedback * fix i18n id typo * fix i18n * address additional round of feedback and fix json form help text Co-authored-by: Elastic Machine --- .../processor_settings_fields.tsx | 4 +- .../processors/append.tsx | 4 +- .../processors/bytes.tsx | 18 +- .../processors/circle.tsx | 18 +- .../common_fields/common_processor_fields.tsx | 7 +- .../common_fields/ignore_missing_field.tsx | 33 ++- .../processors/common_fields/target_field.tsx | 46 +++ .../processors/convert.tsx | 24 +- .../manage_processor_form/processors/csv.tsx | 8 +- .../manage_processor_form/processors/date.tsx | 35 +-- .../processors/date_index_name.tsx | 6 +- .../processors/enrich.tsx | 264 ++++++++++++++++++ .../manage_processor_form/processors/fail.tsx | 40 +++ .../processors/foreach.tsx | 81 ++++++ .../processors/geoip.tsx | 109 ++++++++ .../manage_processor_form/processors/grok.tsx | 134 +++++++++ .../manage_processor_form/processors/gsub.tsx | 142 +++++----- .../processors/html_strip.tsx | 39 +++ .../manage_processor_form/processors/index.ts | 10 + .../processors/inference.tsx | 203 ++++++++++++++ .../manage_processor_form/processors/join.tsx | 71 +++++ .../manage_processor_form/processors/json.tsx | 87 ++++++ .../processors/shared.ts | 56 +++- .../shared/map_processor_type_to_form.tsx | 44 +-- .../translations/translations/ja-JP.json | 4 - .../translations/translations/zh-CN.json | 4 - 26 files changed, 1300 insertions(+), 191 deletions(-) create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/target_field.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/enrich.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/fail.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/foreach.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/geoip.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/grok.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/html_strip.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/inference.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/join.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/json.tsx diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_settings_fields.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_settings_fields.tsx index a6447bc30ac00..6a70592bc2f70 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_settings_fields.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_settings_fields.tsx @@ -5,7 +5,7 @@ */ import React, { FunctionComponent } from 'react'; -import { EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; +import { EuiHorizontalRule } from '@elastic/eui'; import { FormDataProvider } from '../../../../../shared_imports'; import { ProcessorInternal } from '../../types'; @@ -36,7 +36,7 @@ export const ProcessorSettingsFields: FunctionComponent = ({ processor }) return ( <> - + ); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/append.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/append.tsx index 8eb484b56bafe..09d0981adf1c2 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/append.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/append.tsx @@ -14,7 +14,7 @@ import { ComboBoxField, } from '../../../../../../shared_imports'; -import { FieldsConfig } from './shared'; +import { FieldsConfig, to } from './shared'; import { FieldNameField } from './common_fields/field_name_field'; const { emptyField } = fieldValidators; @@ -22,7 +22,7 @@ const { emptyField } = fieldValidators; const fieldsConfig: FieldsConfig = { value: { type: FIELD_TYPES.COMBO_BOX, - deserializer: (v) => (Array.isArray(v) ? v : [String(v)]), + deserializer: to.arrayOfStrings, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.appendForm.valueFieldLabel', { defaultMessage: 'Value', }), diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/bytes.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/bytes.tsx index 64a501f03d454..a76e1a6f3ce9a 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/bytes.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/bytes.tsx @@ -7,23 +7,9 @@ import React, { FunctionComponent } from 'react'; import { i18n } from '@kbn/i18n'; -import { FIELD_TYPES, UseField, Field } from '../../../../../../shared_imports'; - -import { FieldsConfig } from './shared'; import { IgnoreMissingField } from './common_fields/ignore_missing_field'; import { FieldNameField } from './common_fields/field_name_field'; - -const fieldsConfig: FieldsConfig = { - target_field: { - type: FIELD_TYPES.TEXT, - label: i18n.translate('xpack.ingestPipelines.pipelineEditor.bytesForm.targetFieldLabel', { - defaultMessage: 'Target field (optional)', - }), - helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.bytesForm.targetFieldHelpText', { - defaultMessage: 'The field to assign the converted value to', - }), - }, -}; +import { TargetField } from './common_fields/target_field'; export const Bytes: FunctionComponent = () => { return ( @@ -35,7 +21,7 @@ export const Bytes: FunctionComponent = () => { )} /> - + diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/circle.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/circle.tsx index 3a39e597cb8dc..599d2fdbfd413 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/circle.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/circle.tsx @@ -11,7 +11,6 @@ import { FIELD_TYPES, fieldValidators, UseField, - Field, SelectField, NumericField, } from '../../../../../../shared_imports'; @@ -19,22 +18,12 @@ import { import { FieldsConfig } 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'; const { emptyField } = fieldValidators; const fieldsConfig: FieldsConfig = { - target_field: { - type: FIELD_TYPES.TEXT, - label: i18n.translate('xpack.ingestPipelines.pipelineEditor.circleForm.targetFieldLabel', { - defaultMessage: 'Target field (optional)', - }), - helpText: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.circleForm.targetFieldHelpText', - { - defaultMessage: 'By default field is updated in-place.', - } - ), - }, + /* Required fields config */ error_distance: { type: FIELD_TYPES.NUMBER, deserializer: (v) => (typeof v === 'number' && !isNaN(v) ? v : 1.0), @@ -71,6 +60,7 @@ const fieldsConfig: FieldsConfig = { }, shape_type: { type: FIELD_TYPES.SELECT, + serializer: String, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.circleForm.shapeTypeFieldLabel', { defaultMessage: 'Shape type', }), @@ -132,7 +122,7 @@ export const Circle: FunctionComponent = () => { path="fields.shape_type" /> - + diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/common_processor_fields.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/common_processor_fields.tsx index 7ae7b82c31a43..8089b8e7dfad3 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/common_processor_fields.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/common_processor_fields.tsx @@ -16,11 +16,12 @@ import { } from '../../../../../../../shared_imports'; import { TextEditor } from '../../field_components'; +import { to, from } from '../shared'; const ignoreFailureConfig: FieldConfig = { defaultValue: false, - serializer: (v) => (v === false ? undefined : v), - deserializer: (v) => (typeof v === 'boolean' ? v : undefined), + deserializer: to.booleanOrUndef, + serializer: from.defaultBoolToUndef(false), label: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.commonFields.ignoreFailureFieldLabel', { @@ -62,7 +63,7 @@ export const CommonProcessorFields: FunctionComponent = () => { component={TextEditor} componentProps={{ editorProps: { - language: 'painless', + languageId: 'painless', height: 75, options: { minimap: { enabled: false } }, }, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/ignore_missing_field.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/ignore_missing_field.tsx index 08eb0a425ef33..35dd462d88425 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/ignore_missing_field.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/ignore_missing_field.tsx @@ -5,32 +5,47 @@ */ import React, { FunctionComponent } from 'react'; import { i18n } from '@kbn/i18n'; -import { FIELD_TYPES, UseField, ToggleField } from '../../../../../../../shared_imports'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCode } from '@elastic/eui'; -import { FieldsConfig } from '../shared'; +import { + FIELD_TYPES, + UseField, + ToggleField, + FieldConfig, +} from '../../../../../../../shared_imports'; + +import { FieldsConfig, to, from } from '../shared'; export const fieldsConfig: FieldsConfig = { ignore_missing: { type: FIELD_TYPES.TOGGLE, defaultValue: false, - serializer: (v) => (v === false ? undefined : v), - deserializer: (v) => (typeof v === 'boolean' ? v : undefined), + deserializer: to.booleanOrUndef, + serializer: from.defaultBoolToUndef(false), label: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.commonFields.ignoreMissingFieldLabel', { defaultMessage: 'Ignore missing', } ), + helpText: ( + {'field'}, + }} + /> + ), }, }; -interface Props { - helpText?: string; -} +type Props = Partial; -export const IgnoreMissingField: FunctionComponent = ({ helpText }) => ( +export const IgnoreMissingField: FunctionComponent = (props) => ( diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/target_field.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/target_field.tsx new file mode 100644 index 0000000000000..9bf44425a7c5d --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/target_field.tsx @@ -0,0 +1,46 @@ +/* + * 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 { Field, FIELD_TYPES, UseField, FieldConfig } from '../../../../../../../shared_imports'; + +import { FieldsConfig } from '../shared'; + +const fieldsConfig: FieldsConfig = { + target_field: { + type: FIELD_TYPES.TEXT, + deserializer: String, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.targetFieldLabel', { + defaultMessage: 'Target field (optional)', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.commonFields.targetFieldHelpText', + { + defaultMessage: + 'The field to assign the joined value to. If empty, the field is updated in-place.', + } + ), + }, +}; + +type Props = Partial; + +export const TARGET_FIELD_PATH = 'fields.target_field'; + +export const TargetField: FunctionComponent = (props) => { + return ( + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/convert.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/convert.tsx index b45f589bf0f92..2bf642dd9b518 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/convert.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/convert.tsx @@ -11,13 +11,13 @@ import { FIELD_TYPES, fieldValidators, UseField, - Field, SelectField, } from '../../../../../../shared_imports'; import { FieldsConfig } from './shared'; import { FieldNameField } from './common_fields/field_name_field'; import { IgnoreMissingField } from './common_fields/ignore_missing_field'; +import { TargetField } from './common_fields/target_field'; const { emptyField } = fieldValidators; @@ -42,19 +42,6 @@ const fieldsConfig: FieldsConfig = { }, ], }, - /* Optional fields config */ - target_field: { - type: FIELD_TYPES.TEXT, - label: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.targetFieldLabel', { - defaultMessage: 'Target field (optional)', - }), - helpText: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.convertForm.targetFieldHelpText', - { - defaultMessage: 'The field to assign the converted value to.', - } - ), - }, }; export const Convert: FunctionComponent = () => { @@ -128,7 +115,14 @@ export const Convert: FunctionComponent = () => { path="fields.type" /> - + diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/csv.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/csv.tsx index 3ac0179ca02a6..835177dd861d5 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/csv.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/csv.tsx @@ -23,7 +23,7 @@ import { FieldsConfig } from './shared'; import { IgnoreMissingField } from './common_fields/ignore_missing_field'; import { FieldNameField } from './common_fields/field_name_field'; -import { isArrayOfStrings } from './shared'; +import { to } from './shared'; const { minLengthField } = fieldValidators; @@ -47,9 +47,7 @@ const fieldsConfig: FieldsConfig = { /* Required fields config */ target_fields: { type: FIELD_TYPES.COMBO_BOX, - deserializer: (v) => { - return isArrayOfStrings(v) ? v : []; - }, + deserializer: to.arrayOfStrings, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.csvForm.targetFieldsFieldLabel', { defaultMessage: 'Target fields', }), @@ -112,7 +110,7 @@ const fieldsConfig: FieldsConfig = { trim: { type: FIELD_TYPES.TOGGLE, defaultValue: false, - deserializer: (v) => (typeof v === 'boolean' ? v : undefined), + deserializer: to.booleanOrUndef, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.csvForm.trimFieldLabel', { defaultMessage: 'Trim', }), diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date.tsx index 424e84058ac3f..7e3f8e0d7cd70 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date.tsx @@ -17,8 +17,9 @@ import { ComboBoxField, } from '../../../../../../shared_imports'; -import { FieldsConfig, isArrayOfStrings } from './shared'; +import { FieldsConfig, to } from './shared'; import { FieldNameField } from './common_fields/field_name_field'; +import { TargetField } from './common_fields/target_field'; const { minLengthField } = fieldValidators; @@ -26,9 +27,7 @@ const fieldsConfig: FieldsConfig = { /* Required fields config */ formats: { type: FIELD_TYPES.COMBO_BOX, - deserializer: (v) => { - return isArrayOfStrings(v) ? v : []; - }, + deserializer: to.arrayOfStrings, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dateForm.formatsFieldLabel', { defaultMessage: 'Formats', }), @@ -51,22 +50,6 @@ const fieldsConfig: FieldsConfig = { ], }, /* Optional fields config */ - target_field: { - type: FIELD_TYPES.TEXT, - serializer: (v) => (v ? undefined : v), - label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dateForm.targetFieldFieldLabel', { - defaultMessage: 'Target field (optional)', - }), - helpText: ( - {'@timestamp'}, - }} - /> - ), - }, timezone: { type: FIELD_TYPES.TEXT, serializer: (v) => (v ? v : undefined), @@ -112,7 +95,17 @@ export const DateProcessor: FunctionComponent = () => { - + {'@timestamp'}, + }} + /> + } + /> diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date_index_name.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date_index_name.tsx index 387c9ff4e0b46..2a278a251c30f 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date_index_name.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date_index_name.tsx @@ -18,7 +18,7 @@ import { SelectField, } from '../../../../../../shared_imports'; -import { FieldsConfig, isArrayOfStrings } from './shared'; +import { FieldsConfig, to } from './shared'; import { FieldNameField } from './common_fields/field_name_field'; const { emptyField } = fieldValidators; @@ -89,9 +89,7 @@ const fieldsConfig: FieldsConfig = { serializer: (v: string[]) => { return v.length ? v : undefined; }, - deserializer: (v) => { - return isArrayOfStrings(v) ? v : []; - }, + deserializer: to.arrayOfStrings, label: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.dateFormatsFieldLabel', { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/enrich.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/enrich.tsx new file mode 100644 index 0000000000000..31eac38222afb --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/enrich.tsx @@ -0,0 +1,264 @@ +/* + * 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 { FormattedMessage } from '@kbn/i18n/react'; +import { EuiLink } from '@elastic/eui'; +import { + FIELD_TYPES, + fieldValidators, + UseField, + Field, + ToggleField, + NumericField, + SelectField, + ValidationConfig, + useKibana, +} from '../../../../../../shared_imports'; + +import { FieldNameField } from './common_fields/field_name_field'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; +import { TargetField } from './common_fields/target_field'; + +import { FieldsConfig, from, to } from './shared'; + +const { emptyField, numberSmallerThanField, numberGreaterThanField } = fieldValidators; + +const maxMatchesValidators = { + max: numberSmallerThanField({ + than: 128, + allowEquality: true, + message: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.maxMatchesMaxNumberError', + { defaultMessage: 'This number must be less than 128.' } + ), + }), + min: numberGreaterThanField({ + than: 0, + allowEquality: false, + message: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.maxMatchesMinNumberError', + { defaultMessage: 'This number must be greater than 0.' } + ), + }), +}; + +const targetFieldValidator: ValidationConfig = { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.enrichForm.targetFieldRequiredError', { + defaultMessage: 'A target field value is required.', + }) + ), +}; + +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + policy_name: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.enrichForm.policyNameFieldLabel', { + defaultMessage: 'Policy name', + }), + validations: [ + { + validator: emptyField( + i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.policyNameRequiredError', + { + defaultMessage: 'A value is required.', + } + ) + ), + }, + ], + }, + + /* Optional fields config */ + override: { + type: FIELD_TYPES.TOGGLE, + defaultValue: true, + deserializer: to.booleanOrUndef, + serializer: from.defaultBoolToUndef, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.enrichForm.overrideFieldLabel', { + defaultMessage: 'Override', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.overrideFieldHelpText', + { + defaultMessage: 'If enabled, the processor can overwrite pre-existing field values.', + } + ), + }, + + max_matches: { + type: FIELD_TYPES.NUMBER, + defaultValue: 1, + deserializer: (v) => (typeof v === 'number' && !isNaN(v) ? v : 1), + serializer: (v) => { + const n = parseInt(v, 10); + return n === 1 ? undefined : n; + }, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.enrichForm.maxMatchesFieldLabel', { + defaultMessage: 'Maximum matches (optional)', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.maxMatchesFieldHelpText', + { + defaultMessage: + 'Number of matching enrich documents to include in the target field. Accepts 1–128.', + } + ), + validations: [ + { + validator: (v) => { + if (v.value /* value is a string here */) { + return maxMatchesValidators.max(v) ?? maxMatchesValidators.min(v); + } + }, + }, + ], + }, + + shape_relation: { + type: FIELD_TYPES.SELECT, + defaultValue: 'INTERSECTS', + deserializer: String, + serializer: (v) => (v === 'INTERSECTS' ? undefined : v), + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.shapeRelationFieldLabel', + { + defaultMessage: 'Shape relation (optional)', + } + ), + }, +}; + +export const Enrich: FunctionComponent = () => { + const { services } = useKibana(); + const esDocUrl = services.documentation.getEsDocsBasePath(); + return ( + <> + + + + {i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.policyNameHelpText.enrichPolicyLink', + { defaultMessage: 'enrich policy' } + )} + + ), + }} + /> + ), + }} + component={Field} + path="fields.policy_name" + /> + + + + + + + + + {i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.shapeRelationFieldHelpText.geoMatchPoliciesLink', + { defaultMessage: 'geo-match enrich policies' } + )} + + ), + }} + /> + ), + }} + component={SelectField} + componentProps={{ + euiFieldProps: { + options: [ + { + value: 'INTERSECTS', + text: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.intersectsOption', + { defaultMessage: 'Intersects' } + ), + }, + { + value: 'DISJOINT', + text: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichFrom.disjointOption', + { defaultMessage: 'Disjoint' } + ), + }, + { + value: 'WITHIN', + text: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.withinOption', + { defaultMessage: 'Within' } + ), + }, + { + value: 'CONTAINS', + text: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.containsOption', + { defaultMessage: 'Contains' } + ), + }, + ], + }, + }} + path="fields.shape_relation" + /> + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/fail.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/fail.tsx new file mode 100644 index 0000000000000..3befadc3ca5a3 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/fail.tsx @@ -0,0 +1,40 @@ +/* + * 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 { FIELD_TYPES, fieldValidators, UseField, Field } from '../../../../../../shared_imports'; + +import { FieldsConfig } from './shared'; + +const { emptyField } = fieldValidators; + +const fieldsConfig: FieldsConfig = { + message: { + type: FIELD_TYPES.TEXT, + deserializer: String, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.failForm.messageFieldLabel', { + defaultMessage: 'Message', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.failForm.messageHelpText', { + defaultMessage: 'Error message returned by the processor', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.failForm.valueRequiredError', { + defaultMessage: 'A message is required.', + }) + ), + }, + ], + }, +}; + +export const Fail: FunctionComponent = () => { + return ; +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/foreach.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/foreach.tsx new file mode 100644 index 0000000000000..e471f8322f164 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/foreach.tsx @@ -0,0 +1,81 @@ +/* + * 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 { FIELD_TYPES, fieldValidators, UseField } from '../../../../../../shared_imports'; + +import { XJsonEditor } from '../field_components'; + +import { FieldNameField } from './common_fields/field_name_field'; +import { FieldsConfig, to } from './shared'; + +const { emptyField, isJsonField } = fieldValidators; + +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + processor: { + type: FIELD_TYPES.TEXT, + deserializer: to.jsonString, + serializer: JSON.parse, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.foreachForm.processorFieldLabel', { + defaultMessage: 'Processor', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.foreachForm.processorHelpText', { + defaultMessage: 'Ingest processor to run on each array value', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.failForm.processorRequiredError', { + defaultMessage: 'A processor is required.', + }) + ), + }, + { + validator: isJsonField( + i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.failForm.processorInvalidJsonError', + { + defaultMessage: 'Invalid JSON', + } + ) + ), + }, + ], + }, +}; + +export const Foreach: FunctionComponent = () => { + return ( + <> + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/geoip.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/geoip.tsx new file mode 100644 index 0000000000000..ef2aa62c4a7de --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/geoip.tsx @@ -0,0 +1,109 @@ +/* + * 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 { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCode } from '@elastic/eui'; + +import { + FIELD_TYPES, + UseField, + Field, + ComboBoxField, + ToggleField, +} from '../../../../../../shared_imports'; + +import { FieldNameField } from './common_fields/field_name_field'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; +import { FieldsConfig, from, to } from './shared'; +import { TargetField } from './common_fields/target_field'; + +const fieldsConfig: FieldsConfig = { + /* Optional field config */ + database_file: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v === 'GeoLite2-City.mmdb' ? undefined : v), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.geoIPForm.databaseFileLabel', { + defaultMessage: 'Database file (optional)', + }), + helpText: ( + {'GeoLite2-City.mmdb'}, + ingestGeoIP: {'ingest-geoip'}, + }} + /> + ), + }, + + properties: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: to.arrayOfStrings, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.geoIPForm.propertiesFieldLabel', { + defaultMessage: 'Properties (optional)', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.geoIPForm.propertiesFieldHelpText', + { + defaultMessage: + 'Properties added to the target field. Valid properties depend on the database file used.', + } + ), + }, + + first_only: { + type: FIELD_TYPES.TOGGLE, + defaultValue: true, + deserializer: to.booleanOrUndef, + serializer: from.defaultBoolToUndef(true), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.geoIPForm.firstOnlyFieldLabel', { + defaultMessage: 'First only', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.geoIPForm.firstOnlyFieldHelpText', + { + defaultMessage: 'Use the first matching geo data, even if the field contains an array.', + } + ), + }, +}; + +export const GeoIP: FunctionComponent = () => { + return ( + <> + + + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/grok.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/grok.tsx new file mode 100644 index 0000000000000..1ed9898149a67 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/grok.tsx @@ -0,0 +1,134 @@ +/* + * 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 { + FIELD_TYPES, + UseField, + ComboBoxField, + ToggleField, + fieldValidators, +} from '../../../../../../shared_imports'; + +import { XJsonEditor } from '../field_components'; + +import { FieldNameField } from './common_fields/field_name_field'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; +import { FieldsConfig, to, from } from './shared'; + +const { emptyField, isJsonField } = fieldValidators; + +const fieldsConfig: FieldsConfig = { + /* Required field configs */ + patterns: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: to.arrayOfStrings, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.grokForm.patternsFieldLabel', { + defaultMessage: 'Patterns', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.grokForm.patternsHelpText', { + defaultMessage: + 'Grok expressions used to match and extract named capture groups. Uses the first matching expression.', + }), + validations: [ + { + validator: emptyField( + i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.grokForm.patternsValueRequiredError', + { defaultMessage: 'A value is required.' } + ) + ), + }, + ], + }, + /* Optional field configs */ + pattern_definitions: { + type: FIELD_TYPES.TEXT, + deserializer: to.jsonString, + serializer: from.optionalJson, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.grokForm.patternDefinitionsLabel', { + defaultMessage: 'Pattern definitions (optional)', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.grokForm.patternDefinitionsHelpText', + { + defaultMessage: + 'A map of pattern-name and pattern tuples defining custom patterns. Patterns matching existing names will override the pre-existing definition.', + } + ), + validations: [ + { + validator: isJsonField( + i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.grokForm.patternsDefinitionsInvalidJSONError', + { defaultMessage: 'Invalid JSON' } + ), + { + allowEmptyString: true, + } + ), + }, + ], + }, + + trace_match: { + type: FIELD_TYPES.TOGGLE, + defaultValue: false, + deserializer: to.booleanOrUndef, + serializer: from.defaultBoolToUndef(false), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.grokForm.traceMatchFieldLabel', { + defaultMessage: 'Trace match', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.grokForm.traceMatchFieldHelpText', + { + defaultMessage: 'Add metadata about the matching expression to the document', + } + ), + }, +}; + +export const Grok: FunctionComponent = () => { + return ( + <> + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/gsub.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/gsub.tsx index 3148022adaa98..4d3445d469da2 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/gsub.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/gsub.tsx @@ -6,89 +6,75 @@ import React, { FunctionComponent } from 'react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCode } from '@elastic/eui'; -import { - FieldConfig, - FIELD_TYPES, - fieldValidators, - ToggleField, - UseField, - Field, -} from '../../../../../../shared_imports'; -import { TextEditor } from '../field_components'; - -const { emptyField } = fieldValidators; +import { FIELD_TYPES, fieldValidators, UseField, Field } from '../../../../../../shared_imports'; -const fieldConfig: FieldConfig = { - type: FIELD_TYPES.TEXT, - label: i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.fieldFieldLabel', { - defaultMessage: 'Field', - }), - validations: [ - { - validator: emptyField( - i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.fieldRequiredError', { - defaultMessage: 'A field value is required.', - }) - ), - }, - ], -}; +import { TextEditor } from '../field_components'; -const patternConfig: FieldConfig = { - type: FIELD_TYPES.TEXT, - label: i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.patternFieldLabel', { - defaultMessage: 'Pattern', - }), - validations: [ - { - validator: emptyField( - i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.patternRequiredError', { - defaultMessage: 'A pattern value is required.', - }) - ), - }, - ], -}; +import { FieldsConfig } from './shared'; +import { FieldNameField } from './common_fields/field_name_field'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; +import { TargetField } from './common_fields/target_field'; -const replacementConfig: FieldConfig = { - type: FIELD_TYPES.TEXT, - label: i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.replacementFieldLabel', { - defaultMessage: 'Replacement', - }), - validations: [ - { - validator: emptyField( - i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.replacementRequiredError', { - defaultMessage: 'A replacement value is required.', - }) - ), - }, - ], -}; +const { emptyField } = fieldValidators; -const targetConfig: FieldConfig = { - type: FIELD_TYPES.TEXT, - label: i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.targetFieldLabel', { - defaultMessage: 'Target field (optional)', - }), -}; +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + pattern: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.patternFieldLabel', { + defaultMessage: 'Pattern', + }), + deserializer: String, + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.patternFieldHelpText', { + defaultMessage: 'Regular expression used to match substrings in the field', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.patternRequiredError', { + defaultMessage: 'A value is required.', + }) + ), + }, + ], + }, -const ignoreMissingConfig: FieldConfig = { - defaultValue: false, - label: i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.ignoreMissingFieldLabel', { - defaultMessage: 'Ignore missing', - }), - type: FIELD_TYPES.TOGGLE, + replacement: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.replacementFieldLabel', { + defaultMessage: 'Replacement', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.gsubForm.replacementFieldHelpText', + { defaultMessage: 'Replacement text for matches' } + ), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.replacementRequiredError', { + defaultMessage: 'A value is required.', + }) + ), + }, + ], + }, }; export const Gsub: FunctionComponent = () => { return ( <> - + { path="fields.pattern" /> - + - + {'field'}, + }} + /> + } + /> - + ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/html_strip.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/html_strip.tsx new file mode 100644 index 0000000000000..c6ca7df4cc3e7 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/html_strip.tsx @@ -0,0 +1,39 @@ +/* + * 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 { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCode } from '@elastic/eui'; + +import { FieldNameField } from './common_fields/field_name_field'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; +import { TargetField } from './common_fields/target_field'; + +export const HtmlStrip: FunctionComponent = () => { + return ( + <> + + + {'field'} }} + /> + } + /> + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/index.ts index 6996deb2d861c..4974361bf0410 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/index.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/index.ts @@ -14,3 +14,13 @@ export { DateIndexName } from './date_index_name'; export { Dissect } from './dissect'; export { DotExpander } from './dot_expander'; export { Drop } from './drop'; +export { Enrich } from './enrich'; +export { Fail } from './fail'; +export { Foreach } from './foreach'; +export { GeoIP } from './geoip'; +export { Grok } from './grok'; +export { Gsub } from './gsub'; +export { HtmlStrip } from './html_strip'; +export { Inference } from './inference'; +export { Join } from './join'; +export { Json } from './json'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/inference.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/inference.tsx new file mode 100644 index 0000000000000..ee8d7cc55a9f1 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/inference.tsx @@ -0,0 +1,203 @@ +/* + * 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 { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCode, EuiLink } from '@elastic/eui'; + +import { + FIELD_TYPES, + fieldValidators, + UseField, + Field, + useKibana, +} from '../../../../../../shared_imports'; + +import { XJsonEditor } from '../field_components'; + +import { TargetField } from './common_fields/target_field'; + +import { FieldsConfig, to, from } from './shared'; + +const { emptyField, isJsonField } = fieldValidators; + +const INFERENCE_CONFIG_DOCS = { + regression: { + path: 'inference-processor.html#inference-processor-regression-opt', + linkLabel: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.inferenceForm.inferenceConfigField.regressionLinkLabel', + { defaultMessage: 'regression' } + ), + }, + classification: { + path: 'inference-processor.html#inference-processor-classification-opt', + linkLabel: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.inferenceForm.inferenceConfigField.classificationLinkLabel', + { defaultMessage: 'classification' } + ), + }, +}; + +const getInferenceConfigHelpText = (esDocsBasePath: string): React.ReactNode => { + return ( + + {INFERENCE_CONFIG_DOCS.regression.linkLabel} + + ), + classification: ( + + {INFERENCE_CONFIG_DOCS.classification.linkLabel} + + ), + }} + /> + ); +}; + +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + model_id: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.inferenceForm.modelIDFieldLabel', { + defaultMessage: 'Model ID', + }), + deserializer: String, + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.inferenceForm.modelIDFieldHelpText', + { + defaultMessage: 'ID of the model to infer against', + } + ), + validations: [ + { + validator: emptyField( + i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.inferenceForm.patternRequiredError', + { + defaultMessage: 'A model ID value is required.', + } + ) + ), + }, + ], + }, + + /* Optional fields config */ + field_map: { + type: FIELD_TYPES.TEXT, + deserializer: to.jsonString, + serializer: from.optionalJson, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.inferenceForm.fieldMapLabel', { + defaultMessage: 'Field map (optional)', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.inferenceForm.fieldMapHelpText', + { + defaultMessage: + 'Maps document field names to the known field names of the model. Takes precedence over any mappings in the model.', + } + ), + validations: [ + { + validator: isJsonField( + i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.inferenceForm.fieldMapInvalidJSONError', + { defaultMessage: 'Invalid JSON' } + ), + { + allowEmptyString: true, + } + ), + }, + ], + }, + + inference_config: { + type: FIELD_TYPES.TEXT, + deserializer: to.jsonString, + serializer: from.optionalJson, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.inferenceForm.inferenceConfigLabel', + { + defaultMessage: 'Inference configuration (optional)', + } + ), + validations: [ + { + validator: isJsonField( + i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.grokForm.patternsDefinitionsInvalidJSONError', + { defaultMessage: 'Invalid JSON' } + ), + { + allowEmptyString: true, + } + ), + }, + ], + }, +}; + +export const Inference: FunctionComponent = () => { + const { services } = useKibana(); + const esDocUrl = services.documentation.getEsDocsBasePath(); + return ( + <> + + + {'ml.inference.'} }} + /> + } + /> + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/join.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/join.tsx new file mode 100644 index 0000000000000..712d0106459b1 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/join.tsx @@ -0,0 +1,71 @@ +/* + * 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 { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCode } from '@elastic/eui'; + +import { FIELD_TYPES, fieldValidators, UseField, Field } from '../../../../../../shared_imports'; + +import { FieldsConfig } from './shared'; +import { FieldNameField } from './common_fields/field_name_field'; +import { TargetField } from './common_fields/target_field'; + +const { emptyField } = fieldValidators; + +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + separator: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.joinForm.separatorFieldLabel', { + defaultMessage: 'Separator', + }), + deserializer: String, + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.joinForm.separatorFieldHelpText', + { + defaultMessage: 'Separator character', + } + ), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.joinForm.separatorRequiredError', { + defaultMessage: 'A separator value is required.', + }) + ), + }, + ], + }, +}; + +export const Join: FunctionComponent = () => { + return ( + <> + + + + + {'field'}, + }} + /> + } + /> + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/json.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/json.tsx new file mode 100644 index 0000000000000..9d62c67460136 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/json.tsx @@ -0,0 +1,87 @@ +/* + * 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, useEffect, useState } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { + FIELD_TYPES, + UseField, + ToggleField, + useFormContext, +} from '../../../../../../shared_imports'; + +import { FieldsConfig, from, to } from './shared'; +import { FieldNameField } from './common_fields/field_name_field'; +import { TargetField, TARGET_FIELD_PATH } from './common_fields/target_field'; + +const ADD_TO_ROOT_FIELD_PATH = 'fields.add_to_root'; + +const fieldsConfig: FieldsConfig = { + /* Optional fields config */ + add_to_root: { + type: FIELD_TYPES.TOGGLE, + defaultValue: false, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.jsonForm.addToRootFieldLabel', { + defaultMessage: 'Add to root', + }), + deserializer: to.booleanOrUndef, + serializer: from.defaultBoolToUndef(false), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.jsonForm.addToRootFieldHelpText', + { + defaultMessage: + 'Add the JSON object to the top level of the document. Cannot be combined with a target field.', + } + ), + }, +}; + +export const Json: FunctionComponent = () => { + const form = useFormContext(); + const [isAddToPathDisabled, setIsAddToPathDisabled] = useState(false); + useEffect(() => { + const subscription = form.subscribe(({ data: { raw: rawData } }) => { + const hasTargetField = !!rawData[TARGET_FIELD_PATH]; + if (hasTargetField && !isAddToPathDisabled) { + setIsAddToPathDisabled(true); + form.getFields()[ADD_TO_ROOT_FIELD_PATH].setValue(false); + } else if (!hasTargetField && isAddToPathDisabled) { + setIsAddToPathDisabled(false); + } + }); + return subscription.unsubscribe; + }, [form, isAddToPathDisabled]); + + return ( + <> + + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/shared.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/shared.ts index a0a31dd3a8e93..84b308dd9cd7a 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/shared.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/shared.ts @@ -6,11 +6,63 @@ import * as rt from 'io-ts'; import { isRight } from 'fp-ts/lib/Either'; -import { flow } from 'fp-ts/lib/function'; import { FieldConfig } from '../../../../../../shared_imports'; export const arrayOfStrings = rt.array(rt.string); -export const isArrayOfStrings = flow(arrayOfStrings.decode, isRight); + +export function isArrayOfStrings(v: unknown): v is string[] { + const res = arrayOfStrings.decode(v); + return isRight(res); +} + +/** + * Shared deserializer functions. + * + * These are intended to be used in @link{FieldsConfig} as the "deserializer". + * + * Example: + * { + * ... + * deserialize: to.booleanOrUndef, + * ... + * } + * + */ +export const to = { + booleanOrUndef: (v: unknown): boolean | undefined => (typeof v === 'boolean' ? v : undefined), + arrayOfStrings: (v: unknown): string[] => (isArrayOfStrings(v) ? v : []), + jsonString: (v: unknown) => (v ? JSON.stringify(v, null, 2) : '{}'), +}; + +/** + * Shared serializer functions. + * + * These are intended to be used in @link{FieldsConfig} as the "serializer". + * + * Example: + * { + * ... + * serializer: from.optionalJson, + * ... + * } + * + */ +export const from = { + /* Works with `to.jsonString` as deserializer. */ + optionalJson: (v: string) => { + if (v) { + try { + const json = JSON.parse(v); + if (Object.keys(json).length) { + return json; + } + } catch (e) { + // Ignore + } + } + }, + defaultBoolToUndef: (defaultBool: boolean) => (v: boolean) => (v === defaultBool ? undefined : v), +}; export type FieldsConfig = Record; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/map_processor_type_to_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/map_processor_type_to_form.tsx index b5f7df9117f35..854c6632ab94a 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/map_processor_type_to_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/map_processor_type_to_form.tsx @@ -18,6 +18,16 @@ import { Dissect, DotExpander, Drop, + Enrich, + Fail, + Foreach, + GeoIP, + Grok, + Gsub, + HtmlStrip, + Inference, + Join, + Json, } from '../manage_processor_form/processors'; // import { SetProcessor } from './processors/set'; @@ -106,63 +116,70 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { }), }, enrich: { - FieldsComponent: undefined, // TODO: Implement - docLinkPath: '/enrich-processor.html', + FieldsComponent: Enrich, + docLinkPath: '/ingest-enriching-data.html', label: i18n.translate('xpack.ingestPipelines.processors.label.enrich', { defaultMessage: 'Enrich', }), }, fail: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Fail, docLinkPath: '/fail-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.fail', { defaultMessage: 'Fail', }), }, foreach: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Foreach, docLinkPath: '/foreach-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.foreach', { defaultMessage: 'Foreach', }), }, geoip: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: GeoIP, docLinkPath: '/geoip-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.geoip', { defaultMessage: 'GeoIP', }), }, + grok: { + FieldsComponent: Grok, + docLinkPath: '/grok-processor.html', + label: i18n.translate('xpack.ingestPipelines.processors.label.grok', { + defaultMessage: 'Grok', + }), + }, gsub: { - FieldsComponent: undefined, + FieldsComponent: Gsub, docLinkPath: '/gsub-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.gsub', { defaultMessage: 'Gsub', }), }, html_strip: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: HtmlStrip, docLinkPath: '/htmlstrip-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.htmlStrip', { defaultMessage: 'HTML strip', }), }, inference: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Inference, docLinkPath: '/inference-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.inference', { defaultMessage: 'Inference', }), }, join: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Join, docLinkPath: '/join-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.join', { defaultMessage: 'Join', }), }, json: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Json, docLinkPath: '/json-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.json', { defaultMessage: 'JSON', @@ -268,13 +285,6 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { defaultMessage: 'Set', }), }, - grok: { - FieldsComponent: undefined, - docLinkPath: '/grok-processor.html', - label: i18n.translate('xpack.ingestPipelines.processors.label.grok', { - defaultMessage: 'Grok', - }), - }, }; export type ProcessorType = keyof typeof mapProcessorTypeToDescriptor; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d7de5f780d032..56550b8c0dbe9 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9746,14 +9746,10 @@ "xpack.ingestPipelines.pipelineEditor.deleteModal.deleteDescription": "このプロセッサーとエラーハンドラーを削除します。", "xpack.ingestPipelines.pipelineEditor.dropZoneButton.moveHereToolTip": "ここに移動", "xpack.ingestPipelines.pipelineEditor.dropZoneButton.unavailableToolTip": "ここに移動できません", - "xpack.ingestPipelines.pipelineEditor.gsubForm.fieldFieldLabel": "フィールド", - "xpack.ingestPipelines.pipelineEditor.gsubForm.fieldRequiredError": "フィールド値が必要です。", - "xpack.ingestPipelines.pipelineEditor.gsubForm.ignoreMissingFieldLabel": "不足しテイル項目を無視", "xpack.ingestPipelines.pipelineEditor.gsubForm.patternFieldLabel": "パターン", "xpack.ingestPipelines.pipelineEditor.gsubForm.patternRequiredError": "パターン値が必要です。", "xpack.ingestPipelines.pipelineEditor.gsubForm.replacementFieldLabel": "置換", "xpack.ingestPipelines.pipelineEditor.gsubForm.replacementRequiredError": "置換値が必要です。", - "xpack.ingestPipelines.pipelineEditor.gsubForm.targetFieldLabel": "ターゲットフィールド(任意)", "xpack.ingestPipelines.pipelineEditor.item.cancelMoveButtonAriaLabel": "移動のキャンセル", "xpack.ingestPipelines.pipelineEditor.item.descriptionPlaceholder": "説明なし", "xpack.ingestPipelines.pipelineEditor.item.editButtonAriaLabel": "このプロセッサーを編集", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 7795959a8e362..a845a2c9a7f93 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9749,14 +9749,10 @@ "xpack.ingestPipelines.pipelineEditor.deleteModal.deleteDescription": "删除此处理器和其失败时处理程序。", "xpack.ingestPipelines.pipelineEditor.dropZoneButton.moveHereToolTip": "移到此处", "xpack.ingestPipelines.pipelineEditor.dropZoneButton.unavailableToolTip": "无法移到此处", - "xpack.ingestPipelines.pipelineEditor.gsubForm.fieldFieldLabel": "字段", - "xpack.ingestPipelines.pipelineEditor.gsubForm.fieldRequiredError": "字段值必填。", - "xpack.ingestPipelines.pipelineEditor.gsubForm.ignoreMissingFieldLabel": "忽略缺失", "xpack.ingestPipelines.pipelineEditor.gsubForm.patternFieldLabel": "模式", "xpack.ingestPipelines.pipelineEditor.gsubForm.patternRequiredError": "模式值必填。", "xpack.ingestPipelines.pipelineEditor.gsubForm.replacementFieldLabel": "替换", "xpack.ingestPipelines.pipelineEditor.gsubForm.replacementRequiredError": "替换值必填。", - "xpack.ingestPipelines.pipelineEditor.gsubForm.targetFieldLabel": "目标字段(可选)", "xpack.ingestPipelines.pipelineEditor.item.cancelMoveButtonAriaLabel": "取消移动", "xpack.ingestPipelines.pipelineEditor.item.descriptionPlaceholder": "无描述", "xpack.ingestPipelines.pipelineEditor.item.editButtonAriaLabel": "编辑此处理器",