Skip to content

Commit e217c9d

Browse files
Added hidden filter to data streams tab (#85028) (#85800)
* Added hidden filter to data streams tab * Fix i18n import * Fixed tests * hidden ds pr feedback * Added includeHidden query to data streams list * Changed how badge group renders data streams badges Co-authored-by: Kibana Machine <[email protected]> Co-authored-by: Kibana Machine <[email protected]>
1 parent 3573928 commit e217c9d

File tree

15 files changed

+320
-162
lines changed

15 files changed

+320
-162
lines changed

x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export interface DataStreamsTabTestBed extends TestBed<TestSubjects> {
1919
goToDataStreamsList: () => void;
2020
clickEmptyPromptIndexTemplateLink: () => void;
2121
clickIncludeStatsSwitch: () => void;
22-
clickIncludeManagedSwitch: () => void;
22+
toggleViewFilterAt: (index: number) => void;
2323
clickReloadButton: () => void;
2424
clickNameAt: (index: number) => void;
2525
clickIndicesAt: (index: number) => void;
@@ -82,9 +82,16 @@ export const setup = async (overridingDependencies: any = {}): Promise<DataStrea
8282
find('includeStatsSwitch').simulate('click');
8383
};
8484

85-
const clickIncludeManagedSwitch = () => {
86-
const { find } = testBed;
87-
find('includeManagedSwitch').simulate('click');
85+
const toggleViewFilterAt = (index: number) => {
86+
const { find, component } = testBed;
87+
act(() => {
88+
find('viewButton').simulate('click');
89+
});
90+
component.update();
91+
act(() => {
92+
find('filterItem').at(index).simulate('click');
93+
});
94+
component.update();
8895
};
8996

9097
const clickReloadButton = () => {
@@ -197,7 +204,7 @@ export const setup = async (overridingDependencies: any = {}): Promise<DataStrea
197204
goToDataStreamsList,
198205
clickEmptyPromptIndexTemplateLink,
199206
clickIncludeStatsSwitch,
200-
clickIncludeManagedSwitch,
207+
toggleViewFilterAt,
201208
clickReloadButton,
202209
clickNameAt,
203210
clickIndicesAt,
@@ -235,6 +242,7 @@ export const createDataStreamPayload = (dataStream: Partial<DataStream>): DataSt
235242
privileges: {
236243
delete_index: true,
237244
},
245+
hidden: false,
238246
...dataStream,
239247
});
240248

x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {
1919
createNonDataStreamIndex,
2020
} from './data_streams_tab.helpers';
2121

22+
const nonBreakingSpace = ' ';
23+
2224
describe('Data Streams tab', () => {
2325
const { server, httpRequestsMockHelpers } = setupEnvironment();
2426
let testBed: DataStreamsTabTestBed;
@@ -82,6 +84,25 @@ describe('Data Streams tab', () => {
8284
// Assert against the text because the href won't be available, due to dependency upon our core mock.
8385
expect(findEmptyPromptIndexTemplateLink().text()).toBe('Fleet');
8486
});
87+
88+
test('when hidden data streams are filtered by default, the table is rendered empty', async () => {
89+
const hiddenDataStream = createDataStreamPayload({
90+
name: 'hidden-data-stream',
91+
hidden: true,
92+
});
93+
httpRequestsMockHelpers.setLoadDataStreamsResponse([hiddenDataStream]);
94+
95+
testBed = await setup({
96+
plugins: {},
97+
});
98+
99+
await act(async () => {
100+
testBed.actions.goToDataStreamsList();
101+
});
102+
103+
testBed.component.update();
104+
expect(testBed.find('dataStreamTable').text()).toContain('No data streams found');
105+
});
85106
});
86107

87108
describe('when there are data streams', () => {
@@ -397,7 +418,6 @@ describe('Data Streams tab', () => {
397418
});
398419

399420
describe('managed data streams', () => {
400-
const nonBreakingSpace = ' ';
401421
beforeEach(async () => {
402422
const managedDataStream = createDataStreamPayload({
403423
name: 'managed-data-stream',
@@ -429,24 +449,49 @@ describe('Data Streams tab', () => {
429449
]);
430450
});
431451

432-
test('turning off "Include managed" switch hides managed data streams', async () => {
433-
const { exists, actions, component, table } = testBed;
452+
test('turning off "managed" filter hides managed data streams', async () => {
453+
const { actions, table } = testBed;
434454
let { tableCellsValues } = table.getMetaData('dataStreamTable');
435455

436456
expect(tableCellsValues).toEqual([
437457
['', `managed-data-stream${nonBreakingSpace}Managed`, 'green', '1', 'Delete'],
438458
['', 'non-managed-data-stream', 'green', '1', 'Delete'],
439459
]);
440460

441-
expect(exists('includeManagedSwitch')).toBe(true);
461+
actions.toggleViewFilterAt(0);
462+
463+
({ tableCellsValues } = table.getMetaData('dataStreamTable'));
464+
expect(tableCellsValues).toEqual([['', 'non-managed-data-stream', 'green', '1', 'Delete']]);
465+
});
466+
});
467+
468+
describe('hidden data streams', () => {
469+
beforeEach(async () => {
470+
const hiddenDataStream = createDataStreamPayload({
471+
name: 'hidden-data-stream',
472+
hidden: true,
473+
});
474+
httpRequestsMockHelpers.setLoadDataStreamsResponse([hiddenDataStream]);
442475

476+
testBed = await setup({
477+
history: createMemoryHistory(),
478+
});
443479
await act(async () => {
444-
actions.clickIncludeManagedSwitch();
480+
testBed.actions.goToDataStreamsList();
445481
});
446-
component.update();
482+
testBed.component.update();
483+
});
447484

448-
({ tableCellsValues } = table.getMetaData('dataStreamTable'));
449-
expect(tableCellsValues).toEqual([['', 'non-managed-data-stream', 'green', '1', 'Delete']]);
485+
test('show hidden data streams when filter is toggled', () => {
486+
const { table, actions } = testBed;
487+
488+
actions.toggleViewFilterAt(1);
489+
490+
const { tableCellsValues } = table.getMetaData('dataStreamTable');
491+
492+
expect(tableCellsValues).toEqual([
493+
['', `hidden-data-stream${nonBreakingSpace}Hidden`, 'green', '1', 'Delete'],
494+
]);
450495
});
451496
});
452497

x-pack/plugins/index_management/common/lib/data_stream_serialization.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export function deserializeDataStream(dataStreamFromEs: DataStreamFromEs): DataS
1919
maximum_timestamp: maxTimeStamp,
2020
_meta,
2121
privileges,
22+
hidden,
2223
} = dataStreamFromEs;
2324

2425
return {
@@ -39,6 +40,7 @@ export function deserializeDataStream(dataStreamFromEs: DataStreamFromEs): DataS
3940
maxTimeStamp,
4041
_meta,
4142
privileges,
43+
hidden,
4244
};
4345
}
4446

x-pack/plugins/index_management/common/types/data_streams.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export interface DataStreamFromEs {
3838
store_size?: string;
3939
maximum_timestamp?: number;
4040
privileges: PrivilegesFromEs;
41+
hidden: boolean;
4142
}
4243

4344
export interface DataStreamIndexFromEs {
@@ -59,6 +60,7 @@ export interface DataStream {
5960
maxTimeStamp?: number;
6061
_meta?: Meta;
6162
privileges: Privileges;
63+
hidden: boolean;
6264
}
6365

6466
export interface DataStreamIndex {

x-pack/plugins/index_management/public/application/lib/data_streams.tsx

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,34 @@
66

77
import { DataStream } from '../../../common';
88

9-
export const isManagedByIngestManager = (dataStream: DataStream): boolean => {
9+
export const isFleetManaged = (dataStream: DataStream): boolean => {
10+
// TODO check if the wording will change to 'fleet'
1011
return Boolean(dataStream._meta?.managed && dataStream._meta?.managed_by === 'ingest-manager');
1112
};
1213

13-
export const filterDataStreams = (dataStreams: DataStream[]): DataStream[] => {
14-
return dataStreams.filter((dataStream: DataStream) => !isManagedByIngestManager(dataStream));
14+
export const filterDataStreams = (
15+
dataStreams: DataStream[],
16+
visibleTypes: string[]
17+
): DataStream[] => {
18+
return dataStreams.filter((dataStream: DataStream) => {
19+
// include all data streams that are neither hidden nor managed
20+
if (!dataStream.hidden && !isFleetManaged(dataStream)) {
21+
return true;
22+
}
23+
if (dataStream.hidden && visibleTypes.includes('hidden')) {
24+
return true;
25+
}
26+
return isFleetManaged(dataStream) && visibleTypes.includes('managed');
27+
});
28+
};
29+
30+
export const isSelectedDataStreamHidden = (
31+
dataStreams: DataStream[],
32+
selectedDataStreamName?: string
33+
): boolean => {
34+
return (
35+
!!selectedDataStreamName &&
36+
!!dataStreams.find((dataStream: DataStream) => dataStream.name === selectedDataStreamName)
37+
?.hidden
38+
);
1539
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
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+
export { FilterListButton, Filters } from './filter_list_button';
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 from 'react';
8+
import { EuiBadge, EuiBadgeGroup } from '@elastic/eui';
9+
import { FormattedMessage } from '@kbn/i18n/react';
10+
import { DataStream } from '../../../../../common';
11+
import { isFleetManaged } from '../../../lib/data_streams';
12+
13+
interface Props {
14+
dataStream: DataStream;
15+
}
16+
17+
export const DataStreamsBadges: React.FunctionComponent<Props> = ({ dataStream }) => {
18+
const badges = [];
19+
if (isFleetManaged(dataStream)) {
20+
badges.push(
21+
<EuiBadge color="hollow">
22+
<FormattedMessage
23+
id="xpack.idxMgmt.dataStreamList.table.managedDataStreamBadge"
24+
defaultMessage="Managed"
25+
/>
26+
</EuiBadge>
27+
);
28+
}
29+
if (dataStream.hidden) {
30+
badges.push(
31+
<EuiBadge color="hollow">
32+
<FormattedMessage
33+
id="xpack.idxMgmt.dataStreamList.table.hiddenDataStreamBadge"
34+
defaultMessage="Hidden"
35+
/>
36+
</EuiBadge>
37+
);
38+
}
39+
return badges.length > 0 ? (
40+
<>
41+
&nbsp;
42+
<EuiBadgeGroup>{badges}</EuiBadgeGroup>
43+
</>
44+
) : null;
45+
};

x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_detail_panel/data_stream_detail_panel.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { useUrlGenerator } from '../../../../services/use_url_generator';
3232
import { getIndexListUri, getTemplateDetailsLink } from '../../../../services/routing';
3333
import { ILM_PAGES_POLICY_EDIT, ILM_URL_GENERATOR_ID } from '../../../../constants';
3434
import { useAppContext } from '../../../../app_context';
35+
import { DataStreamsBadges } from '../data_stream_badges';
3536

3637
interface DetailsListProps {
3738
details: Array<{
@@ -269,6 +270,7 @@ export const DataStreamDetailPanel: React.FunctionComponent<Props> = ({
269270
<EuiTitle size="m">
270271
<h2 id="dataStreamDetailPanelTitle" data-test-subj="dataStreamDetailPanelTitle">
271272
{dataStreamName}
273+
{dataStream && <DataStreamsBadges dataStream={dataStream} />}
272274
</h2>
273275
</EuiTitle>
274276
</EuiFlyoutHeader>

0 commit comments

Comments
 (0)