diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processor_settings_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processor_settings_form.tsx index 9071cacd4cff5..3072c430655eb 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processor_settings_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processor_settings_form.tsx @@ -5,7 +5,7 @@ */ import { i18n } from '@kbn/i18n'; import React, { FunctionComponent, useCallback, useEffect } from 'react'; -import { EuiButton } from '@elastic/eui'; +import { EuiButton, EuiHorizontalRule } from '@elastic/eui'; import { Form, useForm, FormDataProvider, OnFormUpdateArg } from '../../../../../shared_imports'; @@ -13,6 +13,7 @@ import { ProcessorInternal } from '../../types'; import { getProcessorForm } from './map_processor_type_to_form'; import { CommonProcessorFields, ProcessorTypeField } from './processors/common_fields'; +import { Custom } from './processors/custom'; export type ProcessorSettingsFromOnSubmitArg = Omit; @@ -30,10 +31,10 @@ export const ProcessorSettingsForm: FunctionComponent = ({ const handleSubmit = useCallback( (data: any, isValid: boolean) => { if (isValid) { - const { type, ...options } = data; + const { type, customOptions, ...options } = data; onSubmit({ type, - options, + options: customOptions ? customOptions : options, }); } }, @@ -58,24 +59,30 @@ export const ProcessorSettingsForm: FunctionComponent = ({ return (
+ + + - {({ type }) => { - let FormFields: FunctionComponent | null = null; + {({ type, customOptions, ...options }) => { + let formContent: React.ReactNode | undefined; - if (type) { - FormFields = getProcessorForm(type as any); + if (type?.length) { + const ProcessorFormFields = getProcessorForm(type as any); - // TODO: Handle this error in a different way - if (!FormFields) { - throw new Error(`Could not find form for type ${type}`); + if (ProcessorFormFields) { + formContent = ( + <> + + + + ); + } else { + formContent = ; } - } - return ( - FormFields && ( + return ( <> - - + {formContent} {i18n.translate( 'xpack.ingestPipelines.pipelineEditor.settingsForm.submitButtonLabel', @@ -83,8 +90,11 @@ export const ProcessorSettingsForm: FunctionComponent = ({ )} - ) - ); + ); + } + + // If the user has not yet defined a type, we do not show any settings fields + return null; }} diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/common_fields/common_processor_fields.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/common_fields/common_processor_fields.tsx index 6578ca96e2860..4802653f9e680 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/common_fields/common_processor_fields.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/common_fields/common_processor_fields.tsx @@ -5,8 +5,9 @@ */ import React, { FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; + import { - FormRow, FieldConfig, UseField, FIELD_TYPES, @@ -16,32 +17,39 @@ import { const ignoreFailureConfig: FieldConfig = { defaultValue: false, - label: 'Ignore Failure', + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.commonFields.ignoreFailureFieldLabel', + { + defaultMessage: 'Ignore failure', + } + ), type: FIELD_TYPES.TOGGLE, }; + const ifConfig: FieldConfig = { defaultValue: undefined, - label: 'If', + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.ifFieldLabel', { + defaultMessage: 'Condition (optional)', + }), type: FIELD_TYPES.TEXT, }; + const tagConfig: FieldConfig = { defaultValue: undefined, - label: 'Tag', + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.tagFieldLabel', { + defaultMessage: 'Tag (optional)', + }), type: FIELD_TYPES.TEXT, }; export const CommonProcessorFields: FunctionComponent = () => { return ( <> - - - - - - - - - + + + + + ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/common_fields/processor_type_field.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/common_fields/processor_type_field.tsx index 86fbc4148f3b8..64ffa244e98e5 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/common_fields/processor_type_field.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/common_fields/processor_type_field.tsx @@ -4,14 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ import { i18n } from '@kbn/i18n'; -import { EuiComboBox } from '@elastic/eui'; import React, { FunctionComponent } from 'react'; import { FIELD_TYPES, FieldConfig, UseField, fieldValidators, - FormRow, + ComboBoxField, } from '../../../../../../../shared_imports'; import { types } from '../../map_processor_type_to_form'; @@ -24,8 +23,17 @@ const { emptyField } = fieldValidators; const typeConfig: FieldConfig = { type: FIELD_TYPES.COMBO_BOX, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.typeField.typeFieldLabel', { - defaultMessage: 'Type', + defaultMessage: 'Processor', }), + deserializer: (value: string | undefined) => { + if (value) { + return [value]; + } + return []; + }, + serializer: (value: string[]) => { + return value[0]; + }, validations: [ { validator: emptyField( @@ -39,27 +47,21 @@ const typeConfig: FieldConfig = { export const ProcessorTypeField: FunctionComponent = ({ initialType }) => { return ( - - - {typeField => { - return ( - typeField.setValue(selected?.value)} - selectedOptions={ - typeField.value - ? [{ value: typeField.value as string, label: typeField.value as string }] - : [] - } - singleSelection={{ asPlainText: true }} - options={types.map(type => ({ label: type, value: type }))} - /> - ); - }} - - + ({ label: type, value: type })), + noSuggestions: false, + singleSelection: { + asPlainText: true, + }, + }, + }} + /> ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/custom.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/custom.tsx new file mode 100644 index 0000000000000..61fc31a7b472a --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/custom.tsx @@ -0,0 +1,90 @@ +/* + * 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, + fieldValidators, + UseField, + JsonEditorField, +} from '../../../../../../shared_imports'; + +const { emptyField, isJsonField } = fieldValidators; + +const customConfig: FieldConfig = { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.customForm.optionsFieldLabel', { + defaultMessage: 'Configuration options', + }), + serializer: (value: string) => { + try { + return JSON.parse(value); + } catch (error) { + // swallow error and return non-parsed value; + return value; + } + }, + deserializer: (value: any) => { + if (value === '') { + return '{\n\n}'; + } + return JSON.stringify(value, null, 2); + }, + validations: [ + { + validator: emptyField( + i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.customForm.configurationRequiredError', + { + defaultMessage: 'Configuration options are required.', + } + ) + ), + }, + { + validator: isJsonField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.customForm.invalidJsonError', { + defaultMessage: 'The input is not valid.', + }) + ), + }, + ], +}; + +interface Props { + defaultOptions?: any; +} + +/** + * This is a catch-all component to support settings for custom processors + * or existing processors not yet supported by the UI. + * + * We store the settings in a field called "customOptions" + **/ +export const Custom: FunctionComponent = ({ defaultOptions }) => { + return ( + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/gsub.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/gsub.tsx index db8ec62764190..77f85e61eff6b 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/gsub.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/gsub.tsx @@ -11,7 +11,7 @@ import { FieldConfig, FIELD_TYPES, fieldValidators, - FormRow, + ToggleField, UseField, Field, } from '../../../../../../shared_imports'; @@ -66,33 +66,33 @@ const replacementConfig: FieldConfig = { ], }; +const targetConfig: FieldConfig = { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.targetFieldLabel', { + defaultMessage: 'Target field (optional)', + }), +}; + +const ignoreMissingConfig: FieldConfig = { + defaultValue: false, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.ignoreMissingFieldLabel', { + defaultMessage: 'Ignore missing', + }), + type: FIELD_TYPES.TOGGLE, +}; + export const Gsub: FunctionComponent = () => { return ( <> - - - - - - - - - + + + + + + + + + ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/set.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/set.tsx index a07b58f187a50..4b255b99bb53e 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/set.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_settings_form/processors/set.tsx @@ -11,7 +11,7 @@ import { FieldConfig, FIELD_TYPES, fieldValidators, - FormRow, + ToggleField, UseField, Field, } from '../../../../../../shared_imports'; @@ -50,26 +50,25 @@ const valueConfig: FieldConfig = { ], }; +const overrideConfig: FieldConfig = { + defaultValue: false, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.setForm.overrideFieldLabel', { + defaultMessage: 'Override', + }), + type: FIELD_TYPES.TOGGLE, +}; + /** * Disambiguate name from the Set data structure */ export const SetProcessor: FunctionComponent = () => { return ( <> - - - - - - + + + + + ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/settings_form_flyout.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/settings_form_flyout.tsx index 10c86aea4df4a..d37920a243cb6 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/settings_form_flyout.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/settings_form_flyout.tsx @@ -4,10 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiFlyout, EuiFlyoutBody } from '@elastic/eui'; +import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; import React, { FunctionComponent } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + import { OnFormUpdateArg } from '../../../../shared_imports'; import { ProcessorInternal } from '../types'; @@ -29,6 +31,16 @@ export const SettingsFormFlyout: FunctionComponent = ({ }) => { return ( + + +

+ +

+
+