Skip to content

Commit

Permalink
[Enterprise Search] Index Pipelines JSON Configurations (elastic#142609)
Browse files Browse the repository at this point in the history
* [Enterprise Search] pipelines json configs tab

Add the right panel with tabs for the Search Index  Pipelines page,
along with the JSON configurations tab. The index pipeliens get request
was already returning the index specific ingest pipelines so I added the
default pipeline to this result so we can get all the pipelines related
to an index with a single call.

* removed unnecessary listener

The modal is closed from the pipelines logic and this createApiSuccess
listener ended up being completely unnecessary.
  • Loading branch information
TattdCodeMonkey authored and WafaaNasr committed Oct 11, 2022
1 parent 87c3b8b commit 208e3e4
Show file tree
Hide file tree
Showing 9 changed files with 493 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,11 @@ import {
import { HttpError, Status } from '../../../../../../../common/types/api';
import { MlInferencePipeline } from '../../../../../../../common/types/pipelines';

import { generateEncodedPath } from '../../../../../shared/encode_path_params';
import { getErrorsFromHttpResponse } from '../../../../../shared/flash_messages/handle_api_errors';
import { KibanaLogic } from '../../../../../shared/kibana';
import { MappingsApiLogic } from '../../../../api/mappings/mappings_logic';
import { CreateMlInferencePipelineApiLogic } from '../../../../api/ml_models/create_ml_inference_pipeline';
import { MLModelsApiLogic } from '../../../../api/ml_models/ml_models_logic';

import { SEARCH_INDEX_TAB_PATH } from '../../../../routes';
import { SearchIndexTabId } from '../../search_index';

import { AddInferencePipelineFormErrors, InferencePipelineConfiguration } from './types';
import {
isSupportedMLModel,
Expand Down Expand Up @@ -126,14 +121,6 @@ export const MLInferenceLogic = kea<
},
events: {},
listeners: ({ values, actions }) => ({
createApiSuccess: () => {
KibanaLogic.values.navigateToUrl(
generateEncodedPath(SEARCH_INDEX_TAB_PATH, {
indexName: values.addInferencePipelineModal.indexName,
tabId: SearchIndexTabId.PIPELINES,
})
);
},
createPipeline: () => {
const {
addInferencePipelineModal: { configuration, indexName },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';

import { useValues } from 'kea';

import { EuiBadgeGroup, EuiBadge, EuiToolTip } from '@elastic/eui';

import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';

import { DEFAULT_PIPELINE_NAME } from '../../../../../../common/constants';

import { isManagedPipeline } from '../../../../shared/pipelines/is_managed';

import { IndexPipelinesConfigurationsLogic } from './pipelines_json_configurations_logic';

const ManagedPipelineBadge: React.FC = () => (
<EuiToolTip
position="top"
content={i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.managed.description',
{ defaultMessage: 'This pipeline is managed and cannot be edited' }
)}
>
<EuiBadge iconType="lock" color="warning">
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.managed',
{ defaultMessage: 'Managed' }
)}
</EuiBadge>
</EuiToolTip>
);

const UnmanagedPipelineBadge: React.FC = () => (
<EuiToolTip
position="top"
content={
<FormattedMessage
id="xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.unmanaged.description"
defaultMessage="Edit this pipeline from {ingestPipelines} in Stack Management"
values={{
ingestPipelines: (
<strong>
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.ingestPipelines',
{ defaultMessage: 'Ingest Pipelines' }
)}
</strong>
),
}}
/>
}
>
<EuiBadge iconType="lockOpen">
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.unmanaged',
{ defaultMessage: 'Unmanaged' }
)}
</EuiBadge>
</EuiToolTip>
);

const SharedPipelineBadge: React.FC = () => (
<EuiToolTip
position="top"
content={i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.shared.description',
{ defaultMessage: 'This pipeline is shared across all Enterprise Search ingestion methods' }
)}
>
<EuiBadge iconType="logstashIf" color="hollow">
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.shared',
{ defaultMessage: 'Shared' }
)}
</EuiBadge>
</EuiToolTip>
);

