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

List pipelines #62785

Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* 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 { i18n } from '@kbn/i18n';
import {
EuiFlyout,
EuiFlyoutHeader,
EuiFlyoutBody,
EuiTitle,
EuiDescriptionList,
EuiSpacer,
EuiFlyoutFooter,
EuiFlexGroup,
EuiFlexItem,
EuiButtonEmpty,
} from '@elastic/eui';
import { Pipeline } from '../../../../common/types';

import { PipelineDetailsJsonBlock } from './details_json_block';

export interface Props {
pipeline: Pipeline;
onEditClick: () => void;
onDeleteClick: () => void;
onClose: () => void;
}

export const PipelineDetails: FunctionComponent<Props> = ({
pipeline,
onClose,
onEditClick,
onDeleteClick,
}) => {
const descriptionListItems = [
{
title: i18n.translate('xpack.ingestPipelines.list.pipelineDetails.descriptionTitle', {
defaultMessage: 'Description',
}),
description: pipeline.description ?? '',
},
];

if (pipeline.version) {
descriptionListItems.push({
title: i18n.translate('xpack.ingestPipelines.list.pipelineDetails.versionTitle', {
defaultMessage: 'Version',
}),
description: String(pipeline.version),
});
}

return (
<EuiFlyout
onClose={onClose}
aria-labelledby="pipelineDetailsFlyoutTitle"
size="m"
maxWidth={550}
>
<EuiFlyoutHeader>
<EuiTitle id="pipelineDetailsFlyoutTitle">
<h2>{pipeline.name}</h2>
</EuiTitle>
</EuiFlyoutHeader>

<EuiFlyoutBody>
<EuiDescriptionList listItems={descriptionListItems} />

<EuiSpacer size="m" />

<PipelineDetailsJsonBlock
htmlForId="pipelineDetailsProcessorsJson"
label={i18n.translate('xpack.ingestPipelines.list.pipelineDetails.processorsTitle', {
defaultMessage: 'Processors JSON',
})}
json={pipeline.processors}
/>

{/* On Failure Processor JSON */}
{pipeline.onFailure?.length && (
<>
<EuiSpacer size="m" />
<PipelineDetailsJsonBlock
htmlForId="pipelineDetailsOnFailureProcessorsJson"
label={i18n.translate(
'xpack.ingestPipelines.list.pipelineDetails.failureProcessorsTitle',
{
defaultMessage: 'On failure processors JSON',
}
)}
json={pipeline.onFailure}
/>
</>
)}
{/* End On Failure Processor JSON */}
</EuiFlyoutBody>

<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiButtonEmpty iconType="cross" onClick={onClose} flush="left">
{i18n.translate('xpack.ingestPipelines.list.pipelineDetails.closeButtonLabel', {
defaultMessage: 'Close',
})}
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexGroup gutterSize="none" alignItems="center" justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={onEditClick}>
{i18n.translate('xpack.ingestPipelines.list.pipelineDetails.editButtonLabel', {
defaultMessage: 'Edit',
})}
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty color="danger" onClick={onDeleteClick}>
{i18n.translate('xpack.ingestPipelines.list.pipelineDetails.deleteButtonLabel', {
defaultMessage: 'Delete',
})}
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexGroup>
</EuiFlyoutFooter>
</EuiFlyout>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* 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 { EuiCodeBlock, EuiText } from '@elastic/eui';

export interface Props {
htmlForId: string;
label: string;
json: Record<string, any>;
}

export const PipelineDetailsJsonBlock: FunctionComponent<Props> = ({ label, htmlForId, json }) => (
<>
<EuiText size="s">
<label htmlFor={htmlForId}>
<b>{label}</b>
</label>
</EuiText>
<EuiCodeBlock paddingSize="s" id={htmlForId} language="json" overflowHeight={200} isCopyable>
{JSON.stringify(json, null, 2)}
</EuiCodeBlock>
</>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { EuiButton, EuiEmptyPrompt } from '@elastic/eui';

interface Props {
onClick: () => void;
}

export const EmptyList: FunctionComponent<Props> = ({ onClick }) => (
<EuiEmptyPrompt
iconType="managementApp"
title={
<h2>
{i18n.translate('xpack.ingestPipelines.list.table.emptyPromptTitle', {
defaultMessage: 'Create your first pipeline',
})}
</h2>
}
actions={
<EuiButton onClick={onClick}>
{i18n.translate('xpack.ingestPipelines.list.table.emptyPrompt.createButtonLabel', {
defaultMessage: 'Create pipeline',
})}
</EuiButton>
}
/>
);
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/

export { PipelinesList } from './pipelines_list';
export { PipelinesList } from './main';
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* 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, { useEffect, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';

import {
EuiPageBody,
EuiPageContent,
EuiTitle,
EuiFlexGroup,
EuiFlexItem,
EuiButtonEmpty,
EuiCallOut,
} from '@elastic/eui';

import { EuiSpacer, EuiText } from '@elastic/eui';

import { Pipeline } from '../../../../common/types';
import { useKibana, SectionLoading } from '../../../shared_imports';
import { UIM_PIPELINES_LIST_LOAD } from '../../constants';

import { EmptyList } from './empty_list';
import { PipelineTable } from './table';
import { PipelineDetails } from './details';

export const PipelinesList: React.FunctionComponent = () => {
const { services } = useKibana();

const [selectedPipeline, setSelectedPipeline] = useState<Pipeline | undefined>(undefined);

// Track component loaded
useEffect(() => {
services.metric.trackUiMetric(UIM_PIPELINES_LIST_LOAD);
}, [services.metric]);

const { data, isLoading, error, sendRequest } = services.api.useLoadPipelines();

let content: React.ReactNode;

if (isLoading) {
content = (
<SectionLoading>
<FormattedMessage
id="xpack.ingestPipelines.list.loadingMessage"
defaultMessage="Loading pipelines..."
/>
</SectionLoading>
);
} else if (data?.length) {
content = (
<PipelineTable
onReloadClick={() => {
sendRequest();
}}
onEditPipelineClick={() => {}}
onDeletePipelineClick={() => {}}
onViewPipelineClick={setSelectedPipeline}
pipelines={data}
/>
);
} else {
content = <EmptyList onClick={() => {}} />;
}

return (
<>
<EuiPageBody>
<EuiPageContent>
<EuiTitle size="l">
<EuiFlexGroup alignItems="center">
<EuiFlexItem>
<h1 data-test-subj="appTitle">
<FormattedMessage
id="xpack.ingestPipelines.list.listTitle"
defaultMessage="Ingest Pipelines"
/>
</h1>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
href={services.documentation.getIngestNodeUrl()}
target="_blank"
iconType="help"
>
<FormattedMessage
id="xpack.ingestPipelines.list.pipelinesDocsLinkText"
defaultMessage="Ingest Pipelines docs"
/>
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiTitle>
<EuiSpacer size="s" />
<EuiTitle size="s">
<EuiText color="subdued">
<FormattedMessage
id="xpack.ingestPipelines.list.pipelinesDescription"
defaultMessage="Use ingest node pipelines to pre-process documents before indexing."
/>
</EuiText>
</EuiTitle>
<EuiSpacer size="m" />
{/* Error call out or pipeline table */}
{error ? (
<EuiCallOut
iconType="faceSad"
color="danger"
title={i18n.translate('xpack.ingestPipelines.list.loadErrorTitle', {
defaultMessage: 'Cannot load pipelines, please refresh the page to try again.',
})}
/>
) : (
content
)}
</EuiPageContent>
</EuiPageBody>
{selectedPipeline && (
<PipelineDetails
pipeline={selectedPipeline}
onClose={() => setSelectedPipeline(undefined)}
onDeleteClick={() => {}}
onEditClick={() => {}}
/>
)}
</>
);
};
Loading