mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Ingest Node Pipelines] Sentence-case processor names (#74645)
* wip on fixing processor names * added comment * fix Jest test element selector Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
ce6011e4d5
commit
92289b63ef
6 changed files with 126 additions and 32 deletions
|
@ -89,7 +89,7 @@ const createActions = (testBed: TestBed<TestSubject>) => {
|
||||||
async addProcessor(processorsSelector: string, type: string, options: Record<string, any>) {
|
async addProcessor(processorsSelector: string, type: string, options: Record<string, any>) {
|
||||||
find(`${processorsSelector}.addProcessorButton`).simulate('click');
|
find(`${processorsSelector}.addProcessorButton`).simulate('click');
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
find('processorTypeSelector').simulate('change', [{ value: type, label: type }]);
|
find('processorTypeSelector.input').simulate('change', [{ value: type, label: type }]);
|
||||||
});
|
});
|
||||||
component.update();
|
component.update();
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
|
@ -129,7 +129,7 @@ const createActions = (testBed: TestBed<TestSubject>) => {
|
||||||
find(`${processorSelector}.moreMenu.button`).simulate('click');
|
find(`${processorSelector}.moreMenu.button`).simulate('click');
|
||||||
find(`${processorSelector}.moreMenu.addOnFailureButton`).simulate('click');
|
find(`${processorSelector}.moreMenu.addOnFailureButton`).simulate('click');
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
find('processorTypeSelector').simulate('change', [{ value: type, label: type }]);
|
find('processorTypeSelector.input').simulate('change', [{ value: type, label: type }]);
|
||||||
});
|
});
|
||||||
component.update();
|
component.update();
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
|
|
|
@ -22,6 +22,8 @@ import { ProcessorsDispatch } from '../../processors_reducer';
|
||||||
|
|
||||||
import { ProcessorInfo } from '../processors_tree';
|
import { ProcessorInfo } from '../processors_tree';
|
||||||
|
|
||||||
|
import { getProcessorDescriptor } from '../shared';
|
||||||
|
|
||||||
import './pipeline_processors_editor_item.scss';
|
import './pipeline_processors_editor_item.scss';
|
||||||
|
|
||||||
import { InlineTextInput } from './inline_text_input';
|
import { InlineTextInput } from './inline_text_input';
|
||||||
|
@ -139,7 +141,7 @@ export const PipelineProcessorsEditorItem: FunctionComponent<Props> = memo(
|
||||||
className="pipelineProcessorsEditor__item__processorTypeLabel"
|
className="pipelineProcessorsEditor__item__processorTypeLabel"
|
||||||
color={isDimmed ? 'subdued' : undefined}
|
color={isDimmed ? 'subdued' : undefined}
|
||||||
>
|
>
|
||||||
<b>{processor.type}</b>
|
<b>{getProcessorDescriptor(processor.type)?.label ?? processor.type}</b>
|
||||||
</EuiText>
|
</EuiText>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
<EuiFlexItem className={inlineTextInputContainerClasses} grow={false}>
|
<EuiFlexItem className={inlineTextInputContainerClasses} grow={false}>
|
||||||
|
|
|
@ -23,8 +23,9 @@ import {
|
||||||
import { Form, FormDataProvider, FormHook } from '../../../../../shared_imports';
|
import { Form, FormDataProvider, FormHook } from '../../../../../shared_imports';
|
||||||
import { ProcessorInternal } from '../../types';
|
import { ProcessorInternal } from '../../types';
|
||||||
|
|
||||||
|
import { getProcessorDescriptor } from '../shared';
|
||||||
|
|
||||||
import { DocumentationButton } from './documentation_button';
|
import { DocumentationButton } from './documentation_button';
|
||||||
import { getProcessorFormDescriptor } from './map_processor_type_to_form';
|
|
||||||
import { CommonProcessorFields, ProcessorTypeField } from './processors/common_fields';
|
import { CommonProcessorFields, ProcessorTypeField } from './processors/common_fields';
|
||||||
import { Custom } from './processors/custom';
|
import { Custom } from './processors/custom';
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ export const ProcessorSettingsForm: FunctionComponent<Props> = memo(
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<FormDataProvider pathsToWatch="type">
|
<FormDataProvider pathsToWatch="type">
|
||||||
{({ type }) => {
|
{({ type }) => {
|
||||||
const formDescriptor = getProcessorFormDescriptor(type as any);
|
const formDescriptor = getProcessorDescriptor(type as any);
|
||||||
|
|
||||||
if (formDescriptor) {
|
if (formDescriptor) {
|
||||||
return (
|
return (
|
||||||
|
@ -114,7 +115,7 @@ export const ProcessorSettingsForm: FunctionComponent<Props> = memo(
|
||||||
const { type } = arg;
|
const { type } = arg;
|
||||||
|
|
||||||
if (type?.length) {
|
if (type?.length) {
|
||||||
const formDescriptor = getProcessorFormDescriptor(type as any);
|
const formDescriptor = getProcessorDescriptor(type as any);
|
||||||
|
|
||||||
if (formDescriptor?.FieldsComponent) {
|
if (formDescriptor?.FieldsComponent) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -3,16 +3,42 @@
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import React, { FunctionComponent } from 'react';
|
import React, { FunctionComponent } from 'react';
|
||||||
|
import { flow } from 'fp-ts/lib/function';
|
||||||
|
import { map } from 'fp-ts/lib/Array';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FIELD_TYPES,
|
FIELD_TYPES,
|
||||||
FieldConfig,
|
FieldConfig,
|
||||||
UseField,
|
UseField,
|
||||||
fieldValidators,
|
fieldValidators,
|
||||||
ComboBoxField,
|
|
||||||
} from '../../../../../../../shared_imports';
|
} from '../../../../../../../shared_imports';
|
||||||
import { types } from '../../map_processor_type_to_form';
|
|
||||||
|
import { getProcessorDescriptor, mapProcessorTypeToDescriptor } from '../../../shared';
|
||||||
|
import {
|
||||||
|
FieldValidateResponse,
|
||||||
|
VALIDATION_TYPES,
|
||||||
|
} from '../../../../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib';
|
||||||
|
|
||||||
|
const extractProcessorTypesAndLabels = flow(
|
||||||
|
Object.entries,
|
||||||
|
map(([type, { label }]) => ({
|
||||||
|
label,
|
||||||
|
value: type,
|
||||||
|
})),
|
||||||
|
(arr) => arr.sort((a, b) => a.label.localeCompare(b.label))
|
||||||
|
);
|
||||||
|
|
||||||
|
interface ProcessorTypeAndLabel {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const processorTypesAndLabels: ProcessorTypeAndLabel[] = extractProcessorTypesAndLabels(
|
||||||
|
mapProcessorTypeToDescriptor
|
||||||
|
);
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
initialType?: string;
|
initialType?: string;
|
||||||
|
@ -47,22 +73,76 @@ const typeConfig: FieldConfig = {
|
||||||
|
|
||||||
export const ProcessorTypeField: FunctionComponent<Props> = ({ initialType }) => {
|
export const ProcessorTypeField: FunctionComponent<Props> = ({ initialType }) => {
|
||||||
return (
|
return (
|
||||||
<UseField
|
<UseField config={typeConfig} defaultValue={initialType} path="type">
|
||||||
config={typeConfig}
|
{(typeField) => {
|
||||||
defaultValue={initialType}
|
let selectedOptions: ProcessorTypeAndLabel[];
|
||||||
path="type"
|
if ((typeField.value as string[]).length) {
|
||||||
component={ComboBoxField}
|
const [type] = typeField.value as string[];
|
||||||
componentProps={{
|
const descriptor = getProcessorDescriptor(type);
|
||||||
euiFieldProps: {
|
selectedOptions = descriptor
|
||||||
'data-test-subj': 'processorTypeSelector',
|
? [{ label: descriptor.label, value: type }]
|
||||||
fullWidth: true,
|
: // If there is no label for this processor type, just use the type as the label
|
||||||
options: types.map((type) => ({ label: type, value: type })),
|
[{ label: type, value: type }];
|
||||||
noSuggestions: false,
|
} else {
|
||||||
singleSelection: {
|
selectedOptions = [];
|
||||||
asPlainText: true,
|
}
|
||||||
},
|
|
||||||
},
|
const error = typeField.getErrorsMessages();
|
||||||
|
const isInvalid = error ? Boolean(error.length) : false;
|
||||||
|
|
||||||
|
const onCreateComboOption = (value: string) => {
|
||||||
|
// Note: for now, all validations for a comboBox array item have to be synchronous
|
||||||
|
// If there is a need to support asynchronous validation, we'll work on it (and will need to update the <EuiComboBox /> logic).
|
||||||
|
const { isValid } = typeField.validate({
|
||||||
|
value,
|
||||||
|
validationType: VALIDATION_TYPES.ARRAY_ITEM,
|
||||||
|
}) as FieldValidateResponse;
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
// Return false to explicitly reject the user's input.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newValue = [...(typeField.value as string[]), value];
|
||||||
|
|
||||||
|
typeField.setValue(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EuiFormRow
|
||||||
|
label={typeField.label}
|
||||||
|
labelAppend={typeField.labelAppend}
|
||||||
|
helpText={
|
||||||
|
typeof typeField.helpText === 'function' ? typeField.helpText() : typeField.helpText
|
||||||
|
}
|
||||||
|
error={error}
|
||||||
|
isInvalid={isInvalid}
|
||||||
|
fullWidth
|
||||||
|
data-test-subj="processorTypeSelector"
|
||||||
|
>
|
||||||
|
<EuiComboBox
|
||||||
|
fullWidth
|
||||||
|
placeholder={i18n.translate(
|
||||||
|
'xpack.ingestPipelines.pipelineEditor.typeField.typeFieldComboboxPlaceholder',
|
||||||
|
{
|
||||||
|
defaultMessage: 'Type and then hit "ENTER"',
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
options={processorTypesAndLabels}
|
||||||
|
selectedOptions={selectedOptions}
|
||||||
|
onCreateOption={onCreateComboOption}
|
||||||
|
onChange={(options: EuiComboBoxOptionOption[]) => {
|
||||||
|
typeField.setValue(options.map(({ value }) => value));
|
||||||
|
}}
|
||||||
|
noSuggestions={false}
|
||||||
|
singleSelection={{
|
||||||
|
asPlainText: true,
|
||||||
|
}}
|
||||||
|
data-test-subj="input"
|
||||||
|
/>
|
||||||
|
</EuiFormRow>
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
</UseField>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
getProcessorDescriptor,
|
||||||
|
mapProcessorTypeToDescriptor,
|
||||||
|
ProcessorType,
|
||||||
|
} from './map_processor_type_to_form';
|
|
@ -10,7 +10,7 @@ import { FunctionComponent } from 'react';
|
||||||
// import { SetProcessor } from './processors/set';
|
// import { SetProcessor } from './processors/set';
|
||||||
// import { Gsub } from './processors/gsub';
|
// import { Gsub } from './processors/gsub';
|
||||||
|
|
||||||
interface FieldsFormDescriptor {
|
interface FieldDescriptor {
|
||||||
FieldsComponent?: FunctionComponent;
|
FieldsComponent?: FunctionComponent;
|
||||||
docLinkPath: string;
|
docLinkPath: string;
|
||||||
/**
|
/**
|
||||||
|
@ -19,7 +19,9 @@ interface FieldsFormDescriptor {
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapProcessorTypeToFormDescriptor: Record<string, FieldsFormDescriptor> = {
|
type MapProcessorTypeToDescriptor = Record<string, FieldDescriptor>;
|
||||||
|
|
||||||
|
export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = {
|
||||||
append: {
|
append: {
|
||||||
FieldsComponent: undefined, // TODO: Implement
|
FieldsComponent: undefined, // TODO: Implement
|
||||||
docLinkPath: '/append-processor.html',
|
docLinkPath: '/append-processor.html',
|
||||||
|
@ -262,12 +264,10 @@ const mapProcessorTypeToFormDescriptor: Record<string, FieldsFormDescriptor> = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const types = Object.keys(mapProcessorTypeToFormDescriptor).sort();
|
export type ProcessorType = keyof typeof mapProcessorTypeToDescriptor;
|
||||||
|
|
||||||
export type ProcessorType = keyof typeof mapProcessorTypeToFormDescriptor;
|
export const getProcessorDescriptor = (
|
||||||
|
|
||||||
export const getProcessorFormDescriptor = (
|
|
||||||
type: ProcessorType | string
|
type: ProcessorType | string
|
||||||
): FieldsFormDescriptor | undefined => {
|
): FieldDescriptor | undefined => {
|
||||||
return mapProcessorTypeToFormDescriptor[type as ProcessorType];
|
return mapProcessorTypeToDescriptor[type as ProcessorType];
|
||||||
};
|
};
|
Loading…
Add table
Add a link
Reference in a new issue