From cb949aa1899f5b1362d7a8b35e36becb6fcea88e Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Mon, 24 Aug 2020 15:27:58 -0400 Subject: [PATCH 01/12] fix logic for determining processor input --- .../processor_output.tsx | 43 ++++++++++--------- .../pipeline_processors_editor/deserialize.ts | 41 +++++++++++++++--- .../pipeline_processors_editor/types.ts | 2 +- 3 files changed, 59 insertions(+), 27 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_output.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_output.tsx index c081f69fd41fe..7741d12e7800b 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_output.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_output.tsx @@ -57,9 +57,9 @@ const i18nTexts = { } ), prevProcessorLabel: i18n.translate( - 'xpack.ingestPipelines.processorOutput.previousOutputCodeBlockLabel', + 'xpack.ingestPipelines.processorOutput.processorInputCodeBlockLabel', { - defaultMessage: 'View previous processor output', + defaultMessage: 'Processor input', } ), processorIgnoredErrorLabel: i18n.translate( @@ -83,7 +83,7 @@ export const ProcessorOutput: React.FunctionComponent = ({ } const { - prevProcessorResult, + processorInput, doc: currentResult, ignored_error: ignoredError, error, @@ -167,28 +167,29 @@ export const ProcessorOutput: React.FunctionComponent = ({ )} - {prevProcessorResult?.doc && ( + + + +

{i18nTexts.prevProcessorLabel}

+ + } + > <> - -

{i18nTexts.prevProcessorLabel}

- - } - > - <> - - - - {JSON.stringify(prevProcessorResult.doc, null, 2)} - - -
+ + {/* If there is no processorInput defined (e.g., it's the first processor), we provide the sample document */} + {JSON.stringify( + processorInput ? processorInput : documents[selectedDocumentIndex], + null, + 2 + )} + - )} +
{ignoredError && ( <> diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/deserialize.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/deserialize.ts index 01788c49ec2f1..ceb1e29d01614 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/deserialize.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/deserialize.ts @@ -5,7 +5,13 @@ */ import uuid from 'uuid'; import { Processor } from '../../../../common/types'; -import { ProcessorInternal, VerboseTestOutput, ProcessorResult } from './types'; +import { + ProcessorInternal, + VerboseTestOutput, + Document, + ProcessorResult, + ProcessorResults, +} from './types'; export interface DeserializeArgs { processors: Processor[]; @@ -62,6 +68,33 @@ export const deserialize = ({ processors, onFailure }: DeserializeArgs): Deseria export interface DeserializedProcessorResult { [key: string]: ProcessorResult; } + +/** + * Find the previous state of the sample document in the pipeline + * This typically will be the result from the previous processor + * unless the previous processor had a "skipped" status + */ +const getProcessorInput = ( + processorIndex: number, + document: ProcessorResults, + count = 1 +): Document | undefined => { + const previousProcessorIndex = processorIndex - count; + + if (previousProcessorIndex >= 0) { + const processorResult = document.processor_results[previousProcessorIndex]; + + if (!processorResult.doc) { + const newCount = count + 1; + return getProcessorInput(processorIndex, document, newCount); + } + + return processorResult.doc; + } + + return undefined; +}; + /** * This function takes the verbose response of the simulate API * and maps the results to each processor in the pipeline by the "tag" field @@ -81,11 +114,9 @@ export const deserializeVerboseTestOutput = ( const result = { ...currentResult }; const resultId = result.tag; + // We skip index 0, as the first processor will not have a previous result if (index !== 0) { - // Add the result from the previous processor so that the user - // can easily compare current output to the previous output - // This may be a result from an on_failure processor - result.prevProcessorResult = doc.processor_results[index - 1]; + result.processorInput = getProcessorInput(index, doc); } // The tag is added programatically as a way to map diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/types.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/types.ts index 9083985b0ff2e..a85ed32052e9f 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/types.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/types.ts @@ -94,7 +94,7 @@ export interface ProcessorResult { tag: string; ignored_error?: any; error?: any; - prevProcessorResult?: ProcessorResult; + processorInput?: Document; [key: string]: any; } From 405278d4d5994b848224d9d81cf5c43c5f65765a Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Tue, 25 Aug 2020 16:42:29 -0400 Subject: [PATCH 02/12] clean up workflow when adding/editing sample docs and rerunning simulation --- .../documents_dropdown.scss | 2 +- .../documents_dropdown/documents_dropdown.tsx | 50 ++++--- .../test_pipeline/add_documents_button.tsx | 8 +- .../test_pipeline/test_output_button.tsx | 42 +----- .../test_pipeline/test_pipeline_actions.tsx | 52 ++++--- .../test_pipeline/test_pipeline_flyout.tsx | 113 +++++++++++---- .../tab_documents.tsx | 134 ++++++------------ .../test_pipeline_flyout_tabs/tab_output.tsx | 27 ++-- .../test_pipeline_tabs.tsx | 12 +- .../context/processors_context.tsx | 4 +- 10 files changed, 223 insertions(+), 221 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.scss b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.scss index c5b14dc129b0e..26366fe8beaae 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.scss +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.scss @@ -1,3 +1,3 @@ -.documentsDropdown__selectContainer { +.documentsDropdown { max-width: 200px; } diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx index e9aa5c1d56f73..3da233a0c6a6b 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx @@ -5,11 +5,12 @@ */ import { i18n } from '@kbn/i18n'; import React, { FunctionComponent } from 'react'; -import { EuiSelect, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import { EuiSelect, EuiButtonIcon, EuiToolTip } from '@elastic/eui'; import { Document } from '../../types'; import './documents_dropdown.scss'; +import { TestPipelineFlyoutTab } from '../test_pipeline/test_pipeline_flyout_tabs'; const i18nTexts = { ariaLabel: i18n.translate( @@ -27,6 +28,12 @@ const i18nTexts = { buttonLabel: i18n.translate('xpack.ingestPipelines.pipelineEditor.testPipeline.buttonLabel', { defaultMessage: 'Add documents', }), + iconButtonLabel: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.testPipeline.iconButtonAriaLabel', + { + defaultMessage: 'Manage documents', + } + ), }; const getDocumentOptions = (documents: Document[]) => @@ -39,31 +46,36 @@ interface Props { documents: Document[]; selectedDocumentIndex: number; updateSelectedDocument: (index: number) => void; + openFlyout: (activeFlyoutTab: TestPipelineFlyoutTab) => void; } export const DocumentsDropdown: FunctionComponent = ({ documents, selectedDocumentIndex, updateSelectedDocument, + openFlyout, }) => { return ( - - - - {i18nTexts.dropdownLabel} - - - - { - updateSelectedDocument(Number(e.target.value)); - }} - aria-label={i18nTexts.ariaLabel} - /> - - +
+ { + updateSelectedDocument(Number(e.target.value)); + }} + aria-label={i18nTexts.ariaLabel} + append={ + + openFlyout('documents')} + /> + + } + /> +
); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/add_documents_button.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/add_documents_button.tsx index e3ef9a9ee5390..26492454cbcf5 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/add_documents_button.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/add_documents_button.tsx @@ -6,6 +6,7 @@ import { i18n } from '@kbn/i18n'; import React, { FunctionComponent } from 'react'; import { EuiButtonEmpty } from '@elastic/eui'; +import { TestPipelineFlyoutTab } from './test_pipeline_flyout_tabs'; const i18nTexts = { buttonLabel: i18n.translate('xpack.ingestPipelines.pipelineEditor.testPipeline.buttonLabel', { @@ -14,16 +15,15 @@ const i18nTexts = { }; interface Props { - openTestPipelineFlyout: () => void; + openFlyout: (activeFlyoutTab: TestPipelineFlyoutTab) => void; } -export const AddDocumentsButton: FunctionComponent = ({ openTestPipelineFlyout }) => { +export const AddDocumentsButton: FunctionComponent = ({ openFlyout }) => { return ( openFlyout('documents')} data-test-subj="addDocumentsButton" - iconType="plusInCircleFilled" > {i18nTexts.buttonLabel} diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_output_button.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_output_button.tsx index 361e32c77d59b..6d3ed047ae634 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_output_button.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_output_button.tsx @@ -5,55 +5,25 @@ */ import { i18n } from '@kbn/i18n'; import React, { FunctionComponent } from 'react'; -import { EuiButton, EuiToolTip } from '@elastic/eui'; +import { EuiButton } from '@elastic/eui'; +import { TestPipelineFlyoutTab } from './test_pipeline_flyout_tabs'; const i18nTexts = { buttonLabel: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.testPipeline.outputButtonLabel', { - defaultMessage: 'View output', - } - ), - disabledButtonTooltipLabel: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.testPipeline.outputButtonTooltipLabel', - { - defaultMessage: 'Add documents to view the output', + defaultMessage: 'Output', } ), }; interface Props { - isDisabled: boolean; - openTestPipelineFlyout: () => void; + openFlyout: (activeFlyoutTab: TestPipelineFlyoutTab) => void; } -export const TestOutputButton: FunctionComponent = ({ - isDisabled, - openTestPipelineFlyout, -}) => { - if (isDisabled) { - return ( - {i18nTexts.disabledButtonTooltipLabel}

}> - - {i18nTexts.buttonLabel} - -
- ); - } - +export const TestOutputButton: FunctionComponent = ({ openFlyout }) => { return ( - + openFlyout('output')} data-test-subj="outputButton"> {i18nTexts.buttonLabel} ); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx index eb9d9352e4b90..fd94e48c37dba 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx @@ -4,16 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { FunctionComponent, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { useTestPipelineContext, usePipelineProcessorsContext } from '../../context'; - import { DocumentsDropdown } from '../documents_dropdown'; import { TestPipelineFlyoutTab } from './test_pipeline_flyout_tabs'; import { AddDocumentsButton } from './add_documents_button'; import { TestOutputButton } from './test_output_button'; import { TestPipelineFlyout } from './test_pipeline_flyout'; +const i18nTexts = { + testPipelineActionsLabel: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.testPipeline.testPipelineActionsLabel', + { + defaultMessage: 'Test:', + } + ), +}; + export const TestPipelineActions: FunctionComponent = () => { const { testPipelineData, setCurrentTestPipelineData } = useTestPipelineContext(); @@ -40,35 +49,42 @@ export const TestPipelineActions: FunctionComponent = () => { }); }; + const openFlyout = (activeTab: TestPipelineFlyoutTab) => { + setOpenTestPipelineFlyout(true); + setActiveFlyoutTab(activeTab); + }; + return ( <> - + + + + + {i18nTexts.testPipelineActionsLabel} + + + + {documents ? ( ) : ( - { - setOpenTestPipelineFlyout(true); - setActiveFlyoutTab('documents'); - }} - /> + )} - - { - setOpenTestPipelineFlyout(true); - setActiveFlyoutTab('output'); - }} - /> - + + {testOutputPerProcessor && ( + + + + )} + {openTestPipelineFlyout && ( = ({ config: { documents: cachedDocuments, verbose: cachedVerbose }, } = testPipelineData; + const { form } = useForm({ + schema: documentsSchema, + defaultValue: { + documents: cachedDocuments || '', + }, + }); + const [selectedTab, setSelectedTab] = useState(activeTab); - const [shouldTestImmediately, setShouldTestImmediately] = useState(false); const [isRunningTest, setIsRunningTest] = useState(false); const [testingError, setTestingError] = useState(null); const [testOutput, setTestOutput] = useState(undefined); const handleTestPipeline = useCallback( - async ({ documents, verbose }: HandleTestPipelineArgs) => { + async ( + { documents, verbose }: TestPipelineConfig, + updateProcessorOutput?: boolean + ): Promise<{ isSuccessful: boolean }> => { const serializedProcessors = serialize({ pipeline: processors }); setIsRunningTest(true); @@ -77,7 +87,19 @@ export const TestPipelineFlyout: React.FunctionComponent = ({ if (error) { setTestingError(error); - return; + + // reset the per-processor output + // this is needed in the scenario where the pipeline has already executed, + // but you modified the sample documents and there was an error on re-execution + setCurrentTestPipelineData({ + type: 'updateOutputPerProcessor', + payload: { + isExecutingPipeline: false, + testOutputPerProcessor: undefined, + }, + }); + + return { isSuccessful: false }; } setCurrentTestPipelineData({ @@ -90,6 +112,12 @@ export const TestPipelineFlyout: React.FunctionComponent = ({ }, }); + // We sometimes need to manually refresh the per-processor output + // e.g., when clicking the "Refresh output" button and there have been no state changes + if (updateProcessorOutput) { + updateTestOutputPerProcessor(documents, processors); + } + setTestOutput(currentTestOutput); services.notifications.toasts.addSuccess( @@ -101,27 +129,44 @@ export const TestPipelineFlyout: React.FunctionComponent = ({ } ); - setSelectedTab('output'); + return { isSuccessful: true }; }, - [services.api, processors, setCurrentTestPipelineData, services.notifications.toasts] + [ + processors, + services.api, + services.notifications.toasts, + setCurrentTestPipelineData, + updateTestOutputPerProcessor, + ] ); - useEffect(() => { - if (cachedDocuments) { - setShouldTestImmediately(true); + const validateAndTestPipeline = async () => { + const { isValid, data } = await form.submit(); + + if (!isValid) { + return; } - // We only want to know on initial mount if there are cached documents - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + + const { documents } = data as { documents: Document[] }; + + const { isSuccessful } = await handleTestPipeline({ + documents: documents!, + verbose: cachedVerbose, + }); + + if (isSuccessful) { + setSelectedTab('output'); + } + }; useEffect(() => { - // If the user has already tested the pipeline once, - // use the cached test config and automatically execute the pipeline - if (shouldTestImmediately) { - setShouldTestImmediately(false); - handleTestPipeline({ documents: cachedDocuments!, verbose: cachedVerbose }); + if (cachedDocuments && activeTab === 'output') { + handleTestPipeline({ documents: cachedDocuments, verbose: cachedVerbose }, true); } - }, [handleTestPipeline, cachedDocuments, cachedVerbose, shouldTestImmediately]); + // We only want to know on initial mount if + // there are cached documents and we are on the output tab + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); let tabContent; @@ -138,13 +183,19 @@ export const TestPipelineFlyout: React.FunctionComponent = ({ } else { // default to "Documents" tab tabContent = ( - +
+ + ); } @@ -163,9 +214,15 @@ export const TestPipelineFlyout: React.FunctionComponent = ({ { + if (nextTab === 'output') { + validateAndTestPipeline(); + } else { + form.reset({ defaultValue: { documents: cachedDocuments } }); + setSelectedTab(nextTab); + } + }} selectedTab={selectedTab} - getIsDisabled={(tabId) => !testOutput && tabId === 'output'} /> diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_documents.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_documents.tsx index 8968416683c3e..72f1eacc8610c 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_documents.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_documents.tsx @@ -10,67 +10,23 @@ import { i18n } from '@kbn/i18n'; import { EuiSpacer, EuiText, EuiButton, EuiLink } from '@elastic/eui'; -import { - getUseField, - Field, - JsonEditorField, - Form, - useForm, - useKibana, -} from '../../../../../../shared_imports'; - -import { TestPipelineContext } from '../../../context'; -import { Document } from '../../../types'; -import { DeserializeResult } from '../../../deserialize'; -import { HandleTestPipelineArgs } from '../test_pipeline_flyout'; -import { documentsSchema } from './documents_schema'; +import { getUseField, Field, JsonEditorField, useKibana } from '../../../../../../shared_imports'; const UseField = getUseField({ component: Field }); interface Props { - handleTestPipeline: (data: HandleTestPipelineArgs) => void; - setPerProcessorOutput: (documents: Document[] | undefined, processors: DeserializeResult) => void; + validateAndTestPipeline: () => void; isRunningTest: boolean; - processors: DeserializeResult; - testPipelineData: TestPipelineContext['testPipelineData']; + isSubmitButtonDisabled: boolean; } export const DocumentsTab: React.FunctionComponent = ({ - handleTestPipeline, + validateAndTestPipeline, + isSubmitButtonDisabled, isRunningTest, - setPerProcessorOutput, - processors, - testPipelineData, }) => { const { services } = useKibana(); - const { - config: { documents: cachedDocuments, verbose: cachedVerbose }, - } = testPipelineData; - - const testPipeline = async () => { - const { isValid, data } = await form.submit(); - - if (!isValid) { - return; - } - - const { documents } = data as { documents: Document[] }; - - await handleTestPipeline({ documents: documents!, verbose: cachedVerbose }); - - // This is necessary to update the status and output of each processor - // as verbose may not be enabled - setPerProcessorOutput(documents, processors); - }; - - const { form } = useForm({ - schema: documentsSchema, - defaultValue: { - documents: cachedDocuments || '', - }, - }); - return ( <> @@ -100,52 +56,44 @@ export const DocumentsTab: React.FunctionComponent = ({ -
- {/* Documents editor */} - + {/* Documents editor */} + - + - - {isRunningTest ? ( - - ) : ( - - )} - - + + {isRunningTest ? ( + + ) : ( + + )} + ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_output.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_output.tsx index 586fc9e60017a..f265ec2247ad1 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_output.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_output.tsx @@ -18,10 +18,13 @@ import { } from '@elastic/eui'; import { Document } from '../../../types'; -import { HandleTestPipelineArgs } from '../test_pipeline_flyout'; +import { TestPipelineConfig } from '../test_pipeline_flyout'; interface Props { - handleTestPipeline: (data: HandleTestPipelineArgs) => void; + handleTestPipeline: ( + testPipelineConfig: TestPipelineConfig, + refreshOutputPerProcessor?: boolean + ) => Promise<{ isSuccessful: boolean }>; isRunningTest: boolean; cachedVerbose?: boolean; cachedDocuments: Document[]; @@ -37,12 +40,6 @@ export const OutputTab: React.FunctionComponent = ({ }) => { const [isVerboseEnabled, setIsVerboseEnabled] = useState(Boolean(cachedVerbose)); - const onEnableVerbose = (isVerbose: boolean) => { - setIsVerboseEnabled(isVerbose); - - handleTestPipeline({ documents: cachedDocuments!, verbose: isVerbose }); - }; - let content: React.ReactNode | undefined; if (isRunningTest) { @@ -78,14 +75,22 @@ export const OutputTab: React.FunctionComponent = ({ /> } checked={isVerboseEnabled} - onChange={(e) => onEnableVerbose(e.target.checked)} + onChange={async (e) => { + const isVerbose = e.target.checked; + setIsVerboseEnabled(isVerbose); + + await handleTestPipeline({ documents: cachedDocuments!, verbose: isVerbose }); + }} /> - handleTestPipeline({ documents: cachedDocuments!, verbose: isVerboseEnabled }) + onClick={async () => + await handleTestPipeline( + { documents: cachedDocuments!, verbose: isVerboseEnabled }, + true + ) } iconType="refresh" > diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/test_pipeline_tabs.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/test_pipeline_tabs.tsx index d0ea226e8db80..4665f1d1603b8 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/test_pipeline_tabs.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/test_pipeline_tabs.tsx @@ -13,14 +13,9 @@ export type TestPipelineFlyoutTab = 'documents' | 'output'; interface Props { onTabChange: (tab: TestPipelineFlyoutTab) => void; selectedTab: TestPipelineFlyoutTab; - getIsDisabled: (tab: TestPipelineFlyoutTab) => boolean; } -export const Tabs: React.FunctionComponent = ({ - onTabChange, - selectedTab, - getIsDisabled, -}) => { +export const Tabs: React.FunctionComponent = ({ onTabChange, selectedTab }) => { const tabs: Array<{ id: TestPipelineFlyoutTab; name: React.ReactNode; @@ -29,8 +24,8 @@ export const Tabs: React.FunctionComponent = ({ id: 'documents', name: ( ), }, @@ -49,7 +44,6 @@ export const Tabs: React.FunctionComponent = ({ onClick={() => onTabChange(tab.id)} isSelected={tab.id === selectedTab} key={tab.id} - disabled={getIsDisabled(tab.id)} data-test-subj={tab.id.toLowerCase() + '_tab'} > {tab.name} diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/processors_context.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/processors_context.tsx index 8c59d484acd08..f671500f7a338 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/processors_context.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/processors_context.tsx @@ -208,8 +208,8 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ }; }, [mode, setMode, processorsState, processorsDispatch]); - // Update the test output whenever the processorsState changes (e.g., on move, update, delete) - // Note: updateTestOutputPerProcessor() will only simulate if the user has added sample documents + // Make a request to the simulate API and update the processor output + // whenever the documents or processorsState changes (e.g., on move, update, delete) useEffect(() => { updateTestOutputPerProcessor(documents, processorsState); }, [documents, processorsState, updateTestOutputPerProcessor]); From d05c3663519027c8e7530de5b11c7f45339d478a Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Wed, 26 Aug 2020 22:25:25 -0400 Subject: [PATCH 03/12] add ability to simulate pipeline while editing processor config --- .../manage_processor_form.container.tsx | 49 ++- .../manage_processor_form.tsx | 292 ++++++++++-------- .../processor_settings_fields.tsx | 8 +- .../processors/custom.tsx | 2 +- .../context/processors_context.tsx | 15 +- 5 files changed, 228 insertions(+), 138 deletions(-) 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 083529921b0a7..387b1ec7c75ae 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 @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FunctionComponent, useCallback, useEffect } from 'react'; +import React, { FunctionComponent, useCallback, useEffect, useState } from 'react'; import { useForm, OnFormUpdateArg, FormData, useKibana } from '../../../../../shared_imports'; import { ProcessorInternal } from '../../types'; @@ -24,34 +24,61 @@ interface Props { onOpen: () => void; onClose: () => void; processor?: ProcessorInternal; + formData?: Omit; } export const ManageProcessorForm: FunctionComponent = ({ processor, onFormUpdate, onSubmit, + formData, + onClose, ...rest }) => { const { services } = useKibana(); + const getDefaultProcessorOptions = () => { + let defaultFields; + + if (formData) { + const { options } = formData; + defaultFields = { fields: options }; + } else { + defaultFields = { fields: processor?.options ?? {} }; + } + + return defaultFields; + }; + + const { form } = useForm({ + defaultValue: getDefaultProcessorOptions(), + }); + const handleSubmit = useCallback( - async (data: FormData, isValid: boolean) => { + async (shouldCloseFlyout: boolean = true) => { + const { isValid, data } = await form.submit(); + if (isValid) { - const { type, customOptions, fields } = data; + const { type, customOptions, fields } = data as FormData; onSubmit({ type, options: customOptions ? customOptions : fields, }); + + if (shouldCloseFlyout) { + onClose(); + } } }, - [onSubmit] + [form, onClose, onSubmit] ); - const maybeProcessorOptions = processor?.options; - const { form } = useForm({ - defaultValue: { fields: maybeProcessorOptions ?? {} }, - onSubmit: handleSubmit, - }); + const resetProcessors = () => { + onSubmit({ + type: processor!.type, + options: processor?.options || {}, + }); + }; useEffect(() => { const subscription = form.subscribe(onFormUpdate); @@ -68,7 +95,11 @@ export const ManageProcessorForm: FunctionComponent = ({ {...rest} processor={processor} form={form} + getDefaultProcessorOptions={getDefaultProcessorOptions} esDocsBasePath={services.documentation.getEsDocsBasePath()} + closeFlyout={onClose} + resetProcessors={resetProcessors} + handleSubmit={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 ee8ca71e58446..5dd5f093f568c 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 @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import React, { FunctionComponent, memo, useEffect, useState } from 'react'; +import React, { FunctionComponent, useEffect, useState } from 'react'; import { EuiButton, EuiButtonEmpty, @@ -31,13 +31,19 @@ import { ProcessorSettingsFields } from './processor_settings_fields'; import { DocumentationButton } from './documentation_button'; import { ProcessorOutput } from './processor_output'; +interface Fields { + fields: { [key: string]: any }; +} export interface Props { isOnFailure: boolean; processor?: ProcessorInternal; - form: FormHook; - onClose: () => void; + form: FormHook; onOpen: () => void; esDocsBasePath: string; + getDefaultProcessorOptions: () => Fields; + closeFlyout: () => void; + resetProcessors: () => void; + handleSubmit: (shouldCloseFlyout?: boolean) => Promise; } const updateButtonLabel = i18n.translate( @@ -108,129 +114,167 @@ const getFlyoutTitle = (isOnFailure: boolean, isExistingProcessor: boolean) => { ); }; -export const ManageProcessorForm: FunctionComponent = memo( - ({ processor, form, isOnFailure, onClose, onOpen, esDocsBasePath }) => { - const { testPipelineData, setCurrentTestPipelineData } = useTestPipelineContext(); - const { - testOutputPerProcessor, - config: { selectedDocumentIndex, documents }, - } = testPipelineData; - - const processorOutput = - processor && - testOutputPerProcessor && - testOutputPerProcessor[selectedDocumentIndex][processor.id]; - - const updateSelectedDocument = (index: number) => { - setCurrentTestPipelineData({ - type: 'updateActiveDocument', - payload: { - config: { - selectedDocumentIndex: index, - }, - }, - }); - }; +export const ManageProcessorForm: FunctionComponent = ({ + processor, + form, + isOnFailure, + onOpen, + esDocsBasePath, + getDefaultProcessorOptions, + closeFlyout, + handleSubmit, + resetProcessors, +}) => { + const { testPipelineData, setCurrentTestPipelineData } = useTestPipelineContext(); + const { + testOutputPerProcessor, + config: { selectedDocumentIndex, documents }, + } = testPipelineData; + + const processorOutput = + processor && + testOutputPerProcessor && + testOutputPerProcessor[selectedDocumentIndex][processor.id]; - useEffect( - () => { - onOpen(); + const updateSelectedDocument = (index: number) => { + setCurrentTestPipelineData({ + type: 'updateActiveDocument', + payload: { + config: { + selectedDocumentIndex: index, + }, }, - [] /* eslint-disable-line react-hooks/exhaustive-deps */ - ); + }); + }; - const [activeTab, setActiveTab] = useState('configuration'); - - let flyoutContent: React.ReactNode; - - if (activeTab === 'output') { - flyoutContent = ( - - ); - } else { - flyoutContent = ; - } - - return ( -
- - - - -
- -

{getFlyoutTitle(isOnFailure, Boolean(processor))}

-
-
-
- - - {({ type }) => { - const formDescriptor = getProcessorDescriptor(type as any); - - if (formDescriptor) { - return ( - - ); - } - return null; - }} - - -
-
- - {processor ? ( - <> - - {tabs.map((tab) => ( - { - setActiveTab(tab.id); - }} - isSelected={tab.id === activeTab} - key={tab.id} - data-test-subj={`${tab.id}Tab`} - disabled={ - (tab.id === 'output' && Boolean(testOutputPerProcessor) === false) || - Boolean(processorOutput) === false - } - > - {tab.name} - - ))} - - - - ) : undefined} - - {flyoutContent} - - - - - {cancelButtonLabel} - - - - {processor ? updateButtonLabel : addButtonLabel} - - - - -
-
+ useEffect( + () => { + onOpen(); + }, + [] /* eslint-disable-line react-hooks/exhaustive-deps */ + ); + + const [activeTab, setActiveTab] = useState('configuration'); + + let flyoutContent: React.ReactNode; + + if (activeTab === 'output') { + flyoutContent = ( + + ); + } else { + flyoutContent = ( + ); - }, - (previous, current) => { - return previous.processor === current.processor; } -); + + return ( +
+ { + resetProcessors(); + closeFlyout(); + }} + > + + + +
+ +

{getFlyoutTitle(isOnFailure, Boolean(processor))}

+
+
+
+ + + {({ type }) => { + const formDescriptor = getProcessorDescriptor(type as any); + + if (formDescriptor) { + return ( + + ); + } + return null; + }} + + +
+
+ + {processor ? ( + <> + + {tabs.map((tab) => ( + { + if (tab.id === 'output') { + await handleSubmit(false); + } else { + form.reset({ defaultValue: getDefaultProcessorOptions() }); + } + setActiveTab(tab.id); + }} + isSelected={tab.id === activeTab} + key={tab.id} + data-test-subj={`${tab.id}Tab`} + disabled={ + (tab.id === 'output' && Boolean(testOutputPerProcessor) === false) || + Boolean(processorOutput) === false + } + > + {tab.name} + + ))} + + + + ) : undefined} + + {flyoutContent} + + + + + { + resetProcessors(); + closeFlyout(); + }} + > + {cancelButtonLabel} + + + + { + if (activeTab === 'output') { + return closeFlyout(); + } + await handleSubmit(); + }} + > + {processor ? updateButtonLabel : addButtonLabel} + + + + +
+
+ ); +}; 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 6a70592bc2f70..078cf7252afb8 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 @@ -16,9 +16,13 @@ import { Custom } from './processors/custom'; export interface Props { processor?: ProcessorInternal; + getDefaultProcessorOptions: () => void; } -export const ProcessorSettingsFields: FunctionComponent = ({ processor }) => { +export const ProcessorSettingsFields: FunctionComponent = ({ + processor, + getDefaultProcessorOptions, +}) => { return ( <> @@ -41,7 +45,7 @@ export const ProcessorSettingsFields: FunctionComponent = ({ processor }) ); } - return ; + return ; } // If the user has not yet defined a type, we do not show any settings fields diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/custom.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/custom.tsx index 82fdc81e0a843..ae5ecd118ce44 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/custom.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/custom.tsx @@ -74,7 +74,7 @@ export const Custom: FunctionComponent = ({ defaultOptions }) => { path="customOptions" component={XJsonEditor} config={customConfig} - defaultValue={defaultOptions} + defaultValue={defaultOptions.fields} componentProps={{ editorProps: { 'data-test-subj': 'processorOptionsEditor', diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/processors_context.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/processors_context.tsx index f671500f7a338..b2e68ed5fbacd 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/processors_context.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/processors_context.tsx @@ -106,6 +106,13 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ validate: () => Promise.resolve(true), }); + // We need to keep track of the processor form state if the user + // has made config changes, navigated between tabs (Configuration vs. Output) + // and has not yet submitted the form + const [tempProcessorFormData, setTempProcessorFormData] = useState< + Omit | undefined + >(undefined); + const onFormUpdate = useCallback<(arg: OnFormUpdateArg) => void>( ({ isValid, validate }) => { setFormState({ @@ -149,6 +156,8 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ }); break; case 'managingProcessor': + setTempProcessorFormData(processorTypeAndOptions); + processorsDispatch({ type: 'updateProcessor', payload: { @@ -159,17 +168,18 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ selector: mode.arg.selector, }, }); + break; default: } - setMode({ id: 'idle' }); }, - [processorsDispatch, mode, setMode] + [processorsDispatch, mode] ); const onCloseSettingsForm = useCallback(() => { setMode({ id: 'idle' }); setFormState({ validate: () => Promise.resolve(true) }); + setTempProcessorFormData(undefined); }, [setFormState, setMode]); const onTreeAction = useCallback( @@ -240,6 +250,7 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ onFormUpdate={onFormUpdate} onSubmit={onSubmit} onClose={onCloseSettingsForm} + formData={tempProcessorFormData} /> ) : undefined} {mode.id === 'removingProcessor' && ( From 0a2ea82b17d525d1a27ff360c676ae09f66ef806 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Fri, 28 Aug 2020 20:50:12 -0400 Subject: [PATCH 04/12] refactor test_pipeline_flyout with container component --- .../manage_processor_form.container.tsx | 2 +- .../test_pipeline/test_pipeline_actions.tsx | 2 +- .../test_pipeline_flyout.container.tsx | 177 ++++++++++++++++++ .../test_pipeline/test_pipeline_flyout.tsx | 166 +++------------- .../tab_documents.tsx | 2 +- .../test_pipeline_flyout_tabs/tab_output.tsx | 2 +- 6 files changed, 209 insertions(+), 142 deletions(-) create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout.container.tsx 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 387b1ec7c75ae..31a94b45e1805 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 @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FunctionComponent, useCallback, useEffect, useState } from 'react'; +import React, { FunctionComponent, useCallback, useEffect } from 'react'; import { useForm, OnFormUpdateArg, FormData, useKibana } from '../../../../../shared_imports'; import { ProcessorInternal } from '../../types'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx index fd94e48c37dba..293e3eb1953d6 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx @@ -12,7 +12,7 @@ import { DocumentsDropdown } from '../documents_dropdown'; import { TestPipelineFlyoutTab } from './test_pipeline_flyout_tabs'; import { AddDocumentsButton } from './add_documents_button'; import { TestOutputButton } from './test_output_button'; -import { TestPipelineFlyout } from './test_pipeline_flyout'; +import { TestPipelineFlyout } from './test_pipeline_flyout.container'; const i18nTexts = { testPipelineActionsLabel: i18n.translate( diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout.container.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout.container.tsx new file mode 100644 index 0000000000000..b49eea5b59ab0 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout.container.tsx @@ -0,0 +1,177 @@ +/* + * 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, { useState, useCallback, useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { useKibana, useForm } from '../../../../../shared_imports'; +import { useTestPipelineContext } from '../../context'; +import { serialize } from '../../serialize'; +import { DeserializeResult } from '../../deserialize'; +import { Document } from '../../types'; +import { TestPipelineFlyout as ViewComponent } from './test_pipeline_flyout'; + +import { TestPipelineFlyoutTab } from './test_pipeline_flyout_tabs'; +import { documentsSchema } from './test_pipeline_flyout_tabs/documents_schema'; + +export interface Props { + activeTab: TestPipelineFlyoutTab; + onClose: () => void; + processors: DeserializeResult; +} + +export interface TestPipelineConfig { + documents: Document[]; + verbose?: boolean; +} + +export const TestPipelineFlyout: React.FunctionComponent = ({ + onClose, + activeTab, + processors, +}) => { + const { services } = useKibana(); + + const { + testPipelineData, + setCurrentTestPipelineData, + updateTestOutputPerProcessor, + } = useTestPipelineContext(); + + const { + config: { documents: cachedDocuments, verbose: cachedVerbose }, + } = testPipelineData; + + const { form } = useForm({ + schema: documentsSchema, + defaultValue: { + documents: cachedDocuments || '', + }, + }); + + const [selectedTab, setSelectedTab] = useState(activeTab); + + const [isRunningTest, setIsRunningTest] = useState(false); + const [testingError, setTestingError] = useState(null); + const [testOutput, setTestOutput] = useState(undefined); + + const handleTestPipeline = useCallback( + async ( + { documents, verbose }: TestPipelineConfig, + updateProcessorOutput?: boolean + ): Promise<{ isSuccessful: boolean }> => { + const serializedProcessors = serialize({ pipeline: processors }); + + setIsRunningTest(true); + setTestingError(null); + + const { error, data: currentTestOutput } = await services.api.simulatePipeline({ + documents, + verbose, + pipeline: { ...serializedProcessors }, + }); + + setIsRunningTest(false); + + if (error) { + setTestingError(error); + + // reset the per-processor output + // this is needed in the scenario where the pipeline has already executed, + // but you modified the sample documents and there was an error on re-execution + setCurrentTestPipelineData({ + type: 'updateOutputPerProcessor', + payload: { + isExecutingPipeline: false, + testOutputPerProcessor: undefined, + }, + }); + + return { isSuccessful: false }; + } + + setCurrentTestPipelineData({ + type: 'updateConfig', + payload: { + config: { + documents, + verbose, + }, + }, + }); + + // We sometimes need to manually refresh the per-processor output + // e.g., when clicking the "Refresh output" button and there have been no state changes + if (updateProcessorOutput) { + updateTestOutputPerProcessor(documents, processors); + } + + setTestOutput(currentTestOutput); + + services.notifications.toasts.addSuccess( + i18n.translate('xpack.ingestPipelines.testPipelineFlyout.successNotificationText', { + defaultMessage: 'Pipeline executed', + }), + { + toastLifeTimeMs: 1000, + } + ); + + return { isSuccessful: true }; + }, + [ + processors, + services.api, + services.notifications.toasts, + setCurrentTestPipelineData, + updateTestOutputPerProcessor, + ] + ); + + const validateAndTestPipeline = async () => { + const { isValid, data } = await form.submit(); + + if (!isValid) { + return; + } + + const { documents } = data as { documents: Document[] }; + + const { isSuccessful } = await handleTestPipeline({ + documents: documents!, + verbose: cachedVerbose, + }); + + if (isSuccessful) { + setSelectedTab('output'); + } + }; + + useEffect(() => { + if (cachedDocuments && activeTab === 'output') { + handleTestPipeline({ documents: cachedDocuments, verbose: cachedVerbose }, true); + } + // We only want to know on initial mount if + // there are cached documents and we are on the output tab + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout.tsx index 7f1f1cd36a12c..e370cf81d6a7b 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout.tsx @@ -4,9 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState, useCallback, useEffect } from 'react'; +import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; import { EuiFlyout, @@ -17,19 +16,26 @@ import { EuiCallOut, } from '@elastic/eui'; -import { useKibana, useForm, Form } from '../../../../../shared_imports'; -import { useTestPipelineContext } from '../../context'; -import { serialize } from '../../serialize'; -import { DeserializeResult } from '../../deserialize'; +import { Form, FormHook } from '../../../../../shared_imports'; import { Document } from '../../types'; import { Tabs, TestPipelineFlyoutTab, OutputTab, DocumentsTab } from './test_pipeline_flyout_tabs'; -import { documentsSchema } from './test_pipeline_flyout_tabs/documents_schema'; export interface Props { - activeTab: TestPipelineFlyoutTab; onClose: () => void; - processors: DeserializeResult; + handleTestPipeline: ( + testPipelineConfig: TestPipelineConfig, + refreshOutputPerProcessor?: boolean + ) => Promise<{ isSuccessful: boolean }>; + isRunningTest: boolean; + cachedVerbose?: boolean; + cachedDocuments?: Document[]; + testOutput?: any; + form: FormHook; + validateAndTestPipeline: () => Promise; + selectedTab: TestPipelineFlyoutTab; + setSelectedTab: (selectedTa: TestPipelineFlyoutTab) => void; + testingError: any; } export interface TestPipelineConfig { @@ -38,136 +44,18 @@ export interface TestPipelineConfig { } export const TestPipelineFlyout: React.FunctionComponent = ({ + handleTestPipeline, + isRunningTest, + cachedVerbose, + cachedDocuments, + testOutput, + form, + validateAndTestPipeline, + selectedTab, + setSelectedTab, + testingError, onClose, - activeTab, - processors, }) => { - const { services } = useKibana(); - - const { - testPipelineData, - setCurrentTestPipelineData, - updateTestOutputPerProcessor, - } = useTestPipelineContext(); - - const { - config: { documents: cachedDocuments, verbose: cachedVerbose }, - } = testPipelineData; - - const { form } = useForm({ - schema: documentsSchema, - defaultValue: { - documents: cachedDocuments || '', - }, - }); - - const [selectedTab, setSelectedTab] = useState(activeTab); - - const [isRunningTest, setIsRunningTest] = useState(false); - const [testingError, setTestingError] = useState(null); - const [testOutput, setTestOutput] = useState(undefined); - - const handleTestPipeline = useCallback( - async ( - { documents, verbose }: TestPipelineConfig, - updateProcessorOutput?: boolean - ): Promise<{ isSuccessful: boolean }> => { - const serializedProcessors = serialize({ pipeline: processors }); - - setIsRunningTest(true); - setTestingError(null); - - const { error, data: currentTestOutput } = await services.api.simulatePipeline({ - documents, - verbose, - pipeline: { ...serializedProcessors }, - }); - - setIsRunningTest(false); - - if (error) { - setTestingError(error); - - // reset the per-processor output - // this is needed in the scenario where the pipeline has already executed, - // but you modified the sample documents and there was an error on re-execution - setCurrentTestPipelineData({ - type: 'updateOutputPerProcessor', - payload: { - isExecutingPipeline: false, - testOutputPerProcessor: undefined, - }, - }); - - return { isSuccessful: false }; - } - - setCurrentTestPipelineData({ - type: 'updateConfig', - payload: { - config: { - documents, - verbose, - }, - }, - }); - - // We sometimes need to manually refresh the per-processor output - // e.g., when clicking the "Refresh output" button and there have been no state changes - if (updateProcessorOutput) { - updateTestOutputPerProcessor(documents, processors); - } - - setTestOutput(currentTestOutput); - - services.notifications.toasts.addSuccess( - i18n.translate('xpack.ingestPipelines.testPipelineFlyout.successNotificationText', { - defaultMessage: 'Pipeline executed', - }), - { - toastLifeTimeMs: 1000, - } - ); - - return { isSuccessful: true }; - }, - [ - processors, - services.api, - services.notifications.toasts, - setCurrentTestPipelineData, - updateTestOutputPerProcessor, - ] - ); - - const validateAndTestPipeline = async () => { - const { isValid, data } = await form.submit(); - - if (!isValid) { - return; - } - - const { documents } = data as { documents: Document[] }; - - const { isSuccessful } = await handleTestPipeline({ - documents: documents!, - verbose: cachedVerbose, - }); - - if (isSuccessful) { - setSelectedTab('output'); - } - }; - - useEffect(() => { - if (cachedDocuments && activeTab === 'output') { - handleTestPipeline({ documents: cachedDocuments, verbose: cachedVerbose }, true); - } - // We only want to know on initial mount if - // there are cached documents and we are on the output tab - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - let tabContent; if (selectedTab === 'output') { @@ -216,9 +104,11 @@ export const TestPipelineFlyout: React.FunctionComponent = ({ { if (nextTab === 'output') { + // When switching to the output tab, + // we automatically run the pipeline if documents are defined validateAndTestPipeline(); } else { - form.reset({ defaultValue: { documents: cachedDocuments } }); + form.reset({ defaultValue: { documents: cachedDocuments! } }); setSelectedTab(nextTab); } }} diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_documents.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_documents.tsx index 72f1eacc8610c..1fca848b2af5c 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_documents.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_documents.tsx @@ -15,7 +15,7 @@ import { getUseField, Field, JsonEditorField, useKibana } from '../../../../../. const UseField = getUseField({ component: Field }); interface Props { - validateAndTestPipeline: () => void; + validateAndTestPipeline: () => Promise; isRunningTest: boolean; isSubmitButtonDisabled: boolean; } diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_output.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_output.tsx index f265ec2247ad1..c6820bc93404b 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_output.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_output.tsx @@ -18,7 +18,7 @@ import { } from '@elastic/eui'; import { Document } from '../../../types'; -import { TestPipelineConfig } from '../test_pipeline_flyout'; +import { TestPipelineConfig } from '../test_pipeline_flyout.container'; interface Props { handleTestPipeline: ( From 65be40a3f04ef4348ba01d7015cb9da49838ea84 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Fri, 28 Aug 2020 20:52:13 -0400 Subject: [PATCH 05/12] UX improvements --- .../documents_dropdown/documents_dropdown.tsx | 54 +++++++----- .../processor_output.tsx | 88 +++++++++++-------- .../pipeline_processors_editor_item.scss | 2 +- ...pipeline_processors_editor_item_status.tsx | 55 ++++++++++-- 4 files changed, 134 insertions(+), 65 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx index 3da233a0c6a6b..8825860e319a5 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx @@ -46,7 +46,7 @@ interface Props { documents: Document[]; selectedDocumentIndex: number; updateSelectedDocument: (index: number) => void; - openFlyout: (activeFlyoutTab: TestPipelineFlyoutTab) => void; + openFlyout?: (activeFlyoutTab: TestPipelineFlyoutTab) => void; } export const DocumentsDropdown: FunctionComponent = ({ @@ -55,27 +55,41 @@ export const DocumentsDropdown: FunctionComponent = ({ updateSelectedDocument, openFlyout, }) => { + const shouldAppendActions = typeof openFlyout !== 'undefined'; + return (
- { - updateSelectedDocument(Number(e.target.value)); - }} - aria-label={i18nTexts.ariaLabel} - append={ - - openFlyout('documents')} - /> - - } - /> + {shouldAppendActions ? ( + { + updateSelectedDocument(Number(e.target.value)); + }} + aria-label={i18nTexts.ariaLabel} + append={ + + openFlyout!('documents')} + /> + + } + /> + ) : ( + { + updateSelectedDocument(Number(e.target.value)); + }} + aria-label={i18nTexts.ariaLabel} + /> + )}
); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_output.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_output.tsx index 7741d12e7800b..5d80df14c037e 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_output.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_output.tsx @@ -68,6 +68,12 @@ const i18nTexts = { defaultMessage: 'View ignored error', } ), + documentsDropdownLabel: i18n.translate( + 'xpack.ingestPipelines.processorOutput.documentsDropdownLabel', + { + defaultMessage: 'Test:', + } + ), }; export const ProcessorOutput: React.FunctionComponent = ({ @@ -117,22 +123,56 @@ export const ProcessorOutput: React.FunctionComponent = ({ )} + + + + + + + {i18nTexts.documentsDropdownLabel} + + + + + + + + + + + +

{i18nTexts.prevProcessorLabel}

+
+ } + > + <> + + + + {/* If there is no processorInput defined (e.g., it's the first processor), we provide the sample document */} + {JSON.stringify( + processorInput ? processorInput : documents[selectedDocumentIndex], + null, + 2 + )} + + + + {currentResult && ( <> - - -

{i18nTexts.processorOutputLabel}

-
- - - -
+ +

{i18nTexts.processorOutputLabel}

+
@@ -167,30 +207,6 @@ export const ProcessorOutput: React.FunctionComponent = ({ )} - - - -

{i18nTexts.prevProcessorLabel}

- - } - > - <> - - - - {/* If there is no processorInput defined (e.g., it's the first processor), we provide the sample document */} - {JSON.stringify( - processorInput ? processorInput : documents[selectedDocumentIndex], - null, - 2 - )} - - -
- {ignoredError && ( <> diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item/pipeline_processors_editor_item.scss b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item/pipeline_processors_editor_item.scss index d9c3d84eec082..55630fa96d9b0 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item/pipeline_processors_editor_item.scss +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item/pipeline_processors_editor_item.scss @@ -63,6 +63,6 @@ &__statusContainer { // Prevent content jump when spinner renders - min-width: 12px; + min-width: 15px; } } diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx index 26ff113b97440..3245e813a66ce 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx @@ -6,46 +6,85 @@ import React, { FunctionComponent } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiToolTip, EuiIcon } from '@elastic/eui'; +import { EuiToolTip, EuiIcon, IconType } from '@elastic/eui'; import { ProcessorStatus } from '../types'; interface ProcessorStatusIcon { - icon: string; + icon: IconType; iconColor: string; label: string; } +const ErrorIgnoredIcon: FunctionComponent = () => ( + + + + +); + +const SkippedIcon: FunctionComponent = () => ( + + + +); + +const ErrorIcon: FunctionComponent = () => ( + + + +); + const processorStatusToIconMap: Record = { success: { - icon: 'checkInCircleFilled', + icon: 'check', iconColor: 'success', label: i18n.translate('xpack.ingestPipelines.pipelineEditorItem.successStatusAriaLabel', { defaultMessage: 'Success', }), }, error: { - icon: 'crossInACircleFilled', + icon: ErrorIcon, iconColor: 'danger', label: i18n.translate('xpack.ingestPipelines.pipelineEditorItem.errorStatusAriaLabel', { defaultMessage: 'Error', }), }, error_ignored: { - icon: 'alert', - iconColor: 'warning', + icon: ErrorIgnoredIcon, + iconColor: 'danger', label: i18n.translate('xpack.ingestPipelines.pipelineEditorItem.errorIgnoredStatusAriaLabel', { defaultMessage: 'Error ignored', }), }, dropped: { - icon: 'alert', + icon: 'indexClose', iconColor: 'warning', label: i18n.translate('xpack.ingestPipelines.pipelineEditorItem.droppedStatusAriaLabel', { defaultMessage: 'Dropped', }), }, skipped: { - icon: 'dot', + icon: SkippedIcon, iconColor: 'subdued', label: i18n.translate('xpack.ingestPipelines.pipelineEditorItem.skippedStatusAriaLabel', { defaultMessage: 'Skipped', From 54011733df251120c567d223e85c1c8647d2ce7e Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Tue, 1 Sep 2020 11:36:08 -0400 Subject: [PATCH 06/12] cleanup --- .../components/index.ts | 6 +- ...pipeline_processors_editor_item_status.tsx | 2 +- .../processor_form/add_processor_form.tsx | 139 ++++++++++++++++++ .../documentation_button.tsx | 0 .../edit_processor_form.tsx} | 96 +++++------- .../field_components/index.ts | 0 .../field_components/text_editor.tsx | 0 .../field_components/xjson_editor.tsx | 0 .../index.ts | 6 +- .../processor_form.container.tsx} | 25 ++-- .../processor_output.tsx | 14 +- .../processor_settings_fields.tsx | 6 +- .../processors/append.tsx | 0 .../processors/bytes.tsx | 0 .../processors/circle.tsx | 0 .../common_fields/common_processor_fields.tsx | 0 .../common_fields/field_name_field.tsx | 0 .../common_fields/ignore_missing_field.tsx | 0 .../processors/common_fields/index.ts | 0 .../common_fields/processor_type_field.tsx | 0 .../processors/common_fields/target_field.tsx | 0 .../processors/convert.tsx | 0 .../processors/csv.tsx | 0 .../processors/custom.tsx | 5 +- .../processors/date.tsx | 0 .../processors/date_index_name.tsx | 0 .../processors/dissect.tsx | 0 .../processors/dot_expander.tsx | 0 .../processors/drop.tsx | 0 .../processors/enrich.tsx | 0 .../processors/fail.tsx | 0 .../processors/foreach.tsx | 0 .../processors/geoip.tsx | 0 .../processors/grok.tsx | 0 .../processors/gsub.tsx | 0 .../processors/html_strip.tsx | 0 .../processors/index.ts | 0 .../processors/inference.tsx | 0 .../processors/join.tsx | 0 .../processors/json.tsx | 0 .../processors/set.tsx | 0 .../processors/shared.ts | 0 .../shared/map_processor_type_to_form.tsx | 2 +- .../context/processors_context.tsx | 12 +- .../context/test_pipeline_context.tsx | 10 +- 45 files changed, 231 insertions(+), 92 deletions(-) create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/documentation_button.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form/manage_processor_form.tsx => processor_form/edit_processor_form.tsx} (72%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/field_components/index.ts (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/field_components/text_editor.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/field_components/xjson_editor.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/index.ts (71%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form/manage_processor_form.container.tsx => processor_form/processor_form.container.tsx} (78%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processor_output.tsx (93%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processor_settings_fields.tsx (87%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/append.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/bytes.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/circle.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/common_fields/common_processor_fields.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/common_fields/field_name_field.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/common_fields/ignore_missing_field.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/common_fields/index.ts (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/common_fields/processor_type_field.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/common_fields/target_field.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/convert.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/csv.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/custom.tsx (94%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/date.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/date_index_name.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/dissect.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/dot_expander.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/drop.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/enrich.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/fail.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/foreach.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/geoip.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/grok.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/gsub.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/html_strip.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/index.ts (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/inference.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/join.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/json.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/set.tsx (100%) rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{manage_processor_form => processor_form}/processors/shared.ts (100%) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/index.ts index 435d0ed66c4b0..a8073c4f7e760 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/index.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/index.ts @@ -4,11 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -export { - ManageProcessorForm, - ManageProcessorFormOnSubmitArg, - OnSubmitHandler, -} from './manage_processor_form'; +export { ProcessorForm, ProcessorFormOnSubmitArg, OnSubmitHandler } from './processor_form'; export { ProcessorsTree, ProcessorInfo, OnActionHandler } from './processors_tree'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx index 880f9bc4dfea8..07c47b31d21ef 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx @@ -78,7 +78,7 @@ const processorStatusToIconMap: Record = { }, dropped: { icon: 'indexClose', - iconColor: 'warning', + iconColor: 'subdued', label: i18n.translate('xpack.ingestPipelines.pipelineEditorItem.droppedStatusAriaLabel', { defaultMessage: 'Dropped', }), diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx new file mode 100644 index 0000000000000..8982cb495dd6e --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx @@ -0,0 +1,139 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import React, { FunctionComponent, useEffect } from 'react'; +import { + EuiButton, + EuiButtonEmpty, + EuiFlyout, + EuiFlyoutHeader, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, +} from '@elastic/eui'; + +import { Form, FormDataProvider, FormHook } from '../../../../../shared_imports'; +import { ProcessorInternal } from '../../types'; +import { getProcessorDescriptor } from '../shared'; + +import { DocumentationButton } from './documentation_button'; +import { ProcessorSettingsFields } from './processor_settings_fields'; + +interface Fields { + fields: { [key: string]: any }; +} +export interface Props { + isOnFailure: boolean; + processor?: ProcessorInternal; + form: FormHook; + onOpen: () => void; + esDocsBasePath: string; + getDefaultProcessorOptions: () => Fields; + closeFlyout: () => void; + resetProcessors: () => void; + handleSubmit: (shouldCloseFlyout?: boolean) => Promise; +} + +const addButtonLabel = i18n.translate( + 'xpack.ingestPipelines.addProcessorFormOnFailureFlyout.addButtonLabel', + { defaultMessage: 'Add' } +); + +const cancelButtonLabel = i18n.translate( + 'xpack.ingestPipelines.addProcesorFormOnFailureFlyout.cancelButtonLabel', + { defaultMessage: 'Cancel' } +); + +const getFlyoutTitle = (isOnFailure: boolean) => { + return isOnFailure ? ( + + ) : ( + + ); +}; + +export const AddProcessorForm: FunctionComponent = ({ + isOnFailure, + onOpen, + form, + esDocsBasePath, + getDefaultProcessorOptions, + closeFlyout, + handleSubmit, +}) => { + useEffect( + () => { + onOpen(); + }, + [] /* eslint-disable-line react-hooks/exhaustive-deps */ + ); + + return ( +
+ + + + +
+ +

{getFlyoutTitle(isOnFailure)}

+
+
+
+ + + {({ type }) => { + const formDescriptor = getProcessorDescriptor(type as any); + + if (formDescriptor) { + return ( + + ); + } + return null; + }} + + +
+
+ + + + + + + {cancelButtonLabel} + + + { + await handleSubmit(); + }} + > + {addButtonLabel} + + + + +
+
+ ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/documentation_button.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/documentation_button.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/documentation_button.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/documentation_button.tsx 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/processor_form/edit_processor_form.tsx similarity index 72% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/edit_processor_form.tsx index 5dd5f093f568c..712e9668a179d 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/processor_form/edit_processor_form.tsx @@ -30,13 +30,11 @@ import { getProcessorDescriptor } from '../shared'; import { ProcessorSettingsFields } from './processor_settings_fields'; import { DocumentationButton } from './documentation_button'; import { ProcessorOutput } from './processor_output'; +import { Fields } from './processor_form.container'; -interface Fields { - fields: { [key: string]: any }; -} export interface Props { isOnFailure: boolean; - processor?: ProcessorInternal; + processor: ProcessorInternal; form: FormHook; onOpen: () => void; esDocsBasePath: string; @@ -51,11 +49,6 @@ const updateButtonLabel = i18n.translate( { defaultMessage: 'Update' } ); -const addButtonLabel = i18n.translate( - 'xpack.ingestPipelines.settingsFormOnFailureFlyout.addButtonLabel', - { defaultMessage: 'Add' } -); - const cancelButtonLabel = i18n.translate( 'xpack.ingestPipelines.settingsFormOnFailureFlyout.cancelButtonLabel', { defaultMessage: 'Cancel' } @@ -86,35 +79,21 @@ const tabs: Tab[] = [ }, ]; -const getFlyoutTitle = (isOnFailure: boolean, isExistingProcessor: boolean) => { - if (isExistingProcessor) { - return isOnFailure ? ( - - ) : ( - - ); - } - +const getFlyoutTitle = (isOnFailure: boolean) => { return isOnFailure ? ( ) : ( ); }; -export const ManageProcessorForm: FunctionComponent = ({ +export const EditProcessorForm: FunctionComponent = ({ processor, form, isOnFailure, @@ -129,6 +108,7 @@ export const ManageProcessorForm: FunctionComponent = ({ const { testOutputPerProcessor, config: { selectedDocumentIndex, documents }, + isExecutingPipeline, } = testPipelineData; const processorOutput = @@ -165,6 +145,7 @@ export const ManageProcessorForm: FunctionComponent = ({ documents={documents!} selectedDocumentIndex={selectedDocumentIndex} updateSelectedDocument={updateSelectedDocument} + isExecuting={isExecutingPipeline} /> ); } else { @@ -191,7 +172,7 @@ export const ManageProcessorForm: FunctionComponent = ({
-

{getFlyoutTitle(isOnFailure, Boolean(processor))}

+

{getFlyoutTitle(isOnFailure)}

@@ -215,34 +196,31 @@ export const ManageProcessorForm: FunctionComponent = ({
- {processor ? ( - <> - - {tabs.map((tab) => ( - { - if (tab.id === 'output') { - await handleSubmit(false); - } else { - form.reset({ defaultValue: getDefaultProcessorOptions() }); - } - setActiveTab(tab.id); - }} - isSelected={tab.id === activeTab} - key={tab.id} - data-test-subj={`${tab.id}Tab`} - disabled={ - (tab.id === 'output' && Boolean(testOutputPerProcessor) === false) || - Boolean(processorOutput) === false - } - > - {tab.name} - - ))} - - - - ) : undefined} + + {tabs.map((tab) => ( + { + if (tab.id === 'output') { + await handleSubmit(false); + } else { + form.reset({ defaultValue: getDefaultProcessorOptions() }); + } + setActiveTab(tab.id); + }} + isSelected={tab.id === activeTab} + key={tab.id} + data-test-subj={`${tab.id}Tab`} + disabled={ + tab.id === 'output' && + (Boolean(testOutputPerProcessor) === false || Boolean(processorOutput) === false) + } + > + {tab.name} + + ))} + + + {flyoutContent} @@ -269,7 +247,7 @@ export const ManageProcessorForm: FunctionComponent = ({ await handleSubmit(); }} > - {processor ? updateButtonLabel : addButtonLabel} + {updateButtonLabel}
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/processor_form/field_components/index.ts similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/index.ts rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/field_components/index.ts 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/processor_form/field_components/text_editor.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/text_editor.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/field_components/text_editor.tsx 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/processor_form/field_components/xjson_editor.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/xjson_editor.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/field_components/xjson_editor.tsx diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/index.ts similarity index 71% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/index.ts rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/index.ts index 986bd52e911bf..5a8d2522f1376 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/index.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/index.ts @@ -5,7 +5,7 @@ */ export { - ManageProcessorForm, - ManageProcessorFormOnSubmitArg, + ProcessorFormContainer as ProcessorForm, + ProcessorFormOnSubmitArg, OnSubmitHandler, -} from './manage_processor_form.container'; +} from './processor_form.container'; 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/processor_form/processor_form.container.tsx similarity index 78% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.container.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_form.container.tsx index 31a94b45e1805..b76607d999f9f 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/processor_form/processor_form.container.tsx @@ -9,14 +9,19 @@ import React, { FunctionComponent, useCallback, useEffect } from 'react'; import { useForm, OnFormUpdateArg, FormData, useKibana } from '../../../../../shared_imports'; import { ProcessorInternal } from '../../types'; -import { ManageProcessorForm as ViewComponent } from './manage_processor_form'; +import { EditProcessorForm } from './edit_processor_form'; +import { AddProcessorForm } from './add_processor_form'; -export type ManageProcessorFormOnSubmitArg = Omit; +export type ProcessorFormOnSubmitArg = Omit; -export type OnSubmitHandler = (processor: ManageProcessorFormOnSubmitArg) => void; +export type OnSubmitHandler = (processor: ProcessorFormOnSubmitArg) => void; export type OnFormUpdateHandler = (form: OnFormUpdateArg) => void; +export interface Fields { + fields: { [key: string]: any }; +} + interface Props { onFormUpdate: OnFormUpdateHandler; onSubmit: OnSubmitHandler; @@ -24,24 +29,24 @@ interface Props { onOpen: () => void; onClose: () => void; processor?: ProcessorInternal; - formData?: Omit; + unsavedFormData?: Omit; } -export const ManageProcessorForm: FunctionComponent = ({ +export const ProcessorFormContainer: FunctionComponent = ({ processor, onFormUpdate, onSubmit, - formData, + unsavedFormData, onClose, ...rest }) => { const { services } = useKibana(); - const getDefaultProcessorOptions = () => { + const getDefaultProcessorOptions = (): Fields => { let defaultFields; - if (formData) { - const { options } = formData; + if (unsavedFormData) { + const { options } = unsavedFormData; defaultFields = { fields: options }; } else { defaultFields = { fields: processor?.options ?? {} }; @@ -90,6 +95,8 @@ export const ManageProcessorForm: FunctionComponent = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [onFormUpdate]); + const ViewComponent = processor ? EditProcessorForm : AddProcessorForm; + return ( void; + isExecuting?: boolean; } const i18nTexts = { @@ -74,6 +76,9 @@ const i18nTexts = { defaultMessage: 'Test:', } ), + loadingMessage: i18n.translate('xpack.ingestPipelines.processorOutput.loadingMessage', { + defaultMessage: 'Loading processor output…', + }), }; export const ProcessorOutput: React.FunctionComponent = ({ @@ -81,9 +86,12 @@ export const ProcessorOutput: React.FunctionComponent = ({ documents, selectedDocumentIndex, updateSelectedDocument, + isExecuting, }) => { - // This code should not be reached, - // but if for some reason the output is undefined, we render a callout message + if (isExecuting) { + return {i18nTexts.loadingMessage}; + } + if (!processorOutput) { return ; } @@ -156,7 +164,7 @@ export const ProcessorOutput: React.FunctionComponent = ({ - {/* If there is no processorInput defined (e.g., it's the first processor), we provide the sample document */} + {/* If there is no processorInput defined (i.e., it's the first processor), we provide the sample document */} {JSON.stringify( processorInput ? processorInput : documents[selectedDocumentIndex], null, 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/processor_form/processor_settings_fields.tsx similarity index 87% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_settings_fields.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_settings_fields.tsx index e52c00bccb6ab..6b21ad95f1b9b 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/processor_form/processor_settings_fields.tsx @@ -13,10 +13,11 @@ import { ProcessorInternal } from '../../types'; import { getProcessorDescriptor } from '../shared'; import { CommonProcessorFields, ProcessorTypeField } from './processors/common_fields'; import { Custom } from './processors/custom'; +import { Fields } from './processor_form.container'; export interface Props { processor?: ProcessorInternal; - getDefaultProcessorOptions: () => void; + getDefaultProcessorOptions: () => Fields; } export const ProcessorSettingsFields: FunctionComponent = ({ @@ -32,6 +33,7 @@ export const ProcessorSettingsFields: FunctionComponent = ({ {(arg: any) => { const { type } = arg; + const { fields: defaultOptions } = getDefaultProcessorOptions(); if (type?.length) { const formDescriptor = getProcessorDescriptor(type as any); @@ -45,7 +47,7 @@ export const ProcessorSettingsFields: FunctionComponent = ({ ); } - return ; + return ; } // If the user has not yet defined a type, we do not show any settings fields 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/processor_form/processors/append.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/append.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/append.tsx 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/processor_form/processors/bytes.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/bytes.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/bytes.tsx 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/processor_form/processors/circle.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/circle.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/circle.tsx 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/processor_form/processors/common_fields/common_processor_fields.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/common_processor_fields.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/common_fields/common_processor_fields.tsx 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/processor_form/processors/common_fields/field_name_field.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/field_name_field.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/common_fields/field_name_field.tsx 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/processor_form/processors/common_fields/ignore_missing_field.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/ignore_missing_field.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/common_fields/ignore_missing_field.tsx diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/common_fields/index.ts similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/index.ts rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/common_fields/index.ts 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/processor_form/processors/common_fields/processor_type_field.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/processor_type_field.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/common_fields/processor_type_field.tsx 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/processor_form/processors/common_fields/target_field.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/target_field.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/common_fields/target_field.tsx 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/processor_form/processors/convert.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/convert.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/convert.tsx 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/processor_form/processors/csv.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/csv.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/csv.tsx diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/custom.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/custom.tsx similarity index 94% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/custom.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/custom.tsx index ae5ecd118ce44..24d5f98b011b7 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/custom.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/custom.tsx @@ -17,6 +17,7 @@ import { const { emptyField, isJsonField } = fieldValidators; import { XJsonEditor } from '../field_components'; +import { Fields } from '../processor_form.container'; const customConfig: FieldConfig = { type: FIELD_TYPES.TEXT, @@ -59,7 +60,7 @@ const customConfig: FieldConfig = { }; interface Props { - defaultOptions?: any; + defaultOptions?: Fields['fields']; } /** @@ -74,7 +75,7 @@ export const Custom: FunctionComponent = ({ defaultOptions }) => { path="customOptions" component={XJsonEditor} config={customConfig} - defaultValue={defaultOptions.fields} + defaultValue={defaultOptions} componentProps={{ editorProps: { 'data-test-subj': 'processorOptionsEditor', 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/processor_form/processors/date.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/date.tsx 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/processor_form/processors/date_index_name.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date_index_name.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/date_index_name.tsx 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/processor_form/processors/dissect.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dissect.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/dissect.tsx 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/processor_form/processors/dot_expander.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dot_expander.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/dot_expander.tsx 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/processor_form/processors/drop.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/drop.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/drop.tsx 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/processor_form/processors/enrich.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/enrich.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/enrich.tsx 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/processor_form/processors/fail.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/fail.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/fail.tsx 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/processor_form/processors/foreach.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/foreach.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/foreach.tsx 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/processor_form/processors/geoip.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/geoip.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/geoip.tsx 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/processor_form/processors/grok.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/grok.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/grok.tsx 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/processor_form/processors/gsub.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/gsub.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/gsub.tsx 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/processor_form/processors/html_strip.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/html_strip.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/html_strip.tsx 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/processor_form/processors/index.ts similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/index.ts rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/index.ts 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/processor_form/processors/inference.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/inference.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/inference.tsx 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/processor_form/processors/join.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/join.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/join.tsx 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/processor_form/processors/json.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/json.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/json.tsx 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/processor_form/processors/set.tsx similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/set.tsx 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/processor_form/processors/shared.ts similarity index 100% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/shared.ts rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processors/shared.ts 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 854c6632ab94a..766154a9f921e 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 @@ -28,7 +28,7 @@ import { Inference, Join, Json, -} from '../manage_processor_form/processors'; +} from '../processor_form/processors'; // import { SetProcessor } from './processors/set'; // import { Gsub } from './processors/gsub'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/processors_context.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/processors_context.tsx index b2e68ed5fbacd..5969ed8dab2f0 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/processors_context.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/processors_context.tsx @@ -38,7 +38,7 @@ import { OnActionHandler } from '../components/processors_tree'; import { ProcessorRemoveModal, PipelineProcessorsItemTooltip, - ManageProcessorForm, + ProcessorForm, OnSubmitHandler, } from '../components'; @@ -109,7 +109,7 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ // We need to keep track of the processor form state if the user // has made config changes, navigated between tabs (Configuration vs. Output) // and has not yet submitted the form - const [tempProcessorFormData, setTempProcessorFormData] = useState< + const [unsavedProcessorFormData, setUnsavedProcessorFormData] = useState< Omit | undefined >(undefined); @@ -156,7 +156,7 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ }); break; case 'managingProcessor': - setTempProcessorFormData(processorTypeAndOptions); + setUnsavedProcessorFormData(processorTypeAndOptions); processorsDispatch({ type: 'updateProcessor', @@ -179,7 +179,7 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ const onCloseSettingsForm = useCallback(() => { setMode({ id: 'idle' }); setFormState({ validate: () => Promise.resolve(true) }); - setTempProcessorFormData(undefined); + setUnsavedProcessorFormData(undefined); }, [setFormState, setMode]); const onTreeAction = useCallback( @@ -243,14 +243,14 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ )} {mode.id === 'managingProcessor' || mode.id === 'creatingProcessor' ? ( - ) : undefined} {mode.id === 'removingProcessor' && ( diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/test_pipeline_context.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/test_pipeline_context.tsx index f764f403de79b..9aafeafa10b27 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/test_pipeline_context.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/context/test_pipeline_context.tsx @@ -5,6 +5,8 @@ */ import React, { useCallback, useContext, useReducer, Reducer } from 'react'; +import { i18n } from '@kbn/i18n'; + import { useKibana } from '../../../../shared_imports'; import { DeserializedProcessorResult, @@ -161,6 +163,12 @@ export const TestPipelineContextProvider = ({ children }: { children: React.Reac }, }); + services.notifications.toasts.addError(error, { + title: i18n.translate('xpack.ingestPipelines.testPipeline.errorNotificationText', { + defaultMessage: 'Error executing pipeline', + }), + }); + return; } @@ -172,7 +180,7 @@ export const TestPipelineContextProvider = ({ children }: { children: React.Reac }, }); }, - [services.api] + [services.api, services.notifications.toasts] ); return ( From f48508d85249a993fddf3f3f2601c133d8176923 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Tue, 1 Sep 2020 14:23:31 -0400 Subject: [PATCH 07/12] more UX improvements --- .../documents_dropdown.scss | 3 - .../documents_dropdown/documents_dropdown.tsx | 151 ++++++++------ ...pipeline_processors_editor_item_status.tsx | 40 +--- .../processor_form/processor_output/index.ts | 7 + .../processor_output/processor_output.scss | 5 + .../processor_output.tsx | 192 ++++++++---------- .../components/shared/index.ts | 2 + .../shared/status_icons/error_icon.tsx | 18 ++ .../status_icons/error_ignored_icon.tsx | 24 +++ .../components/shared/status_icons/index.ts | 9 + .../shared/status_icons/skipped_icon.tsx | 18 ++ 11 files changed, 260 insertions(+), 209 deletions(-) delete mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.scss create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.scss rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/{ => processor_output}/processor_output.tsx (53%) create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/error_icon.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/error_ignored_icon.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/skipped_icon.tsx diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.scss b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.scss deleted file mode 100644 index 26366fe8beaae..0000000000000 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.scss +++ /dev/null @@ -1,3 +0,0 @@ -.documentsDropdown { - max-width: 200px; -} diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx index 431474f9a6de1..10e75949bfaf9 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx @@ -4,49 +4,51 @@ * you may not use this file except in compliance with the Elastic License. */ import { i18n } from '@kbn/i18n'; -import React, { FunctionComponent } from 'react'; -import { EuiSelect, EuiButtonIcon, EuiToolTip } from '@elastic/eui'; +import React, { FunctionComponent, useState } from 'react'; +import { + EuiSelect, + EuiButton, + EuiButtonIcon, + EuiToolTip, + EuiPopover, + EuiContextMenu, + EuiButtonEmpty, + EuiContextMenuPanel, + EuiPopoverTitle, + EuiSelectable, + EuiHorizontalRule, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, +} from '@elastic/eui'; import { Document } from '../../types'; -import './documents_dropdown.scss'; import { TestPipelineFlyoutTab } from '../test_pipeline/test_pipeline_flyout_tabs'; const i18nTexts = { - ariaLabel: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.testPipeline.documentsDropdownAriaLabel', - { - defaultMessage: 'Select documents', - } - ), dropdownLabel: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.testPipeline.documentsdropdownLabel', { defaultMessage: 'Documents:', } ), - buttonLabel: i18n.translate('xpack.ingestPipelines.pipelineEditor.testPipeline.buttonLabel', { - defaultMessage: 'Add documents', - }), - iconButtonLabel: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.testPipeline.iconButtonAriaLabel', + addDocumentsButtonLabel: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.testPipeline.buttonLabel', { - defaultMessage: 'Manage documents', + defaultMessage: 'Add documents', } ), + popoverTitle: i18n.translate('xpack.ingestPipelines.pipelineEditor.testPipeline.popoverTitle', { + defaultMessage: 'Test documents', + }), }; -const getDocumentOptions = (documents: Document[]) => - documents.map((doc, index) => ({ - value: index, - text: doc._id, - })); - interface Props { documents: Document[]; selectedDocumentIndex: number; updateSelectedDocument: (index: number) => void; - openFlyout?: (activeFlyoutTab: TestPipelineFlyoutTab) => void; + openFlyout: (activeFlyoutTab: TestPipelineFlyoutTab) => void; } export const DocumentsDropdown: FunctionComponent = ({ @@ -55,42 +57,77 @@ export const DocumentsDropdown: FunctionComponent = ({ updateSelectedDocument, openFlyout, }) => { - const shouldAppendActions = typeof openFlyout !== 'undefined'; + const [showPopover, setShowPopover] = useState(false); + + const managePipelineButton = ( + setShowPopover((previousBool) => !previousBool)} + iconType="arrowDown" + iconSide="right" + > + {i18n.translate('xpack.ingestPipelines.pipelineEditor.testPipeline.selectedDocumentLabel', { + defaultMessage: 'Document {selectedDocument}', + values: { + selectedDocument: selectedDocumentIndex + 1, + }, + })} + + ); return ( -
- {shouldAppendActions ? ( - { - updateSelectedDocument(Number(e.target.value)); - }} - aria-label={i18nTexts.ariaLabel} - append={ - - openFlyout!('documents')} - /> - - } - /> - ) : ( - { - updateSelectedDocument(Number(e.target.value)); - }} - aria-label={i18nTexts.ariaLabel} - data-test-subj="documentsDropdown" - /> - )} -
+ setShowPopover(false)} + button={managePipelineButton} + panelPaddingSize="none" + withTitle + repositionOnScroll + > + ({ + index, + checked: selectedDocumentIndex === index ? 'on' : undefined, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.testPipeline.documentLabel', { + defaultMessage: 'Document {documentNumber}', + values: { + documentNumber: index + 1, + }, + }), + }))} + onChange={(newOptions) => { + const selectedOption = newOptions.find((option) => option.checked === 'on'); + updateSelectedDocument(selectedOption.index); + setShowPopover(false); + }} + > + {(list, search) => ( +
+ {i18nTexts.popoverTitle} + {list} +
+ )} +
+ + + + + + { + openFlyout!('documents'); + setPopoverOpen(false); + }} + data-test-subj="addDocumentsButton" + > + {i18nTexts.addDocumentsButtonLabel} + + + + + +
); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx index 07c47b31d21ef..5236940438ff3 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx @@ -8,6 +8,7 @@ import React, { FunctionComponent } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip, EuiIcon, IconType } from '@elastic/eui'; import { ProcessorStatus } from '../types'; +import { ErrorIcon, ErrorIgnoredIcon, SkippedIcon } from './shared'; interface ProcessorStatusIcon { icon: IconType; @@ -15,45 +16,6 @@ interface ProcessorStatusIcon { label: string; } -const ErrorIgnoredIcon: FunctionComponent = () => ( - - - - -); - -const SkippedIcon: FunctionComponent = () => ( - - - -); - -const ErrorIcon: FunctionComponent = () => ( - - - -); - const processorStatusToIconMap: Record = { success: { icon: 'check', diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/index.ts new file mode 100644 index 0000000000000..3b506fc9296e3 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/index.ts @@ -0,0 +1,7 @@ +/* + * 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 { ProcessorOutput } from './processor_output'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.scss b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.scss new file mode 100644 index 0000000000000..f26fb1a369929 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.scss @@ -0,0 +1,5 @@ +.processorOutput { + &__callOutCodeBlock > pre { + background: transparent; + } +} diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx similarity index 53% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx index cba5ed8d34b0b..9b490b9df321f 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx @@ -12,14 +12,15 @@ import { EuiCallOut, EuiCodeBlock, EuiText, - EuiFlexGroup, - EuiFlexItem, EuiSpacer, + EuiSelect, } from '@elastic/eui'; -import { SectionLoading } from '../../../../../shared_imports'; -import { ProcessorResult, Document } from '../../types'; -import { DocumentsDropdown } from '../documents_dropdown'; +import { SectionLoading } from '../../../../../../shared_imports'; +import { ProcessorResult, Document } from '../../../types'; +import { ErrorIcon, ErrorIgnoredIcon, SkippedIcon } from '../../shared'; + +import './processor_output.scss'; export interface Props { processorOutput?: ProcessorResult; @@ -49,31 +50,31 @@ const i18nTexts = { processorOutputLabel: i18n.translate( 'xpack.ingestPipelines.processorOutput.processorOutputCodeBlockLabel', { - defaultMessage: 'Processor output', + defaultMessage: 'Data out', } ), - processorErrorLabel: i18n.translate( + processorErrorTitle: i18n.translate( 'xpack.ingestPipelines.processorOutput.processorErrorCodeBlockLabel', { - defaultMessage: 'Processor error', + defaultMessage: 'There was an error', } ), prevProcessorLabel: i18n.translate( 'xpack.ingestPipelines.processorOutput.processorInputCodeBlockLabel', { - defaultMessage: 'Processor input', + defaultMessage: 'Data in', } ), - processorIgnoredErrorLabel: i18n.translate( + processorIgnoredErrorTitle: i18n.translate( 'xpack.ingestPipelines.processorOutput.ignoredErrorCodeBlockLabel', { - defaultMessage: 'View ignored error', + defaultMessage: 'There was an error that was ignored', } ), documentsDropdownLabel: i18n.translate( 'xpack.ingestPipelines.processorOutput.documentsDropdownLabel', { - defaultMessage: 'Test:', + defaultMessage: 'Test data:', } ), loadingMessage: i18n.translate('xpack.ingestPipelines.processorOutput.loadingMessage', { @@ -104,54 +105,78 @@ export const ProcessorOutput: React.FunctionComponent = ({ status, } = processorOutput!; + const getOutputContent = () => { + switch (status) { + case 'skipped': + return ; + case 'dropped': + return ; + case 'success': + return ( + + {JSON.stringify(currentResult, null, 2)} + + ); + case 'error': + return ( + + + {JSON.stringify(error, null, 2)} + + + ); + case 'error_ignored': + return ( + + + {JSON.stringify(ignoredError, null, 2)} + + + ); + default: + // TODO + } + }; + return ( -
+

{i18nTexts.tabDescription}

- {/* There is no output for "skipped" status, so we render an info callout */} - {status === 'skipped' && ( - <> - - - - )} - - {/* There is no output for "dropped status", so we render a warning callout */} - {status === 'dropped' && ( - <> - - - - )} - - - - - - {i18nTexts.documentsDropdownLabel} - - - - - - - + {/* Documents dropdown */} + ({ + value: index, + text: i18n.translate('xpack.ingestPipelines.processorOutput.documentLabel', { + defaultMessage: 'Document {number}', + values: { + number: index + 1, + }, + }), + }))} + value={selectedDocumentIndex} + onChange={(e) => { + updateSelectedDocument(Number(e.target.value)); + }} + aria-label={i18nTexts.documentsDropdownLabel} + prepend={i18nTexts.documentsDropdownLabel} + /> + {/* Data-in accordion */} = ({ - {currentResult && ( - <> - - - -

{i18nTexts.processorOutputLabel}

-
- - - - - {JSON.stringify(currentResult, null, 2)} - - - )} - - {error && ( - <> - - - - -

{i18nTexts.processorErrorLabel}

-
- - - -
- - + - - {JSON.stringify(error, null, 2)} - - - )} + {/* Data-out content */} + + {i18nTexts.processorOutputLabel} + - {ignoredError && ( - <> - + - -

{i18nTexts.processorIgnoredErrorLabel}

- - } - > - <> - - - - {JSON.stringify(ignoredError, null, 2)} - - -
- - )} + {getOutputContent()}
); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/index.ts index 1b4b975b5305e..3f258bf279e42 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/index.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/index.ts @@ -9,3 +9,5 @@ export { mapProcessorTypeToDescriptor, ProcessorType, } from './map_processor_type_to_form'; + +export { ErrorIcon, ErrorIgnoredIcon, SkippedIcon } from './status_icons'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/error_icon.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/error_icon.tsx new file mode 100644 index 0000000000000..58cb56d4f768d --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/error_icon.tsx @@ -0,0 +1,18 @@ +/* + * 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'; + +export const ErrorIcon: FunctionComponent = () => ( + + + +); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/error_ignored_icon.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/error_ignored_icon.tsx new file mode 100644 index 0000000000000..74ceda7687f02 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/error_ignored_icon.tsx @@ -0,0 +1,24 @@ +/* + * 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'; + +export const ErrorIgnoredIcon: FunctionComponent = () => ( + + + + +); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/index.ts new file mode 100644 index 0000000000000..9fe0871e445eb --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/index.ts @@ -0,0 +1,9 @@ +/* + * 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 { ErrorIcon } from './error_icon'; +export { ErrorIgnoredIcon } from './error_ignored_icon'; +export { SkippedIcon } from './skipped_icon'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/skipped_icon.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/skipped_icon.tsx new file mode 100644 index 0000000000000..c540bd3790fb0 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/status_icons/skipped_icon.tsx @@ -0,0 +1,18 @@ +/* + * 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'; + +export const SkippedIcon: FunctionComponent = () => ( + + + +); From a6849406b5d5d83020563b9be29de684e88e8457 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Tue, 1 Sep 2020 23:24:32 -0400 Subject: [PATCH 08/12] fix TS and update tests --- .../__jest__/test_pipeline.helpers.tsx | 4 +- .../__jest__/test_pipeline.test.tsx | 15 ++++--- .../documents_dropdown/documents_dropdown.tsx | 15 ++++--- .../processor_form/add_processor_form.tsx | 3 -- .../processor_form.container.tsx | 39 ++++++++++++------- .../processor_output/processor_output.tsx | 8 +++- 6 files changed, 49 insertions(+), 35 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.helpers.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.helpers.tsx index fec3259fa019b..513a5b169610c 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.helpers.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.helpers.tsx @@ -140,8 +140,8 @@ const createActions = (testBed: TestBed) => { component.update(); }, - clickProcessorOutputTab() { - act(() => { + async clickProcessorOutputTab() { + await act(async () => { find('outputTab').simulate('click'); }); component.update(); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.test.tsx index 339c840bb86f1..76edb49d25a1e 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.test.tsx @@ -44,7 +44,7 @@ describe('Test pipeline', () => { describe('Test pipeline actions', () => { it('should successfully add sample documents and execute the pipeline', async () => { - const { find, actions, exists } = testBed; + const { actions, exists } = testBed; httpRequestsMockHelpers.setSimulatePipelineResponse(SIMULATE_RESPONSE); @@ -59,7 +59,6 @@ describe('Test pipeline', () => { expect(exists('testPipelineFlyout')).toBe(true); expect(exists('documentsTabContent')).toBe(true); expect(exists('outputTabContent')).toBe(false); - expect(find('outputTab').props().disabled).toEqual(true); // Add sample documents and click run actions.addDocumentsJson(JSON.stringify(DOCUMENTS)); @@ -89,21 +88,25 @@ describe('Test pipeline', () => { }); // Verify output tab is active - expect(find('outputTab').props().disabled).toEqual(false); expect(exists('documentsTabContent')).toBe(false); expect(exists('outputTabContent')).toBe(true); // Click reload button and verify request const totalRequests = server.requests.length; await actions.clickRefreshOutputButton(); - expect(server.requests.length).toBe(totalRequests + 1); + // There will be two requests made to the simulate API + // the second request will have verbose enabled to update the processor results + expect(server.requests.length).toBe(totalRequests + 2); + expect(server.requests[server.requests.length - 2].url).toBe( + '/api/ingest_pipelines/simulate' + ); expect(server.requests[server.requests.length - 1].url).toBe( '/api/ingest_pipelines/simulate' ); // Click verbose toggle and verify request await actions.toggleVerboseSwitch(); - expect(server.requests.length).toBe(totalRequests + 2); + expect(server.requests.length).toBe(totalRequests + 3); expect(server.requests[server.requests.length - 1].url).toBe( '/api/ingest_pipelines/simulate' ); @@ -231,7 +234,7 @@ describe('Test pipeline', () => { expect(exists('processorSettingsForm')).toBe(true); // Navigate to "Output" tab - actions.clickProcessorOutputTab(); + await actions.clickProcessorOutputTab(); // Verify content expect(exists('processorOutputTabContent')).toBe(true); }); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx index 10e75949bfaf9..873c5eccbdeb0 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx @@ -6,14 +6,9 @@ import { i18n } from '@kbn/i18n'; import React, { FunctionComponent, useState } from 'react'; import { - EuiSelect, EuiButton, - EuiButtonIcon, - EuiToolTip, EuiPopover, - EuiContextMenu, EuiButtonEmpty, - EuiContextMenuPanel, EuiPopoverTitle, EuiSelectable, EuiHorizontalRule, @@ -83,11 +78,12 @@ export const DocumentsDropdown: FunctionComponent = ({ panelPaddingSize="none" withTitle repositionOnScroll + data-test-subj="documentsDropdown" > ({ - index, + key: index.toString(), checked: selectedDocumentIndex === index ? 'on' : undefined, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.testPipeline.documentLabel', { defaultMessage: 'Document {documentNumber}', @@ -98,7 +94,10 @@ export const DocumentsDropdown: FunctionComponent = ({ }))} onChange={(newOptions) => { const selectedOption = newOptions.find((option) => option.checked === 'on'); - updateSelectedDocument(selectedOption.index); + if (selectedOption) { + updateSelectedDocument(Number(selectedOption.key!)); + } + setShowPopover(false); }} > @@ -118,7 +117,7 @@ export const DocumentsDropdown: FunctionComponent = ({ size="s" onClick={() => { openFlyout!('documents'); - setPopoverOpen(false); + setShowPopover(false); }} data-test-subj="addDocumentsButton" > diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx index 8982cb495dd6e..5b3bd7f260e84 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx @@ -20,7 +20,6 @@ import { } from '@elastic/eui'; import { Form, FormDataProvider, FormHook } from '../../../../../shared_imports'; -import { ProcessorInternal } from '../../types'; import { getProcessorDescriptor } from '../shared'; import { DocumentationButton } from './documentation_button'; @@ -31,13 +30,11 @@ interface Fields { } export interface Props { isOnFailure: boolean; - processor?: ProcessorInternal; form: FormHook; onOpen: () => void; esDocsBasePath: string; getDefaultProcessorOptions: () => Fields; closeFlyout: () => void; - resetProcessors: () => void; handleSubmit: (shouldCloseFlyout?: boolean) => Promise; } diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_form.container.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_form.container.tsx index b76607d999f9f..63e377eb4f259 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_form.container.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_form.container.tsx @@ -95,18 +95,29 @@ export const ProcessorFormContainer: FunctionComponent = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [onFormUpdate]); - const ViewComponent = processor ? EditProcessorForm : AddProcessorForm; - - return ( - - ); + if (processor) { + return ( + + ); + } else { + return ( + + ); + } }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx index 9b490b9df321f..e12e553646818 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx @@ -120,7 +120,11 @@ export const ProcessorOutput: React.FunctionComponent = ({ case 'error': return ( - + {JSON.stringify(error, null, 2)} @@ -147,7 +151,7 @@ export const ProcessorOutput: React.FunctionComponent = ({ }; return ( -
+

{i18nTexts.tabDescription}

From bad79134f5e1055e38a8df85e60e1aead1fcb5e9 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Wed, 2 Sep 2020 09:42:57 -0400 Subject: [PATCH 09/12] fix i18n + cleanup --- .../pipeline_processors_editor.helpers.tsx | 10 ++++--- .../pipeline_processors_editor.test.tsx | 2 +- .../__jest__/test_pipeline.helpers.tsx | 3 +- .../__jest__/test_pipeline.test.tsx | 2 +- .../components/documents_dropdown/index.ts | 7 ----- .../components/index.ts | 2 -- .../processor_form/add_processor_form.tsx | 2 +- .../processor_form/edit_processor_form.tsx | 6 ++-- .../processor_output/processor_output.tsx | 28 +++++++++++++++---- .../documents_dropdown.tsx | 15 ++++++---- .../test_pipeline/test_pipeline_actions.tsx | 2 +- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 13 files changed, 46 insertions(+), 35 deletions(-) delete mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/index.ts rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/{documents_dropdown => test_pipeline}/documents_dropdown.tsx (91%) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/pipeline_processors_editor.helpers.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/pipeline_processors_editor.helpers.tsx index 2e7a47e0c93de..e46e5156e30f3 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/pipeline_processors_editor.helpers.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/pipeline_processors_editor.helpers.tsx @@ -126,7 +126,7 @@ const createActions = (testBed: TestBed) => { }); }); await act(async () => { - find('processorSettingsForm.submitButton').simulate('click'); + find('addProcessorForm.submitButton').simulate('click'); }); }, @@ -166,7 +166,7 @@ const createActions = (testBed: TestBed) => { }); }); await act(async () => { - find('processorSettingsForm.submitButton').simulate('click'); + find('addProcessorForm.submitButton').simulate('click'); }); }, @@ -202,8 +202,10 @@ type TestSubject = | 'pipelineEditorDoneButton' | 'pipelineEditorOnFailureToggle' | 'addProcessorsButtonLevel1' - | 'processorSettingsForm' - | 'processorSettingsForm.submitButton' + | 'editProcessorForm' + | 'editProcessorForm.submitButton' + | 'addProcessorForm.submitButton' + | 'addProcessorForm' | 'processorOptionsEditor' | 'processorSettingsFormFlyout' | 'processorTypeSelector' diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/pipeline_processors_editor.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/pipeline_processors_editor.test.tsx index b12f324528167..dcbd46acba1b2 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/pipeline_processors_editor.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/pipeline_processors_editor.test.tsx @@ -180,7 +180,7 @@ describe('Pipeline Editor', () => { it('prevents moving a processor while in edit mode', () => { const { find, exists } = testBed; find('processors>0.manageItemButton').simulate('click'); - expect(exists('processorSettingsForm')).toBe(true); + expect(exists('editProcessorForm')).toBe(true); expect(find('processors>0.moveItemButton').props().disabled).toBe(true); expect(find('processors>1.moveItemButton').props().disabled).toBe(true); }); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.helpers.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.helpers.tsx index 513a5b169610c..f4c89d7a1058a 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.helpers.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.helpers.tsx @@ -224,7 +224,8 @@ type TestSubject = | 'processorStatusIcon' | 'documentsTab' | 'manageItemButton' - | 'processorSettingsForm' + | 'addProcessorForm' + | 'editProcessorForm' | 'configurationTab' | 'outputTab' | 'processorOutputTabContent' diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.test.tsx index 76edb49d25a1e..e5118a6e465af 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/__jest__/test_pipeline.test.tsx @@ -231,7 +231,7 @@ describe('Test pipeline', () => { // Click processor to open manage flyout await actions.clickProcessor('processors>0'); // Verify flyout opened - expect(exists('processorSettingsForm')).toBe(true); + expect(exists('editProcessorForm')).toBe(true); // Navigate to "Output" tab await actions.clickProcessorOutputTab(); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/index.ts deleted file mode 100644 index a8b55788647fb..0000000000000 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * 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 { DocumentsDropdown } from './documents_dropdown'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/index.ts index a8073c4f7e760..d476202aa43bb 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/index.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/index.ts @@ -18,6 +18,4 @@ export { OnDoneLoadJsonHandler, LoadFromJsonButton } from './load_from_json'; export { TestPipelineActions } from './test_pipeline'; -export { DocumentsDropdown } from './documents_dropdown'; - export { PipelineProcessorsItemTooltip, Position } from './pipeline_processors_editor_item_tooltip'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx index 5b3bd7f260e84..a5abcda709a95 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx @@ -79,7 +79,7 @@ export const AddProcessorForm: FunctionComponent = ({ ); return ( -
+ diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/edit_processor_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/edit_processor_form.tsx index 712e9668a179d..8ab4d72309879 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/edit_processor_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/edit_processor_form.tsx @@ -45,12 +45,12 @@ export interface Props { } const updateButtonLabel = i18n.translate( - 'xpack.ingestPipelines.settingsFormOnFailureFlyout.updateButtonLabel', + 'xpack.ingestPipelines.processorFormFlyout.updateButtonLabel', { defaultMessage: 'Update' } ); const cancelButtonLabel = i18n.translate( - 'xpack.ingestPipelines.settingsFormOnFailureFlyout.cancelButtonLabel', + 'xpack.ingestPipelines.processorFormFlyout.cancelButtonLabel', { defaultMessage: 'Cancel' } ); @@ -158,7 +158,7 @@ export const EditProcessorForm: FunctionComponent = ({ } return ( - + = ({ status, } = processorOutput!; + const NoOutputCallOut: FunctionComponent = () => ( + + ); + const getOutputContent = () => { switch (status) { case 'skipped': @@ -112,11 +122,15 @@ export const ProcessorOutput: React.FunctionComponent = ({ case 'dropped': return ; case 'success': - return ( - - {JSON.stringify(currentResult, null, 2)} - - ); + if (currentResult) { + return ( + + {JSON.stringify(currentResult, null, 2)} + + ); + } + + return ; case 'error': return ( @@ -124,6 +138,7 @@ export const ProcessorOutput: React.FunctionComponent = ({ language="json" paddingSize="none" className="processorOutput__callOutCodeBlock" + transparentBackground > {JSON.stringify(error, null, 2)} @@ -140,13 +155,14 @@ export const ProcessorOutput: React.FunctionComponent = ({ className="processorOutput__callOutCodeBlock" language="json" paddingSize="none" + transparentBackground > {JSON.stringify(ignoredError, null, 2)} ); default: - // TODO + return NoOutputCallout; } }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown.tsx similarity index 91% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown.tsx index 873c5eccbdeb0..0b51b6ca37b19 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/documents_dropdown/documents_dropdown.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown.tsx @@ -23,20 +23,23 @@ import { TestPipelineFlyoutTab } from '../test_pipeline/test_pipeline_flyout_tab const i18nTexts = { dropdownLabel: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.testPipeline.documentsdropdownLabel', + 'xpack.ingestPipelines.pipelineEditor.testPipeline.documentsdropdown.dropdownLabel', { defaultMessage: 'Documents:', } ), addDocumentsButtonLabel: i18n.translate( - 'xpack.ingestPipelines.pipelineEditor.testPipeline.buttonLabel', + 'xpack.ingestPipelines.pipelineEditor.testPipeline.documentsDropdown.buttonLabel', { defaultMessage: 'Add documents', } ), - popoverTitle: i18n.translate('xpack.ingestPipelines.pipelineEditor.testPipeline.popoverTitle', { - defaultMessage: 'Test documents', - }), + popoverTitle: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.testPipeline.documentsDropdown.popoverTitle', + { + defaultMessage: 'Test documents', + } + ), }; interface Props { @@ -116,7 +119,7 @@ export const DocumentsDropdown: FunctionComponent = ({ { - openFlyout!('documents'); + openFlyout('documents'); setShowPopover(false); }} data-test-subj="addDocumentsButton" diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx index 293e3eb1953d6..fc3d094650c48 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import { useTestPipelineContext, usePipelineProcessorsContext } from '../../context'; -import { DocumentsDropdown } from '../documents_dropdown'; +import { DocumentsDropdown } from './documents_dropdown'; import { TestPipelineFlyoutTab } from './test_pipeline_flyout_tabs'; import { AddDocumentsButton } from './add_documents_button'; import { TestOutputButton } from './test_output_button'; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 093ef4d6f1873..77e781e2505ac 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9733,7 +9733,6 @@ "xpack.ingestPipelines.requestFlyout.descriptionText": "このElasticsearchリクエストは、このパイプラインを作成または更新します。", "xpack.ingestPipelines.requestFlyout.namedTitle": "「{name}」のリクエスト", "xpack.ingestPipelines.requestFlyout.unnamedTitle": "リクエスト", - "xpack.ingestPipelines.settingsFormOnFailureFlyout.addButtonLabel": "追加", "xpack.ingestPipelines.settingsFormOnFailureFlyout.cancelButtonLabel": "キャンセル", "xpack.ingestPipelines.tabs.outputTabTitle": "アウトプット", "xpack.ingestPipelines.testPipelineFlyout.documentsForm.documentsFieldLabel": "ドキュメント", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index ea04b1e14d959..79cfd73919884 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9736,7 +9736,6 @@ "xpack.ingestPipelines.requestFlyout.descriptionText": "此 Elasticsearch 请求将创建或更新管道。", "xpack.ingestPipelines.requestFlyout.namedTitle": "对“{name}”的请求", "xpack.ingestPipelines.requestFlyout.unnamedTitle": "请求", - "xpack.ingestPipelines.settingsFormOnFailureFlyout.addButtonLabel": "添加", "xpack.ingestPipelines.settingsFormOnFailureFlyout.cancelButtonLabel": "取消", "xpack.ingestPipelines.tabs.outputTabTitle": "输出", "xpack.ingestPipelines.testPipelineFlyout.documentsForm.documentsFieldLabel": "文档", From d8107bc0871a5b99bb5761e6d904f8c09bdb4bbf Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Wed, 2 Sep 2020 10:15:51 -0400 Subject: [PATCH 10/12] fix i18n + TS --- .../processor_output/processor_output.tsx | 12 +++--------- .../components/pipeline_processors_editor/index.ts | 7 +------ x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 4 files changed, 4 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx index a0c9048d6023c..08a13fc6c5df1 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { FunctionComponent } from 'react'; import { i18n } from '@kbn/i18n'; import { @@ -31,12 +31,6 @@ export interface Props { } const i18nTexts = { - noOutputCalloutTitle: i18n.translate( - 'xpack.ingestPipelines.processorOutput.noOutputCalloutTitle', - { - defaultMessage: 'Unable to load the processor output.', - } - ), tabDescription: i18n.translate('xpack.ingestPipelines.processorOutput.descriptionText', { defaultMessage: 'View how the processor affects the ingest document as it passes through the pipeline.', @@ -88,7 +82,7 @@ const i18nTexts = { }), }; -export const ProcessorOutput: React.FunctionComponent = ({ +export const ProcessorOutput: FunctionComponent = ({ processorOutput, documents, selectedDocumentIndex, @@ -162,7 +156,7 @@ export const ProcessorOutput: React.FunctionComponent = ({ ); default: - return NoOutputCallout; + return ; } }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/index.ts index 71b2e2fa8f7f1..c462b19c79327 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/index.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/index.ts @@ -14,9 +14,4 @@ export { OnUpdateHandlerArg, OnUpdateHandler } from './types'; export { SerializeResult } from './serialize'; -export { - LoadFromJsonButton, - OnDoneLoadJsonHandler, - TestPipelineActions, - DocumentsDropdown, -} from './components'; +export { LoadFromJsonButton, OnDoneLoadJsonHandler, TestPipelineActions } from './components'; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 77e781e2505ac..d9286bb071a79 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9733,7 +9733,6 @@ "xpack.ingestPipelines.requestFlyout.descriptionText": "このElasticsearchリクエストは、このパイプラインを作成または更新します。", "xpack.ingestPipelines.requestFlyout.namedTitle": "「{name}」のリクエスト", "xpack.ingestPipelines.requestFlyout.unnamedTitle": "リクエスト", - "xpack.ingestPipelines.settingsFormOnFailureFlyout.cancelButtonLabel": "キャンセル", "xpack.ingestPipelines.tabs.outputTabTitle": "アウトプット", "xpack.ingestPipelines.testPipelineFlyout.documentsForm.documentsFieldLabel": "ドキュメント", "xpack.ingestPipelines.testPipelineFlyout.documentsForm.documentsJsonError": "ドキュメントJSONが無効です。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 79cfd73919884..8e7a23312f3a9 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9736,7 +9736,6 @@ "xpack.ingestPipelines.requestFlyout.descriptionText": "此 Elasticsearch 请求将创建或更新管道。", "xpack.ingestPipelines.requestFlyout.namedTitle": "对“{name}”的请求", "xpack.ingestPipelines.requestFlyout.unnamedTitle": "请求", - "xpack.ingestPipelines.settingsFormOnFailureFlyout.cancelButtonLabel": "取消", "xpack.ingestPipelines.tabs.outputTabTitle": "输出", "xpack.ingestPipelines.testPipelineFlyout.documentsForm.documentsFieldLabel": "文档", "xpack.ingestPipelines.testPipelineFlyout.documentsForm.documentsJsonError": "文档 JSON 无效。", From 1aa0ef4c0131c6d5e65b28712d3ff45e292fdfc0 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Mon, 14 Sep 2020 15:10:19 -0400 Subject: [PATCH 11/12] address review feedback --- .../processor_form/add_processor_form.tsx | 4 +- .../processor_form/edit_processor_form.tsx | 17 +++----- .../processor_form.container.tsx | 40 ++++++++++--------- .../processor_output/processor_output.scss | 11 ++++- .../processor_output/processor_output.tsx | 20 ++++++++-- .../processor_settings_fields.tsx | 10 +---- .../documents_dropdown.scss | 3 ++ .../documents_dropdown.tsx | 7 +++- .../test_pipeline/documents_dropdown/index.ts | 7 ++++ .../context/processors_context.tsx | 11 ----- 10 files changed, 71 insertions(+), 59 deletions(-) create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown/documents_dropdown.scss rename x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/{ => documents_dropdown}/documents_dropdown.tsx (94%) create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown/index.ts diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx index a5abcda709a95..5231a3d17811b 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/add_processor_form.tsx @@ -33,7 +33,6 @@ export interface Props { form: FormHook; onOpen: () => void; esDocsBasePath: string; - getDefaultProcessorOptions: () => Fields; closeFlyout: () => void; handleSubmit: (shouldCloseFlyout?: boolean) => Promise; } @@ -67,7 +66,6 @@ export const AddProcessorForm: FunctionComponent = ({ onOpen, form, esDocsBasePath, - getDefaultProcessorOptions, closeFlyout, handleSubmit, }) => { @@ -110,7 +108,7 @@ export const AddProcessorForm: FunctionComponent = ({ - + diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/edit_processor_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/edit_processor_form.tsx index 8ab4d72309879..e449ed75b6343 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/edit_processor_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/edit_processor_form.tsx @@ -34,14 +34,13 @@ import { Fields } from './processor_form.container'; export interface Props { isOnFailure: boolean; - processor: ProcessorInternal; form: FormHook; onOpen: () => void; esDocsBasePath: string; - getDefaultProcessorOptions: () => Fields; closeFlyout: () => void; resetProcessors: () => void; handleSubmit: (shouldCloseFlyout?: boolean) => Promise; + getProcessor: () => ProcessorInternal; } const updateButtonLabel = i18n.translate( @@ -94,12 +93,11 @@ const getFlyoutTitle = (isOnFailure: boolean) => { }; export const EditProcessorForm: FunctionComponent = ({ - processor, + getProcessor, form, isOnFailure, onOpen, esDocsBasePath, - getDefaultProcessorOptions, closeFlyout, handleSubmit, resetProcessors, @@ -111,6 +109,8 @@ export const EditProcessorForm: FunctionComponent = ({ isExecutingPipeline, } = testPipelineData; + const processor = getProcessor(); + const processorOutput = processor && testOutputPerProcessor && @@ -149,12 +149,7 @@ export const EditProcessorForm: FunctionComponent = ({ /> ); } else { - flyoutContent = ( - - ); + flyoutContent = ; } return ( @@ -203,7 +198,7 @@ export const EditProcessorForm: FunctionComponent = ({ if (tab.id === 'output') { await handleSubmit(false); } else { - form.reset({ defaultValue: getDefaultProcessorOptions() }); + form.reset({ defaultValue: { fields: processor.options } }); } setActiveTab(tab.id); }} diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_form.container.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_form.container.tsx index 63e377eb4f259..332908d0756f2 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_form.container.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_form.container.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FunctionComponent, useCallback, useEffect } from 'react'; +import React, { FunctionComponent, useCallback, useEffect, useRef } from 'react'; import { useForm, OnFormUpdateArg, FormData, useKibana } from '../../../../../shared_imports'; import { ProcessorInternal } from '../../types'; @@ -29,34 +29,36 @@ interface Props { onOpen: () => void; onClose: () => void; processor?: ProcessorInternal; - unsavedFormData?: Omit; } export const ProcessorFormContainer: FunctionComponent = ({ processor, onFormUpdate, onSubmit, - unsavedFormData, onClose, ...rest }) => { const { services } = useKibana(); - const getDefaultProcessorOptions = (): Fields => { - let defaultFields; + // We need to keep track of the processor form state if the user + // has made config changes, navigated between tabs (Configuration vs. Output) + // and has not yet submitted the form + const unsavedFormState = useRef(); - if (unsavedFormData) { - const { options } = unsavedFormData; - defaultFields = { fields: options }; + const getProcessor = useCallback((): ProcessorInternal => { + let options; + + if (unsavedFormState?.current) { + options = unsavedFormState.current; } else { - defaultFields = { fields: processor?.options ?? {} }; + options = processor?.options ?? {}; } - return defaultFields; - }; + return { ...processor, options } as ProcessorInternal; + }, [processor, unsavedFormState]); const { form } = useForm({ - defaultValue: getDefaultProcessorOptions(), + defaultValue: { fields: getProcessor().options }, }); const handleSubmit = useCallback( @@ -65,9 +67,13 @@ export const ProcessorFormContainer: FunctionComponent = ({ if (isValid) { const { type, customOptions, fields } = data as FormData; + const options = customOptions ? customOptions : fields; + + unsavedFormState.current = options; + onSubmit({ type, - options: customOptions ? customOptions : fields, + options, }); if (shouldCloseFlyout) { @@ -78,12 +84,12 @@ export const ProcessorFormContainer: FunctionComponent = ({ [form, onClose, onSubmit] ); - const resetProcessors = () => { + const resetProcessors = useCallback(() => { onSubmit({ type: processor!.type, options: processor?.options || {}, }); - }; + }, [onSubmit, processor]); useEffect(() => { const subscription = form.subscribe(onFormUpdate); @@ -99,9 +105,8 @@ export const ProcessorFormContainer: FunctionComponent = ({ return ( = ({ pre { - background: transparent; + &__callOut { + &--customIcon { + .euiCallOutHeader { + align-items: center; + } + } + &__codeBlock > pre { + background: transparent; + } } } diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx index 08a13fc6c5df1..bd0ce6ca2cd52 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/processor_form/processor_output/processor_output.tsx @@ -112,7 +112,13 @@ export const ProcessorOutput: FunctionComponent = ({ const getOutputContent = () => { switch (status) { case 'skipped': - return ; + return ( + + ); case 'dropped': return ; case 'success': @@ -127,11 +133,16 @@ export const ProcessorOutput: FunctionComponent = ({ return ; case 'error': return ( - + {JSON.stringify(error, null, 2)} @@ -144,9 +155,10 @@ export const ProcessorOutput: FunctionComponent = ({ iconType={ErrorIgnoredIcon} title={i18nTexts.processorIgnoredErrorTitle} color="warning" + className="processorOutput__callOut processorOutput__callOut--customIcon" > Fields; } -export const ProcessorSettingsFields: FunctionComponent = ({ - processor, - getDefaultProcessorOptions, -}) => { +export const ProcessorSettingsFields: FunctionComponent = ({ processor }) => { return ( <> @@ -33,7 +28,6 @@ export const ProcessorSettingsFields: FunctionComponent = ({ {(arg: any) => { const { type } = arg; - const { fields: defaultOptions } = getDefaultProcessorOptions(); if (type?.length) { const formDescriptor = getProcessorDescriptor(type as any); @@ -59,7 +53,7 @@ export const ProcessorSettingsFields: FunctionComponent = ({ ); } - return ; + return ; } // If the user has not yet defined a type, we do not show any settings fields diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown/documents_dropdown.scss b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown/documents_dropdown.scss new file mode 100644 index 0000000000000..5deb48a2f01a7 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown/documents_dropdown.scss @@ -0,0 +1,3 @@ +.documentsDropdownPanel { + min-width: 200px; +} diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown/documents_dropdown.tsx similarity index 94% rename from x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown.tsx rename to x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown/documents_dropdown.tsx index 0b51b6ca37b19..269a697a33c17 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/documents_dropdown/documents_dropdown.tsx @@ -17,9 +17,11 @@ import { EuiSpacer, } from '@elastic/eui'; -import { Document } from '../../types'; +import { Document } from '../../../types'; -import { TestPipelineFlyoutTab } from '../test_pipeline/test_pipeline_flyout_tabs'; +import { TestPipelineFlyoutTab } from '../test_pipeline_flyout_tabs'; + +import './documents_dropdown.scss'; const i18nTexts = { dropdownLabel: i18n.translate( @@ -82,6 +84,7 @@ export const DocumentsDropdown: FunctionComponent = ({ withTitle repositionOnScroll data-test-subj="documentsDropdown" + panelClassName="documentsDropdownPanel" > = ({ validate: () => Promise.resolve(true), }); - // We need to keep track of the processor form state if the user - // has made config changes, navigated between tabs (Configuration vs. Output) - // and has not yet submitted the form - const [unsavedProcessorFormData, setUnsavedProcessorFormData] = useState< - Omit | undefined - >(undefined); - const onFormUpdate = useCallback<(arg: OnFormUpdateArg) => void>( ({ isValid, validate }) => { setFormState({ @@ -156,8 +149,6 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ }); break; case 'managingProcessor': - setUnsavedProcessorFormData(processorTypeAndOptions); - processorsDispatch({ type: 'updateProcessor', payload: { @@ -179,7 +170,6 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ const onCloseSettingsForm = useCallback(() => { setMode({ id: 'idle' }); setFormState({ validate: () => Promise.resolve(true) }); - setUnsavedProcessorFormData(undefined); }, [setFormState, setMode]); const onTreeAction = useCallback( @@ -250,7 +240,6 @@ export const PipelineProcessorsContextProvider: FunctionComponent = ({ onFormUpdate={onFormUpdate} onSubmit={onSubmit} onClose={onCloseSettingsForm} - unsavedFormData={unsavedProcessorFormData} /> ) : undefined} {mode.id === 'removingProcessor' && ( From 7f87c1a013ca8ebc8348598ae7d49a7be569324b Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Tue, 15 Sep 2020 12:33:13 -0400 Subject: [PATCH 12/12] address design feedback --- .../components/pipeline_processors_editor_item_status.tsx | 6 +++--- .../components/test_pipeline/test_output_button.tsx | 2 +- .../components/test_pipeline/test_pipeline_actions.tsx | 2 +- .../test_pipeline_flyout_tabs/tab_documents.tsx | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx index 5236940438ff3..08d456b47180c 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/pipeline_processors_editor_item_status.tsx @@ -18,7 +18,7 @@ interface ProcessorStatusIcon { const processorStatusToIconMap: Record = { success: { - icon: 'check', + icon: 'checkInCircleFilled', iconColor: 'success', label: i18n.translate('xpack.ingestPipelines.pipelineEditorItem.successStatusAriaLabel', { defaultMessage: 'Success', @@ -54,7 +54,7 @@ const processorStatusToIconMap: Record = { }, inactive: { icon: 'dot', - iconColor: 'subdued', + iconColor: '#D3DAE6', // $euiColorLightShade label: i18n.translate('xpack.ingestPipelines.pipelineEditorItem.inactiveStatusAriaLabel', { defaultMessage: 'Not run', }), @@ -65,7 +65,7 @@ const processorStatusToIconMap: Record = { // This is not expected and likely means we need to modify the code to support a new status const unknownStatus = { icon: 'dot', - iconColor: 'subdued', + iconColor: '#D3DAE6', // $euiColorLightShade label: i18n.translate('xpack.ingestPipelines.pipelineEditorItem.unknownStatusAriaLabel', { defaultMessage: 'Unknown', }), diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_output_button.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_output_button.tsx index 22f2d923bda7a..9018042229590 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_output_button.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_output_button.tsx @@ -12,7 +12,7 @@ const i18nTexts = { buttonLabel: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.testPipeline.outputButtonLabel', { - defaultMessage: 'Output', + defaultMessage: 'View output', } ), }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx index fc3d094650c48..cec02db26729d 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_actions.tsx @@ -18,7 +18,7 @@ const i18nTexts = { testPipelineActionsLabel: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.testPipeline.testPipelineActionsLabel', { - defaultMessage: 'Test:', + defaultMessage: 'Test pipeline:', } ), }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_documents.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_documents.tsx index b3114d296f3a0..b2326644340a7 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_documents.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/test_pipeline/test_pipeline_flyout_tabs/tab_documents.tsx @@ -82,6 +82,7 @@ export const DocumentsTab: React.FunctionComponent = ({ size="s" isLoading={isRunningTest} disabled={isSubmitButtonDisabled} + iconType="play" > {isRunningTest ? (