From df1882eac025d2db7ca6cefbb1b19071d1b14888 Mon Sep 17 00:00:00 2001 From: Ignacio Rivas Date: Mon, 19 Jul 2021 10:12:46 +0300 Subject: [PATCH] [Ingest Pipelines] Allow to update an existing processor and change its type (#105765) * Patch bugs * Add tests for allowing to edit the type of an existing processor * Add more tests * Add docs Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../pipeline_processors_editor.helpers.tsx | 7 ++++ .../pipeline_processors_editor.test.tsx | 32 +++++++++++++++++++ .../__jest__/test_pipeline.helpers.tsx | 7 ++++ .../__jest__/test_pipeline.test.tsx | 15 +++++++++ .../processor_form/edit_processor_form.tsx | 5 +++ .../context/processors_context.tsx | 10 +++++- 6 files changed, 75 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/pipeline_processors_editor.helpers.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/pipeline_processors_editor.helpers.tsx index 4677ea4b747b..79ffd28c9e78 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/pipeline_processors_editor.helpers.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/pipeline_processors_editor.helpers.tsx @@ -99,6 +99,13 @@ const createActions = (testBed: TestBed) => { component.update(); }, + async setProcessorType(type: string) { + await act(async () => { + find('processorTypeSelector.input').simulate('change', [{ value: type }]); + }); + component.update(); + }, + removeProcessor(processorSelector: string) { find(`${processorSelector}.moreMenu.button`).simulate('click'); find(`${processorSelector}.moreMenu.deleteButton`).simulate('click'); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/pipeline_processors_editor.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/pipeline_processors_editor.test.tsx index fbc46159c4e1..5b02927ab873 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/pipeline_processors_editor.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/pipeline_processors_editor.test.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import { act } from 'react-dom/test-utils'; import { setup, SetupResult } from './pipeline_processors_editor.helpers'; import { Pipeline } from '../../../../../common/types'; @@ -120,6 +121,37 @@ describe('Pipeline Editor', () => { }); }); + it('allows to edit an existing processor and change its type', async () => { + const { actions, exists, component, find } = testBed; + + // Open one of the existing processors + actions.openProcessorEditor('processors>2'); + expect(exists('editProcessorForm')).toBeTruthy(); + + // Change its type to `append` and set the missing required fields + await actions.setProcessorType('append'); + await act(async () => { + find('appendValueField.input').simulate('change', [{ label: 'some_value' }]); + }); + component.update(); + + await actions.submitProcessorForm(); + + const [onUpdateResult] = onUpdate.mock.calls[onUpdate.mock.calls.length - 1]; + const { + processors: { 2: editedProcessor }, + } = onUpdateResult.getData(); + + expect(editedProcessor.append).toEqual({ + if: undefined, + tag: undefined, + description: undefined, + ignore_failure: undefined, + field: 'test', + value: ['some_value'], + }); + }); + it('removes a processor', () => { const { actions } = testBed; // processor>0 denotes the first processor in the top-level processors array. diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.helpers.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.helpers.tsx index c980f84910fa..88e5c62a5b1d 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.helpers.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.helpers.tsx @@ -102,6 +102,13 @@ const createActions = (testBed: TestBed) => { component.update(); }, + async clickProcessorConfigurationTab() { + await act(async () => { + find('configurationTab').simulate('click'); + }); + component.update(); + }, + async clickProcessorOutputTab() { await act(async () => { find('outputTab').simulate('click'); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.test.tsx index 91384e36c839..607978512e20 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.test.tsx @@ -356,6 +356,21 @@ describe('Test pipeline', () => { expect(statusIconLabel).toEqual('Success'); }); + describe('Configuration tab', () => { + it('should not clear up form when clicking configuration tab', async () => { + const { actions, find, exists } = testBed; + + // Click processor to open manage flyout + await actions.clickProcessor('processors>0'); + // Verify flyout opened + expect(exists('editProcessorForm')).toBe(true); + // Click the "Configuration" tab + await actions.clickProcessorConfigurationTab(); + // Verify type selector has not changed + expect(find('processorTypeSelector.input').text()).toBe('Set'); + }); + }); + describe('Output tab', () => { beforeEach(async () => { const { actions } = testBed; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/edit_processor_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/edit_processor_form.tsx index c63842f28f7e..c80b9b136339 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/edit_processor_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/edit_processor_form.tsx @@ -196,6 +196,11 @@ export const EditProcessorForm: FunctionComponent = ({ {tabs.map((tab) => ( { + // No need to do anything if user clicks the already active tab + if (tab.id === activeTab) { + return; + } + if (tab.id === 'output') { await handleSubmit(false); } else { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/context/processors_context.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/context/processors_context.tsx index ddf996de7805..6233b220ae77 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/context/processors_context.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/context/processors_context.tsx @@ -158,18 +158,26 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ 'internal_networks_field', ]; + // If the processor type is changed while editing, we need to ignore unkownOptions as they + // will contain the fields from the previous processor resulting in the wrong request. + const hasProcessorTypeChanged = mode.arg.processor.type !== processorTypeAndOptions.type; // The processor that we are updating may have options configured the UI does not know about - const unknownOptions = omit(mode.arg.processor.options, knownOptionNames); + const unknownOptions = hasProcessorTypeChanged + ? {} + : omit(mode.arg.processor.options, knownOptionNames); // In order to keep the options we don't get back from our UI, we merge the known and unknown options const updatedProcessorOptions = { ...processorTypeAndOptions.options, ...unknownOptions, }; + processorsDispatch({ type: 'updateProcessor', payload: { processor: { ...mode.arg.processor, + // Always prefer the newly selected processor type, as it might change during editing + type: processorTypeAndOptions.type, options: updatedProcessorOptions, }, selector: mode.arg.selector,