Skip to content

Commit 89c43f5

Browse files
Merge branch 'feature/ingest-node-pipelines' of github.com:elastic/kibana into ingest-pipelines/create-ui
2 parents 21a354f + 699ebef commit 89c43f5

File tree

9 files changed

+419
-78
lines changed

9 files changed

+419
-78
lines changed
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import React, { FunctionComponent } from 'react';
8+
import { i18n } from '@kbn/i18n';
9+
import {
10+
EuiFlyout,
11+
EuiFlyoutHeader,
12+
EuiFlyoutBody,
13+
EuiTitle,
14+
EuiDescriptionList,
15+
EuiSpacer,
16+
EuiFlyoutFooter,
17+
EuiFlexGroup,
18+
EuiFlexItem,
19+
EuiButtonEmpty,
20+
} from '@elastic/eui';
21+
import { Pipeline } from '../../../../common/types';
22+
23+
import { PipelineDetailsJsonBlock } from './details_json_block';
24+
25+
export interface Props {
26+
pipeline: Pipeline;
27+
onEditClick: () => void;
28+
onDeleteClick: () => void;
29+
onClose: () => void;
30+
}
31+
32+
export const PipelineDetails: FunctionComponent<Props> = ({
33+
pipeline,
34+
onClose,
35+
onEditClick,
36+
onDeleteClick,
37+
}) => {
38+
const descriptionListItems = [
39+
{
40+
title: i18n.translate('xpack.ingestPipelines.list.pipelineDetails.descriptionTitle', {
41+
defaultMessage: 'Description',
42+
}),
43+
description: pipeline.description ?? '',
44+
},
45+
];
46+
47+
if (pipeline.version) {
48+
descriptionListItems.push({
49+
title: i18n.translate('xpack.ingestPipelines.list.pipelineDetails.versionTitle', {
50+
defaultMessage: 'Version',
51+
}),
52+
description: String(pipeline.version),
53+
});
54+
}
55+
56+
return (
57+
<EuiFlyout
58+
onClose={onClose}
59+
aria-labelledby="pipelineDetailsFlyoutTitle"
60+
size="m"
61+
maxWidth={550}
62+
>
63+
<EuiFlyoutHeader>
64+
<EuiTitle id="pipelineDetailsFlyoutTitle">
65+
<h2>{pipeline.name}</h2>
66+
</EuiTitle>
67+
</EuiFlyoutHeader>
68+
69+
<EuiFlyoutBody>
70+
<EuiDescriptionList listItems={descriptionListItems} />
71+
72+
<EuiSpacer size="m" />
73+
74+
<PipelineDetailsJsonBlock
75+
htmlForId="pipelineDetailsProcessorsJson"
76+
label={i18n.translate('xpack.ingestPipelines.list.pipelineDetails.processorsTitle', {
77+
defaultMessage: 'Processors JSON',
78+
})}
79+
json={pipeline.processors}
80+
/>
81+
82+
{/* On Failure Processor JSON */}
83+
{pipeline.onFailure?.length && (
84+
<>
85+
<EuiSpacer size="m" />
86+
<PipelineDetailsJsonBlock
87+
htmlForId="pipelineDetailsOnFailureProcessorsJson"
88+
label={i18n.translate(
89+
'xpack.ingestPipelines.list.pipelineDetails.failureProcessorsTitle',
90+
{
91+
defaultMessage: 'On failure processors JSON',
92+
}
93+
)}
94+
json={pipeline.onFailure}
95+
/>
96+
</>
97+
)}
98+
{/* End On Failure Processor JSON */}
99+
</EuiFlyoutBody>
100+
101+
<EuiFlyoutFooter>
102+
<EuiFlexGroup justifyContent="spaceBetween">
103+
<EuiFlexItem grow={false}>
104+
<EuiButtonEmpty iconType="cross" onClick={onClose} flush="left">
105+
{i18n.translate('xpack.ingestPipelines.list.pipelineDetails.closeButtonLabel', {
106+
defaultMessage: 'Close',
107+
})}
108+
</EuiButtonEmpty>
109+
</EuiFlexItem>
110+
<EuiFlexGroup gutterSize="none" alignItems="center" justifyContent="flexEnd">
111+
<EuiFlexItem grow={false}>
112+
<EuiButtonEmpty onClick={onEditClick}>
113+
{i18n.translate('xpack.ingestPipelines.list.pipelineDetails.editButtonLabel', {
114+
defaultMessage: 'Edit',
115+
})}
116+
</EuiButtonEmpty>
117+
</EuiFlexItem>
118+
<EuiFlexItem grow={false}>
119+
<EuiButtonEmpty color="danger" onClick={onDeleteClick}>
120+
{i18n.translate('xpack.ingestPipelines.list.pipelineDetails.deleteButtonLabel', {
121+
defaultMessage: 'Delete',
122+
})}
123+
</EuiButtonEmpty>
124+
</EuiFlexItem>
125+
</EuiFlexGroup>
126+
</EuiFlexGroup>
127+
</EuiFlyoutFooter>
128+
</EuiFlyout>
129+
);
130+
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import React, { FunctionComponent } from 'react';
8+
import { EuiCodeBlock, EuiText } from '@elastic/eui';
9+
10+
export interface Props {
11+
htmlForId: string;
12+
label: string;
13+
json: Record<string, any>;
14+
}
15+
16+
export const PipelineDetailsJsonBlock: FunctionComponent<Props> = ({ label, htmlForId, json }) => (
17+
<>
18+
<EuiText size="s">
19+
<label htmlFor={htmlForId}>
20+
<b>{label}</b>
21+
</label>
22+
</EuiText>
23+
<EuiCodeBlock paddingSize="s" id={htmlForId} language="json" overflowHeight={200} isCopyable>
24+
{JSON.stringify(json, null, 2)}
25+
</EuiCodeBlock>
26+
</>
27+
);
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
import React, { FunctionComponent } from 'react';
7+
import { i18n } from '@kbn/i18n';
8+
import { EuiButton, EuiEmptyPrompt } from '@elastic/eui';
9+
10+
interface Props {
11+
onClick: () => void;
12+
}
13+
14+
export const EmptyList: FunctionComponent<Props> = ({ onClick }) => (
15+
<EuiEmptyPrompt
16+
iconType="managementApp"
17+
title={
18+
<h2>
19+
{i18n.translate('xpack.ingestPipelines.list.table.emptyPromptTitle', {
20+
defaultMessage: 'Create your first pipeline',
21+
})}
22+
</h2>
23+
}
24+
actions={
25+
<EuiButton onClick={onClick}>
26+
{i18n.translate('xpack.ingestPipelines.list.table.emptyPrompt.createButtonLabel', {
27+
defaultMessage: 'Create pipeline',
28+
})}
29+
</EuiButton>
30+
}
31+
/>
32+
);

x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
export { PipelinesList } from './pipelines_list';
7+
export { PipelinesList } from './main';
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import React, { useEffect, useState } from 'react';
8+
import { i18n } from '@kbn/i18n';
9+
import { FormattedMessage } from '@kbn/i18n/react';
10+
11+
import {
12+
EuiPageBody,
13+
EuiPageContent,
14+
EuiTitle,
15+
EuiFlexGroup,
16+
EuiFlexItem,
17+
EuiButtonEmpty,
18+
EuiCallOut,
19+
} from '@elastic/eui';
20+
21+
import { EuiSpacer, EuiText } from '@elastic/eui';
22+
23+
import { Pipeline } from '../../../../common/types';
24+
import { useKibana, SectionLoading } from '../../../shared_imports';
25+
import { UIM_PIPELINES_LIST_LOAD } from '../../constants';
26+
27+
import { EmptyList } from './empty_list';
28+
import { PipelineTable } from './table';
29+
import { PipelineDetails } from './details';
30+
31+
export const PipelinesList: React.FunctionComponent = () => {
32+
const { services } = useKibana();
33+
34+
const [selectedPipeline, setSelectedPipeline] = useState<Pipeline | undefined>(undefined);
35+
36+
// Track component loaded
37+
useEffect(() => {
38+
services.metric.trackUiMetric(UIM_PIPELINES_LIST_LOAD);
39+
services.breadcrumbs.setBreadcrumbs('home');
40+
}, [services.metric, services.breadcrumb, services.breadcrumbs]);
41+
42+
const { data, isLoading, error, sendRequest } = services.api.useLoadPipelines();
43+
44+
let content: React.ReactNode;
45+
46+
if (isLoading) {
47+
content = (
48+
<SectionLoading>
49+
<FormattedMessage
50+
id="xpack.ingestPipelines.list.loadingMessage"
51+
defaultMessage="Loading pipelines..."
52+
/>
53+
</SectionLoading>
54+
);
55+
} else if (data?.length) {
56+
content = (
57+
<PipelineTable
58+
onReloadClick={() => {
59+
sendRequest();
60+
}}
61+
onEditPipelineClick={() => {}}
62+
onDeletePipelineClick={() => {}}
63+
onViewPipelineClick={setSelectedPipeline}
64+
pipelines={data}
65+
/>
66+
);
67+
} else {
68+
content = <EmptyList onClick={() => {}} />;
69+
}
70+
71+
return (
72+
<>
73+
<EuiPageBody>
74+
<EuiPageContent>
75+
<EuiTitle size="l">
76+
<EuiFlexGroup alignItems="center">
77+
<EuiFlexItem>
78+
<h1 data-test-subj="appTitle">
79+
<FormattedMessage
80+
id="xpack.ingestPipelines.list.listTitle"
81+
defaultMessage="Ingest Pipelines"
82+
/>
83+
</h1>
84+
</EuiFlexItem>
85+
<EuiFlexItem grow={false}>
86+
<EuiButtonEmpty
87+
href={services.documentation.getIngestNodeUrl()}
88+
target="_blank"
89+
iconType="help"
90+
>
91+
<FormattedMessage
92+
id="xpack.ingestPipelines.list.pipelinesDocsLinkText"
93+
defaultMessage="Ingest Pipelines docs"
94+
/>
95+
</EuiButtonEmpty>
96+
</EuiFlexItem>
97+
</EuiFlexGroup>
98+
</EuiTitle>
99+
<EuiSpacer size="s" />
100+
<EuiTitle size="s">
101+
<EuiText color="subdued">
102+
<FormattedMessage
103+
id="xpack.ingestPipelines.list.pipelinesDescription"
104+
defaultMessage="Use ingest node pipelines to pre-process documents before indexing."
105+
/>
106+
</EuiText>
107+
</EuiTitle>
108+
<EuiSpacer size="m" />
109+
{/* Error call out or pipeline table */}
110+
{error ? (
111+
<EuiCallOut
112+
iconType="faceSad"
113+
color="danger"
114+
title={i18n.translate('xpack.ingestPipelines.list.loadErrorTitle', {
115+
defaultMessage: 'Cannot load pipelines, please refresh the page to try again.',
116+
})}
117+
/>
118+
) : (
119+
content
120+
)}
121+
</EuiPageContent>
122+
</EuiPageBody>
123+
{selectedPipeline && (
124+
<PipelineDetails
125+
pipeline={selectedPipeline}
126+
onClose={() => setSelectedPipeline(undefined)}
127+
onDeleteClick={() => {}}
128+
onEditClick={() => {}}
129+
/>
130+
)}
131+
</>
132+
);
133+
};

0 commit comments

Comments
 (0)