diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts index 313ebefb85301..04843cae6a57e 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts @@ -21,6 +21,7 @@ export type TestSubjects = | 'filterList.filterItem' | 'ilmPolicyLink' | 'includeStatsSwitch' + | 'includeManagedSwitch' | 'indexTable' | 'indexTableIncludeHiddenIndicesToggle' | 'indexTableIndexNameLink' diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts index 148b20e5de533..4e0486e55720d 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts @@ -19,6 +19,7 @@ export interface DataStreamsTabTestBed extends TestBed { goToDataStreamsList: () => void; clickEmptyPromptIndexTemplateLink: () => void; clickIncludeStatsSwitch: () => void; + clickIncludeManagedSwitch: () => void; clickReloadButton: () => void; clickNameAt: (index: number) => void; clickIndicesAt: (index: number) => void; @@ -80,6 +81,11 @@ export const setup = async (overridingDependencies: any = {}): Promise { + const { find } = testBed; + find('includeManagedSwitch').simulate('click'); + }; + const clickReloadButton = () => { const { find } = testBed; find('reloadButton').simulate('click'); @@ -183,6 +189,7 @@ export const setup = async (overridingDependencies: any = {}): Promise ({ - name, +export const createDataStreamPayload = (dataStream: Partial): DataStream => ({ + name: 'my-data-stream', timeStampField: { name: '@timestamp' }, indices: [ { @@ -216,6 +223,7 @@ export const createDataStreamPayload = (name: string): DataStream => ({ indexTemplateName: 'indexTemplate', storageSize: '1b', maxTimeStamp: 420, + ...dataStream, }); export const createDataStreamBackingIndex = (indexName: string, dataStreamName: string) => ({ diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts index 633184c9afecc..a76d5dc99cbaf 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts @@ -99,10 +99,10 @@ describe('Data Streams tab', () => { createNonDataStreamIndex('non-data-stream-index'), ]); - const dataStreamForDetailPanel = createDataStreamPayload('dataStream1'); + const dataStreamForDetailPanel = createDataStreamPayload({ name: 'dataStream1' }); setLoadDataStreamsResponse([ dataStreamForDetailPanel, - createDataStreamPayload('dataStream2'), + createDataStreamPayload({ name: 'dataStream2' }), ]); setLoadDataStreamResponse(dataStreamForDetailPanel); @@ -287,9 +287,9 @@ describe('Data Streams tab', () => { createDataStreamBackingIndex('data-stream-index2', 'dataStream2'), ]); - const dataStreamDollarSign = createDataStreamPayload('%dataStream'); - setLoadDataStreamsResponse([dataStreamDollarSign]); - setLoadDataStreamResponse(dataStreamDollarSign); + const dataStreamPercentSign = createDataStreamPayload({ name: '%dataStream' }); + setLoadDataStreamsResponse([dataStreamPercentSign]); + setLoadDataStreamResponse(dataStreamPercentSign); testBed = await setup({ history: createMemoryHistory(), @@ -327,10 +327,10 @@ describe('Data Streams tab', () => { test('with an ILM url generator and an ILM policy', async () => { const { setLoadDataStreamsResponse, setLoadDataStreamResponse } = httpRequestsMockHelpers; - const dataStreamForDetailPanel = { - ...createDataStreamPayload('dataStream1'), + const dataStreamForDetailPanel = createDataStreamPayload({ + name: 'dataStream1', ilmPolicyName: 'my_ilm_policy', - }; + }); setLoadDataStreamsResponse([dataStreamForDetailPanel]); setLoadDataStreamResponse(dataStreamForDetailPanel); @@ -351,7 +351,7 @@ describe('Data Streams tab', () => { test('with an ILM url generator and no ILM policy', async () => { const { setLoadDataStreamsResponse, setLoadDataStreamResponse } = httpRequestsMockHelpers; - const dataStreamForDetailPanel = createDataStreamPayload('dataStream1'); + const dataStreamForDetailPanel = createDataStreamPayload({ name: 'dataStream1' }); setLoadDataStreamsResponse([dataStreamForDetailPanel]); setLoadDataStreamResponse(dataStreamForDetailPanel); @@ -373,10 +373,10 @@ describe('Data Streams tab', () => { test('without an ILM url generator and with an ILM policy', async () => { const { setLoadDataStreamsResponse, setLoadDataStreamResponse } = httpRequestsMockHelpers; - const dataStreamForDetailPanel = { - ...createDataStreamPayload('dataStream1'), + const dataStreamForDetailPanel = createDataStreamPayload({ + name: 'dataStream1', ilmPolicyName: 'my_ilm_policy', - }; + }); setLoadDataStreamsResponse([dataStreamForDetailPanel]); setLoadDataStreamResponse(dataStreamForDetailPanel); @@ -395,4 +395,58 @@ describe('Data Streams tab', () => { expect(findDetailPanelIlmPolicyName().contains('my_ilm_policy')).toBeTruthy(); }); }); + + describe('managed data streams', () => { + const nonBreakingSpace = ' '; + beforeEach(async () => { + const managedDataStream = createDataStreamPayload({ + name: 'managed-data-stream', + _meta: { + package: 'test', + managed: true, + managed_by: 'ingest-manager', + }, + }); + const nonManagedDataStream = createDataStreamPayload({ name: 'non-managed-data-stream' }); + httpRequestsMockHelpers.setLoadDataStreamsResponse([managedDataStream, nonManagedDataStream]); + + testBed = await setup({ + history: createMemoryHistory(), + }); + await act(async () => { + testBed.actions.goToDataStreamsList(); + }); + testBed.component.update(); + }); + + test('listed in the table with Managed label', () => { + const { table } = testBed; + const { tableCellsValues } = table.getMetaData('dataStreamTable'); + + expect(tableCellsValues).toEqual([ + ['', `managed-data-stream${nonBreakingSpace}Managed`, 'green', '1', 'Delete'], + ['', 'non-managed-data-stream', 'green', '1', 'Delete'], + ]); + }); + + test('turning off "Include managed" switch hides managed data streams', async () => { + const { exists, actions, component, table } = testBed; + let { tableCellsValues } = table.getMetaData('dataStreamTable'); + + expect(tableCellsValues).toEqual([ + ['', `managed-data-stream${nonBreakingSpace}Managed`, 'green', '1', 'Delete'], + ['', 'non-managed-data-stream', 'green', '1', 'Delete'], + ]); + + expect(exists('includeManagedSwitch')).toBe(true); + + await act(async () => { + actions.clickIncludeManagedSwitch(); + }); + component.update(); + + ({ tableCellsValues } = table.getMetaData('dataStreamTable')); + expect(tableCellsValues).toEqual([['', 'non-managed-data-stream', 'green', '1', 'Delete']]); + }); + }); }); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts index db4624d4389ff..9a5dca01e1b98 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts @@ -74,7 +74,9 @@ describe('', () => { // The detail panel should still appear even if there are no data streams. httpRequestsMockHelpers.setLoadDataStreamsResponse([]); - httpRequestsMockHelpers.setLoadDataStreamResponse(createDataStreamPayload('dataStream1')); + httpRequestsMockHelpers.setLoadDataStreamResponse( + createDataStreamPayload({ name: 'dataStream1' }) + ); testBed = await setup({ history: createMemoryHistory(), diff --git a/x-pack/plugins/index_management/common/lib/data_stream_serialization.ts b/x-pack/plugins/index_management/common/lib/data_stream_serialization.ts index 69004eaa020eb..2d8e038d2a60f 100644 --- a/x-pack/plugins/index_management/common/lib/data_stream_serialization.ts +++ b/x-pack/plugins/index_management/common/lib/data_stream_serialization.ts @@ -17,6 +17,7 @@ export function deserializeDataStream(dataStreamFromEs: DataStreamFromEs): DataS ilm_policy: ilmPolicyName, store_size: storageSize, maximum_timestamp: maxTimeStamp, + _meta, } = dataStreamFromEs; return { @@ -35,6 +36,7 @@ export function deserializeDataStream(dataStreamFromEs: DataStreamFromEs): DataS ilmPolicyName, storageSize, maxTimeStamp, + _meta, }; } diff --git a/x-pack/plugins/index_management/common/types/data_streams.ts b/x-pack/plugins/index_management/common/types/data_streams.ts index 7c348f9a8085d..adb7104043fbb 100644 --- a/x-pack/plugins/index_management/common/types/data_streams.ts +++ b/x-pack/plugins/index_management/common/types/data_streams.ts @@ -10,6 +10,14 @@ interface TimestampFieldFromEs { type TimestampField = TimestampFieldFromEs; +interface MetaFieldFromEs { + managed_by: string; + package: any; + managed: boolean; +} + +type MetaField = MetaFieldFromEs; + export type HealthFromEs = 'GREEN' | 'YELLOW' | 'RED'; export interface DataStreamFromEs { @@ -17,6 +25,7 @@ export interface DataStreamFromEs { timestamp_field: TimestampFieldFromEs; indices: DataStreamIndexFromEs[]; generation: number; + _meta?: MetaFieldFromEs; status: HealthFromEs; template: string; ilm_policy?: string; @@ -41,6 +50,7 @@ export interface DataStream { ilmPolicyName?: string; storageSize?: string; maxTimeStamp?: number; + _meta?: MetaField; } export interface DataStreamIndex { diff --git a/x-pack/plugins/index_management/public/application/lib/data_streams.tsx b/x-pack/plugins/index_management/public/application/lib/data_streams.tsx new file mode 100644 index 0000000000000..ca5297e399339 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/lib/data_streams.tsx @@ -0,0 +1,15 @@ +/* + * 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 { DataStream } from '../../../common'; + +export const isManagedByIngestManager = (dataStream: DataStream): boolean => { + return Boolean(dataStream._meta?.managed && dataStream._meta?.managed_by === 'ingest-manager'); +}; + +export const filterDataStreams = (dataStreams: DataStream[]): DataStream[] => { + return dataStreams.filter((dataStream: DataStream) => !isManagedByIngestManager(dataStream)); +}; diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx index 20b93d9d71d04..0df5697a4281a 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx @@ -32,6 +32,7 @@ import { documentationService } from '../../../services/documentation'; import { Section } from '../home'; import { DataStreamTable } from './data_stream_table'; import { DataStreamDetailPanel } from './data_stream_detail_panel'; +import { filterDataStreams } from '../../../lib/data_streams'; interface MatchParams { dataStreamName?: string; @@ -52,6 +53,7 @@ export const DataStreamList: React.FunctionComponent ); } else if (Array.isArray(dataStreams) && dataStreams.length > 0) { + const filteredDataStreams = isIncludeManagedChecked + ? dataStreams + : filterDataStreams(dataStreams); content = ( <> - {/* TODO: Add a switch for toggling on data streams created by Ingest Manager */} + + + + setIsIncludeManagedChecked(e.target.checked)} + data-test-subj="includeManagedSwitch" + /> + + + + + + + @@ -212,7 +245,7 @@ export const DataStreamList: React.FunctionComponent = ({ }), truncateText: true, sortable: true, - render: (name: DataStream['name']) => { + render: (name: DataStream['name'], dataStream: DataStream) => { return ( - - {name} - + + + {name} + + {isManagedByIngestManager(dataStream) ? ( + +   + + + + + + + ) : null} + ); }, }); @@ -121,7 +151,7 @@ export const DataStreamTable: React.FunctionComponent = ({ name: i18n.translate('xpack.idxMgmt.dataStreamList.table.actionDeleteText', { defaultMessage: 'Delete', }), - description: i18n.translate('xpack.idxMgmt.dataStreamList.table.actionDeleteDecription', { + description: i18n.translate('xpack.idxMgmt.dataStreamList.table.actionDeleteDescription', { defaultMessage: 'Delete this data stream', }), icon: 'trash', diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index cd45a4f01fc64..7115f8c6eeb6f 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -8143,7 +8143,6 @@ "xpack.idxMgmt.dataStreamList.loadingDataStreamsErrorMessage": "データストリームの読み込み中にエラーが発生", "xpack.idxMgmt.dataStreamList.reloadDataStreamsButtonLabel": "再読み込み", "xpack.idxMgmt.dataStreamList.table.actionColumnTitle": "アクション", - "xpack.idxMgmt.dataStreamList.table.actionDeleteDecription": "このデータストリームを削除", "xpack.idxMgmt.dataStreamList.table.actionDeleteText": "削除", "xpack.idxMgmt.dataStreamList.table.deleteDataStreamsButtonLabel": "{count, plural, one {個のデータストリーム} other {個のデータストリーム}}を削除", "xpack.idxMgmt.dataStreamList.table.healthColumnTitle": "ヘルス", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 97396b09ca6c6..b945c443741b6 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -8151,7 +8151,6 @@ "xpack.idxMgmt.dataStreamList.loadingDataStreamsErrorMessage": "加载数据流时出错", "xpack.idxMgmt.dataStreamList.reloadDataStreamsButtonLabel": "重新加载", "xpack.idxMgmt.dataStreamList.table.actionColumnTitle": "操作", - "xpack.idxMgmt.dataStreamList.table.actionDeleteDecription": "删除此数据流", "xpack.idxMgmt.dataStreamList.table.actionDeleteText": "删除", "xpack.idxMgmt.dataStreamList.table.deleteDataStreamsButtonLabel": "删除{count, plural, one {数据流} other {数据流} }", "xpack.idxMgmt.dataStreamList.table.healthColumnTitle": "运行状况",