diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/index.ts index 6f7b55a3ea4b02..6ce9eefd26445a 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/index.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/index.ts @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { OnXJsonEditorUpdateHandler, XJsonEditor } from './xjson_editor'; +export { XJsonEditor } from './xjson_editor'; +export { TextEditor } from './text_editor'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/text_editor.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/text_editor.tsx new file mode 100644 index 00000000000000..1d0e36c0d526c7 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/text_editor.tsx @@ -0,0 +1,38 @@ +/* + * 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 { EuiPanel } from '@elastic/eui'; +import React, { FunctionComponent } from 'react'; +import { EuiFormRow } from '@elastic/eui'; +import { + CodeEditor, + FieldHook, + getFieldValidityAndErrorMessage, +} from '../../../../../../shared_imports'; + +interface Props { + field: FieldHook; + editorProps: { [key: string]: any }; +} + +export const TextEditor: FunctionComponent = ({ field, editorProps }) => { + const { value, helpText, setValue, label } = field; + const { errorMessage } = getFieldValidityAndErrorMessage(field); + + return ( + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/xjson_editor.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/xjson_editor.tsx index a8456ad0ffd72c..228094c0dfac58 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/xjson_editor.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/xjson_editor.tsx @@ -4,25 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiPanel } from '@elastic/eui'; import { XJsonLang } from '@kbn/monaco'; import React, { FunctionComponent, useCallback } from 'react'; -import { EuiFormRow } from '@elastic/eui'; -import { - CodeEditor, - FieldHook, - getFieldValidityAndErrorMessage, - Monaco, -} from '../../../../../../shared_imports'; +import { FieldHook, Monaco } from '../../../../../../shared_imports'; -export type OnXJsonEditorUpdateHandler = (arg: { - data: { - raw: string; - format(): T; - }; - validate(): boolean; - isValid: boolean | undefined; -}) => void; +import { TextEditor } from './text_editor'; interface Props { field: FieldHook; @@ -30,9 +16,8 @@ interface Props { } export const XJsonEditor: FunctionComponent = ({ field, editorProps }) => { - const { value, helpText, setValue, label } = field; + const { value, setValue } = field; const { xJson, setXJson, convertToJson } = Monaco.useXJsonMode(value); - const { errorMessage } = getFieldValidityAndErrorMessage(field); const onChange = useCallback( (s) => { @@ -42,25 +27,18 @@ export const XJsonEditor: FunctionComponent = ({ field, editorProps }) => [setValue, setXJson, convertToJson] ); return ( - - - { - XJsonLang.registerGrammarChecker(m); - }} - options={{ minimap: { enabled: false } }} - onChange={onChange} - {...(editorProps as any)} - /> - - + { + XJsonLang.registerGrammarChecker(m); + }, + onChange, + ...editorProps, + }} + /> ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.container.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.container.tsx index ea137b87e66d5d..84551ce152099a 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.container.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.container.tsx @@ -40,18 +40,19 @@ export const ManageProcessorForm: FunctionComponent = ({ const handleSubmit = useCallback( async (data: FormData, isValid: boolean) => { if (isValid) { - const { type, customOptions, ...options } = data; + const { type, customOptions, fields } = data; onSubmit({ type, - options: customOptions ? customOptions : options, + options: customOptions ? customOptions : fields, }); } }, [onSubmit] ); + const maybeProcessorOptions = processor?.options; const { form } = useForm({ - defaultValue: processor?.options, + defaultValue: { fields: maybeProcessorOptions ?? {} }, onSubmit: handleSubmit, }); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.tsx index 4e172cce630276..ad6d191be802df 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.tsx @@ -14,12 +14,12 @@ import { EuiFlyoutHeader, EuiFlyoutBody, EuiFlyoutFooter, - EuiSpacer, EuiTabs, EuiTab, EuiTitle, EuiFlexGroup, EuiFlexItem, + EuiSpacer, } from '@elastic/eui'; import { Form, FormDataProvider, FormHook } from '../../../../../shared_imports'; 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 6b2568bad3afc1..a6447bc30ac00f 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 } from '@elastic/eui'; +import { EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; import { FormDataProvider } from '../../../../../shared_imports'; import { ProcessorInternal } from '../../types'; @@ -36,6 +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 new file mode 100644 index 00000000000000..09d0981adf1c29 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/append.tsx @@ -0,0 +1,56 @@ +/* + * 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, + ComboBoxField, +} from '../../../../../../shared_imports'; + +import { FieldsConfig, to } from './shared'; +import { FieldNameField } from './common_fields/field_name_field'; + +const { emptyField } = fieldValidators; + +const fieldsConfig: FieldsConfig = { + value: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: to.arrayOfStrings, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.appendForm.valueFieldLabel', { + defaultMessage: 'Value', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.appendForm.valueFieldHelpText', { + defaultMessage: 'The value to be appended by this processor.', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.appendForm.valueRequiredError', { + defaultMessage: 'A value to set is required.', + }) + ), + }, + ], + }, +}; + +export const Append: FunctionComponent = () => { + return ( + <> + + + + + ); +}; 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 new file mode 100644 index 00000000000000..a76e1a6f3ce9a4 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/bytes.tsx @@ -0,0 +1,29 @@ +/* + * 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 { IgnoreMissingField } from './common_fields/ignore_missing_field'; +import { FieldNameField } from './common_fields/field_name_field'; +import { TargetField } from './common_fields/target_field'; + +export const Bytes: FunctionComponent = () => { + return ( + <> + + + + + + + ); +}; 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 new file mode 100644 index 00000000000000..599d2fdbfd413d --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/circle.tsx @@ -0,0 +1,130 @@ +/* + * 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, + SelectField, + NumericField, +} from '../../../../../../shared_imports'; + +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 = { + /* Required fields config */ + error_distance: { + type: FIELD_TYPES.NUMBER, + deserializer: (v) => (typeof v === 'number' && !isNaN(v) ? v : 1.0), + serializer: Number, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.circleForm.errorDistanceFieldLabel', + { + defaultMessage: 'Error distance', + } + ), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.circleForm.errorDistanceHelpText', + { + defaultMessage: + 'The difference between the resulting inscribed distance from center to side and the circle’s radius (measured in meters for geo_shape, unit-less for shape).', + } + ), + validations: [ + { + validator: ({ value }) => { + return isNaN(Number(value)) + ? { + message: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.circleForm.errorDistanceError', + { + defaultMessage: 'An error distance value is required.', + } + ), + } + : undefined; + }, + }, + ], + }, + shape_type: { + type: FIELD_TYPES.SELECT, + serializer: String, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.circleForm.shapeTypeFieldLabel', { + defaultMessage: 'Shape type', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.circleForm.shapeTypeFieldHelpText', + { defaultMessage: 'Which field mapping type is to be used.' } + ), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.circleForm.shapeTypeRequiredError', { + defaultMessage: 'A shape type value is required.', + }) + ), + }, + ], + }, +}; + +export const Circle: FunctionComponent = () => { + return ( + <> + + + + + + + + + + + ); +}; 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 4802653f9e6807..8089b8e7dfad34 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 @@ -15,41 +15,65 @@ import { ToggleField, } from '../../../../../../../shared_imports'; +import { TextEditor } from '../../field_components'; +import { to, from } from '../shared'; + const ignoreFailureConfig: FieldConfig = { defaultValue: false, + deserializer: to.booleanOrUndef, + serializer: from.defaultBoolToUndef(false), label: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.commonFields.ignoreFailureFieldLabel', { defaultMessage: 'Ignore failure', } ), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.commonFields.ignoreFailureHelpText', + { defaultMessage: 'Ignore failures for this processor.' } + ), type: FIELD_TYPES.TOGGLE, }; const ifConfig: FieldConfig = { - defaultValue: undefined, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.ifFieldLabel', { defaultMessage: 'Condition (optional)', }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.ifFieldHelpText', { + defaultMessage: 'Conditionally execute this processor.', + }), type: FIELD_TYPES.TEXT, }; const tagConfig: FieldConfig = { - defaultValue: undefined, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.tagFieldLabel', { defaultMessage: 'Tag (optional)', }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.tagFieldHelpText', { + defaultMessage: 'An identifier for this processor. Useful for debugging and metrics.', + }), type: FIELD_TYPES.TEXT, }; export const CommonProcessorFields: FunctionComponent = () => { return ( - <> - +
+ - + - - + +
); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/field_name_field.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/field_name_field.tsx new file mode 100644 index 00000000000000..7ef5ba6768c190 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/field_name_field.tsx @@ -0,0 +1,58 @@ +/* + * 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, + Field, + fieldValidators, + ValidationConfig, +} from '../../../../../../../shared_imports'; + +import { FieldsConfig } from '../shared'; + +const { emptyField } = fieldValidators; + +export const fieldsConfig: FieldsConfig = { + field: { + type: FIELD_TYPES.TEXT, + deserializer: String, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.fieldFieldLabel', { + defaultMessage: 'Field', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.fieldRequiredError', { + defaultMessage: 'A field value is required.', + }) + ), + }, + ], + }, +}; + +interface Props { + helpText?: React.ReactNode; + /** + * The field name requires a value. Processor specific validation + * checks can be added here. + */ + additionalValidations?: ValidationConfig[]; +} + +export const FieldNameField: FunctionComponent = ({ helpText, additionalValidations }) => ( + +); 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 new file mode 100644 index 00000000000000..c1c9d20664c04e --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/ignore_missing_field.tsx @@ -0,0 +1,37 @@ +/* + * 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, ToggleField } from '../../../../../../../shared_imports'; + +import { FieldsConfig, to, from } from '../shared'; + +export const fieldsConfig: FieldsConfig = { + ignore_missing: { + type: FIELD_TYPES.TOGGLE, + defaultValue: false, + deserializer: to.booleanOrUndef, + serializer: from.defaultBoolToUndef(false), + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.commonFields.ignoreMissingFieldLabel', + { + defaultMessage: 'Ignore missing', + } + ), + }, +}; + +interface Props { + helpText?: string; +} + +export const IgnoreMissingField: FunctionComponent = ({ helpText }) => ( + +); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/processor_type_field.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/processor_type_field.tsx index 71ee4a714a28e3..e4ad90f61af0a1 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/processor_type_field.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/processor_type_field.tsx @@ -46,20 +46,12 @@ interface Props { const { emptyField } = fieldValidators; -const typeConfig: FieldConfig = { +const typeConfig: FieldConfig = { type: FIELD_TYPES.COMBO_BOX, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.typeField.typeFieldLabel', { defaultMessage: 'Processor', }), - deserializer: (value: string | undefined) => { - if (value) { - return [value]; - } - return []; - }, - serializer: (value: string[]) => { - return value[0]; - }, + deserializer: String, validations: [ { validator: emptyField( @@ -73,11 +65,11 @@ const typeConfig: FieldConfig = { export const ProcessorTypeField: FunctionComponent = ({ initialType }) => { return ( - + config={typeConfig} defaultValue={initialType} path="type"> {(typeField) => { let selectedOptions: ProcessorTypeAndLabel[]; - if ((typeField.value as string[]).length) { - const [type] = typeField.value as string[]; + if (typeField.value?.length) { + const type = typeField.value; const descriptor = getProcessorDescriptor(type); selectedOptions = descriptor ? [{ label: descriptor.label, value: type }] @@ -103,9 +95,7 @@ export const ProcessorTypeField: FunctionComponent = ({ initialType }) => return false; } - const newValue = [...(typeField.value as string[]), value]; - - typeField.setValue(newValue); + typeField.setValue(value); }; return ( @@ -131,8 +121,9 @@ export const ProcessorTypeField: FunctionComponent = ({ initialType }) => options={processorTypesAndLabels} selectedOptions={selectedOptions} onCreateOption={onCreateComboOption} - onChange={(options: EuiComboBoxOptionOption[]) => { - typeField.setValue(options.map(({ value }) => value)); + onChange={(options: Array>) => { + const [selection] = options; + typeField.setValue(selection?.value! ?? ''); }} noSuggestions={false} singleSelection={{ 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 00000000000000..c9d536dcb41c3f --- /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,43 @@ +/* + * 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.jsonForm.targetFieldLabel', { + defaultMessage: 'Target field (optional)', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.jsonForm.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 new file mode 100644 index 00000000000000..2bf642dd9b5187 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/convert.tsx @@ -0,0 +1,130 @@ +/* + * 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, + 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; + +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + type: { + type: FIELD_TYPES.TEXT, + defaultValue: '', + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.typeFieldLabel', { + defaultMessage: 'Type', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.typeFieldHelpText', { + defaultMessage: 'The type to convert the existing value to.', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.typeRequiredError', { + defaultMessage: 'A type value is required.', + }) + ), + }, + ], + }, +}; + +export const Convert: FunctionComponent = () => { + return ( + <> + + + + + + + + + ); +}; 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 new file mode 100644 index 00000000000000..835177dd861d56 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/csv.tsx @@ -0,0 +1,162 @@ +/* + * 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 { EuiCode } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { + FIELD_TYPES, + fieldValidators, + UseField, + Field, + ToggleField, + ComboBoxField, + ValidationFunc, +} from '../../../../../../shared_imports'; + +import { FieldsConfig } from './shared'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; +import { FieldNameField } from './common_fields/field_name_field'; + +import { to } from './shared'; + +const { minLengthField } = fieldValidators; + +/** + * Allow empty strings ('') to pass this validation. + */ +const isStringLengthOne: ValidationFunc = ({ value }) => { + return typeof value === 'string' && value !== '' && value.length !== 1 + ? { + message: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.convertForm.separatorLengthError', + { + defaultMessage: 'A separator value must be 1 character.', + } + ), + } + : undefined; +}; + +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + target_fields: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: to.arrayOfStrings, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.csvForm.targetFieldsFieldLabel', { + defaultMessage: 'Target fields', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.csvForm.targetFieldsHelpText', { + defaultMessage: 'The array of fields to assign extracted values to.', + }), + validations: [ + { + validator: minLengthField({ + length: 1, + message: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.csvForm.targetFieldRequiredError', + { + defaultMessage: 'A target fields value is required.', + } + ), + }), + }, + ], + }, + /* Optional fields config */ + separator: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.separatorFieldLabel', { + defaultMessage: 'Separator (optional)', + }), + validations: [ + { + validator: isStringLengthOne, + }, + ], + helpText: ( + {','} }} + /> + ), + }, + quote: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.quoteFieldLabel', { + defaultMessage: 'Quote (optional)', + }), + validations: [ + { + validator: isStringLengthOne, + }, + ], + helpText: ( + {'"'} }} + /> + ), + }, + trim: { + type: FIELD_TYPES.TOGGLE, + defaultValue: false, + deserializer: to.booleanOrUndef, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.csvForm.trimFieldLabel', { + defaultMessage: 'Trim', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.csvForm.trimFieldHelpText', { + defaultMessage: 'Trim whitespaces in unquoted fields', + }), + }, + empty_value: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.emptyValueFieldLabel', { + defaultMessage: 'Empty value (optional)', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.convertForm.emptyValueFieldHelpText', + { + defaultMessage: + 'Value used to fill empty fields, empty fields will be skipped if this is not provided.', + } + ), + }, +}; + +export const CSV: FunctionComponent = () => { + return ( + <> + + + + + + + + + + + + + + + ); +}; 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 new file mode 100644 index 00000000000000..7e3f8e0d7cd701 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date.tsx @@ -0,0 +1,115 @@ +/* + * 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 { EuiCode } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { + FIELD_TYPES, + fieldValidators, + UseField, + Field, + ComboBoxField, +} from '../../../../../../shared_imports'; + +import { FieldsConfig, to } from './shared'; +import { FieldNameField } from './common_fields/field_name_field'; +import { TargetField } from './common_fields/target_field'; + +const { minLengthField } = fieldValidators; + +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + formats: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: to.arrayOfStrings, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dateForm.formatsFieldLabel', { + defaultMessage: 'Formats', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.dateForm.formatsFieldHelpText', { + defaultMessage: + 'An array of the expected date formats. Can be a java time pattern or one of the following formats: ISO8601, UNIX, UNIX_MS, or TAI64N.', + }), + validations: [ + { + validator: minLengthField({ + length: 1, + message: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateForm.formatsRequiredError', + { + defaultMessage: 'A value for formats is required.', + } + ), + }), + }, + ], + }, + /* Optional fields config */ + timezone: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dateForm.timezoneFieldLabel', { + defaultMessage: 'Timezone (optional)', + }), + helpText: ( + {'UTC'} }} + /> + ), + }, + locale: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dateForm.localeFieldLabel', { + defaultMessage: 'Locale (optional)', + }), + helpText: ( + {'ENGLISH'} }} + /> + ), + }, +}; + +/** + * Disambiguate from global Date object + */ +export const DateProcessor: FunctionComponent = () => { + return ( + <> + + + + + {'@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 new file mode 100644 index 00000000000000..2a278a251c30f0 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date_index_name.tsx @@ -0,0 +1,240 @@ +/* + * 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 { EuiCode } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { + FIELD_TYPES, + fieldValidators, + UseField, + Field, + ComboBoxField, + SelectField, +} from '../../../../../../shared_imports'; + +import { FieldsConfig, to } from './shared'; +import { FieldNameField } from './common_fields/field_name_field'; + +const { emptyField } = fieldValidators; + +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + date_rounding: { + type: FIELD_TYPES.SELECT, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.dateRoundingFieldLabel', + { + defaultMessage: 'Date rounding', + } + ), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.dateRoundingFieldHelpText', + { + defaultMessage: 'How to round the date when formatting the date into the index name.', + } + ), + validations: [ + { + validator: emptyField( + i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.dateRoundingRequiredError', + { + defaultMessage: 'A field value is required.', + } + ) + ), + }, + ], + }, + /* Optional fields config */ + index_name_prefix: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.indexNamePrefixFieldLabel', + { + defaultMessage: 'Index name prefix (optional)', + } + ), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.indexNamePrefixFieldHelpText', + { defaultMessage: 'A prefix of the index name to be prepended before the printed date.' } + ), + }, + index_name_format: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.indexNameFormatFieldLabel', + { + defaultMessage: 'Index name format (optional)', + } + ), + helpText: ( + {'yyyy-MM-dd'} }} + /> + ), + }, + date_formats: { + type: FIELD_TYPES.COMBO_BOX, + serializer: (v: string[]) => { + return v.length ? v : undefined; + }, + deserializer: to.arrayOfStrings, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.dateFormatsFieldLabel', + { + defaultMessage: 'Date formats (optional)', + } + ), + helpText: ( + {"yyyy-MM-dd'T'HH:mm:ss.SSSXX"} }} + /> + ), + }, + timezone: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.timezoneFieldLabel', + { + defaultMessage: 'Timezone (optional)', + } + ), + helpText: ( + {'UTC'} }} + /> + ), + }, + locale: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.localeFieldLabel', + { + defaultMessage: 'Locale (optional)', + } + ), + helpText: ( + {'ENGLISH'} }} + /> + ), + }, +}; + +/** + * Disambiguate from global Date object + */ +export const DateIndexName: FunctionComponent = () => { + return ( + <> + + + + + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dissect.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dissect.tsx new file mode 100644 index 00000000000000..5f9f55ced1a256 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dissect.tsx @@ -0,0 +1,99 @@ +/* + * 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 { EuiCode } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { TextEditor } from '../field_components'; + +import { + FieldConfig, + FIELD_TYPES, + fieldValidators, + UseField, + Field, +} from '../../../../../../shared_imports'; + +import { FieldNameField } from './common_fields/field_name_field'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; + +const { emptyField } = fieldValidators; + +const fieldsConfig: Record = { + /* Required field config */ + pattern: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dissectForm.patternFieldLabel', { + defaultMessage: 'Pattern', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dissectForm.patternFieldHelpText', + { + defaultMessage: 'The pattern to apply to the field.', + } + ), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.dissectForm.patternRequiredError', { + defaultMessage: 'A pattern value is required.', + }) + ), + }, + ], + }, + /* Optional field config */ + append_separator: { + type: FIELD_TYPES.TEXT, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dissectForm.appendSeparatorparaotrFieldLabel', + { + defaultMessage: 'Append separator (optional)', + } + ), + helpText: ( + {'""'} }} + /> + ), + }, +}; + +export const Dissect: FunctionComponent = () => { + return ( + <> + + + + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dot_expander.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dot_expander.tsx new file mode 100644 index 00000000000000..f25482178c79de --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dot_expander.tsx @@ -0,0 +1,55 @@ +/* + * 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 { FieldConfig, FIELD_TYPES, UseField, Field } from '../../../../../../shared_imports'; + +import { FieldNameField } from './common_fields/field_name_field'; + +const fieldsConfig: Record = { + path: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dotExpanderForm.pathFieldLabel', { + defaultMessage: 'Path', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.dotExpanderForm.pathHelpText', { + defaultMessage: 'Only required if the field to expand is part another object field.', + }), + }, +}; + +export const DotExpander: FunctionComponent = () => { + return ( + <> + { + if (typeof value === 'string' && value.length) { + return !value.includes('.') + ? { + message: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dotExpanderForm.fieldNameHelpText', + { defaultMessage: 'A field value requires at least one dot character.' } + ), + } + : undefined; + } + }, + }, + ]} + /> + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/drop.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/drop.tsx new file mode 100644 index 00000000000000..87b6cb76cdccec --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/drop.tsx @@ -0,0 +1,14 @@ +/* + * 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 { FunctionComponent } from 'react'; + +/** + * This fields component has no unique fields + */ +export const Drop: FunctionComponent = () => { + return null; +}; 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 00000000000000..20b0470d8fc6ba --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/enrich.tsx @@ -0,0 +1,226 @@ +/* + * 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, + ToggleField, + NumericField, + SelectField, + ValidationConfig, +} 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', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.enrichForm.policyNameHelpText', { + defaultMessage: 'The name of the enrich policy to use.', + }), + validations: [ + { + validator: emptyField( + i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.policyNameRequiredError', + { + defaultMessage: 'A field 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: + 'Whether this processor will update fields with pre-existing non-null-valued field. When set to false, such fields will not be overridden.', + } + ), + }, + + 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: 'Max matches (optional)', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.maxMatchesFieldHelpText', + { + defaultMessage: + 'The maximum number of matched documents to include under the configured target field. The target_field will be turned into a json array if max_matches is higher than 1, otherwise target_field will become a json object', + } + ), + 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)', + } + ), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.enrichForm.shapeRelationFieldHelpText', + { + defaultMessage: + 'A spatial relation operator used to match the geo_shape of incoming documents to documents in the enrich index. This option is only used for geo_match enrich policy types.', + } + ), + }, +}; + +export const Enrich: FunctionComponent = () => { + return ( + <> + + + + + + + + + + + + + + + ); +}; 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 00000000000000..8d53aaa75e29bd --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/fail.tsx @@ -0,0 +1,44 @@ +/* + * 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: 'The error message thrown 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 00000000000000..afaa9e74879b6a --- /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: 'The processor to execute against each field 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 00000000000000..22aa2f000bab36 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/geoip.tsx @@ -0,0 +1,101 @@ +/* + * 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'} }} + /> + ), + }, + + 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: + 'Controls what properties are added to the target field. Values depend on what is available from the database file.', + } + ), + }, + + 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', + }), + }, +}; + +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 00000000000000..d3565ddf4e3318 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/grok.tsx @@ -0,0 +1,159 @@ +/* + * 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: + 'An ordered list of grok expressions to match and extract named captures with. Returns on the first expression in the list that matches.', + }), + validations: [ + { + validator: emptyField( + i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.grokForm.patternsValueRequiredError', + { defaultMessage: 'A value for patterns 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: 'Whether to insert pattern match metadata.', + } + ), + }, + + properties: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: to.arrayOfStrings, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.grokForm.propertiesFieldLabel', { + defaultMessage: 'Properties (optional)', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.grokForm.propertiesFieldHelpText', + { + defaultMessage: + 'Controls what properties are added to the target field. Values depend on what is available from the database file.', + } + ), + }, + + first_only: { + type: FIELD_TYPES.TOGGLE, + defaultValue: true, + deserializer: to.booleanOrUndef, + serializer: from.defaultBoolToUndef(true), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.grokForm.firstOnlyFieldLabel', { + defaultMessage: 'First only', + }), + }, +}; + +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 77f85e61eff6b4..33a456c961501c 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 @@ -7,92 +7,94 @@ import React, { FunctionComponent } from 'react'; import { i18n } from '@kbn/i18n'; -import { - FieldConfig, - FIELD_TYPES, - fieldValidators, - ToggleField, - UseField, - Field, -} from '../../../../../../shared_imports'; +import { FIELD_TYPES, fieldValidators, UseField, Field } from '../../../../../../shared_imports'; -const { emptyField } = fieldValidators; - -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: 'The pattern to be replaced.', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.patternRequiredError', { + defaultMessage: 'A pattern 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: 'The string to replace the matching patterns with.' } + ), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.replacementRequiredError', { + defaultMessage: 'A replacement value is required.', + }) + ), + }, + ], + }, }; export const Gsub: FunctionComponent = () => { return ( <> - + - + - + - + - + ); }; 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 00000000000000..11999d26b4f2a8 --- /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,37 @@ +/* + * 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 { 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 ( + <> + + + + + + + ); +}; 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 new file mode 100644 index 00000000000000..4974361bf04106 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/index.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +export { Append } from './append'; +export { Bytes } from './bytes'; +export { Circle } from './circle'; +export { Convert } from './convert'; +export { CSV } from './csv'; +export { DateProcessor } from './date'; +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 00000000000000..73ef1bffdbe395 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/inference.tsx @@ -0,0 +1,201 @@ +/* + * 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: 'The ID of the model to load and 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 the document field names to the known field names of the model. This mapping takes precedence over any default mappings provided in the model configuration.', + } + ), + 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 00000000000000..fa17513beacb58 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/join.tsx @@ -0,0 +1,67 @@ +/* + * 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'; +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: 'The separator character', + } + ), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.joinForm.separatorRequiredError', { + defaultMessage: 'A separator value is required.', + }) + ), + }, + ], + }, +}; + +export const Join: FunctionComponent = () => { + return ( + <> + + + + + + + ); +}; 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 00000000000000..3c391084c0b53f --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/json.tsx @@ -0,0 +1,82 @@ +/* + * 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: + 'Inject the serialized JSON to the top level of the JSON document. A target field cannot be combined with this option.', + } + ), + }, +}; + +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/set.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set.tsx index 1ba6a14d0448d8..88cea620ae804e 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set.tsx @@ -64,11 +64,11 @@ const overrideConfig: FieldConfig = { export const SetProcessor: FunctionComponent = () => { 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 new file mode 100644 index 00000000000000..84b308dd9cd7ab --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/shared.ts @@ -0,0 +1,68 @@ +/* + * 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 * as rt from 'io-ts'; +import { isRight } from 'fp-ts/lib/Either'; + +import { FieldConfig } from '../../../../../../shared_imports'; + +export const arrayOfStrings = rt.array(rt.string); + +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 7055721fc8b07c..5ad51edb9024a9 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 @@ -7,6 +7,29 @@ import { i18n } from '@kbn/i18n'; import { FunctionComponent } from 'react'; +import { + Append, + Bytes, + Circle, + Convert, + CSV, + DateProcessor, + DateIndexName, + Dissect, + DotExpander, + Drop, + Enrich, + Fail, + Foreach, + GeoIP, + Grok, + Gsub, + HtmlStrip, + Inference, + Join, + Json, +} from '../manage_processor_form/processors'; + // import { SetProcessor } from './processors/set'; // import { Gsub } from './processors/gsub'; @@ -23,133 +46,140 @@ type MapProcessorTypeToDescriptor = Record; export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { append: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Append, docLinkPath: '/append-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.append', { defaultMessage: 'Append', }), }, bytes: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Bytes, docLinkPath: '/bytes-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.bytes', { defaultMessage: 'Bytes', }), }, circle: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Circle, docLinkPath: '/ingest-circle-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.circle', { defaultMessage: 'Circle', }), }, convert: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Convert, docLinkPath: '/convert-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.convert', { defaultMessage: 'Convert', }), }, csv: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: CSV, docLinkPath: '/csv-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.csv', { defaultMessage: 'CSV', }), }, date: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: DateProcessor, docLinkPath: '/date-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.date', { defaultMessage: 'Date', }), }, date_index_name: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: DateIndexName, docLinkPath: '/date-index-name-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.dateIndexName', { defaultMessage: 'Date Index Name', }), }, dissect: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Dissect, docLinkPath: '/dissect-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.dissect', { defaultMessage: 'Dissect', }), }, dot_expander: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: DotExpander, docLinkPath: '/dot-expand-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.dotExpander', { defaultMessage: 'Dot Expander', }), }, drop: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Drop, docLinkPath: '/drop-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.drop', { defaultMessage: 'Drop', }), }, enrich: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Enrich, docLinkPath: '/enrich-processor.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', @@ -255,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/ingest_pipelines/public/shared_imports.ts b/x-pack/plugins/ingest_pipelines/public/shared_imports.ts index d2c4b73a487679..936db37f0c6292 100644 --- a/x-pack/plugins/ingest_pipelines/public/shared_imports.ts +++ b/x-pack/plugins/ingest_pipelines/public/shared_imports.ts @@ -43,6 +43,8 @@ export { FieldConfig, FieldHook, getFieldValidityAndErrorMessage, + ValidationFunc, + ValidationConfig, } from '../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib'; export { @@ -57,6 +59,9 @@ export { FormRow, ToggleField, ComboBoxField, + RadioGroupField, + NumericField, + SelectField, } from '../../../../src/plugins/es_ui_shared/static/forms/components'; export {