Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Ingest pipelines] Implement tabs in processor flyout #74469

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ describe('Pipeline Editor', () => {

it('prevents moving a processor while in edit mode', () => {
const { find, exists } = testBed;
find('processors>0.editItemButton').simulate('click');
find('processors>0.manageItemButton').simulate('click');
expect(exists('processorSettingsForm')).toBe(true);
expect(find('processors>0.moveItemButton').props().disabled).toBe(true);
expect(find('processors>1.moveItemButton').props().disabled).toBe(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
*/

export {
ProcessorSettingsForm,
ProcessorSettingsFromOnSubmitArg,
ManageProcessorForm,
ManageProcessorFormOnSubmitArg,
OnSubmitHandler,
} from './processor_settings_form';
} from './manage_processor_form';

export { ProcessorsTree, ProcessorInfo, OnActionHandler } from './processors_tree';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

export {
ProcessorSettingsForm,
ProcessorSettingsFromOnSubmitArg,
ManageProcessorForm,
ManageProcessorFormOnSubmitArg,
OnSubmitHandler,
} from './processor_settings_form.container';
} from './manage_processor_form.container';
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import React, { FunctionComponent, useCallback, useEffect } from 'react';
import { useForm, OnFormUpdateArg, FormData } from '../../../../../shared_imports';
import { ProcessorInternal } from '../../types';

import { ProcessorSettingsForm as ViewComponent } from './processor_settings_form';
import { ManageProcessorForm as ViewComponent } from './manage_processor_form';
import { usePipelineProcessorsContext } from '../../context';

export type ProcessorSettingsFromOnSubmitArg = Omit<ProcessorInternal, 'id'>;
export type ManageProcessorFormOnSubmitArg = Omit<ProcessorInternal, 'id'>;

export type OnSubmitHandler = (processor: ProcessorSettingsFromOnSubmitArg) => void;
export type OnSubmitHandler = (processor: ManageProcessorFormOnSubmitArg) => void;

export type OnFormUpdateHandler = (form: OnFormUpdateArg<any>) => void;

Expand All @@ -27,7 +27,7 @@ interface Props {
processor?: ProcessorInternal;
}

export const ProcessorSettingsForm: FunctionComponent<Props> = ({
export const ManageProcessorForm: FunctionComponent<Props> = ({
processor,
onFormUpdate,
onSubmit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,28 @@

import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { FunctionComponent, memo, useEffect } from 'react';
import React, { FunctionComponent, memo, useEffect, useState } from 'react';
import {
EuiButton,
EuiButtonEmpty,
EuiHorizontalRule,
EuiFlyout,
EuiFlyoutHeader,
EuiFlyoutBody,
EuiFlyoutFooter,
EuiSpacer,
EuiTabs,
EuiTab,
EuiTitle,
EuiFlexGroup,
EuiFlexItem,
} from '@elastic/eui';

import { Form, FormDataProvider, FormHook } from '../../../../../shared_imports';
import { ProcessorInternal } from '../../types';

import { getProcessorDescriptor } from '../shared';

import { ProcessorSettingsFields } from './processor_settings_fields';
import { DocumentationButton } from './documentation_button';
import { CommonProcessorFields, ProcessorTypeField } from './processors/common_fields';
import { Custom } from './processors/custom';

export interface Props {
isOnFailure: boolean;
Expand All @@ -42,6 +42,7 @@ const updateButtonLabel = i18n.translate(
'xpack.ingestPipelines.settingsFormOnFailureFlyout.updateButtonLabel',
{ defaultMessage: 'Update' }
);

const addButtonLabel = i18n.translate(
'xpack.ingestPipelines.settingsFormOnFailureFlyout.addButtonLabel',
{ defaultMessage: 'Add' }
Expand All @@ -52,27 +53,66 @@ const cancelButtonLabel = i18n.translate(
{ defaultMessage: 'Cancel' }
);

export const ProcessorSettingsForm: FunctionComponent<Props> = memo(
({ processor, form, isOnFailure, onClose, onOpen, esDocsBasePath }) => {
const flyoutTitleContent = isOnFailure ? (
export type TabType = 'configuration';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these used externally? If not, I think we should remove export

Copy link
Contributor

@jloleysens jloleysens Aug 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, ignore I see it is being used in getIsDisabled


interface Tab {
id: TabType;
name: string;
}

const tabs: Tab[] = [
{
id: 'configuration',
name: i18n.translate(
'xpack.ingestPipelines.settingsFormOnFailureFlyout.configurationTabTitle',
{
defaultMessage: 'Configuration',
}
),
},
];

const getFlyoutTitle = (isOnFailure: boolean, isExistingProcessor: boolean) => {
if (isExistingProcessor) {
return isOnFailure ? (
<FormattedMessage
id="xpack.ingestPipelines.settingsFormOnFailureFlyout.title"
defaultMessage="Configure on-failure processor"
id="xpack.ingestPipelines.settingsFormOnFailureFlyout.manageOnFailureTitle"
defaultMessage="Manage on-failure processor"
/>
) : (
<FormattedMessage
id="xpack.ingestPipelines.settingsFormFlyout.title"
defaultMessage="Configure processor"
id="xpack.ingestPipelines.settingsFormOnFailureFlyout.manageTitle"
defaultMessage="Manage processor"
/>
);
}

return isOnFailure ? (
<FormattedMessage
id="xpack.ingestPipelines.settingsFormOnFailureFlyout.configureOnFailureTitle"
defaultMessage="Configure on-failure processor"
/>
) : (
<FormattedMessage
id="xpack.ingestPipelines.settingsFormOnFailureFlyout.configureTitle"
defaultMessage="Configure processor"
/>
);
};

export const ManageProcessorForm: FunctionComponent<Props> = memo(
({ processor, form, isOnFailure, onClose, onOpen, esDocsBasePath }) => {
useEffect(
() => {
onOpen();
},
[] /* eslint-disable-line react-hooks/exhaustive-deps */
);

const [activeTab, setActiveTab] = useState<TabType>('configuration');

const flyoutContent = <ProcessorSettingsFields processor={processor} />;

return (
<Form data-test-subj="processorSettingsForm" form={form}>
<EuiFlyout size="m" maxWidth={720} onClose={onClose}>
Expand All @@ -81,11 +121,10 @@ export const ProcessorSettingsForm: FunctionComponent<Props> = memo(
<EuiFlexItem>
<div>
<EuiTitle size="m">
<h2>{flyoutTitleContent}</h2>
<h2>{getFlyoutTitle(isOnFailure, Boolean(processor))}</h2>
</EuiTitle>
</div>
</EuiFlexItem>

<EuiFlexItem grow={false}>
<FormDataProvider pathsToWatch="type">
{({ type }) => {
Expand All @@ -106,46 +145,35 @@ export const ProcessorSettingsForm: FunctionComponent<Props> = memo(
</EuiFlexGroup>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<ProcessorTypeField initialType={processor?.type} />

<EuiHorizontalRule />

<FormDataProvider pathsToWatch="type">
{(arg: any) => {
const { type } = arg;

if (type?.length) {
const formDescriptor = getProcessorDescriptor(type as any);

if (formDescriptor?.FieldsComponent) {
return (
<>
<formDescriptor.FieldsComponent />
<CommonProcessorFields />
</>
);
}
return <Custom defaultOptions={processor?.options} />;
}

// If the user has not yet defined a type, we do not show any settings fields
return null;
}}
</FormDataProvider>
{processor ? (
<>
<EuiTabs>
{tabs.map((tab) => (
<EuiTab
onClick={() => {
setActiveTab(tab.id);
}}
isSelected={tab.id === activeTab}
key={tab.id}
data-test-subj={`${tab.id}Tab`}
>
{tab.name}
</EuiTab>
))}
</EuiTabs>
<EuiSpacer />
</>
) : undefined}

{flyoutContent}
</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={onClose}>{cancelButtonLabel}</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
fill
data-test-subj="submitButton"
onClick={() => {
form.submit();
}}
>
<EuiButton fill data-test-subj="submitButton" onClick={form.submit}>
{processor ? updateButtonLabel : addButtonLabel}
</EuiButton>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React, { FunctionComponent } from 'react';
import { EuiHorizontalRule } from '@elastic/eui';

import { FormDataProvider } from '../../../../../shared_imports';
import { ProcessorInternal } from '../../types';

import { getProcessorDescriptor } from '../shared';
import { CommonProcessorFields, ProcessorTypeField } from './processors/common_fields';
import { Custom } from './processors/custom';

export interface Props {
processor?: ProcessorInternal;
}

export const ProcessorSettingsFields: FunctionComponent<Props> = ({ processor }) => {
return (
<>
<ProcessorTypeField initialType={processor?.type} />

<EuiHorizontalRule />

<FormDataProvider pathsToWatch="type">
{(arg: any) => {
const { type } = arg;

if (type?.length) {
const formDescriptor = getProcessorDescriptor(type as any);

if (formDescriptor?.FieldsComponent) {
return (
<>
<formDescriptor.FieldsComponent />
<CommonProcessorFields />
</>
);
}
return <Custom defaultOptions={processor?.options} />;
}

// If the user has not yet defined a type, we do not show any settings fields
return null;
}}
</FormDataProvider>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
import classNames from 'classnames';
import React, { FunctionComponent, memo } from 'react';
import {
EuiButtonIcon,
EuiButtonToggle,
EuiFlexGroup,
EuiFlexItem,
EuiLink,
EuiPanel,
EuiText,
EuiToolTip,
Expand Down Expand Up @@ -57,9 +57,9 @@ export const PipelineProcessorsEditorItem: FunctionComponent<Props> = memo(
const isInMoveMode = Boolean(movingProcessor);
const isMovingThisProcessor = processor.id === movingProcessor?.id;
const isEditingThisProcessor =
editor.mode.id === 'editingProcessor' && processor.id === editor.mode.arg.processor.id;
editor.mode.id === 'managingProcessor' && processor.id === editor.mode.arg.processor.id;
const isEditingOtherProcessor =
editor.mode.id === 'editingProcessor' && !isEditingThisProcessor;
editor.mode.id === 'managingProcessor' && !isEditingThisProcessor;
const isMovingOtherProcessor = editor.mode.id === 'movingProcessor' && !isMovingThisProcessor;
const isDimmed = isEditingOtherProcessor || isMovingOtherProcessor;

Expand All @@ -70,11 +70,6 @@ export const PipelineProcessorsEditorItem: FunctionComponent<Props> = memo(
'pipelineProcessorsEditor__item--dimmed': isDimmed,
});

const actionElementClasses = classNames({
// eslint-disable-next-line @typescript-eslint/naming-convention
'pipelineProcessorsEditor__item--displayNone': isInMoveMode,
});

const inlineTextInputContainerClasses = classNames({
// eslint-disable-next-line @typescript-eslint/naming-convention
'pipelineProcessorsEditor__item--displayNone': isInMoveMode && !processor.options.description,
Expand Down Expand Up @@ -141,7 +136,18 @@ export const PipelineProcessorsEditorItem: FunctionComponent<Props> = memo(
className="pipelineProcessorsEditor__item__processorTypeLabel"
color={isDimmed ? 'subdued' : undefined}
>
<b>{getProcessorDescriptor(processor.type)?.label ?? processor.type}</b>
<EuiLink
disabled={isEditorNotInIdleMode}
onClick={() => {
editor.setMode({
id: 'managingProcessor',
arg: { processor, selector },
});
}}
data-test-subj="manageItemButton"
>
<b>{getProcessorDescriptor(processor.type)?.label ?? processor.type}</b>
</EuiLink>
</EuiText>
</EuiFlexItem>
<EuiFlexItem className={inlineTextInputContainerClasses} grow={false}>
Expand Down Expand Up @@ -174,25 +180,6 @@ export const PipelineProcessorsEditorItem: FunctionComponent<Props> = memo(
placeholder={i18nTexts.descriptionPlaceholder}
/>
</EuiFlexItem>
<EuiFlexItem className={actionElementClasses} grow={false}>
{!isInMoveMode && (
<EuiToolTip content={i18nTexts.editButtonLabel}>
<EuiButtonIcon
data-test-subj="editItemButton"
disabled={isEditorNotInIdleMode}
aria-label={i18nTexts.editButtonLabel}
iconType="pencil"
size="s"
onClick={() => {
editor.setMode({
id: 'editingProcessor',
arg: { processor, selector },
});
}}
/>
</EuiToolTip>
)}
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
Expand Down
Loading