const IndexPipelineBadge: React.FC = () => (
<EuiToolTip
position="top"
content={i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.indexSpecific.description',
{ defaultMessage: 'This pipeline contains configurations specific to this index only' }
)}
>
<EuiBadge iconType="document" color="hollow">
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.indexSpecific',
{ defaultMessage: 'Index specific' }
)}
</EuiBadge>
</EuiToolTip>
);

const MlInferenceBadge: React.FC = () => (
<EuiToolTip
position="top"
content={i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.mlInference.description',
{
defaultMessage:
'This pipeline references one or more ML Inference Pipelines for this index',
}
)}
>
<EuiBadge iconType="compute" color="hollow">
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.mlInference',
{ defaultMessage: 'ML Inference' }
)}
</EuiBadge>
</EuiToolTip>
);

export const PipelineJSONBadges: React.FC = () => {
const {
indexName,
selectedPipeline: pipeline,
selectedPipelineId: pipelineName,
} = useValues(IndexPipelinesConfigurationsLogic);
if (!pipeline) {
return <></>;
}
const badges: JSX.Element[] = [];
if (isManagedPipeline(pipeline)) {
badges.push(<ManagedPipelineBadge />);
} else {
badges.push(<UnmanagedPipelineBadge />);
}
if (pipelineName === DEFAULT_PIPELINE_NAME) {
badges.push(<SharedPipelineBadge />);
}
if (pipelineName?.endsWith('@ml-inference')) {
badges.push(<MlInferenceBadge />);
} else if (pipelineName?.includes(indexName)) {
badges.push(<IndexPipelineBadge />);
}
return <EuiBadgeGroup gutterSize="s">{badges}</EuiBadgeGroup>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@ import React from 'react';

import { useActions, useValues } from 'kea';

import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiSpacer } from '@elastic/eui';
import {
EuiFlexGroup,
EuiFlexItem,
EuiLink,
EuiPanel,
EuiSpacer,
EuiTabbedContent,
EuiTabbedContentTab,
} from '@elastic/eui';

import { i18n } from '@kbn/i18n';

Expand All @@ -21,6 +29,7 @@ import { IngestPipelinesCard } from './ingest_pipelines_card';
import { AddMLInferencePipelineButton } from './ml_inference/add_ml_inference_button';
import { AddMLInferencePipelineModal } from './ml_inference/add_ml_inference_pipeline_modal';
import { MlInferencePipelineProcessorsCard } from './ml_inference_pipeline_processors_card';
import { PipelinesJSONConfigurations } from './pipelines_json_configurations';
import { PipelinesLogic } from './pipelines_logic';

