Skip to content

Commit

Permalink
[Ingest Pipelines] Highlight deprecated pipelines (elastic#174814)
Browse files Browse the repository at this point in the history
Partially addresses elastic#170805

## Summary

With elastic/elasticsearch#101148 we now can
alert the users when an ingest pipeline will soon be deprecated and
shouldnt be relied upon. This PR adds a badge and a callout to the
ingest pipelines UI to alert the users about this.

##### How to test

* Start up kibana and es
* Navigate to Stack management -> Ingest pipelines
* Verify that:
  * Deprecated pipelines are hidden by default
* Upon enabling filtering to see them they should pop up on the table
with a badge
* Verify that deprecated policies are highlighted and when editing, we
also show a warning callout.

### Screenshot 
<img width="1386" alt="Screenshot 2024-02-05 at 16 02 18"
src="https://github.com/elastic/kibana/assets/6585477/739d6fea-5f15-4da4-aee8-cae8f412a040">

---------

Co-authored-by: Kibana Machine <[email protected]>
Co-authored-by: Yulia Čech <[email protected]>
Co-authored-by: Yulia Cech <[email protected]>
  • Loading branch information
4 people authored and fkanout committed Feb 7, 2024
1 parent d3be891 commit 36a9596
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export type PipelineFormTestSubjects =
| 'showRequestLink'
| 'apiRequestFlyout'
| 'apiRequestFlyout.apiRequestFlyoutTitle'
| 'deprecatedPipelineCallout'
| 'testPipelineFlyout'
| 'testPipelineFlyout.title'
| 'documentationLink';
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type PipelinesEditTestBed = TestBed<PipelineFormTestSubjects> & {
export const PIPELINE_TO_EDIT = {
name: 'my_pipeline',
description: 'pipeline description',
deprecated: true,
processors: [
{
set: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import { omit } from 'lodash';
import { act } from 'react-dom/test-utils';

import { setupEnvironment, pageHelpers } from './helpers';
Expand Down Expand Up @@ -47,6 +48,12 @@ describe('<PipelinesEdit />', () => {
expect(nameInput.props().disabled).toEqual(true);
});

it('should show deprecated callout', () => {
const { exists } = testBed;

expect(exists('deprecatedPipelineCallout')).toBe(true);
});

describe('form submission', () => {
it('should send the correct payload with changed values', async () => {
const UPDATED_DESCRIPTION = 'updated pipeline description';
Expand All @@ -62,7 +69,7 @@ describe('<PipelinesEdit />', () => {
`${API_BASE_PATH}/${name}`,
expect.objectContaining({
body: JSON.stringify({
...pipelineDefinition,
...omit(pipelineDefinition, 'deprecated'),
description: UPDATED_DESCRIPTION,
}),
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { API_BASE_PATH } from '../../common/constants';

import { setupEnvironment, pageHelpers } from './helpers';
import { PipelineListTestBed } from './helpers/pipelines_list.helpers';
import { Pipeline } from '../../common/types';

const { setup } = pageHelpers.pipelinesList;

Expand Down Expand Up @@ -39,7 +40,14 @@ describe('<PipelinesList />', () => {
processors: [],
};

const pipelines = [pipeline1, pipeline2];
const pipeline3 = {
name: 'test_pipeline3',
description: 'test_pipeline3 description',
processors: [],
deprecated: true,
};

const pipelines = [pipeline1, pipeline2, pipeline3];

httpRequestsMockHelpers.setLoadPipelinesResponse(pipelines);

Expand All @@ -66,6 +74,30 @@ describe('<PipelinesList />', () => {
});
});

test('deprecated pipelines are hidden by default', async () => {
const { table, component } = testBed;
const { tableCellsValues } = table.getMetaData('pipelinesTable');

// Table should shouldnt show any deprecated pipelines by default
const pipelinesWithoutDeprecated = pipelines.filter(
(pipeline: Pipeline) => !pipeline?.deprecated
);
expect(tableCellsValues.length).toEqual(pipelinesWithoutDeprecated.length);

// Enable filtering by deprecated pipelines
const searchInput = component.find('.euiFieldSearch').first();
(searchInput.instance() as unknown as HTMLInputElement).value = 'is:deprecated';
searchInput.simulate('keyup', { key: 'Enter', keyCode: 13, which: 13 });
component.update();

// Table should now show only deprecated pipelines
const { tableCellsValues: tableCellValuesUpdated } = table.getMetaData('pipelinesTable');
const pipelinesWithDeprecated = pipelines.filter(
(pipeline: Pipeline) => pipeline?.deprecated
);
expect(tableCellValuesUpdated.length).toEqual(pipelinesWithDeprecated.length);
});

test('should reload the pipeline data', async () => {
const { actions } = testBed;

Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/ingest_pipelines/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface Pipeline {
_meta?: { [key: string]: any };
on_failure?: Processor[];
isManaged?: boolean;
deprecated?: boolean;
}

export interface PipelinesByName {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,25 @@ const ManagedPipelineCallout = () => (
</EuiCallOut>
);

const DeprecatedPipelineCallout = () => (
<EuiCallOut
color="warning"
iconType="warning"
data-test-subj="deprecatedPipelineCallout"
title={
<FormattedMessage
id="xpack.ingestPipelines.edit.deprecatedCalloutTitle"
defaultMessage="This pipeline is deprecated"
/>
}
>
<FormattedMessage
id="xpack.ingestPipelines.edit.deprecatedCalloutDescription"
defaultMessage="This pipeline is no longer supported and might be removed in a future release. Instead, use one of the other pipelines available or create a new one."
/>
</EuiCallOut>
);

export const PipelinesEdit: React.FunctionComponent<RouteComponentProps<MatchParams>> = ({
match: {
params: { name },
Expand Down Expand Up @@ -167,6 +186,12 @@ export const PipelinesEdit: React.FunctionComponent<RouteComponentProps<MatchPar
<EuiSpacer size="l" />
</>
)}
{pipeline?.deprecated && (
<>
<DeprecatedPipelineCallout />
<EuiSpacer size="l" />
</>
)}

<PipelineForm
onSave={onSave}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ import {
EuiButton,
EuiBadge,
EuiCodeBlock,
EuiToolTip,
} from '@elastic/eui';

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

import { deprecatedPipelineBadge } from './table';
import { PipelineDetailsJsonBlock } from './details_json_block';
import { stringifyJson } from '../../lib/utils';

Expand Down Expand Up @@ -120,6 +122,16 @@ export const PipelineDetailsFlyout: FunctionComponent<Props> = ({
<h2>{pipeline.name}</h2>
</EuiTitle>
</EuiFlexItem>
{pipeline.deprecated ? (
<EuiFlexItem grow={false}>
{' '}
<EuiToolTip content={deprecatedPipelineBadge.badgeTooltip}>
<EuiBadge color="warning" data-test-subj="isDeprecatedBadge">
{deprecatedPipelineBadge.badge}
</EuiBadge>
</EuiToolTip>
</EuiFlexItem>
) : null}
{pipeline.isManaged ? (
<EuiFlexItem grow={false}>
{' '}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import React, { FunctionComponent, useState } from 'react';
import React, { FunctionComponent, useState, useMemo } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {
Expand All @@ -17,6 +17,11 @@ import {
EuiPopover,
EuiContextMenu,
EuiBadge,
EuiToolTip,
EuiFilterGroup,
EuiSelectable,
EuiFilterButton,
EuiSelectableOption,
} from '@elastic/eui';
import { reactRouterNavigate } from '@kbn/kibana-react-plugin/public';

Expand All @@ -31,13 +36,38 @@ export interface Props {
onDeletePipelineClick: (pipelineName: string[]) => void;
}

export const deprecatedPipelineBadge = {
badge: i18n.translate('xpack.ingestPipelines.list.table.deprecatedBadgeLabel', {
defaultMessage: 'Deprecated',
}),
badgeTooltip: i18n.translate('xpack.ingestPipelines.list.table.deprecatedBadgeTooltip', {
defaultMessage:
'This pipeline is no longer supported and might be removed in a future release. Instead, use one of the other pipelines available or create a new one.',
}),
};

const deprecatedFilterLabel = i18n.translate(
'xpack.ingestPipelines.list.table.deprecatedFilterLabel',
{
defaultMessage: 'Deprecated',
}
);

const managedFilterLabel = i18n.translate('xpack.ingestPipelines.list.table.managedFilterLabel', {
defaultMessage: 'Managed',
});

export const PipelineTable: FunctionComponent<Props> = ({
pipelines,
onReloadClick,
onEditPipelineClick,
onClonePipelineClick,
onDeletePipelineClick,
}) => {
const [filterOptions, setFilterOptions] = useState<EuiSelectableOption[]>([
{ key: 'managed', label: managedFilterLabel },
{ key: 'deprecated', label: deprecatedFilterLabel, checked: 'off' },
]);
const { history } = useKibana().services;
const [selection, setSelection] = useState<Pipeline[]>([]);
const [showPopover, setShowPopover] = useState(false);
Expand Down Expand Up @@ -65,6 +95,43 @@ export const PipelineTable: FunctionComponent<Props> = ({
},
];

const filteredPipelines = useMemo(() => {
return (pipelines || []).filter((pipeline) => {
const deprecatedFilter = filterOptions.find(({ key }) => key === 'deprecated')?.checked;
const managedFilter = filterOptions.find(({ key }) => key === 'managed')?.checked;
return !(
(deprecatedFilter === 'off' && pipeline.deprecated) ||
(deprecatedFilter === 'on' && !pipeline.deprecated) ||
(managedFilter === 'off' && pipeline.isManaged) ||
(managedFilter === 'on' && !pipeline.isManaged)
);
});
}, [pipelines, filterOptions]);

const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const onButtonClick = () => {
setIsPopoverOpen(!isPopoverOpen);
};
const closePopover = () => {
setIsPopoverOpen(false);
};

const button = (
<EuiFilterButton
iconType="arrowDown"
badgeColor="success"
onClick={onButtonClick}
isSelected={isPopoverOpen}
numFilters={filterOptions.filter((item) => item.checked !== 'off').length}
hasActiveFilters={!!filterOptions.find((item) => item.checked === 'on')}
numActiveFilters={filterOptions.filter((item) => item.checked === 'on').length}
>
{i18n.translate('xpack.ingestPipelines.list.table.filtersButtonLabel', {
defaultMessage: 'Filters',
})}
</EuiFilterButton>
);

const tableProps: EuiInMemoryTableProps<Pipeline> = {
itemId: 'name',
isSelectable: true,
Expand Down Expand Up @@ -111,6 +178,7 @@ export const PipelineTable: FunctionComponent<Props> = ({
})}
</EuiButton>,
<EuiPopover
key="createPipelinePopover"
isOpen={showPopover}
closePopover={() => setShowPopover(false)}
button={
Expand Down Expand Up @@ -147,11 +215,34 @@ export const PipelineTable: FunctionComponent<Props> = ({
},
filters: [
{
type: 'is',
field: 'isManaged',
name: i18n.translate('xpack.ingestPipelines.list.table.isManagedFilterLabel', {
defaultMessage: 'Managed',
}),
type: 'custom_component',
component: () => {
return (
<EuiFilterGroup>
<EuiPopover
id="popoverID"
button={button}
isOpen={isPopoverOpen}
closePopover={closePopover}
panelPaddingSize="none"
>
<EuiSelectable
allowExclusions
aria-label={i18n.translate(
'xpack.ingestPipelines.list.table.filtersAriaLabel',
{
defaultMessage: 'Filters',
}
)}
options={filterOptions as EuiSelectableOption[]}
onChange={setFilterOptions}
>
{(list) => <div style={{ width: 300 }}>{list}</div>}
</EuiSelectable>
</EuiPopover>
</EuiFilterGroup>
);
},
},
],
},
Expand All @@ -175,6 +266,16 @@ export const PipelineTable: FunctionComponent<Props> = ({
})}
>
{name}
{pipeline.deprecated && (
<>
&nbsp;
<EuiToolTip content={deprecatedPipelineBadge.badgeTooltip}>
<EuiBadge color="warning" data-test-subj="isDeprecatedBadge">
{deprecatedPipelineBadge.badge}
</EuiBadge>
</EuiToolTip>
</>
)}
{pipeline.isManaged && (
<>
&nbsp;
Expand Down Expand Up @@ -236,7 +337,7 @@ export const PipelineTable: FunctionComponent<Props> = ({
],
},
],
items: pipelines ?? [],
items: filteredPipelines,
};

return <EuiInMemoryTable {...tableProps} />;
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -21022,7 +21022,6 @@
"xpack.ingestPipelines.list.table.emptyPromptDescription": "Utilisez des pipelines pour retirer ou transformer des champs, extraire des valeurs à partir de texte et enrichir vos données avant l’indexation.",
"xpack.ingestPipelines.list.table.emptyPromptDocumentionLink": "En savoir plus",
"xpack.ingestPipelines.list.table.emptyPromptTitle": "Commencer en créant un pipeline",
"xpack.ingestPipelines.list.table.isManagedFilterLabel": "Géré",
"xpack.ingestPipelines.list.table.managedBadgeLabel": "Géré",
"xpack.ingestPipelines.list.table.nameColumnTitle": "Nom",
"xpack.ingestPipelines.list.table.reloadButtonLabel": "Recharger",
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -21036,7 +21036,6 @@
"xpack.ingestPipelines.list.table.emptyPromptDescription": "パイプラインを使用すると、フィールドの削除または変換、テキストからの値の抽出、インデックス前のデータの強化を行うことができます。",
"xpack.ingestPipelines.list.table.emptyPromptDocumentionLink": "詳細",
"xpack.ingestPipelines.list.table.emptyPromptTitle": "パイプラインを作成して開始",
"xpack.ingestPipelines.list.table.isManagedFilterLabel": "管理中",
"xpack.ingestPipelines.list.table.managedBadgeLabel": "管理中",
"xpack.ingestPipelines.list.table.nameColumnTitle": "名前",
"xpack.ingestPipelines.list.table.reloadButtonLabel": "再読み込み",
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -21129,7 +21129,6 @@
"xpack.ingestPipelines.list.table.emptyPromptDescription": "在建立索引之前,请使用管道删除或转换字段,从文本中提取值,并扩充您的数据。",
"xpack.ingestPipelines.list.table.emptyPromptDocumentionLink": "了解详情",
"xpack.ingestPipelines.list.table.emptyPromptTitle": "首先创建管道",
"xpack.ingestPipelines.list.table.isManagedFilterLabel": "托管",
"xpack.ingestPipelines.list.table.managedBadgeLabel": "托管",
"xpack.ingestPipelines.list.table.nameColumnTitle": "名称",
"xpack.ingestPipelines.list.table.reloadButtonLabel": "重新加载",
Expand Down

0 comments on commit 36a9596

Please sign in to comment.