[Index Management] Support data retention on Data Streams tab (#165263)

This commit is contained in:
Alison Goryachev 2023-09-18 12:37:02 -04:00 committed by GitHub
parent a6c25b15aa
commit be01217b19
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 239 additions and 154 deletions

View file

@ -49,11 +49,34 @@ POST %25%7B%5B%40metadata%5D%5Bbeat%5D%7D-%25%7B%5B%40metadata%5D%5Bversion%5D%7
}
```
Create a data stream configured with data stream lifecyle.
```
PUT _index_template/my-index-template
{
"index_patterns": ["my-data-stream*"],
"data_stream": { },
"priority": 500,
"template": {
"lifecycle": {
"data_retention": "7d"
}
},
"_meta": {
"description": "Template with data stream lifecycle"
}
}
```
```
PUT _data_stream/my-data-stream
```
## Index templates tab
### Quick steps for testing
**Legacy index templates** are only shown in the UI on stateful *and* if a user has existing legacy index templates. You can test this functionality by creating one in Console:
**Legacy index templates** are only shown in the UI on stateful _and_ if a user has existing legacy index templates. You can test this functionality by creating one in Console:
```
PUT _template/template_1
@ -67,6 +90,7 @@ On serverless, Elasticsearch does not support legacy index templates and therefo
To test **Cloud-managed templates**:
1. Add `cluster.metadata.managed_index_templates` setting via Dev Tools:
```
PUT /_cluster/settings
{
@ -77,6 +101,7 @@ PUT /_cluster/settings
```
2. Create a template with the format: `.cloud-<template_name>` via Dev Tools.
```
PUT _template/.cloud-example
{
@ -101,4 +126,4 @@ In 7.x, the UI supports types defined as part of the mappings for legacy index t
}
}
}
```
```

View file

@ -8,7 +8,6 @@
import { act } from 'react-dom/test-utils';
import { ReactWrapper } from 'enzyme';
import { EuiDescriptionListDescription } from '@elastic/eui';
import {
registerTestBed,
TestBed,
@ -43,8 +42,9 @@ export interface DataStreamsTabTestBed extends TestBed<TestSubjects> {
findDetailPanelTitle: () => string;
findEmptyPromptIndexTemplateLink: () => ReactWrapper;
findDetailPanelIlmPolicyLink: () => ReactWrapper;
findDetailPanelIlmPolicyName: () => ReactWrapper;
findDetailPanelIlmPolicyDetail: () => ReactWrapper;
findDetailPanelIndexTemplateLink: () => ReactWrapper;
findDetailPanelDataRetentionDetail: () => ReactWrapper;
}
export const setup = async (
@ -211,10 +211,14 @@ export const setup = async (
return find('indexTemplateLink');
};
const findDetailPanelIlmPolicyName = () => {
const descriptionList = testBed.component.find(EuiDescriptionListDescription);
// ilm policy is the last in the details list
return descriptionList.last();
const findDetailPanelIlmPolicyDetail = () => {
const { find } = testBed;
return find('ilmPolicyDetail');
};
const findDetailPanelDataRetentionDetail = () => {
const { find } = testBed;
return find('dataRetentionDetail');
};
return {
@ -240,8 +244,9 @@ export const setup = async (
findDetailPanelTitle,
findEmptyPromptIndexTemplateLink,
findDetailPanelIlmPolicyLink,
findDetailPanelIlmPolicyName,
findDetailPanelIlmPolicyDetail,
findDetailPanelIndexTemplateLink,
findDetailPanelDataRetentionDetail,
};
};
@ -264,6 +269,9 @@ export const createDataStreamPayload = (dataStream: Partial<DataStream>): DataSt
delete_index: true,
},
hidden: false,
lifecycle: {
data_retention: '7d',
},
...dataStream,
});

View file

@ -170,8 +170,8 @@ describe('Data Streams tab', () => {
const { tableCellsValues } = table.getMetaData('dataStreamTable');
expect(tableCellsValues).toEqual([
['', 'dataStream1', 'green', '1', 'Delete'],
['', 'dataStream2', 'green', '1', 'Delete'],
['', 'dataStream1', 'green', '1', '7d', 'Delete'],
['', 'dataStream2', 'green', '1', '7d', 'Delete'],
]);
});
@ -209,8 +209,8 @@ describe('Data Streams tab', () => {
// The table renders with the stats columns though.
const { tableCellsValues } = table.getMetaData('dataStreamTable');
expect(tableCellsValues).toEqual([
['', 'dataStream1', 'green', 'December 31st, 1969 7:00:00 PM', '5b', '1', 'Delete'],
['', 'dataStream2', 'green', 'December 31st, 1969 7:00:00 PM', '1kb', '1', 'Delete'],
['', 'dataStream1', 'green', 'December 31st, 1969 7:00:00 PM', '5b', '1', '7d', 'Delete'],
['', 'dataStream2', 'green', 'December 31st, 1969 7:00:00 PM', '1kb', '1', '7d', 'Delete'],
]);
});
@ -229,8 +229,8 @@ describe('Data Streams tab', () => {
// the human-readable string values.
const { tableCellsValues } = table.getMetaData('dataStreamTable');
expect(tableCellsValues).toEqual([
['', 'dataStream1', 'green', 'December 31st, 1969 7:00:00 PM', '5b', '1', 'Delete'],
['', 'dataStream2', 'green', 'December 31st, 1969 7:00:00 PM', '1kb', '1', 'Delete'],
['', 'dataStream1', 'green', 'December 31st, 1969 7:00:00 PM', '5b', '1', '7d', 'Delete'],
['', 'dataStream2', 'green', 'December 31st, 1969 7:00:00 PM', '1kb', '1', '7d', 'Delete'],
]);
});
@ -335,6 +335,12 @@ describe('Data Streams tab', () => {
expect(find('summaryTab').exists()).toBeTruthy();
expect(find('title').text().trim()).toBe('indexTemplate');
});
test('shows data retention detail when configured', async () => {
const { actions, findDetailPanelDataRetentionDetail } = testBed;
await actions.clickNameAt(0);
expect(findDetailPanelDataRetentionDetail().exists()).toBeTruthy();
});
});
});
@ -423,10 +429,10 @@ describe('Data Streams tab', () => {
});
testBed.component.update();
const { actions, findDetailPanelIlmPolicyLink, findDetailPanelIlmPolicyName } = testBed;
const { actions, findDetailPanelIlmPolicyLink, findDetailPanelIlmPolicyDetail } = testBed;
await actions.clickNameAt(0);
expect(findDetailPanelIlmPolicyLink().exists()).toBeFalsy();
expect(findDetailPanelIlmPolicyName().contains('None')).toBeTruthy();
expect(findDetailPanelIlmPolicyDetail().exists()).toBeFalsy();
});
test('without an ILM url locator and with an ILM policy', async () => {
@ -453,10 +459,10 @@ describe('Data Streams tab', () => {
});
testBed.component.update();
const { actions, findDetailPanelIlmPolicyLink, findDetailPanelIlmPolicyName } = testBed;
const { actions, findDetailPanelIlmPolicyLink, findDetailPanelIlmPolicyDetail } = testBed;
await actions.clickNameAt(0);
expect(findDetailPanelIlmPolicyLink().exists()).toBeFalsy();
expect(findDetailPanelIlmPolicyName().contains('my_ilm_policy')).toBeTruthy();
expect(findDetailPanelIlmPolicyDetail().contains('my_ilm_policy')).toBeTruthy();
});
});
@ -489,8 +495,8 @@ describe('Data Streams tab', () => {
const { tableCellsValues } = table.getMetaData('dataStreamTable');
expect(tableCellsValues).toEqual([
['', `managed-data-stream${nonBreakingSpace}Fleet-managed`, 'green', '1', 'Delete'],
['', 'non-managed-data-stream', 'green', '1', 'Delete'],
['', `managed-data-stream${nonBreakingSpace}Fleet-managed`, 'green', '1', '7d', 'Delete'],
['', 'non-managed-data-stream', 'green', '1', '7d', 'Delete'],
]);
});
@ -499,14 +505,16 @@ describe('Data Streams tab', () => {
let { tableCellsValues } = table.getMetaData('dataStreamTable');
expect(tableCellsValues).toEqual([
['', `managed-data-stream${nonBreakingSpace}Fleet-managed`, 'green', '1', 'Delete'],
['', 'non-managed-data-stream', 'green', '1', 'Delete'],
['', `managed-data-stream${nonBreakingSpace}Fleet-managed`, 'green', '1', '7d', 'Delete'],
['', 'non-managed-data-stream', 'green', '1', '7d', 'Delete'],
]);
actions.toggleViewFilterAt(0);
({ tableCellsValues } = table.getMetaData('dataStreamTable'));
expect(tableCellsValues).toEqual([['', 'non-managed-data-stream', 'green', '1', 'Delete']]);
expect(tableCellsValues).toEqual([
['', 'non-managed-data-stream', 'green', '1', '7d', 'Delete'],
]);
});
});
@ -537,7 +545,7 @@ describe('Data Streams tab', () => {
const { tableCellsValues } = table.getMetaData('dataStreamTable');
expect(tableCellsValues).toEqual([
['', `hidden-data-stream${nonBreakingSpace}Hidden`, 'green', '1', 'Delete'],
['', `hidden-data-stream${nonBreakingSpace}Hidden`, 'green', '1', '7d', 'Delete'],
]);
});
});
@ -570,8 +578,8 @@ describe('Data Streams tab', () => {
const { tableCellsValues } = table.getMetaData('dataStreamTable');
expect(tableCellsValues).toEqual([
['', 'dataStreamNoDelete', 'green', '1', ''],
['', 'dataStreamWithDelete', 'green', '1', 'Delete'],
['', 'dataStreamNoDelete', 'green', '1', '7d', ''],
['', 'dataStreamWithDelete', 'green', '1', '7d', 'Delete'],
]);
});

View file

@ -5,9 +5,9 @@
* 2.0.
*/
import { DataStream, DataStreamFromEs, Health } from '../types';
import { DataStream, EnhancedDataStreamFromEs, Health } from '../types';
export function deserializeDataStream(dataStreamFromEs: DataStreamFromEs): DataStream {
export function deserializeDataStream(dataStreamFromEs: EnhancedDataStreamFromEs): DataStream {
const {
name,
timestamp_field: timeStampField,
@ -22,6 +22,7 @@ export function deserializeDataStream(dataStreamFromEs: DataStreamFromEs): DataS
_meta,
privileges,
hidden,
lifecycle,
} = dataStreamFromEs;
return {
@ -44,9 +45,12 @@ export function deserializeDataStream(dataStreamFromEs: DataStreamFromEs): DataS
_meta,
privileges,
hidden,
lifecycle,
};
}
export function deserializeDataStreamList(dataStreamsFromEs: DataStreamFromEs[]): DataStream[] {
export function deserializeDataStreamList(
dataStreamsFromEs: EnhancedDataStreamFromEs[]
): DataStream[] {
return dataStreamsFromEs.map((dataStream) => deserializeDataStream(dataStream));
}

View file

@ -5,20 +5,20 @@
* 2.0.
*/
import {
ByteSize,
IndicesDataLifecycleWithRollover,
IndicesDataStream,
IndicesDataStreamsStatsDataStreamsStatsItem,
Metadata,
} from '@elastic/elasticsearch/lib/api/types';
interface TimestampFieldFromEs {
name: string;
}
type TimestampField = TimestampFieldFromEs;
interface MetaFromEs {
managed_by: string;
package: any;
managed: boolean;
}
type Meta = MetaFromEs;
interface PrivilegesFromEs {
delete_index: boolean;
}
@ -27,20 +27,13 @@ type Privileges = PrivilegesFromEs;
export type HealthFromEs = 'GREEN' | 'YELLOW' | 'RED';
export interface DataStreamFromEs {
name: string;
timestamp_field: TimestampFieldFromEs;
indices: DataStreamIndexFromEs[];
generation: number;
_meta?: MetaFromEs;
status: HealthFromEs;
template: string;
ilm_policy?: string;
store_size?: string;
store_size_bytes?: number;
maximum_timestamp?: number;
privileges: PrivilegesFromEs;
hidden: boolean;
export interface EnhancedDataStreamFromEs extends IndicesDataStream {
store_size?: IndicesDataStreamsStatsDataStreamsStatsItem['store_size'];
store_size_bytes?: IndicesDataStreamsStatsDataStreamsStatsItem['store_size_bytes'];
maximum_timestamp?: IndicesDataStreamsStatsDataStreamsStatsItem['maximum_timestamp'];
privileges: {
delete_index: boolean;
};
}
export interface DataStreamIndexFromEs {
@ -58,12 +51,13 @@ export interface DataStream {
health: Health;
indexTemplateName: string;
ilmPolicyName?: string;
storageSize?: string;
storageSize?: ByteSize;
storageSizeBytes?: number;
maxTimeStamp?: number;
_meta?: Meta;
_meta?: Metadata;
privileges: Privileges;
hidden: boolean;
lifecycle?: IndicesDataLifecycleWithRollover;
}
export interface DataStreamIndex {

View file

@ -13,7 +13,7 @@ export * from './mappings';
export * from './templates';
export type { DataStreamFromEs, Health, DataStream, DataStreamIndex } from './data_streams';
export type { EnhancedDataStreamFromEs, Health, DataStream, DataStreamIndex } from './data_streams';
export * from './component_templates';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { useState } from 'react';
import React, { useState, Fragment } from 'react';
import { i18n } from '@kbn/i18n';
import {
EuiButton,
@ -41,24 +41,16 @@ interface DetailsListProps {
name: string;
toolTip: string;
content: any;
dataTestSubj: string;
}>;
}
const DetailsList: React.FunctionComponent<DetailsListProps> = ({ details }) => {
const groups: any[] = [];
let items: any[];
const descriptionListItems = details.map((detail, index) => {
const { name, toolTip, content, dataTestSubj } = detail;
details.forEach((detail, index) => {
const { name, toolTip, content } = detail;
if (index % 2 === 0) {
items = [];
groups.push(<EuiFlexGroup key={groups.length}>{items}</EuiFlexGroup>);
}
items.push(
<EuiFlexItem key={name}>
return (
<Fragment key={`${name}-${index}`}>
<EuiDescriptionListTitle>
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexItem grow={false}>{name}</EuiFlexItem>
@ -69,12 +61,27 @@ const DetailsList: React.FunctionComponent<DetailsListProps> = ({ details }) =>
</EuiFlexGroup>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription>{content}</EuiDescriptionListDescription>
</EuiFlexItem>
<EuiDescriptionListDescription data-test-subj={dataTestSubj}>
{content}
</EuiDescriptionListDescription>
</Fragment>
);
});
return <EuiDescriptionList textStyle="reverse">{groups}</EuiDescriptionList>;
const midpoint = Math.ceil(descriptionListItems.length / 2);
const descriptionListColumnOne = descriptionListItems.slice(0, midpoint);
const descriptionListColumnTwo = descriptionListItems.slice(-midpoint);
return (
<EuiFlexGroup>
<EuiFlexItem>
<EuiDescriptionList textStyle="reverse">{descriptionListColumnOne}</EuiDescriptionList>
</EuiFlexItem>
<EuiFlexItem>
<EuiDescriptionList textStyle="reverse">{descriptionListColumnTwo}</EuiDescriptionList>
</EuiFlexItem>
</EuiFlexGroup>
);
};
interface Props {
@ -123,23 +130,64 @@ export const DataStreamDetailPanel: React.FunctionComponent<Props> = ({
ilmPolicyName,
storageSize,
maxTimeStamp,
lifecycle,
} = dataStream;
const details = [
const getManagementDetails = () => {
const managementDetails = [];
if (lifecycle?.data_retention) {
managementDetails.push({
name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.dataRetentionTitle', {
defaultMessage: 'Data retention',
}),
toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.dataRetentionToolTip', {
defaultMessage: 'The amount of time to retain the data in the data stream.',
}),
content: lifecycle.data_retention,
dataTestSubj: 'dataRetentionDetail',
});
}
if (ilmPolicyName) {
managementDetails.push({
name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyTitle', {
defaultMessage: 'Index lifecycle policy',
}),
toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyToolTip', {
defaultMessage: `The index lifecycle policy that manages the data in the data stream.`,
}),
content: ilmPolicyLink ? (
<EuiLink data-test-subj={'ilmPolicyLink'} href={ilmPolicyLink}>
{ilmPolicyName}
</EuiLink>
) : (
ilmPolicyName
),
dataTestSubj: 'ilmPolicyDetail',
});
}
return managementDetails;
};
const defaultDetails = [
{
name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.healthTitle', {
defaultMessage: 'Health',
}),
toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.healthToolTip', {
defaultMessage: `The health of the data stream's current backing indices`,
defaultMessage: `The health of the data stream's current backing indices.`,
}),
content: <DataHealth health={health} />,
dataTestSubj: 'healthDetail',
},
{
name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.maxTimeStampTitle', {
defaultMessage: 'Last updated',
}),
toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.maxTimeStampToolTip', {
defaultMessage: 'The most recent document to be added to the data stream',
defaultMessage: 'The most recent document to be added to the data stream.',
}),
content: maxTimeStamp ? (
humanizeTimeStamp(maxTimeStamp)
@ -150,22 +198,24 @@ export const DataStreamDetailPanel: React.FunctionComponent<Props> = ({
})}
</em>
),
dataTestSubj: 'lastUpdatedDetail',
},
{
name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.storageSizeTitle', {
defaultMessage: 'Storage size',
}),
toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.storageSizeToolTip', {
defaultMessage: `Total size of all shards in the data streams backing indices`,
defaultMessage: `The total size of all shards in the data streams backing indices.`,
}),
content: storageSize,
dataTestSubj: 'storageSizeDetail',
},
{
name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.indicesTitle', {
defaultMessage: 'Indices',
}),
toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.indicesToolTip', {
defaultMessage: `The data stream's current backing indices`,
defaultMessage: `The data stream's current backing indices.`,
}),
content: (
<EuiLink
@ -177,24 +227,27 @@ export const DataStreamDetailPanel: React.FunctionComponent<Props> = ({
{indices.length}
</EuiLink>
),
dataTestSubj: 'indicesDetail',
},
{
name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.timestampFieldTitle', {
defaultMessage: 'Timestamp field',
}),
toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.timestampFieldToolTip', {
defaultMessage: 'Timestamp field shared by all documents in the data stream',
defaultMessage: 'The timestamp field shared by all documents in the data stream.',
}),
content: timeStampField.name,
dataTestSubj: 'timestampDetail',
},
{
name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.generationTitle', {
defaultMessage: 'Generation',
}),
toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.generationToolTip', {
defaultMessage: 'Cumulative count of backing indices created for the data stream',
defaultMessage: 'The number of backing indices generated for the data stream.',
}),
content: generation,
dataTestSubj: 'generationDetail',
},
{
name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.indexTemplateTitle', {
@ -202,7 +255,7 @@ export const DataStreamDetailPanel: React.FunctionComponent<Props> = ({
}),
toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.indexTemplateToolTip', {
defaultMessage:
'The index template that configured the data stream and configures its backing indices',
'The index template that configured the data stream and configures its backing indices.',
}),
content: (
<EuiLink
@ -212,31 +265,13 @@ export const DataStreamDetailPanel: React.FunctionComponent<Props> = ({
{indexTemplateName}
</EuiLink>
),
},
{
name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyTitle', {
defaultMessage: 'Index lifecycle policy',
}),
toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyToolTip', {
defaultMessage: `The index lifecycle policy that manages the data stream's data`,
}),
content:
ilmPolicyName && ilmPolicyLink ? (
<EuiLink data-test-subj={'ilmPolicyLink'} href={ilmPolicyLink}>
{ilmPolicyName}
</EuiLink>
) : (
ilmPolicyName || (
<em>
{i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyContentNoneMessage', {
defaultMessage: `None`,
})}
</em>
)
),
dataTestSubj: 'indexTemplateDetail',
},
];
const managementDetails = getManagementDetails();
const details = [...defaultDetails, ...managementDetails];
content = <DetailsList details={details} />;
}

View file

@ -8,7 +8,14 @@
import React, { useState, Fragment } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiInMemoryTable, EuiBasicTableColumn, EuiButton, EuiLink } from '@elastic/eui';
import {
EuiInMemoryTable,
EuiBasicTableColumn,
EuiButton,
EuiLink,
EuiIcon,
EuiToolTip,
} from '@elastic/eui';
import { ScopedHistory } from '@kbn/core/public';
import { DataStream } from '../../../../../../common/types';
@ -71,7 +78,6 @@ export const DataStreamTable: React.FunctionComponent<Props> = ({
render: (health: DataStream['health']) => {
return <DataHealth health={health} />;
},
width: '100px',
});
if (includeStats) {
@ -80,7 +86,6 @@ export const DataStreamTable: React.FunctionComponent<Props> = ({
name: i18n.translate('xpack.idxMgmt.dataStreamList.table.maxTimeStampColumnTitle', {
defaultMessage: 'Last updated',
}),
width: '300px',
truncateText: true,
sortable: true,
render: (maxTimeStamp: DataStream['maxTimeStamp']) =>
@ -120,6 +125,28 @@ export const DataStreamTable: React.FunctionComponent<Props> = ({
),
});
columns.push({
field: 'lifecycle',
name: (
<EuiToolTip
content={i18n.translate('xpack.idxMgmt.dataStreamList.table.dataRetentionColumnTooltip', {
defaultMessage:
'Data will be be kept at least this long before it is automatically deleted. Only applies to data streams managed by a data stream lifecycle. This value might not apply to all data if the data stream also has an index lifecycle policy.',
})}
>
<span>
{i18n.translate('xpack.idxMgmt.dataStreamList.table.dataRetentionColumnTitle', {
defaultMessage: 'Data retention',
})}{' '}
<EuiIcon size="s" color="subdued" type="questionInCircle" />
</span>
</EuiToolTip>
),
truncateText: true,
sortable: true,
render: (lifecycle: DataStream['lifecycle']) => lifecycle?.data_retention,
});
columns.push({
name: i18n.translate('xpack.idxMgmt.dataStreamList.table.actionColumnTitle', {
defaultMessage: 'Actions',

View file

@ -8,55 +8,28 @@
import { schema, TypeOf } from '@kbn/config-schema';
import { IScopedClusterClient } from '@kbn/core/server';
import {
IndicesDataStream,
IndicesDataStreamsStatsDataStreamsStatsItem,
SecurityHasPrivilegesResponse,
} from '@elastic/elasticsearch/lib/api/types';
import { deserializeDataStream, deserializeDataStreamList } from '../../../../common/lib';
import { DataStreamFromEs } from '../../../../common/types';
import { EnhancedDataStreamFromEs } from '../../../../common/types';
import { RouteDependencies } from '../../../types';
import { addBasePath } from '..';
interface PrivilegesFromEs {
username: string;
has_all_requested: boolean;
cluster: Record<string, boolean>;
index: Record<string, Record<string, boolean>>;
application: Record<string, boolean>;
}
interface StatsFromEs {
data_stream: string;
store_size: string;
store_size_bytes: number;
maximum_timestamp: number;
}
const enhanceDataStreams = ({
dataStreams,
dataStreamsStats,
dataStreamsPrivileges,
}: {
dataStreams: DataStreamFromEs[];
dataStreamsStats?: StatsFromEs[];
dataStreamsPrivileges?: PrivilegesFromEs;
}): DataStreamFromEs[] => {
return dataStreams.map((dataStream: DataStreamFromEs) => {
let enhancedDataStream = { ...dataStream };
if (dataStreamsStats) {
// eslint-disable-next-line @typescript-eslint/naming-convention
const { store_size, store_size_bytes, maximum_timestamp } =
dataStreamsStats.find(
({ data_stream: statsName }: { data_stream: string }) => statsName === dataStream.name
) || {};
enhancedDataStream = {
...enhancedDataStream,
store_size,
store_size_bytes,
maximum_timestamp,
};
}
enhancedDataStream = {
...enhancedDataStream,
dataStreams: IndicesDataStream[];
dataStreamsStats?: IndicesDataStreamsStatsDataStreamsStatsItem[];
dataStreamsPrivileges?: SecurityHasPrivilegesResponse;
}): EnhancedDataStreamFromEs[] => {
return dataStreams.map((dataStream) => {
const enhancedDataStream: EnhancedDataStreamFromEs = {
...dataStream,
privileges: {
delete_index: dataStreamsPrivileges
? dataStreamsPrivileges.index[dataStream.name].delete_index
@ -64,6 +37,17 @@ const enhanceDataStreams = ({
},
};
if (dataStreamsStats) {
const currentDataStreamStats: IndicesDataStreamsStatsDataStreamsStatsItem | undefined =
dataStreamsStats.find(({ data_stream: statsName }) => statsName === dataStream.name);
if (currentDataStreamStats) {
enhancedDataStream.store_size = currentDataStreamStats.store_size;
enhancedDataStream.store_size_bytes = currentDataStreamStats.store_size_bytes;
enhancedDataStream.maximum_timestamp = currentDataStreamStats.maximum_timestamp;
}
}
return enhancedDataStream;
});
};
@ -125,11 +109,8 @@ export function registerGetAllRoute({ router, lib: { handleEsError }, config }:
}
const enhancedDataStreams = enhanceDataStreams({
// @ts-expect-error DataStreamFromEs conflicts with @elastic/elasticsearch IndicesGetDataStreamIndicesGetDataStreamItem
dataStreams,
// @ts-expect-error StatsFromEs conflicts with @elastic/elasticsearch IndicesDataStreamsStatsDataStreamsStatsItem
dataStreamsStats,
// @ts-expect-error PrivilegesFromEs conflicts with @elastic/elasticsearch ApplicationsPrivileges
dataStreamsPrivileges,
});
@ -164,11 +145,8 @@ export function registerGetOneRoute({ router, lib: { handleEsError }, config }:
}
const enhancedDataStreams = enhanceDataStreams({
// @ts-expect-error DataStreamFromEs conflicts with @elastic/elasticsearch IndicesGetDataStreamIndicesGetDataStreamItem
dataStreams,
// @ts-expect-error StatsFromEs conflicts with @elastic/elasticsearch IndicesDataStreamsStatsDataStreamsStatsItem
dataStreamsStats,
// @ts-expect-error PrivilegesFromEs conflicts with @elastic/elasticsearch ApplicationsPrivileges
dataStreamsPrivileges,
});
const body = deserializeDataStream(enhancedDataStreams[0]);

View file

@ -17347,7 +17347,6 @@
"xpack.idxMgmt.dataStreamDetailPanel.generationToolTip": "Nombre cumulatif d'index de sauvegarde créés pour le flux de données",
"xpack.idxMgmt.dataStreamDetailPanel.healthTitle": "Intégrité",
"xpack.idxMgmt.dataStreamDetailPanel.healthToolTip": "Intégrité des index de sauvegarde actuels du flux de données",
"xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyContentNoneMessage": "Aucun",
"xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyTitle": "Stratégie de cycle de vie des index",
"xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyToolTip": "Stratégie de cycle de vie de l'index qui gère les données du flux de données",
"xpack.idxMgmt.dataStreamDetailPanel.indexTemplateTitle": "Modèle d'index",

View file

@ -17361,7 +17361,6 @@
"xpack.idxMgmt.dataStreamDetailPanel.generationToolTip": "データストリームに作成されたバッキングインデックスの累積数",
"xpack.idxMgmt.dataStreamDetailPanel.healthTitle": "ヘルス",
"xpack.idxMgmt.dataStreamDetailPanel.healthToolTip": "データストリームの現在のバッキングインデックスのヘルス",
"xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyContentNoneMessage": "なし",
"xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyTitle": "インデックスライフサイクルポリシー",
"xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyToolTip": "データストリームのデータを管理するインデックスライフサイクルポリシー",
"xpack.idxMgmt.dataStreamDetailPanel.indexTemplateTitle": "インデックステンプレート",

View file

@ -17361,7 +17361,6 @@
"xpack.idxMgmt.dataStreamDetailPanel.generationToolTip": "为数据流创建的后备索引的累积计数",
"xpack.idxMgmt.dataStreamDetailPanel.healthTitle": "运行状况",
"xpack.idxMgmt.dataStreamDetailPanel.healthToolTip": "数据流的当前后备索引的运行状况",
"xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyContentNoneMessage": "无",
"xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyTitle": "索引生命周期策略",
"xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyToolTip": "用于管理数据流数据的索引生命周期策略",
"xpack.idxMgmt.dataStreamDetailPanel.indexTemplateTitle": "索引模板",

View file

@ -112,6 +112,9 @@ export default function ({ getService }: FtrProviderContext) {
expect(testDataStream).to.eql({
name: testDataStreamName,
lifecycle: {
enabled: true,
},
privileges: {
delete_index: true,
},
@ -166,6 +169,9 @@ export default function ({ getService }: FtrProviderContext) {
indexTemplateName: testDataStreamName,
maxTimeStamp: 0,
hidden: false,
lifecycle: {
enabled: true,
},
});
});
@ -197,6 +203,9 @@ export default function ({ getService }: FtrProviderContext) {
indexTemplateName: testDataStreamName,
maxTimeStamp: 0,
hidden: false,
lifecycle: {
enabled: true,
},
});
});
});