export const SearchIndexPipelines: React.FC = () => {
Expand All @@ -34,6 +43,19 @@ export const SearchIndexPipelines: React.FC = () => {
useActions(PipelinesLogic);
const apiIndex = isApiIndex(index);

const pipelinesTabs: EuiTabbedContentTab[] = [
{
content: <PipelinesJSONConfigurations />,
id: 'json-configurations',
name: i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations',
{
defaultMessage: 'JSON configurations',
}
),
},
];

return (
<>
<EuiSpacer />
Expand Down Expand Up @@ -82,8 +104,7 @@ export const SearchIndexPipelines: React.FC = () => {
>
<IngestPipelinesCard />
</DataPanel>
</EuiFlexItem>
<EuiFlexItem grow={5}>
<EuiSpacer />
<DataPanel
hasBorder
footerDocLink={
Expand Down Expand Up @@ -134,6 +155,15 @@ export const SearchIndexPipelines: React.FC = () => {
<MlInferencePipelineProcessorsCard />
</DataPanel>
</EuiFlexItem>
<EuiFlexItem grow={5}>
<EuiPanel color="subdued">
<EuiTabbedContent
tabs={pipelinesTabs}
initialSelectedTab={pipelinesTabs[0]}
autoFocus="selected"
/>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
{showAddMlInferencePipelineModal && (
<AddMLInferencePipelineModal onClose={closeAddMlInferencePipelineModal} />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';

import { useActions, useValues } from 'kea';

import {
EuiButtonEmpty,
EuiCodeBlock,
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiLink,
EuiNotificationBadge,
EuiSelect,
EuiSpacer,
} from '@elastic/eui';

import { i18n } from '@kbn/i18n';

import { DataPanel } from '../../../../shared/data_panel/data_panel';
import { docLinks } from '../../../../shared/doc_links';
import { HttpLogic } from '../../../../shared/http';
import { isManagedPipeline } from '../../../../shared/pipelines/is_managed';

import { PipelineJSONBadges } from './pipeline_json_badges';
import { IndexPipelinesConfigurationsLogic } from './pipelines_json_configurations_logic';

export const PipelinesJSONConfigurations: React.FC = () => {
const { http } = useValues(HttpLogic);
const { pipelineNames, selectedPipeline, selectedPipelineId, selectedPipelineJSON } = useValues(
IndexPipelinesConfigurationsLogic
);
const { selectPipeline } = useActions(IndexPipelinesConfigurationsLogic);
return (
<>
<EuiSpacer />
<DataPanel
hasBorder
title={
<h2>
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.title',
{ defaultMessage: 'Pipeline configurations' }
)}
</h2>
}
subtitle={i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.subtitle',
{ defaultMessage: 'View the JSON for your pipeline configurations on this index.' }
)}
footerDocLink={
<EuiLink href={docLinks.ingestPipelines} target="_blank" color="subdued">
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.ingestionPipelines.docLink',
{
defaultMessage: 'Learn more about how Enterprise Search uses ingest pipelines',
}
)}
</EuiLink>
}
action={
pipelineNames.length > 0 && (
<EuiNotificationBadge size="m">{pipelineNames.length}</EuiNotificationBadge>
)
}
iconType="visVega"
>
<EuiFormRow
fullWidth
label={i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.selectLabel',
{ defaultMessage: 'Select an ingest pipeline to view' }
)}
>
<EuiSelect
fullWidth
options={pipelineNames.map((name) => ({ text: name, value: name }))}
value={selectedPipelineId}
onChange={(e) => selectPipeline(e.target.value)}
/>
</EuiFormRow>
<EuiSpacer size="m" />
{selectedPipeline && (
<>
<EuiFlexGroup alignItems="center">
<EuiFlexItem>
<PipelineJSONBadges />
</EuiFlexItem>
<EuiFlexItem grow={false}>
{isManagedPipeline(selectedPipeline) ? (
<EuiButtonEmpty
size="s"
flush="both"
iconType="eye"
color="primary"
href={http.basePath.prepend(
`/app/management/ingest/ingest_pipelines/?pipeline=${selectedPipelineId}`
)}
>
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.action.view',
{
defaultMessage: 'View in Stack Management',
}
)}
</EuiButtonEmpty>
) : (
<EuiButtonEmpty
size="s"
flush="both"
iconType="pencil"
color="primary"
href={http.basePath.prepend(
`/app/management/ingest/ingest_pipelines/edit/${selectedPipelineId}`
)}
>
{i18n.translate(
'xpack.enterpriseSearch.content.indices.pipelines.tabs.jsonConfigurations.action.edit',
{
defaultMessage: 'Edit in Stack Management',
}
)}
</EuiButtonEmpty>
)}
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="m" />
<EuiCodeBlock language="json" overflowHeight={300} isCopyable>
{selectedPipelineJSON}
</EuiCodeBlock>
</>
)}
</DataPanel>
</>
);
};
Loading

0 comments on commit 208e3e4

Please sign in to comment.