diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx index a59c4d9878aea5..dc375f63700484 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx @@ -248,6 +248,27 @@ export const setup = async (arg?: { appServicesContext: Partial { + const enablePhase = async () => { + await act(async () => { + find('enableDeletePhaseButton').simulate('click'); + }); + component.update(); + }; + + const disablePhase = async () => { + await act(async () => { + find('disableDeletePhaseButton').simulate('click'); + }); + component.update(); + }; + + return { + enablePhase, + disablePhase, + }; + }; + return { ...testBed, actions: { @@ -303,7 +324,7 @@ export const setup = async (arg?: { appServicesContext: Partial', () => { // Set max docs to test whether we keep the unknown fields in that object after serializing await actions.hot.setMaxDocs('1000'); // Remove the delete phase to ensure that we also correctly remove data - await actions.delete.enable(false); + await actions.delete.disablePhase(); await actions.savePolicy(); const latestRequest = server.requests[server.requests.length - 1]; @@ -89,7 +89,7 @@ describe('', () => { unknown_setting: true, }, }, - min_age: '0ms', + min_age: '0d', }, }, }); @@ -255,7 +255,7 @@ describe('', () => { "priority": 50, }, }, - "min_age": "0ms", + "min_age": "0d", } `); }); @@ -310,7 +310,7 @@ describe('', () => { "number_of_shards": 123, }, }, - "min_age": "0ms", + "min_age": "0d", }, }, } @@ -839,7 +839,7 @@ describe('', () => { expect(actions.timeline.hasColdPhase()).toBe(true); expect(actions.timeline.hasDeletePhase()).toBe(false); - await actions.delete.enable(true); + await actions.delete.enablePhase(); expect(actions.timeline.hasHotPhase()).toBe(true); expect(actions.timeline.hasWarmPhase()).toBe(true); expect(actions.timeline.hasColdPhase()).toBe(true); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx b/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx index a9a351e394f7ff..7c199e2ced7651 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx +++ b/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx @@ -99,6 +99,13 @@ const activatePhase = async (rendered: ReactWrapper, phase: string) => { }); rendered.update(); }; +const activateDeletePhase = async (rendered: ReactWrapper) => { + const testSubject = `enableDeletePhaseButton`; + await act(async () => { + await findTestSubject(rendered, testSubject).simulate('click'); + }); + rendered.update(); +}; const openNodeAttributesSection = async (rendered: ReactWrapper, phase: string) => { const getControls = () => findTestSubject(rendered, `${phase}-dataTierAllocationControls`); await act(async () => { @@ -454,6 +461,11 @@ describe('edit policy', () => { waitForFormLibValidation(rendered); expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.nonNegativeNumberRequired]); }); + + test("doesn't show min age input", async () => { + const rendered = mountWithIntl(component); + expect(findTestSubject(rendered, 'hot-selectedMinimumAge').exists()).toBeFalsy(); + }); }); describe('warm phase', () => { beforeEach(() => { @@ -670,6 +682,13 @@ describe('edit policy', () => { expect(rendered.find('.euiLoadingSpinner').exists()).toBeFalsy(); expect(findTestSubject(rendered, 'defaultAllocationNotice').exists()).toBeFalsy(); }); + + test('shows min age input only when enabled', async () => { + const rendered = mountWithIntl(component); + expect(findTestSubject(rendered, 'warm-selectedMinimumAge').exists()).toBeFalsy(); + await activatePhase(rendered, 'warm'); + expect(findTestSubject(rendered, 'warm-selectedMinimumAge').exists()).toBeTruthy(); + }); }); describe('cold phase', () => { beforeEach(() => { @@ -807,13 +826,20 @@ describe('edit policy', () => { expect(rendered.find('.euiLoadingSpinner').exists()).toBeFalsy(); expect(findTestSubject(rendered, 'defaultAllocationNotice').exists()).toBeFalsy(); }); + + test('shows min age input only when enabled', async () => { + const rendered = mountWithIntl(component); + expect(findTestSubject(rendered, 'cold-selectedMinimumAge').exists()).toBeFalsy(); + await activatePhase(rendered, 'cold'); + expect(findTestSubject(rendered, 'cold-selectedMinimumAge').exists()).toBeTruthy(); + }); }); describe('delete phase', () => { test('should allow 0 for phase timing', async () => { const rendered = mountWithIntl(component); await noRollover(rendered); await setPolicyName(rendered, 'mypolicy'); - await activatePhase(rendered, 'delete'); + await activateDeletePhase(rendered); await setPhaseAfter(rendered, 'delete', '0'); waitForFormLibValidation(rendered); expectedErrorMessages(rendered, []); @@ -822,11 +848,18 @@ describe('edit policy', () => { const rendered = mountWithIntl(component); await noRollover(rendered); await setPolicyName(rendered, 'mypolicy'); - await activatePhase(rendered, 'delete'); + await activateDeletePhase(rendered); await setPhaseAfter(rendered, 'delete', '-1'); waitForFormLibValidation(rendered); expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.nonNegativeNumberRequired]); }); + + test('is hidden when disabled', async () => { + const rendered = mountWithIntl(component); + expect(findTestSubject(rendered, 'delete-phaseContent').exists()).toBeFalsy(); + await activateDeletePhase(rendered); + expect(findTestSubject(rendered, 'delete-phaseContent').exists()).toBeTruthy(); + }); }); describe('not on cloud', () => { beforeEach(() => { diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/active_badge.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/active_badge.tsx deleted file mode 100644 index f3a6ee7276cdef..00000000000000 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/active_badge.tsx +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 React from 'react'; -import { EuiBadge } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; - -export const ActiveBadge = () => { - return ( - - - - ); -}; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/active_highlight/active_highlight.scss b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/active_highlight/active_highlight.scss deleted file mode 100644 index 96ca0c3a610671..00000000000000 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/active_highlight/active_highlight.scss +++ /dev/null @@ -1,16 +0,0 @@ -.ilmActivePhaseHighlight { - border-left: $euiBorderWidthThin solid $euiColorLightShade; - height: 100%; - - &.hotPhase.active { - border-left-color: $euiColorVis9_behindText; - } - - &.warmPhase.active { - border-left-color: $euiColorVis5_behindText; - } - - &.coldPhase.active { - border-left-color: $euiColorVis1_behindText; - } -} diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/index.ts index a84d15e6c19dae..dc4f1e31d3696e 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/index.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/index.ts @@ -5,14 +5,12 @@ * 2.0. */ -export { ActiveBadge } from './active_badge'; export { LearnMoreLink } from './learn_more_link'; export { OptionalLabel } from './optional_label'; export { PolicyJsonFlyout } from './policy_json_flyout'; export { DescribedFormRow, ToggleFieldWithDescribedFormRow } from './described_form_row'; export { FieldLoadingError } from './field_loading_error'; -export { ActiveHighlight } from './active_highlight'; export { Timeline } from './timeline'; export { FormErrorsCallout } from './form_errors_callout'; - +export { PhaseFooter } from './phase_footer'; export * from './phases'; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/active_highlight/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/infinity_icon/index.ts similarity index 82% rename from x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/active_highlight/index.ts rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/infinity_icon/index.ts index c8d3b6540dc3d2..850f3e4e07aed2 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/active_highlight/index.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/infinity_icon/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { ActiveHighlight } from './active_highlight'; +export { InfinityIcon } from './infinity_icon'; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/infinity_icon.svg.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/infinity_icon/infinity_icon.svg.tsx similarity index 100% rename from x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/infinity_icon.svg.tsx rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/infinity_icon/infinity_icon.svg.tsx diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/active_highlight/active_highlight.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/infinity_icon/infinity_icon.tsx similarity index 51% rename from x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/active_highlight/active_highlight.tsx rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/infinity_icon/infinity_icon.tsx index bae73c3cefa5d9..435e6a909acd10 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/active_highlight/active_highlight.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/infinity_icon/infinity_icon.tsx @@ -6,13 +6,9 @@ */ import React, { FunctionComponent } from 'react'; +import { EuiIcon, EuiIconProps } from '@elastic/eui'; +import { InfinityIconSvg } from './infinity_icon.svg'; -import './active_highlight.scss'; - -interface Props { - phase: 'hot' | 'warm' | 'cold'; - enabled: boolean; -} -export const ActiveHighlight: FunctionComponent = ({ phase, enabled }) => { - return
; -}; +export const InfinityIcon: FunctionComponent> = (props) => ( + +); diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_footer/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_footer/index.ts new file mode 100644 index 00000000000000..724904a1f188e4 --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_footer/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { PhaseFooter } from './phase_footer'; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_footer/phase_footer.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_footer/phase_footer.tsx new file mode 100644 index 00000000000000..82f0725bfe7d0f --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_footer/phase_footer.tsx @@ -0,0 +1,94 @@ +/* + * 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 React, { FunctionComponent } from 'react'; + +import { i18n } from '@kbn/i18n'; + +import { EuiText, EuiButtonGroup, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +import { PhasesExceptDelete } from '../../../../../../common/types'; + +import { usePhaseTimings } from '../../form'; + +import { InfinityIconSvg } from '../infinity_icon/infinity_icon.svg'; + +interface Props { + phase: PhasesExceptDelete; +} + +export const PhaseFooter: FunctionComponent = ({ phase }) => { + const { + isDeletePhaseEnabled, + setDeletePhaseEnabled: setValue, + [phase]: phaseConfiguration, + } = usePhaseTimings(); + + if (!phaseConfiguration.isFinalDataPhase) { + return null; + } + + const phaseDescription = isDeletePhaseEnabled + ? i18n.translate('xpack.indexLifecycleMgmt.editPolicy.phaseTiming.beforeDeleteDescription', { + defaultMessage: 'Data will be deleted after this phase', + }) + : i18n.translate('xpack.indexLifecycleMgmt.editPolicy.phaseTiming.foreverTimingDescription', { + defaultMessage: 'Data will remain in this phase forever', + }); + + const selectedButton = isDeletePhaseEnabled + ? 'ilmEnableDeletePhaseButton' + : 'ilmDisableDeletePhaseButton'; + + const buttons = [ + { + id: `ilmDisableDeletePhaseButton`, + label: i18n.translate( + 'xpack.indexLifecycleMgmt.editPolicy.deletePhase.disablePhaseButtonLabel', + { + defaultMessage: 'Keep data in this phase forever', + } + ), + iconType: InfinityIconSvg, + }, + { + id: `ilmEnableDeletePhaseButton`, + label: i18n.translate( + 'xpack.indexLifecycleMgmt.editPolicy.deletePhase.enablePhaseButtonLabel', + { + defaultMessage: 'Delete data after this phase', + } + ), + iconType: 'trash', + 'data-test-subj': 'enableDeletePhaseButton', + }, + ]; + + return ( + + + + {phaseDescription} + + + + { + setValue(id === 'ilmEnableDeletePhaseButton'); + }} + isIconOnly={true} + /> + + + ); +}; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_icon/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_icon/index.ts new file mode 100644 index 00000000000000..26fda5d9292840 --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_icon/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { PhaseIcon } from './phase_icon'; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_icon/phase_icon.scss b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_icon/phase_icon.scss new file mode 100644 index 00000000000000..7c6a5aefdde6ed --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_icon/phase_icon.scss @@ -0,0 +1,33 @@ +.ilmPhaseIcon { + width: $euiSizeXL; + height: $euiSizeXL; + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + background-color: $euiColorLightestShade; + &--disabled { + margin-top: $euiSizeS; + width: $euiSize; + height: $euiSize; + } + &--delete { + background-color: $euiColorLightShade; + } + &__inner--hot { + fill: $euiColorVis9_behindText; + } + &__inner--warm { + fill: $euiColorVis5_behindText; + } + &__inner--cold { + fill: $euiColorVis1_behindText; + } + &__inner--delete { + fill: $euiColorDarkShade; + } + + &__inner--disabled { + fill: $euiColorMediumShade; + } +} diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_icon/phase_icon.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_icon/phase_icon.tsx new file mode 100644 index 00000000000000..8c0a0bcca1d76b --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phase_icon/phase_icon.tsx @@ -0,0 +1,32 @@ +/* + * 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 React, { FunctionComponent } from 'react'; +import { EuiIcon } from '@elastic/eui'; +import { Phases } from '../../../../../../common/types'; +import './phase_icon.scss'; +interface Props { + enabled: boolean; + phase: string & keyof Phases; +} +export const PhaseIcon: FunctionComponent = ({ enabled, phase }) => { + return ( +
+ {enabled ? ( + + ) : ( + + )} +
+ ); +}; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/delete_phase/delete_phase.scss b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/delete_phase/delete_phase.scss new file mode 100644 index 00000000000000..60a39c7f1e9a67 --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/delete_phase/delete_phase.scss @@ -0,0 +1,11 @@ +.ilmDeletePhase { + .euiCommentEvent { + &__header { + padding: $euiSize; + background-color: $euiColorEmptyShade; + } + &__body { + padding: $euiSize; + } + } +} diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/delete_phase/delete_phase.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/delete_phase/delete_phase.tsx index c2da9246effb70..c65699ca126907 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/delete_phase/delete_phase.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/delete_phase/delete_phase.tsx @@ -5,107 +5,85 @@ * 2.0. */ -import React, { FunctionComponent, Fragment } from 'react'; +import React, { FunctionComponent } from 'react'; import { get } from 'lodash'; +import { + EuiFlexItem, + EuiFlexGroup, + EuiTitle, + EuiButtonEmpty, + EuiSpacer, + EuiText, + EuiComment, +} from '@elastic/eui'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiDescribedFormGroup, EuiTextColor, EuiFormRow } from '@elastic/eui'; -import { useFormData, ToggleField } from '../../../../../../shared_imports'; +import { useFormData } from '../../../../../../shared_imports'; -import { UseField } from '../../../form'; +import { i18nTexts } from '../../../i18n_texts'; -import { ActiveBadge, LearnMoreLink, OptionalLabel } from '../../index'; +import { usePhaseTimings } from '../../../form'; import { MinAgeField, SnapshotPoliciesField } from '../shared_fields'; +import './delete_phase.scss'; +import { PhaseIcon } from '../../phase_icon'; +import { PhaseErrorIndicator } from '../phase/phase_error_indicator'; const formFieldPaths = { enabled: '_meta.delete.enabled', }; export const DeletePhase: FunctionComponent = () => { + const { setDeletePhaseEnabled } = usePhaseTimings(); const [formData] = useFormData({ watch: formFieldPaths.enabled, }); const enabled = get(formData, formFieldPaths.enabled); - return ( -
- -

- -

{' '} - {enabled && } -
- } - titleSize="s" - description={ - -

- -

- -
- } - fullWidth - > - {enabled && } - - {enabled ? ( - - - - } - description={ - - {' '} - - - } - titleSize="xs" - fullWidth + if (!enabled) { + return null; + } + const phaseTitle = ( + + + +

{i18nTexts.editPolicy.titles.delete}

+
+
+ + + setDeletePhaseEnabled(false)} + data-test-subj={'disableDeletePhaseButton'} > - - - - - } - > - - -
- ) : null} -
+ + + + + + + + + ); + + return ( + } + className="ilmDeletePhase ilmPhase" + timelineIcon={} + > + + {i18nTexts.editPolicy.descriptions.delete} + + + + ); }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/phase/phase.scss b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/phase/phase.scss new file mode 100644 index 00000000000000..15f2dc508a365f --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/phase/phase.scss @@ -0,0 +1,27 @@ +.ilmPhase { + .euiCommentEvent { + &__header { + padding: $euiSize; + } + &__body { + padding: $euiSize; + } + } + .ilmSettingsButton { + color: $euiColorPrimary; + padding: $euiSizeS; + } + .euiCommentTimeline { + padding-top: $euiSize; + &::before { + height: calc(100% + #{$euiSizeXXL}); + } + } + &--enabled { + .euiCommentEvent { + &__header { + background-color: $euiColorEmptyShade; + } + } + } +} diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/phase/phase.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/phase/phase.tsx index f7e0f8e20e0506..0ac6f6922ec1e1 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/phase/phase.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/phase/phase.tsx @@ -5,126 +5,120 @@ * 2.0. */ -import React, { FunctionComponent, useState } from 'react'; +import React, { FunctionComponent } from 'react'; import { EuiFlexGroup, EuiFlexItem, - EuiPanel, EuiTitle, - EuiSpacer, EuiText, - EuiButtonEmpty, + EuiComment, + EuiAccordion, + EuiSpacer, + EuiBadge, } from '@elastic/eui'; import { get } from 'lodash'; import { FormattedMessage } from '@kbn/i18n/react'; +import { PhasesExceptDelete } from '../../../../../../../common/types'; import { ToggleField, useFormData } from '../../../../../../shared_imports'; import { i18nTexts } from '../../../i18n_texts'; +import { FormInternal } from '../../../types'; + import { UseField } from '../../../form'; -import { ActiveHighlight } from '../../active_highlight'; -import { MinAgeField } from '../shared_fields'; import { PhaseErrorIndicator } from './phase_error_indicator'; +import { MinAgeField } from '../shared_fields'; +import { PhaseIcon } from '../../phase_icon'; +import { PhaseFooter } from '../../phase_footer'; +import './phase.scss'; + interface Props { - phase: 'hot' | 'warm' | 'cold'; + phase: PhasesExceptDelete; } export const Phase: FunctionComponent = ({ children, phase }) => { const enabledPath = `_meta.${phase}.enabled`; - const [formData] = useFormData({ + const [formData] = useFormData({ watch: [enabledPath], }); + const isHotPhase = phase === 'hot'; // hot phase is always enabled - const enabled = get(formData, enabledPath) || phase === 'hot'; + const enabled = get(formData, enabledPath) || isHotPhase; - const [isShowingSettings, setShowingSettings] = useState(false); - return ( - + const phaseTitle = ( + + {!isHotPhase && ( + + + + )} - + +

{i18nTexts.editPolicy.titles[phase]}

+
- - - - - - {phase !== 'hot' && ( - - - - )} - - - - -

{i18nTexts.editPolicy.titles[phase]}

-
-
- - - -
-
-
-
- {enabled && ( - - - - {phase !== 'hot' && } - - - { - setShowingSettings(!isShowingSettings); - }} - size="xs" - iconType="controlsVertical" - iconSide="left" - aria-controls={`${phase}-phaseContent`} - > - - - - - - )} -
- - - {i18nTexts.editPolicy.descriptions[phase]} - - - {enabled && ( -
- - {children} -
- )} -
+ {isHotPhase && ( + + + + + + )} + +
); + + // @ts-ignore + const minAge = !isHotPhase && enabled ? : null; + + return ( + } + className={`ilmPhase ${enabled ? 'ilmPhase--enabled' : ''}`} + > + + {i18nTexts.editPolicy.descriptions[phase]} + + + {enabled && ( + <> + + + } + buttonClassName="ilmSettingsButton" + extraAction={} + > + + {children} + + + )} + + ); }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/phase/phase_error_indicator.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/phase/phase_error_indicator.tsx index 98fdfe73ecbd82..647f12669cf773 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/phase/phase_error_indicator.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/phase/phase_error_indicator.tsx @@ -9,10 +9,11 @@ import { i18n } from '@kbn/i18n'; import React, { FunctionComponent, memo } from 'react'; import { EuiIconTip } from '@elastic/eui'; +import { Phases } from '../../../../../../../common/types'; import { useFormErrorsContext } from '../../../form'; interface Props { - phase: 'hot' | 'warm' | 'cold'; + phase: string & keyof Phases; } const i18nTexts = { diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/forcemerge_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/forcemerge_field.tsx index 2d5f5babe1e2ad..bbdcbbf4759ef0 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/forcemerge_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/forcemerge_field.tsx @@ -8,7 +8,9 @@ import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { CheckBoxField, NumericField } from '../../../../../../shared_imports'; +import uuid from 'uuid'; +import { EuiCheckbox, EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; +import { NumericField } from '../../../../../../shared_imports'; import { i18nTexts } from '../../../i18n_texts'; @@ -67,16 +69,29 @@ export const ForcemergeField: React.FunctionComponent = ({ phase }) => { }, }} /> - + + + {(field) => ( + + + + + + + + + + )} + ); }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/min_age_field/min_age_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/min_age_field/min_age_field.tsx index 60af830356ab9b..2f1a058f5a9436 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/min_age_field/min_age_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/min_age_field/min_age_field.tsx @@ -75,7 +75,12 @@ export const MinAgeField: FunctionComponent = ({ phase }): React.ReactEle const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); return ( - + = ({ phase }) => config={{ defaultValue: cloud?.isCloudEnabled ? CLOUD_DEFAULT_REPO : undefined, - label: i18nTexts.editPolicy.searchableSnapshotsFieldLabel, validations: [ { validator: emptyField( diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/snapshot_policies_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/snapshot_policies_field.tsx index 2cbd5cea6165aa..f9c973d14b3e22 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/snapshot_policies_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/snapshot_policies_field.tsx @@ -10,7 +10,13 @@ import { get } from 'lodash'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { EuiCallOut, EuiComboBoxOptionOption, EuiLink, EuiSpacer } from '@elastic/eui'; +import { + EuiCallOut, + EuiComboBoxOptionOption, + EuiDescribedFormGroup, + EuiLink, + EuiSpacer, +} from '@elastic/eui'; import { ComboBoxField, useFormData } from '../../../../../../shared_imports'; import { useLoadSnapshotPolicies } from '../../../../../services/api'; @@ -18,7 +24,7 @@ import { useLoadSnapshotPolicies } from '../../../../../services/api'; import { useEditPolicyContext } from '../../../edit_policy_context'; import { UseField } from '../../../form'; -import { FieldLoadingError } from '../../'; +import { FieldLoadingError, LearnMoreLink, OptionalLabel } from '../../'; const waitForSnapshotFormField = 'phases.delete.actions.wait_for_snapshot.policy'; @@ -137,43 +143,78 @@ export const SnapshotPoliciesField: React.FunctionComponent = () => { } return ( - <> - path={waitForSnapshotFormField}> - {(field) => { - const singleSelectionArray: [selectedSnapshot?: string] = field.value - ? [field.value] - : []; + + + + } + description={ + <> + {' '} + + + } + titleSize="xs" + fullWidth + > + <> + + path={waitForSnapshotFormField} + componentProps={{ + label: ( + <> + + + + ), + }} + > + {(field) => { + const singleSelectionArray: [selectedSnapshot?: string] = field.value + ? [field.value] + : []; - return ( - { - field.setValue(newOption); - }, - onChange: (options: EuiComboBoxOptionOption[]) => { - if (options.length > 0) { - field.setValue(options[0].label); - } else { - field.setValue(''); - } - }, - }} - /> - ); - }} - - {calloutContent} - + return ( + { + field.setValue(newOption); + }, + onChange: (options: EuiComboBoxOptionOption[]) => { + if (options.length > 0) { + field.setValue(options[0].label); + } else { + field.setValue(''); + } + }, + }} + /> + ); + }} + + {calloutContent} + + ); }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/timeline.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/timeline.tsx index 3ebd5935b8d3f3..2d83009bd4df49 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/timeline.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/timeline/timeline.tsx @@ -6,15 +6,10 @@ */ import { i18n } from '@kbn/i18n'; + import React, { FunctionComponent, memo } from 'react'; -import { - EuiIcon, - EuiIconProps, - EuiFlexGroup, - EuiFlexItem, - EuiTitle, - EuiIconTip, -} from '@elastic/eui'; + +import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiIconTip } from '@elastic/eui'; import { PhasesExceptDelete } from '../../../../../../common/types'; @@ -25,15 +20,13 @@ import { AbsoluteTimings, } from '../../lib'; -import './timeline.scss'; -import { InfinityIconSvg } from './infinity_icon.svg'; +import { InfinityIcon } from '../infinity_icon'; + import { TimelinePhaseText } from './components'; const exists = (v: unknown) => v != null; -const InfinityIcon: FunctionComponent> = (props) => ( - -); +import './timeline.scss'; const toPercent = (n: number, total: number) => (n / total) * 100; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx index 749327a2dd441c..0c7b5565372a55 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx @@ -239,19 +239,19 @@ export const EditPolicy: React.FunctionComponent = ({ history }) => { - +
+ - + - + - + - + - - - + +
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/components/form.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/components/form.tsx index 429ae37b76013a..be8243cab289ff 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/components/form.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/components/form.tsx @@ -11,6 +11,7 @@ import { Form as LibForm, FormHook } from '../../../../../shared_imports'; import { ConfigurationIssuesProvider } from '../configuration_issues_context'; import { FormErrorsProvider } from '../form_errors_context'; +import { PhaseTimingsProvider } from '../phase_timings_context'; interface Props { form: FormHook; @@ -19,7 +20,9 @@ interface Props { export const Form: FunctionComponent = ({ form, children }) => ( - {children} + + {children} + ); diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/index.ts index 753148f55db426..734a12a72bd304 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/index.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/index.ts @@ -21,3 +21,9 @@ export { } from './configuration_issues_context'; export { FormErrorsProvider, useFormErrorsContext } from './form_errors_context'; + +export { + PhaseTimingsProvider, + usePhaseTimings, + PhaseTimingConfiguration, +} from './phase_timings_context'; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/phase_timings_context.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/phase_timings_context.tsx new file mode 100644 index 00000000000000..92cc8eeead91af --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/phase_timings_context.tsx @@ -0,0 +1,73 @@ +/* + * 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 React, { createContext, FunctionComponent, useContext } from 'react'; +import { useFormData } from '../../../../shared_imports'; +import { FormInternal } from '../types'; +import { UseField } from './index'; + +export interface PhaseTimingConfiguration { + /** + * Whether this is the final, non-delete, phase. + */ + isFinalDataPhase: boolean; +} + +const getPhaseTimingConfiguration = ( + formData: FormInternal +): { + hot: PhaseTimingConfiguration; + warm: PhaseTimingConfiguration; + cold: PhaseTimingConfiguration; +} => { + const isWarmPhaseEnabled = formData?._meta?.warm?.enabled; + const isColdPhaseEnabled = formData?._meta?.cold?.enabled; + return { + hot: { isFinalDataPhase: !isWarmPhaseEnabled && !isColdPhaseEnabled }, + warm: { isFinalDataPhase: isWarmPhaseEnabled && !isColdPhaseEnabled }, + cold: { isFinalDataPhase: isColdPhaseEnabled }, + }; +}; +export interface PhaseTimings { + hot: PhaseTimingConfiguration; + warm: PhaseTimingConfiguration; + cold: PhaseTimingConfiguration; + isDeletePhaseEnabled: boolean; + setDeletePhaseEnabled: (enabled: boolean) => void; +} + +const PhaseTimingsContext = createContext(null as any); + +export const PhaseTimingsProvider: FunctionComponent = ({ children }) => { + const [formData] = useFormData({ + watch: ['_meta.warm.enabled', '_meta.cold.enabled', '_meta.delete.enabled'], + }); + + return ( + + {(field) => { + return ( + + {children} + + ); + }} + + ); +}; +export const usePhaseTimings = () => { + const ctx = useContext(PhaseTimingsContext); + if (!ctx) throw new Error('Cannot use phase timings outside of phase timings context'); + + return ctx; +}; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/schema.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/schema.ts index ee84be231f4ccc..600a660657863c 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/schema.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/schema.ts @@ -70,7 +70,7 @@ export const schema: FormSchema = { ), }, minAgeUnit: { - defaultValue: 'ms', + defaultValue: 'd', }, bestCompression: { label: i18nTexts.editPolicy.bestCompressionFieldLabel, @@ -361,6 +361,18 @@ export const schema: FormSchema = { }, ], }, + actions: { + wait_for_snapshot: { + policy: { + label: i18n.translate( + 'xpack.indexLifecycleMgmt.editPolicy.waitForSnapshot.snapshotPolicyFieldLabel', + { + defaultMessage: 'Policy name (optional)', + } + ), + }, + }, + }, }, }, }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts index 55af738d7d7aeb..5deba8607cd527 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts @@ -188,6 +188,9 @@ export const i18nTexts = { cold: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.coldPhase.coldPhaseTitle', { defaultMessage: 'Cold phase', }), + delete: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.deletePhase.deletePhaseTitle', { + defaultMessage: 'Delete Data', + }), }, descriptions: { hot: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.hotPhase.hotPhaseDescription', { @@ -202,6 +205,13 @@ export const i18nTexts = { defaultMessage: 'You are querying your index less frequently, so you can allocate shards on significantly less performant hardware. Because your queries are slower, you can reduce the number of replicas.', }), + delete: i18n.translate( + 'xpack.indexLifecycleMgmt.editPolicy.deletePhase.deletePhaseDescription', + { + defaultMessage: + 'You no longer need your index. You can define when it is safe to delete it.', + } + ), }, }, }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.test.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.test.ts index 9f96bbfb25c729..7ec20cc2a5966a 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.test.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.test.ts @@ -289,7 +289,7 @@ describe('Conversion of absolute policy timing to relative timing', () => { }, }) ) - ).toEqual({ total: 'Forever', hot: 'Forever', warm: undefined, cold: undefined }); + ).toEqual({ total: 'forever', hot: 'forever', warm: undefined, cold: undefined }); }); test('hot, then always warm', () => { @@ -308,7 +308,7 @@ describe('Conversion of absolute policy timing to relative timing', () => { }, }) ) - ).toEqual({ total: 'Forever', hot: 'Less than a day', warm: 'Forever', cold: undefined }); + ).toEqual({ total: 'forever', hot: 'less than a day', warm: 'forever', cold: undefined }); }); test('hot, then warm, then always cold', () => { @@ -333,10 +333,10 @@ describe('Conversion of absolute policy timing to relative timing', () => { }) ) ).toEqual({ - total: 'Forever', + total: 'forever', hot: '30 days', warm: '4 days', - cold: 'Forever', + cold: 'forever', }); }); @@ -357,7 +357,7 @@ describe('Conversion of absolute policy timing to relative timing', () => { }, }) ) - ).toEqual({ total: 'Forever', hot: '34 days', warm: undefined, cold: 'Forever' }); + ).toEqual({ total: 'forever', hot: '34 days', warm: undefined, cold: 'forever' }); }); }); @@ -445,7 +445,7 @@ describe('Conversion of absolute policy timing to relative timing', () => { total: '61 days', hot: '24 days', warm: '37 days', - cold: 'Less than a day', + cold: 'less than a day', }); }); @@ -474,7 +474,7 @@ describe('Conversion of absolute policy timing to relative timing', () => { total: '61 days', hot: '61 days', warm: undefined, - cold: 'Less than a day', + cold: 'less than a day', }); }); @@ -506,8 +506,8 @@ describe('Conversion of absolute policy timing to relative timing', () => { ).toEqual({ total: '61 days', hot: '61 days', - warm: 'Less than a day', - cold: 'Less than a day', + warm: 'less than a day', + cold: 'less than a day', }); }); }); diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.ts index 10c26702e81f13..73ff8c76b92336 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/lib/absolute_timing_to_relative_timing.ts @@ -35,11 +35,11 @@ type MinAgePhase = 'warm' | 'cold' | 'delete'; type Phase = 'hot' | MinAgePhase; const i18nTexts = { - forever: i18n.translate('xpack.indexLifecycleMgmt.relativeTiming.Forever', { - defaultMessage: 'Forever', + forever: i18n.translate('xpack.indexLifecycleMgmt.relativeTiming.forever', { + defaultMessage: 'forever', }), lessThanADay: i18n.translate('xpack.indexLifecycleMgmt.relativeTiming.lessThanADay', { - defaultMessage: 'Less than a day', + defaultMessage: 'less than a day', }), day: i18n.translate('xpack.indexLifecycleMgmt.relativeTiming.day', { defaultMessage: 'day', diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 79467c6de15ac4..00d839171eb237 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9408,7 +9408,6 @@ "xpack.idxMgmt.unfreezeIndicesAction.successfullyUnfrozeIndicesMessage": "[{indexNames}] の凍結が解除されました", "xpack.idxMgmt.updateIndexSettingsAction.settingsSuccessUpdateMessage": "インデックス {indexName} の設定が更新されました", "xpack.idxMgmt.validators.string.invalidJSONError": "無効な JSON フォーマット。", - "xpack.indexLifecycleMgmt.activePhaseMessage": "アクティブ", "xpack.indexLifecycleMgmt.addLifecyclePolicyActionButtonLabel": "ライフサイクルポリシーを追加", "xpack.indexLifecycleMgmt.appTitle": "インデックスライフサイクルポリシー", "xpack.indexLifecycleMgmt.breadcrumb.editPolicyLabel": "ポリシーの編集", @@ -9457,8 +9456,6 @@ "xpack.indexLifecycleMgmt.editPolicy.deletePhase.customPolicyLink": "新しいポリシーを作成", "xpack.indexLifecycleMgmt.editPolicy.deletePhase.customPolicyMessage": "既存のスナップショットポリシーの名前を入力するか、この名前で{link}。", "xpack.indexLifecycleMgmt.editPolicy.deletePhase.customPolicyTitle": "ポリシー名が見つかりません", - "xpack.indexLifecycleMgmt.editPolicy.deletePhase.deletePhaseDescriptionText": "今後インデックスは必要ありません。 いつ安全に削除できるかを定義できます。", - "xpack.indexLifecycleMgmt.editPolicy.deletePhase.deletePhaseLabel": "削除フェーズ", "xpack.indexLifecycleMgmt.editPolicy.deletePhase.noPoliciesCreatedLink": "スナップショットライフサイクルポリシーを作成", "xpack.indexLifecycleMgmt.editPolicy.deletePhase.noPoliciesCreatedMessage": "{link}して、クラスタースナップショットの作成と削除を自動化します。", "xpack.indexLifecycleMgmt.editPolicy.deletePhase.noPoliciesCreatedTitle": "スナップショットポリシーが見つかりません", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 326789fb1d6af8..38816133d6a241 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9432,7 +9432,6 @@ "xpack.idxMgmt.unfreezeIndicesAction.successfullyUnfrozeIndicesMessage": "成功取消冻结:[{indexNames}]", "xpack.idxMgmt.updateIndexSettingsAction.settingsSuccessUpdateMessage": "已成功更新索引 {indexName} 的设置", "xpack.idxMgmt.validators.string.invalidJSONError": "JSON 格式无效。", - "xpack.indexLifecycleMgmt.activePhaseMessage": "活动", "xpack.indexLifecycleMgmt.addLifecyclePolicyActionButtonLabel": "添加生命周期策略", "xpack.indexLifecycleMgmt.appTitle": "索引生命周期策略", "xpack.indexLifecycleMgmt.breadcrumb.editPolicyLabel": "编辑策略", @@ -9481,8 +9480,6 @@ "xpack.indexLifecycleMgmt.editPolicy.deletePhase.customPolicyLink": "创建新策略", "xpack.indexLifecycleMgmt.editPolicy.deletePhase.customPolicyMessage": "输入现有快照策略的名称,或使用此名称{link}。", "xpack.indexLifecycleMgmt.editPolicy.deletePhase.customPolicyTitle": "未找到策略名称", - "xpack.indexLifecycleMgmt.editPolicy.deletePhase.deletePhaseDescriptionText": "您不再需要自己的索引。 您可以定义安全删除它的时间。", - "xpack.indexLifecycleMgmt.editPolicy.deletePhase.deletePhaseLabel": "删除阶段", "xpack.indexLifecycleMgmt.editPolicy.deletePhase.noPoliciesCreatedLink": "创建快照生命周期策略", "xpack.indexLifecycleMgmt.editPolicy.deletePhase.noPoliciesCreatedMessage": "{link}以自动创建和删除集群快照。", "xpack.indexLifecycleMgmt.editPolicy.deletePhase.noPoliciesCreatedTitle": "找不到快照策略",