mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[Index Management] Add data retention to component template UI (#170837)
This commit is contained in:
parent
9b29b1898e
commit
02ccb7788a
14 changed files with 267 additions and 8 deletions
|
@ -8,15 +8,18 @@
|
||||||
import { IndexSettings } from './indices';
|
import { IndexSettings } from './indices';
|
||||||
import { Aliases } from './aliases';
|
import { Aliases } from './aliases';
|
||||||
import { Mappings } from './mappings';
|
import { Mappings } from './mappings';
|
||||||
|
import { DataStream, DataRetention } from '.';
|
||||||
|
|
||||||
export interface ComponentTemplateSerialized {
|
export interface ComponentTemplateSerialized {
|
||||||
template: {
|
template: {
|
||||||
settings?: IndexSettings;
|
settings?: IndexSettings;
|
||||||
aliases?: Aliases;
|
aliases?: Aliases;
|
||||||
mappings?: Mappings;
|
mappings?: Mappings;
|
||||||
|
lifecycle?: DataStream['lifecycle'];
|
||||||
};
|
};
|
||||||
version?: number;
|
version?: number;
|
||||||
_meta?: { [key: string]: any };
|
_meta?: { [key: string]: any };
|
||||||
|
lifecycle?: DataRetention;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ComponentTemplateDeserialized extends ComponentTemplateSerialized {
|
export interface ComponentTemplateDeserialized extends ComponentTemplateSerialized {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { breadcrumbService, IndexManagementBreadcrumb } from '../../../../servic
|
||||||
import { setupEnvironment } from './helpers';
|
import { setupEnvironment } from './helpers';
|
||||||
import { API_BASE_PATH } from './helpers/constants';
|
import { API_BASE_PATH } from './helpers/constants';
|
||||||
import { setup, ComponentTemplateCreateTestBed } from './helpers/component_template_create.helpers';
|
import { setup, ComponentTemplateCreateTestBed } from './helpers/component_template_create.helpers';
|
||||||
|
import { serializeAsESLifecycle } from '../../../../../../common/lib/data_stream_serialization';
|
||||||
|
|
||||||
jest.mock('@kbn/kibana-react-plugin/public', () => {
|
jest.mock('@kbn/kibana-react-plugin/public', () => {
|
||||||
const original = jest.requireActual('@kbn/kibana-react-plugin/public');
|
const original = jest.requireActual('@kbn/kibana-react-plugin/public');
|
||||||
|
@ -98,6 +99,19 @@ describe('<ComponentTemplateCreate />', () => {
|
||||||
expect(exists('metaEditor')).toBe(true);
|
expect(exists('metaEditor')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should toggle the data retention field', async () => {
|
||||||
|
const { exists, component, form } = testBed;
|
||||||
|
|
||||||
|
expect(exists('valueDataRetentionField')).toBe(false);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
form.toggleEuiSwitch('dataRetentionToggle.input');
|
||||||
|
});
|
||||||
|
component.update();
|
||||||
|
|
||||||
|
expect(exists('valueDataRetentionField')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
describe('Validation', () => {
|
describe('Validation', () => {
|
||||||
test('should require a name', async () => {
|
test('should require a name', async () => {
|
||||||
const { form, actions, component, find } = testBed;
|
const { form, actions, component, find } = testBed;
|
||||||
|
@ -120,6 +134,11 @@ describe('<ComponentTemplateCreate />', () => {
|
||||||
const COMPONENT_TEMPLATE_NAME = 'comp-1';
|
const COMPONENT_TEMPLATE_NAME = 'comp-1';
|
||||||
const SETTINGS = { number_of_shards: 1 };
|
const SETTINGS = { number_of_shards: 1 };
|
||||||
const ALIASES = { my_alias: {} };
|
const ALIASES = { my_alias: {} };
|
||||||
|
const LIFECYCLE = {
|
||||||
|
enabled: true,
|
||||||
|
value: 2,
|
||||||
|
unit: 'd',
|
||||||
|
};
|
||||||
|
|
||||||
const BOOLEAN_MAPPING_FIELD = {
|
const BOOLEAN_MAPPING_FIELD = {
|
||||||
name: 'boolean_datatype',
|
name: 'boolean_datatype',
|
||||||
|
@ -136,7 +155,10 @@ describe('<ComponentTemplateCreate />', () => {
|
||||||
component.update();
|
component.update();
|
||||||
|
|
||||||
// Complete step 1 (logistics)
|
// Complete step 1 (logistics)
|
||||||
await actions.completeStepLogistics({ name: COMPONENT_TEMPLATE_NAME });
|
await actions.completeStepLogistics({
|
||||||
|
name: COMPONENT_TEMPLATE_NAME,
|
||||||
|
lifecycle: LIFECYCLE,
|
||||||
|
});
|
||||||
|
|
||||||
// Complete step 2 (index settings)
|
// Complete step 2 (index settings)
|
||||||
await actions.completeStepSettings(SETTINGS);
|
await actions.completeStepSettings(SETTINGS);
|
||||||
|
@ -199,6 +221,7 @@ describe('<ComponentTemplateCreate />', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
aliases: ALIASES,
|
aliases: ALIASES,
|
||||||
|
lifecycle: serializeAsESLifecycle(LIFECYCLE),
|
||||||
},
|
},
|
||||||
_kbnMeta: { usedBy: [], isManaged: false },
|
_kbnMeta: { usedBy: [], isManaged: false },
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -19,6 +19,7 @@ const COMPONENT_TEMPLATE: ComponentTemplateDeserialized = {
|
||||||
mappings: { properties: { ip_address: { type: 'ip' } } },
|
mappings: { properties: { ip_address: { type: 'ip' } } },
|
||||||
aliases: { mydata: {} },
|
aliases: { mydata: {} },
|
||||||
settings: { number_of_shards: 1 },
|
settings: { number_of_shards: 1 },
|
||||||
|
lifecycle: { enabled: true, data_retention: '4d' },
|
||||||
},
|
},
|
||||||
version: 1,
|
version: 1,
|
||||||
_meta: { description: 'component template test' },
|
_meta: { description: 'component template test' },
|
||||||
|
@ -72,6 +73,7 @@ describe('<ComponentTemplateDetails />', () => {
|
||||||
expect(exists('summaryTabContent.usedByTitle')).toBe(true);
|
expect(exists('summaryTabContent.usedByTitle')).toBe(true);
|
||||||
expect(exists('summaryTabContent.versionTitle')).toBe(true);
|
expect(exists('summaryTabContent.versionTitle')).toBe(true);
|
||||||
expect(exists('summaryTabContent.metaTitle')).toBe(true);
|
expect(exists('summaryTabContent.metaTitle')).toBe(true);
|
||||||
|
expect(exists('summaryTabContent.dataRetentionTitle')).toBe(true);
|
||||||
|
|
||||||
// [Settings tab] Navigate to tab and verify content
|
// [Settings tab] Navigate to tab and verify content
|
||||||
act(() => {
|
act(() => {
|
||||||
|
|
|
@ -78,6 +78,7 @@ export type ComponentTemplateDetailsTestSubjects =
|
||||||
| 'summaryTabContent.usedByTitle'
|
| 'summaryTabContent.usedByTitle'
|
||||||
| 'summaryTabContent.versionTitle'
|
| 'summaryTabContent.versionTitle'
|
||||||
| 'summaryTabContent.metaTitle'
|
| 'summaryTabContent.metaTitle'
|
||||||
|
| 'summaryTabContent.dataRetentionTitle'
|
||||||
| 'notInUseCallout'
|
| 'notInUseCallout'
|
||||||
| 'aliasesTabContent'
|
| 'aliasesTabContent'
|
||||||
| 'noAliasesCallout'
|
| 'noAliasesCallout'
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
|
|
||||||
import { TestBed } from '@kbn/test-jest-helpers';
|
import { TestBed } from '@kbn/test-jest-helpers';
|
||||||
|
import { DataRetention } from '../../../../../../../common';
|
||||||
|
|
||||||
interface MappingField {
|
interface MappingField {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -52,11 +53,28 @@ export const getFormActions = (testBed: TestBed) => {
|
||||||
.simulate('click');
|
.simulate('click');
|
||||||
};
|
};
|
||||||
|
|
||||||
const completeStepLogistics = async ({ name }: { name: string }) => {
|
const completeStepLogistics = async ({
|
||||||
|
name,
|
||||||
|
lifecycle,
|
||||||
|
}: {
|
||||||
|
name: string;
|
||||||
|
lifecycle: DataRetention;
|
||||||
|
}) => {
|
||||||
const { form, component } = testBed;
|
const { form, component } = testBed;
|
||||||
// Add name field
|
// Add name field
|
||||||
form.setInputValue('nameField.input', name);
|
form.setInputValue('nameField.input', name);
|
||||||
|
|
||||||
|
if (lifecycle && lifecycle.enabled) {
|
||||||
|
act(() => {
|
||||||
|
form.toggleEuiSwitch('dataRetentionToggle.input');
|
||||||
|
});
|
||||||
|
component.update();
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
form.setInputValue('valueDataRetentionField', String(lifecycle.value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
clickNextButton();
|
clickNextButton();
|
||||||
});
|
});
|
||||||
|
@ -164,6 +182,8 @@ export type ComponentTemplateFormTestSubjects =
|
||||||
| 'stepReview.content'
|
| 'stepReview.content'
|
||||||
| 'stepReview.summaryTab'
|
| 'stepReview.summaryTab'
|
||||||
| 'stepReview.requestTab'
|
| 'stepReview.requestTab'
|
||||||
|
| 'valueDataRetentionField'
|
||||||
|
| 'dataRetentionToggle.input'
|
||||||
| 'versionField'
|
| 'versionField'
|
||||||
| 'aliasesEditor'
|
| 'aliasesEditor'
|
||||||
| 'mappingsEditor'
|
| 'mappingsEditor'
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {
|
||||||
EuiLink,
|
EuiLink,
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
|
|
||||||
|
import { getLifecycleValue } from '../../../lib/data_streams';
|
||||||
import { ComponentTemplateDeserialized } from '../shared_imports';
|
import { ComponentTemplateDeserialized } from '../shared_imports';
|
||||||
import { useComponentTemplatesContext } from '../component_templates_context';
|
import { useComponentTemplatesContext } from '../component_templates_context';
|
||||||
|
|
||||||
|
@ -27,13 +28,15 @@ interface Props {
|
||||||
showCallToAction?: boolean;
|
showCallToAction?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const INFINITE_AS_ICON = true;
|
||||||
|
|
||||||
export const TabSummary: React.FunctionComponent<Props> = ({
|
export const TabSummary: React.FunctionComponent<Props> = ({
|
||||||
componentTemplateDetails,
|
componentTemplateDetails,
|
||||||
showCallToAction,
|
showCallToAction,
|
||||||
}) => {
|
}) => {
|
||||||
const { getUrlForApp } = useComponentTemplatesContext();
|
const { getUrlForApp } = useComponentTemplatesContext();
|
||||||
|
|
||||||
const { version, _meta, _kbnMeta } = componentTemplateDetails;
|
const { version, _meta, _kbnMeta, template } = componentTemplateDetails;
|
||||||
|
|
||||||
const { usedBy } = _kbnMeta;
|
const { usedBy } = _kbnMeta;
|
||||||
const templateIsInUse = usedBy.length > 0;
|
const templateIsInUse = usedBy.length > 0;
|
||||||
|
@ -118,6 +121,20 @@ export const TabSummary: React.FunctionComponent<Props> = ({
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{template.lifecycle && (
|
||||||
|
<>
|
||||||
|
<EuiDescriptionListTitle data-test-subj="dataRetentionTitle">
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.idxMgmt.componentTemplateDetails.summaryTab.dataRetentionDescriptionListTitle"
|
||||||
|
defaultMessage="Data retention"
|
||||||
|
/>
|
||||||
|
</EuiDescriptionListTitle>
|
||||||
|
<EuiDescriptionListDescription>
|
||||||
|
{getLifecycleValue(template.lifecycle, INFINITE_AS_ICON)}
|
||||||
|
</EuiDescriptionListDescription>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Version (optional) */}
|
{/* Version (optional) */}
|
||||||
{typeof version !== 'undefined' && (
|
{typeof version !== 'undefined' && (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -19,6 +19,10 @@ import {
|
||||||
StepMappingsContainer,
|
StepMappingsContainer,
|
||||||
StepAliasesContainer,
|
StepAliasesContainer,
|
||||||
} from '../../shared_imports';
|
} from '../../shared_imports';
|
||||||
|
import {
|
||||||
|
serializeAsESLifecycle,
|
||||||
|
deserializeESLifecycle,
|
||||||
|
} from '../../../../../../common/lib/data_stream_serialization';
|
||||||
import { useComponentTemplatesContext } from '../../component_templates_context';
|
import { useComponentTemplatesContext } from '../../component_templates_context';
|
||||||
import { StepLogisticsContainer, StepReviewContainer } from './steps';
|
import { StepLogisticsContainer, StepReviewContainer } from './steps';
|
||||||
|
|
||||||
|
@ -96,14 +100,17 @@ export const ComponentTemplateForm = ({
|
||||||
onStepChange,
|
onStepChange,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const {
|
const {
|
||||||
template: { settings, mappings, aliases },
|
template: { settings, mappings, aliases, lifecycle },
|
||||||
...logistics
|
...logistics
|
||||||
} = defaultValue;
|
} = defaultValue;
|
||||||
|
|
||||||
const { documentation } = useComponentTemplatesContext();
|
const { documentation } = useComponentTemplatesContext();
|
||||||
|
|
||||||
const wizardDefaultValue: WizardContent = {
|
const wizardDefaultValue: WizardContent = {
|
||||||
logistics,
|
logistics: {
|
||||||
|
...logistics,
|
||||||
|
...(lifecycle ? { lifecycle: deserializeESLifecycle(lifecycle) } : {}),
|
||||||
|
},
|
||||||
settings,
|
settings,
|
||||||
mappings,
|
mappings,
|
||||||
aliases,
|
aliases,
|
||||||
|
@ -162,6 +169,10 @@ export const ComponentTemplateForm = ({
|
||||||
delete outputTemplate.template.aliases;
|
delete outputTemplate.template.aliases;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (outputTemplate.lifecycle) {
|
||||||
|
delete outputTemplate.lifecycle;
|
||||||
|
}
|
||||||
|
|
||||||
return outputTemplate;
|
return outputTemplate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -177,9 +188,14 @@ export const ComponentTemplateForm = ({
|
||||||
settings: wizardData.settings,
|
settings: wizardData.settings,
|
||||||
mappings: wizardData.mappings,
|
mappings: wizardData.mappings,
|
||||||
aliases: wizardData.aliases,
|
aliases: wizardData.aliases,
|
||||||
|
lifecycle: wizardData.logistics.lifecycle
|
||||||
|
? serializeAsESLifecycle(wizardData.logistics.lifecycle)
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return cleanupComponentTemplateObject(outputComponentTemplate);
|
return cleanupComponentTemplateObject(
|
||||||
|
outputComponentTemplate as ComponentTemplateDeserialized
|
||||||
|
);
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
|
@ -24,8 +24,12 @@ import {
|
||||||
getFormRow,
|
getFormRow,
|
||||||
Field,
|
Field,
|
||||||
Forms,
|
Forms,
|
||||||
|
NumericField,
|
||||||
JsonEditorField,
|
JsonEditorField,
|
||||||
|
useFormData,
|
||||||
} from '../../../shared_imports';
|
} from '../../../shared_imports';
|
||||||
|
import { DataRetention } from '../../../../../../../common';
|
||||||
|
import { UnitField, timeUnits } from '../../../../shared';
|
||||||
import { useComponentTemplatesContext } from '../../../component_templates_context';
|
import { useComponentTemplatesContext } from '../../../component_templates_context';
|
||||||
import { logisticsFormSchema } from './step_logistics_schema';
|
import { logisticsFormSchema } from './step_logistics_schema';
|
||||||
|
|
||||||
|
@ -48,6 +52,13 @@ export const StepLogistics: React.FunctionComponent<Props> = React.memo(
|
||||||
|
|
||||||
const { isValid: isFormValid, submit, getFormData, subscribe } = form;
|
const { isValid: isFormValid, submit, getFormData, subscribe } = form;
|
||||||
|
|
||||||
|
const [{ lifecycle }] = useFormData<{
|
||||||
|
lifecycle: DataRetention;
|
||||||
|
}>({
|
||||||
|
form,
|
||||||
|
watch: ['lifecycle.enabled', 'lifecycle.infiniteDataRetention'],
|
||||||
|
});
|
||||||
|
|
||||||
const { documentation } = useComponentTemplatesContext();
|
const { documentation } = useComponentTemplatesContext();
|
||||||
|
|
||||||
const [isMetaVisible, setIsMetaVisible] = useState<boolean>(
|
const [isMetaVisible, setIsMetaVisible] = useState<boolean>(
|
||||||
|
@ -134,6 +145,64 @@ export const StepLogistics: React.FunctionComponent<Props> = React.memo(
|
||||||
/>
|
/>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
|
|
||||||
|
{/* Data retention field */}
|
||||||
|
<FormRow
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.idxMgmt.componentTemplateForm.stepLogistics.dataRetentionTitle"
|
||||||
|
defaultMessage="Data retention"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
description={
|
||||||
|
<>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.idxMgmt.componentTemplateForm.stepLogistics.dataRetentionDescription"
|
||||||
|
defaultMessage="Data will be kept at least this long before being automatically deleted."
|
||||||
|
/>
|
||||||
|
<EuiSpacer size="m" />
|
||||||
|
<UseField
|
||||||
|
path="lifecycle.enabled"
|
||||||
|
componentProps={{ 'data-test-subj': 'dataRetentionToggle' }}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{lifecycle?.enabled && (
|
||||||
|
<UseField
|
||||||
|
path="lifecycle.value"
|
||||||
|
component={NumericField}
|
||||||
|
labelAppend={
|
||||||
|
<UseField
|
||||||
|
path="lifecycle.infiniteDataRetention"
|
||||||
|
data-test-subj="infiniteDataRetentionToggle"
|
||||||
|
componentProps={{
|
||||||
|
euiFieldProps: {
|
||||||
|
compressed: true,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
componentProps={{
|
||||||
|
euiFieldProps: {
|
||||||
|
disabled: lifecycle?.infiniteDataRetention,
|
||||||
|
'data-test-subj': 'valueDataRetentionField',
|
||||||
|
min: 1,
|
||||||
|
append: (
|
||||||
|
<UnitField
|
||||||
|
path="lifecycle.unit"
|
||||||
|
options={timeUnits}
|
||||||
|
disabled={lifecycle?.infiniteDataRetention}
|
||||||
|
euiFieldProps={{
|
||||||
|
'data-test-subj': 'unitDataRetentionField',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</FormRow>
|
||||||
|
|
||||||
{/* version field */}
|
{/* version field */}
|
||||||
<FormRow
|
<FormRow
|
||||||
title={
|
title={
|
||||||
|
|
|
@ -58,6 +58,89 @@ export const logisticsFormSchema: FormSchema = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
'lifecycle.enabled': {
|
||||||
|
type: FIELD_TYPES.TOGGLE,
|
||||||
|
label: i18n.translate(
|
||||||
|
'xpack.idxMgmt.componentTemplateForm.stepLogistics.enableDataRetentionLabel',
|
||||||
|
{
|
||||||
|
defaultMessage: 'Enable data retention',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
'lifecycle.infiniteDataRetention': {
|
||||||
|
type: FIELD_TYPES.TOGGLE,
|
||||||
|
label: i18n.translate(
|
||||||
|
'xpack.idxMgmt.componentTemplateForm.stepLogistics.infiniteDataRetentionLabel',
|
||||||
|
{
|
||||||
|
defaultMessage: 'Keep data indefinitely',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
'lifecycle.value': {
|
||||||
|
type: FIELD_TYPES.TEXT,
|
||||||
|
label: i18n.translate(
|
||||||
|
'xpack.idxMgmt.componentTemplateForm.stepLogistics.fieldDataRetentionValueLabel',
|
||||||
|
{
|
||||||
|
defaultMessage: 'Data Retention',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
formatters: [toInt],
|
||||||
|
validations: [
|
||||||
|
{
|
||||||
|
validator: ({ value, formData }) => {
|
||||||
|
// If infiniteRetentionPeriod is set, we dont need to validate the data retention field
|
||||||
|
if (formData['lifecycle.infiniteDataRetention']) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return {
|
||||||
|
message: i18n.translate(
|
||||||
|
'xpack.idxMgmt.dataStreamsDetailsPanel.stepLogistics.dataRetentionFieldRequiredError',
|
||||||
|
{
|
||||||
|
defaultMessage: 'A data retention value is required.',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value <= 0) {
|
||||||
|
return {
|
||||||
|
message: i18n.translate(
|
||||||
|
'xpack.idxMgmt.dataStreamsDetailsPanel.stepLogistics.dataRetentionFieldNonNegativeError',
|
||||||
|
{
|
||||||
|
defaultMessage: `A positive value is required.`,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value % 1 !== 0) {
|
||||||
|
return {
|
||||||
|
message: i18n.translate(
|
||||||
|
'xpack.idxMgmt.dataStreamsDetailsPanel.stepLogistics.dataRetentionFieldDecimalError',
|
||||||
|
{
|
||||||
|
defaultMessage: `The value should be an integer number.`,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'lifecycle.unit': {
|
||||||
|
type: FIELD_TYPES.TEXT,
|
||||||
|
label: i18n.translate(
|
||||||
|
'xpack.idxMgmt.componentTemplateForm.stepLogistics.fieldDataRetentionUnitLabel',
|
||||||
|
{
|
||||||
|
defaultMessage: 'Time unit',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
defaultValue: 'd',
|
||||||
|
},
|
||||||
version: {
|
version: {
|
||||||
type: FIELD_TYPES.NUMBER,
|
type: FIELD_TYPES.NUMBER,
|
||||||
label: i18n.translate('xpack.idxMgmt.componentTemplateForm.stepLogistics.versionFieldLabel', {
|
label: i18n.translate('xpack.idxMgmt.componentTemplateForm.stepLogistics.versionFieldLabel', {
|
||||||
|
|
|
@ -28,7 +28,9 @@ import {
|
||||||
serializeComponentTemplate,
|
serializeComponentTemplate,
|
||||||
} from '../../../shared_imports';
|
} from '../../../shared_imports';
|
||||||
import { MANAGED_BY_FLEET } from '../../../constants';
|
import { MANAGED_BY_FLEET } from '../../../constants';
|
||||||
|
import { getLifecycleValue } from '../../../../../lib/data_streams';
|
||||||
|
|
||||||
|
const INFINITE_AS_ICON = true;
|
||||||
const { stripEmptyFields } = serializers;
|
const { stripEmptyFields } = serializers;
|
||||||
|
|
||||||
const getDescriptionText = (data: any) => {
|
const getDescriptionText = (data: any) => {
|
||||||
|
@ -123,6 +125,17 @@ export const StepReview: React.FunctionComponent<Props> = React.memo(
|
||||||
<EuiDescriptionListDescription>
|
<EuiDescriptionListDescription>
|
||||||
{getDescriptionText(serializedTemplate?.aliases)}
|
{getDescriptionText(serializedTemplate?.aliases)}
|
||||||
</EuiDescriptionListDescription>
|
</EuiDescriptionListDescription>
|
||||||
|
|
||||||
|
{/* Data retention */}
|
||||||
|
<EuiDescriptionListTitle>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.idxMgmt.componentTemplateForm.stepReview.summaryTab.dataRetentionLabel"
|
||||||
|
defaultMessage="Data retention"
|
||||||
|
/>
|
||||||
|
</EuiDescriptionListTitle>
|
||||||
|
<EuiDescriptionListDescription>
|
||||||
|
{getLifecycleValue(serializedTemplate?.lifecycle, INFINITE_AS_ICON)}
|
||||||
|
</EuiDescriptionListDescription>
|
||||||
</EuiDescriptionList>
|
</EuiDescriptionList>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
{isFleetDatastreamsVisible && dataStreams && (
|
{isFleetDatastreamsVisible && dataStreams && (
|
||||||
|
|
|
@ -41,12 +41,14 @@ export {
|
||||||
useForm,
|
useForm,
|
||||||
Form,
|
Form,
|
||||||
getUseField,
|
getUseField,
|
||||||
|
useFormData,
|
||||||
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
|
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getFormRow,
|
getFormRow,
|
||||||
Field,
|
Field,
|
||||||
JsonEditorField,
|
JsonEditorField,
|
||||||
|
NumericField,
|
||||||
} from '@kbn/es-ui-shared-plugin/static/forms/components';
|
} from '@kbn/es-ui-shared-plugin/static/forms/components';
|
||||||
|
|
||||||
export { isJSON } from '@kbn/es-ui-shared-plugin/static/validators/string';
|
export { isJSON } from '@kbn/es-ui-shared-plugin/static/validators/string';
|
||||||
|
|
|
@ -33,9 +33,9 @@ export function registerGetAllRoute({ router, lib: { handleEsError } }: RouteDep
|
||||||
const { index_templates: indexTemplates } =
|
const { index_templates: indexTemplates } =
|
||||||
await client.asCurrentUser.indices.getIndexTemplate();
|
await client.asCurrentUser.indices.getIndexTemplate();
|
||||||
|
|
||||||
const body = componentTemplates.map((componentTemplate: ComponentTemplateFromEs) => {
|
const body = componentTemplates.map((componentTemplate) => {
|
||||||
const deserializedComponentTemplateListItem = deserializeComponentTemplateList(
|
const deserializedComponentTemplateListItem = deserializeComponentTemplateList(
|
||||||
componentTemplate,
|
componentTemplate as ComponentTemplateFromEs,
|
||||||
// @ts-expect-error TemplateSerialized.index_patterns not compatible with IndicesIndexTemplate.index_patterns
|
// @ts-expect-error TemplateSerialized.index_patterns not compatible with IndicesIndexTemplate.index_patterns
|
||||||
indexTemplates
|
indexTemplates
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,6 +13,12 @@ export const componentTemplateSchema = schema.object({
|
||||||
settings: schema.maybe(schema.object({}, { unknowns: 'allow' })),
|
settings: schema.maybe(schema.object({}, { unknowns: 'allow' })),
|
||||||
aliases: schema.maybe(schema.object({}, { unknowns: 'allow' })),
|
aliases: schema.maybe(schema.object({}, { unknowns: 'allow' })),
|
||||||
mappings: schema.maybe(schema.object({}, { unknowns: 'allow' })),
|
mappings: schema.maybe(schema.object({}, { unknowns: 'allow' })),
|
||||||
|
lifecycle: schema.maybe(
|
||||||
|
schema.object({
|
||||||
|
enabled: schema.boolean(),
|
||||||
|
data_retention: schema.maybe(schema.string()),
|
||||||
|
})
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
version: schema.maybe(schema.number()),
|
version: schema.maybe(schema.number()),
|
||||||
_meta: schema.maybe(schema.object({}, { unknowns: 'allow' })),
|
_meta: schema.maybe(schema.object({}, { unknowns: 'allow' })),
|
||||||
|
|
|
@ -147,6 +147,10 @@ export default function ({ getService }: FtrProviderContext) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
lifecycle: {
|
||||||
|
enabled: true,
|
||||||
|
data_retention: '2d',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
_meta: {
|
_meta: {
|
||||||
description: 'set number of shards to one',
|
description: 'set number of shards to one',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue