Skip to content

Commit

Permalink
[Index Management] Fix small edit lifecycle bugs (elastic#168560)
Browse files Browse the repository at this point in the history
  • Loading branch information
sabarasaba authored Oct 16, 2023
1 parent cde3293 commit 3488c83
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,5 @@ export type TestSubjects =
| 'filter-option-h'
| 'infiniteRetentionPeriod.input'
| 'saveButton'
| 'dataRetentionDetail'
| 'createIndexSaveButton';
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ export const createDataStreamPayload = (dataStream: Partial<DataStream>): DataSt
},
hidden: false,
lifecycle: {
enabled: true,
data_retention: '7d',
},
...dataStream,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,55 @@ describe('Data Streams tab', () => {
});

describe('update data retention', () => {
test('Should show disabled or infinite retention period accordingly in table and flyout', async () => {
const { setLoadDataStreamsResponse, setLoadDataStreamResponse } = httpRequestsMockHelpers;

const ds1 = createDataStreamPayload({
name: 'dataStream1',
lifecycle: {
enabled: false,
},
});
const ds2 = createDataStreamPayload({
name: 'dataStream2',
lifecycle: {
enabled: true,
},
});

setLoadDataStreamsResponse([ds1, ds2]);
setLoadDataStreamResponse(ds1.name, ds1);

testBed = await setup(httpSetup, {
history: createMemoryHistory(),
url: urlServiceMock,
});
await act(async () => {
testBed.actions.goToDataStreamsList();
});
testBed.component.update();

const { actions, find, table } = testBed;
const { tableCellsValues } = table.getMetaData('dataStreamTable');

expect(tableCellsValues).toEqual([
['', 'dataStream1', 'green', '1', 'Disabled', 'Delete'],
['', 'dataStream2', 'green', '1', '', 'Delete'],
]);

await actions.clickNameAt(0);
expect(find('dataRetentionDetail').text()).toBe('Disabled');

await act(async () => {
testBed.find('closeDetailsButton').simulate('click');
});
testBed.component.update();

setLoadDataStreamResponse(ds2.name, ds2);
await actions.clickNameAt(1);
expect(find('dataRetentionDetail').text()).toBe('Keep data indefinitely');
});

test('can set data retention period', async () => {
const {
actions: { clickNameAt, clickEditDataRetentionButton },
Expand Down
4 changes: 3 additions & 1 deletion x-pack/plugins/index_management/common/types/data_streams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ export interface DataStream {
_meta?: Metadata;
privileges: Privileges;
hidden: boolean;
lifecycle?: IndicesDataLifecycleWithRollover;
lifecycle?: IndicesDataLifecycleWithRollover & {
enabled?: boolean;
};
}

export interface DataStreamIndex {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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 { getLifecycleValue } from './data_streams';

describe('Data stream helpers', () => {
describe('getLifecycleValue', () => {
it('Knows when it should be marked as disabled', () => {
expect(
getLifecycleValue({
enabled: false,
})
).toBe('Disabled');

expect(getLifecycleValue()).toBe('Disabled');
});

it('knows when it should be marked as infinite', () => {
expect(
getLifecycleValue({
enabled: true,
})
).toBe('Keep data indefinitely');
});

it('knows when it has a defined data retention period', () => {
expect(
getLifecycleValue({
enabled: true,
data_retention: '2d',
})
).toBe('2d');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
* 2.0.
*/

import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiIcon, EuiToolTip } from '@elastic/eui';

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

export const isFleetManaged = (dataStream: DataStream): boolean => {
Expand Down Expand Up @@ -38,3 +42,37 @@ export const isSelectedDataStreamHidden = (
?.hidden
);
};

export const getLifecycleValue = (
lifecycle?: DataStream['lifecycle'],
inifniteAsIcon?: boolean
) => {
if (!lifecycle?.enabled) {
return i18n.translate('xpack.idxMgmt.dataStreamList.dataRetentionDisabled', {
defaultMessage: 'Disabled',
});
} else if (!lifecycle?.data_retention) {
const infiniteDataRetention = i18n.translate(
'xpack.idxMgmt.dataStreamList.dataRetentionInfinite',
{
defaultMessage: 'Keep data indefinitely',
}
);

if (inifniteAsIcon) {
return (
<EuiToolTip
data-test-subj="infiniteRetention"
position="top"
content={infiniteDataRetention}
>
<EuiIcon type="infinity" />
</EuiToolTip>
);
}

return infiniteDataRetention;
}

return lifecycle?.data_retention;
};
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
} from '@elastic/eui';

import { DiscoverLink } from '../../../../lib/discover_link';
import { getLifecycleValue } from '../../../../lib/data_streams';
import { SectionLoading, reactRouterNavigate } from '../../../../../shared_imports';
import { SectionError, Error, DataHealth } from '../../../../components';
import { useLoadDataStream } from '../../../../services/api';
Expand Down Expand Up @@ -147,19 +148,6 @@ export const DataStreamDetailPanel: React.FunctionComponent<Props> = ({
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', {
Expand Down Expand Up @@ -278,6 +266,16 @@ export const DataStreamDetailPanel: React.FunctionComponent<Props> = ({
),
dataTestSubj: 'indexTemplateDetail',
},
{
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: getLifecycleValue(lifecycle),
dataTestSubj: 'dataRetentionDetail',
},
];

const managementDetails = getManagementDetails();
Expand Down Expand Up @@ -376,7 +374,7 @@ export const DataStreamDetailPanel: React.FunctionComponent<Props> = ({
}
}}
dataStreamName={dataStreamName}
dataRetention={dataStream?.lifecycle?.data_retention as string}
lifecycle={dataStream?.lifecycle}
/>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { ScopedHistory } from '@kbn/core/public';

import { DataStream } from '../../../../../../common/types';
import { getLifecycleValue } from '../../../../lib/data_streams';
import { UseRequestResponse, reactRouterNavigate } from '../../../../../shared_imports';
import { getDataStreamDetailsLink, getIndexListUri } from '../../../../services/routing';
import { DataHealth } from '../../../../components';
Expand All @@ -34,6 +35,8 @@ interface Props {
filters?: string;
}

const INFINITE_AS_ICON = true;

export const DataStreamTable: React.FunctionComponent<Props> = ({
dataStreams,
reload,
Expand Down Expand Up @@ -144,7 +147,7 @@ export const DataStreamTable: React.FunctionComponent<Props> = ({
),
truncateText: true,
sortable: true,
render: (lifecycle: DataStream['lifecycle']) => lifecycle?.data_retention,
render: (lifecycle: DataStream['lifecycle']) => getLifecycleValue(lifecycle, INFINITE_AS_ICON),
});

columns.push({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ import {
} from '../../../../../shared_imports';

import { documentationService } from '../../../../services/documentation';
import { splitSizeAndUnits } from '../../../../../../common';
import { splitSizeAndUnits, DataStream } from '../../../../../../common';
import { useAppContext } from '../../../../app_context';
import { UnitField } from './unit_field';
import { updateDataRetention } from '../../../../services/api';

interface Props {
dataRetention: string;
lifecycle: DataStream['lifecycle'];
dataStreamName: string;
onClose: (data?: { hasUpdatedDataRetention: boolean }) => void;
}
Expand Down Expand Up @@ -83,33 +83,6 @@ export const timeUnits = [
}
),
},
{
value: 'ms',
text: i18n.translate(
'xpack.idxMgmt.dataStreamsDetailsPanel.editDataRetentionModal.timeUnits.millisecondsLabel',
{
defaultMessage: 'milliseconds',
}
),
},
{
value: 'micros',
text: i18n.translate(
'xpack.idxMgmt.dataStreamsDetailsPanel.editDataRetentionModal.timeUnits.microsecondsLabel',
{
defaultMessage: 'microseconds',
}
),
},
{
value: 'nanos',
text: i18n.translate(
'xpack.idxMgmt.dataStreamsDetailsPanel.editDataRetentionModal.timeUnits.nanosecondsLabel',
{
defaultMessage: 'nanoseconds',
}
),
},
];

const configurationFormSchema: FormSchema = {
Expand All @@ -124,7 +97,12 @@ const configurationFormSchema: FormSchema = {
formatters: [fieldFormatters.toInt],
validations: [
{
validator: ({ value }) => {
validator: ({ value, formData }) => {
// If infiniteRetentionPeriod is set, we dont need to validate the data retention field
if (formData.infiniteRetentionPeriod) {
return undefined;
}

if (!value) {
return {
message: i18n.translate(
Expand Down Expand Up @@ -171,11 +149,11 @@ const configurationFormSchema: FormSchema = {
};

export const EditDataRetentionModal: React.FunctionComponent<Props> = ({
dataRetention,
lifecycle,
dataStreamName,
onClose,
}) => {
const { size, unit } = splitSizeAndUnits(dataRetention);
const { size, unit } = splitSizeAndUnits(lifecycle?.data_retention as string);
const {
services: { notificationService },
} = useAppContext();
Expand All @@ -184,7 +162,10 @@ export const EditDataRetentionModal: React.FunctionComponent<Props> = ({
defaultValue: {
dataRetention: size,
timeUnit: unit || 'd',
infiniteRetentionPeriod: !dataRetention,
// When data retention is not set and lifecycle is enabled, is the only scenario in
// which data retention will be infinite. If lifecycle isnt set or is not enabled, we
// dont have inifinite data retention.
infiniteRetentionPeriod: lifecycle?.enabled && !lifecycle?.data_retention,
},
schema: configurationFormSchema,
id: 'editDataRetentionForm',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ export default function ({ getService }: FtrProviderContext) {
},
},
},
lifecycle: {
// @ts-expect-error @elastic/elasticsearch enabled prop is not typed yet
enabled: true,
},
},
data_stream: {},
},
Expand Down Expand Up @@ -85,8 +89,7 @@ export default function ({ getService }: FtrProviderContext) {
expect(typeof storageSizeBytes).to.be('number');
};

// FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/168021
describe.skip('Data streams', function () {
describe('Data streams', function () {
describe('Get', () => {
const testDataStreamName = 'test-data-stream';

Expand Down
Loading

0 comments on commit 3488c83

Please sign in to comment.