Skip to content

Commit

Permalink
Merge branch 'feature/ingest-node-pipelines' of github.com:elastic/ki…
Browse files Browse the repository at this point in the history
…bana into ingest-node-pipelines/privileges

* 'feature/ingest-node-pipelines' of github.com:elastic/kibana:
  [Ingest Node Pipelines] Clone Pipeline (#64049)

# Conflicts:
#	x-pack/plugins/ingest_pipelines/public/application/app.tsx
  • Loading branch information
jloleysens committed Apr 22, 2020
2 parents 98b16e1 + 34cb91a commit a04a980
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 16 deletions.
3 changes: 2 additions & 1 deletion x-pack/plugins/ingest_pipelines/public/application/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ import {
NotAuthorizedSection,
} from '../shared_imports';

import { PipelinesList, PipelinesCreate, PipelinesEdit } from './sections';
import { PipelinesList, PipelinesCreate, PipelinesEdit, PipelinesClone } from './sections';

export const AppWithoutRouter = () => (
<Switch>
<Route exact path={BASE_PATH} component={PipelinesList} />
<Route exact path={`${BASE_PATH}/create/:sourceName`} component={PipelinesClone} />
<Route exact path={`${BASE_PATH}/create`} component={PipelinesCreate} />
<Route exact path={`${BASE_PATH}/edit/:name`} component={PipelinesEdit} />
</Switch>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ export { PipelinesList } from './pipelines_list';
export { PipelinesCreate } from './pipelines_create';

export { PipelinesEdit } from './pipelines_edit';

export { PipelinesClone } from './pipelines_clone';
Original file line number Diff line number Diff line change
@@ -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 { PipelinesClone } from './pipelines_clone';
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* 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, useEffect } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';

import { SectionLoading, useKibana } from '../../../shared_imports';

import { PipelinesCreate } from '../pipelines_create';

export interface ParamProps {
sourceName: string;
}

/**
* This section is a wrapper around the create section where we receive a pipeline name
* to load and set as the source pipeline for the {@link PipelinesCreate} form.
*/
export const PipelinesClone: FunctionComponent<RouteComponentProps<ParamProps>> = props => {
const { sourceName } = props.match.params;
const { services } = useKibana();

const { error, data: pipeline, isLoading, isInitialRequest } = services.api.useLoadPipeline(
decodeURIComponent(sourceName)
);

useEffect(() => {
if (error && !isLoading) {
services.notifications!.toasts.addError(error, {
title: i18n.translate('xpack.ingestPipelines.clone.loadSourcePipelineErrorTitle', {
defaultMessage: 'Cannot load {name}.',
values: { name: sourceName },
}),
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [error, isLoading]);

if (isLoading && isInitialRequest) {
return (
<SectionLoading>
<FormattedMessage
id="xpack.ingestPipelines.clone.loadingPipelinesDescription"
defaultMessage="Loading pipeline…"
/>
</SectionLoading>
);
} else {
// We still show the create form even if we were not able to load the
// latest pipeline data.
const sourcePipeline = pipeline ? { ...pipeline, name: `${pipeline.name}-copy` } : undefined;
return <PipelinesCreate {...props} sourcePipeline={sourcePipeline} />;
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,17 @@ import { Pipeline } from '../../../../common/types';
import { useKibana } from '../../../shared_imports';
import { PipelineForm } from '../../components';

export const PipelinesCreate: React.FunctionComponent<RouteComponentProps> = ({ history }) => {
interface Props {
/**
* This value may be passed in to prepopulate the creation form
*/
sourcePipeline?: Pipeline;
}

export const PipelinesCreate: React.FunctionComponent<RouteComponentProps & Props> = ({
history,
sourcePipeline,
}) => {
const { services } = useKibana();

const [isSaving, setIsSaving] = useState<boolean>(false);
Expand Down Expand Up @@ -87,6 +97,7 @@ export const PipelinesCreate: React.FunctionComponent<RouteComponentProps> = ({
<EuiSpacer size="l" />

<PipelineForm
defaultValue={sourcePipeline}
onSave={onSave}
onCancel={onCancel}
isSaving={isSaving}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { FunctionComponent } from 'react';
import React, { FunctionComponent, useState } from 'react';
import { i18n } from '@kbn/i18n';
import {
EuiFlyout,
Expand All @@ -18,14 +18,20 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiButtonEmpty,
EuiIcon,
EuiPopover,
EuiContextMenu,
EuiButton,
} from '@elastic/eui';

import { Pipeline } from '../../../../common/types';

import { PipelineDetailsJsonBlock } from './details_json_block';

export interface Props {
pipeline: Pipeline;
onEditClick: (pipelineName: string) => void;
onCloneClick: (pipelineName: string) => void;
onDeleteClick: (pipelineName: string[]) => void;
onClose: () => void;
}
Expand All @@ -34,8 +40,63 @@ export const PipelineDetails: FunctionComponent<Props> = ({
pipeline,
onClose,
onEditClick,
onCloneClick,
onDeleteClick,
}) => {
const [showPopover, setShowPopover] = useState(false);
const actionMenuItems = [
/**
* Edit pipeline
*/
{
name: i18n.translate('xpack.ingestPipelines.list.pipelineDetails.editActionLabel', {
defaultMessage: 'Edit',
}),
icon: <EuiIcon type="pencil" />,
onClick: () => onEditClick(pipeline.name),
},
/**
* Clone pipeline
*/
{
name: i18n.translate('xpack.ingestPipelines.list.pipelineDetails.cloneActionLabel', {
defaultMessage: 'Clone',
}),
icon: <EuiIcon type="copy" />,
onClick: () => onCloneClick(pipeline.name),
},
/**
* Delete pipeline
*/
{
name: i18n.translate('xpack.ingestPipelines.list.pipelineDetails.deleteActionLabel', {
defaultMessage: 'Delete',
}),
icon: <EuiIcon type="trash" />,
onClick: () => onDeleteClick([pipeline.name]),
},
];

const managePipelineButton = (
<EuiButton
data-test-subj="managePipelineButton"
aria-label={i18n.translate(
'xpack.ingestPipelines.list.pipelineDetails.managePipelineActionsAriaLabel',
{
defaultMessage: 'Manage pipeline',
}
)}
onClick={() => setShowPopover(previousBool => !previousBool)}
iconType="arrowUp"
iconSide="right"
fill
>
{i18n.translate('xpack.ingestPipelines.list.pipelineDetails.managePipelineButtonLabel', {
defaultMessage: 'Manage',
})}
</EuiButton>
);

return (
<EuiFlyout
onClose={onClose}
Expand Down Expand Up @@ -115,18 +176,31 @@ export const PipelineDetails: FunctionComponent<Props> = ({
</EuiFlexItem>
<EuiFlexGroup gutterSize="none" alignItems="center" justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={() => onEditClick(pipeline.name)}>
{i18n.translate('xpack.ingestPipelines.list.pipelineDetails.editButtonLabel', {
defaultMessage: 'Edit',
})}
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty color="danger" onClick={() => onDeleteClick([pipeline.name])}>
{i18n.translate('xpack.ingestPipelines.list.pipelineDetails.deleteButtonLabel', {
defaultMessage: 'Delete',
})}
</EuiButtonEmpty>
<EuiPopover
isOpen={showPopover}
closePopover={() => setShowPopover(false)}
button={managePipelineButton}
panelPaddingSize="none"
withTitle
repositionOnScroll
>
<EuiContextMenu
initialPanelId={0}
data-test-subj="autoFollowPatternActionContextMenu"
panels={[
{
id: 0,
title: i18n.translate(
'xpack.ingestPipelines.list.pipelineDetails.managePipelinePanelTitle',
{
defaultMessage: 'Pipeline options',
}
),
items: actionMenuItems,
},
]}
/>
</EuiPopover>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ export const PipelinesList: React.FunctionComponent<RouteComponentProps> = ({ hi
history.push(encodeURI(`${BASE_PATH}/edit/${encodeURIComponent(name)}`));
};

const clonePipeline = (name: string) => {
history.push(encodeURI(`${BASE_PATH}/create/${encodeURIComponent(name)}`));
};

if (isLoading) {
content = (
<SectionLoading>
Expand All @@ -66,6 +70,7 @@ export const PipelinesList: React.FunctionComponent<RouteComponentProps> = ({ hi
onReloadClick={sendRequest}
onEditPipelineClick={editPipeline}
onDeletePipelineClick={setPipelinesToDelete}
onClonePipelineClick={clonePipeline}
onViewPipelineClick={setSelectedPipeline}
pipelines={data}
/>
Expand Down Expand Up @@ -130,8 +135,9 @@ export const PipelinesList: React.FunctionComponent<RouteComponentProps> = ({ hi
<PipelineDetails
pipeline={selectedPipeline}
onClose={() => setSelectedPipeline(undefined)}
onDeleteClick={setPipelinesToDelete}
onEditClick={editPipeline}
onCloneClick={clonePipeline}
onDeleteClick={setPipelinesToDelete}
/>
)}
{pipelinesToDelete?.length > 0 ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface Props {
pipelines: Pipeline[];
onReloadClick: () => void;
onEditPipelineClick: (pipelineName: string) => void;
onClonePipelineClick: (pipelineName: string) => void;
onDeletePipelineClick: (pipelineName: string[]) => void;
onViewPipelineClick: (pipeline: Pipeline) => void;
}
Expand All @@ -23,6 +24,7 @@ export const PipelineTable: FunctionComponent<Props> = ({
pipelines,
onReloadClick,
onEditPipelineClick,
onClonePipelineClick,
onDeletePipelineClick,
onViewPipelineClick,
}) => {
Expand All @@ -32,6 +34,7 @@ export const PipelineTable: FunctionComponent<Props> = ({
<EuiInMemoryTable
itemId="name"
isSelectable
sorting={{ sort: { field: 'name', direction: 'asc' } }}
selection={{
onSelectionChange: setSelection,
}}
Expand Down Expand Up @@ -90,6 +93,7 @@ export const PipelineTable: FunctionComponent<Props> = ({
name: i18n.translate('xpack.ingestPipelines.list.table.nameColumnTitle', {
defaultMessage: 'Name',
}),
sortable: true,
render: (name: string, pipeline) => (
<EuiLink onClick={() => onViewPipelineClick(pipeline)}>{name}</EuiLink>
),
Expand All @@ -100,6 +104,7 @@ export const PipelineTable: FunctionComponent<Props> = ({
}),
actions: [
{
isPrimary: true,
name: i18n.translate('xpack.ingestPipelines.list.table.editActionLabel', {
defaultMessage: 'Edit',
}),
Expand All @@ -112,6 +117,19 @@ export const PipelineTable: FunctionComponent<Props> = ({
onClick: ({ name }) => onEditPipelineClick(name),
},
{
name: i18n.translate('xpack.ingestPipelines.list.table.cloneActionLabel', {
defaultMessage: 'Clone',
}),
description: i18n.translate(
'xpack.ingestPipelines.list.table.cloneActionDescription',
{ defaultMessage: 'Clone this pipeline' }
),
type: 'icon',
icon: 'copy',
onClick: ({ name }) => onClonePipelineClick(name),
},
{
isPrimary: true,
name: i18n.translate('xpack.ingestPipelines.list.table.deleteActionLabel', {
defaultMessage: 'Delete',
}),
Expand Down

0 comments on commit a04a980

Please sign in to comment.