mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[ILM] TS conversion of Index Management plugin extension (#76517)
* [ILM] TS conversion of Index Management plugin extension * [ILM] Implement review suggestions * [ILM] Fix jest test Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
6e339d319d
commit
70b4b89270
14 changed files with 331 additions and 129 deletions
|
@ -134,6 +134,7 @@ exports[`extend index management ilm summary extension should return extension w
|
|||
},
|
||||
"step_time_millis": 1544187776208,
|
||||
},
|
||||
"isFrozen": false,
|
||||
"name": "testy3",
|
||||
"primary": "1",
|
||||
"primary_size": "6.5kb",
|
||||
|
@ -326,6 +327,82 @@ exports[`extend index management ilm summary extension should return extension w
|
|||
className="euiSpacer euiSpacer--s"
|
||||
/>
|
||||
</EuiSpacer>
|
||||
<EuiPopover
|
||||
anchorPosition="downCenter"
|
||||
button={
|
||||
<EuiButtonEmpty
|
||||
onClick={[Function]}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Stack trace"
|
||||
id="xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.stackTraceButton"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
}
|
||||
closePopover={[Function]}
|
||||
display="inlineBlock"
|
||||
hasArrow={true}
|
||||
id="stackPopover"
|
||||
isOpen={false}
|
||||
ownFocus={false}
|
||||
panelPaddingSize="m"
|
||||
>
|
||||
<EuiOutsideClickDetector
|
||||
isDisabled={true}
|
||||
onOutsideClick={[Function]}
|
||||
>
|
||||
<div
|
||||
className="euiPopover euiPopover--anchorDownCenter"
|
||||
id="stackPopover"
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onMouseUp={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<div
|
||||
className="euiPopover__anchor"
|
||||
>
|
||||
<EuiButtonEmpty
|
||||
onClick={[Function]}
|
||||
>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<EuiButtonContent
|
||||
className="euiButtonEmpty__content"
|
||||
iconSide="left"
|
||||
textProps={
|
||||
Object {
|
||||
"className": "euiButtonEmpty__text",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiButtonContent euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Stack trace"
|
||||
id="xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.stackTraceButton"
|
||||
values={Object {}}
|
||||
>
|
||||
Stack trace
|
||||
</FormattedMessage>
|
||||
</span>
|
||||
</span>
|
||||
</EuiButtonContent>
|
||||
</button>
|
||||
</EuiButtonEmpty>
|
||||
</div>
|
||||
</div>
|
||||
</EuiOutsideClickDetector>
|
||||
</EuiPopover>
|
||||
</div>
|
||||
</EuiText>
|
||||
</div>
|
||||
|
@ -588,6 +665,7 @@ exports[`extend index management ilm summary extension should return extension w
|
|||
"step": "complete",
|
||||
"step_time_millis": 1544187775867,
|
||||
},
|
||||
"isFrozen": false,
|
||||
"name": "testy3",
|
||||
"primary": "1",
|
||||
"primary_size": "6.5kb",
|
|
@ -8,7 +8,8 @@ import moment from 'moment-timezone';
|
|||
import axios from 'axios';
|
||||
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
|
||||
|
||||
import { mountWithIntl } from '../../../test_utils/enzyme_helpers';
|
||||
import { mountWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { usageCollectionPluginMock } from '../../../../src/plugins/usage_collection/public/mocks';
|
||||
import {
|
||||
retryLifecycleActionExtension,
|
||||
removeLifecyclePolicyActionExtension,
|
||||
|
@ -19,19 +20,22 @@ import {
|
|||
} from '../public/extend_index_management';
|
||||
import { init as initHttp } from '../public/application/services/http';
|
||||
import { init as initUiMetric } from '../public/application/services/ui_metric';
|
||||
import { Index } from '../public/application/services/policies/types';
|
||||
|
||||
// We need to init the http with a mock for any tests that depend upon the http service.
|
||||
// For example, add_lifecycle_confirm_modal makes an API request in its componentDidMount
|
||||
// lifecycle method. If we don't mock this, CI will fail with "Call retries were exceeded".
|
||||
initHttp(axios.create({ adapter: axiosXhrAdapter }), (path) => path);
|
||||
initUiMetric({ reportUiStats: () => {} });
|
||||
// This expects HttpSetup but we're giving it AxiosInstance.
|
||||
// @ts-ignore
|
||||
initHttp(axios.create({ adapter: axiosXhrAdapter }));
|
||||
initUiMetric(usageCollectionPluginMock.createSetupContract());
|
||||
|
||||
jest.mock('../../../plugins/index_management/public', async () => {
|
||||
const { indexManagementMock } = await import('../../../plugins/index_management/public/mocks.ts');
|
||||
const { indexManagementMock } = await import('../../../plugins/index_management/public/mocks');
|
||||
return indexManagementMock.createSetup();
|
||||
});
|
||||
|
||||
const indexWithoutLifecyclePolicy = {
|
||||
const indexWithoutLifecyclePolicy: Index = {
|
||||
health: 'yellow',
|
||||
status: 'open',
|
||||
name: 'noPolicy',
|
||||
|
@ -43,13 +47,14 @@ const indexWithoutLifecyclePolicy = {
|
|||
size: '3.4kb',
|
||||
primary_size: '3.4kb',
|
||||
aliases: 'none',
|
||||
isFrozen: false,
|
||||
ilm: {
|
||||
index: 'testy1',
|
||||
managed: false,
|
||||
},
|
||||
};
|
||||
|
||||
const indexWithLifecyclePolicy = {
|
||||
const indexWithLifecyclePolicy: Index = {
|
||||
health: 'yellow',
|
||||
status: 'open',
|
||||
name: 'testy3',
|
||||
|
@ -61,6 +66,7 @@ const indexWithLifecyclePolicy = {
|
|||
size: '6.5kb',
|
||||
primary_size: '6.5kb',
|
||||
aliases: 'none',
|
||||
isFrozen: false,
|
||||
ilm: {
|
||||
index: 'testy3',
|
||||
managed: true,
|
||||
|
@ -87,6 +93,7 @@ const indexWithLifecycleError = {
|
|||
size: '6.5kb',
|
||||
primary_size: '6.5kb',
|
||||
aliases: 'none',
|
||||
isFrozen: false,
|
||||
ilm: {
|
||||
index: 'testy3',
|
||||
managed: true,
|
||||
|
@ -115,10 +122,12 @@ const indexWithLifecycleError = {
|
|||
|
||||
moment.tz.setDefault('utc');
|
||||
|
||||
const getUrlForApp = (appId, options) => {
|
||||
const getUrlForApp = (appId: string, options: any) => {
|
||||
return appId + '/' + (options ? options.path : '');
|
||||
};
|
||||
|
||||
const reloadIndices = () => {};
|
||||
|
||||
describe('extend index management', () => {
|
||||
describe('retry lifecycle action extension', () => {
|
||||
test('should return null when no indices have index lifecycle policy', () => {
|
||||
|
@ -153,6 +162,7 @@ describe('extend index management', () => {
|
|||
test('should return null when no indices have index lifecycle policy', () => {
|
||||
const extension = removeLifecyclePolicyActionExtension({
|
||||
indices: [indexWithoutLifecyclePolicy],
|
||||
reloadIndices,
|
||||
});
|
||||
expect(extension).toBeNull();
|
||||
});
|
||||
|
@ -160,6 +170,7 @@ describe('extend index management', () => {
|
|||
test('should return null when some indices have index lifecycle policy', () => {
|
||||
const extension = removeLifecyclePolicyActionExtension({
|
||||
indices: [indexWithoutLifecyclePolicy, indexWithLifecyclePolicy],
|
||||
reloadIndices,
|
||||
});
|
||||
expect(extension).toBeNull();
|
||||
});
|
||||
|
@ -167,6 +178,7 @@ describe('extend index management', () => {
|
|||
test('should return extension when all indices have lifecycle policy', () => {
|
||||
const extension = removeLifecyclePolicyActionExtension({
|
||||
indices: [indexWithLifecycleError, indexWithLifecycleError],
|
||||
reloadIndices,
|
||||
});
|
||||
expect(extension).toBeDefined();
|
||||
expect(extension).toMatchSnapshot();
|
||||
|
@ -175,16 +187,18 @@ describe('extend index management', () => {
|
|||
|
||||
describe('add lifecycle policy action extension', () => {
|
||||
test('should return null when index has index lifecycle policy', () => {
|
||||
const extension = addLifecyclePolicyActionExtension(
|
||||
{ indices: [indexWithLifecyclePolicy] },
|
||||
getUrlForApp
|
||||
);
|
||||
const extension = addLifecyclePolicyActionExtension({
|
||||
indices: [indexWithLifecyclePolicy],
|
||||
reloadIndices,
|
||||
getUrlForApp,
|
||||
});
|
||||
expect(extension).toBeNull();
|
||||
});
|
||||
|
||||
test('should return null when more than one index is passed', () => {
|
||||
const extension = addLifecyclePolicyActionExtension({
|
||||
indices: [indexWithoutLifecyclePolicy, indexWithoutLifecyclePolicy],
|
||||
reloadIndices,
|
||||
getUrlForApp,
|
||||
});
|
||||
expect(extension).toBeNull();
|
||||
|
@ -193,10 +207,11 @@ describe('extend index management', () => {
|
|||
test('should return extension when one index is passed and it does not have lifecycle policy', () => {
|
||||
const extension = addLifecyclePolicyActionExtension({
|
||||
indices: [indexWithoutLifecyclePolicy],
|
||||
reloadIndices,
|
||||
getUrlForApp,
|
||||
});
|
||||
expect(extension.renderConfirmModal).toBeDefined;
|
||||
const component = extension.renderConfirmModal(jest.fn());
|
||||
expect(extension?.renderConfirmModal).toBeDefined();
|
||||
const component = extension!.renderConfirmModal(jest.fn());
|
||||
const rendered = mountWithIntl(component);
|
||||
expect(rendered.exists('.euiModal--confirmation'));
|
||||
});
|
|
@ -12,7 +12,7 @@ import {
|
|||
UIM_POLICY_ATTACH_INDEX_TEMPLATE,
|
||||
UIM_POLICY_DETACH_INDEX,
|
||||
UIM_INDEX_RETRY_STEP,
|
||||
} from '../constants/ui_metric';
|
||||
} from '../constants';
|
||||
|
||||
import { trackUiMetric } from './ui_metric';
|
||||
import { sendGet, sendPost, sendDelete, useRequest } from './http';
|
||||
|
@ -78,7 +78,11 @@ export const removeLifecycleForIndex = async (indexNames: string[]) => {
|
|||
return response;
|
||||
};
|
||||
|
||||
export const addLifecyclePolicyToIndex = async (body: GenericObject) => {
|
||||
export const addLifecyclePolicyToIndex = async (body: {
|
||||
indexName: string;
|
||||
policyName: string;
|
||||
alias: string;
|
||||
}) => {
|
||||
const response = await sendPost(`index/add`, body);
|
||||
// Only track successful actions.
|
||||
trackUiMetric(METRIC_TYPE.COUNT, UIM_POLICY_ATTACH_INDEX);
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { Index as IndexInterface } from '../../../../../index_management/public';
|
||||
|
||||
export interface SerializedPolicy {
|
||||
name: string;
|
||||
phases: Phases;
|
||||
|
@ -169,3 +171,36 @@ export interface FrozenPhase
|
|||
export interface DeletePhase extends CommonPhaseSettings, PhaseWithMinAge {
|
||||
waitForSnapshotPolicy: string;
|
||||
}
|
||||
|
||||
export interface IndexLifecyclePolicy {
|
||||
index: string;
|
||||
managed: boolean;
|
||||
action?: string;
|
||||
action_time_millis?: number;
|
||||
age?: string;
|
||||
failed_step?: string;
|
||||
failed_step_retry_count?: number;
|
||||
is_auto_retryable_error?: boolean;
|
||||
lifecycle_date_millis?: number;
|
||||
phase?: string;
|
||||
phase_execution?: {
|
||||
policy: string;
|
||||
modified_date_in_millis: number;
|
||||
version: number;
|
||||
phase_definition: SerializedPhase;
|
||||
};
|
||||
phase_time_millis?: number;
|
||||
policy?: string;
|
||||
step?: string;
|
||||
step_info?: {
|
||||
reason?: string;
|
||||
stack_trace?: string;
|
||||
type?: string;
|
||||
message?: string;
|
||||
};
|
||||
step_time_millis?: number;
|
||||
}
|
||||
|
||||
export interface Index extends IndexInterface {
|
||||
ilm: IndexLifecyclePolicy;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import React, { Component, Fragment } from 'react';
|
|||
import { get } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { ApplicationStart } from 'kibana/public';
|
||||
|
||||
import {
|
||||
EuiLink,
|
||||
EuiSelect,
|
||||
|
@ -26,9 +28,25 @@ import {
|
|||
import { loadPolicies, addLifecyclePolicyToIndex } from '../../application/services/api';
|
||||
import { showApiError } from '../../application/services/api_errors';
|
||||
import { toasts } from '../../application/services/notification';
|
||||
import { Index, PolicyFromES } from '../../application/services/policies/types';
|
||||
|
||||
export class AddLifecyclePolicyConfirmModal extends Component {
|
||||
constructor(props) {
|
||||
interface Props {
|
||||
indexName: string;
|
||||
closeModal: () => void;
|
||||
index: Index;
|
||||
reloadIndices: () => void;
|
||||
getUrlForApp: ApplicationStart['getUrlForApp'];
|
||||
}
|
||||
|
||||
interface State {
|
||||
selectedPolicyName: string;
|
||||
selectedAlias: string;
|
||||
policies: PolicyFromES[];
|
||||
policyErrorMessage?: string;
|
||||
}
|
||||
|
||||
export class AddLifecyclePolicyConfirmModal extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
policies: [],
|
||||
|
@ -41,7 +59,7 @@ export class AddLifecyclePolicyConfirmModal extends Component {
|
|||
const { selectedPolicyName, selectedAlias } = this.state;
|
||||
if (!selectedPolicyName) {
|
||||
this.setState({
|
||||
policyError: i18n.translate(
|
||||
policyErrorMessage: i18n.translate(
|
||||
'xpack.indexLifecycleMgmt.indexManagementTable.addLifecyclePolicyConfirmModal.noPolicySelectedErrorMessage',
|
||||
{ defaultMessage: 'You must select a policy.' }
|
||||
),
|
||||
|
@ -81,7 +99,7 @@ export class AddLifecyclePolicyConfirmModal extends Component {
|
|||
);
|
||||
}
|
||||
};
|
||||
renderAliasFormElement = (selectedPolicy) => {
|
||||
renderAliasFormElement = (selectedPolicy?: PolicyFromES) => {
|
||||
const { selectedAlias } = this.state;
|
||||
const { index } = this.props;
|
||||
const showAliasSelect =
|
||||
|
@ -109,7 +127,7 @@ export class AddLifecyclePolicyConfirmModal extends Component {
|
|||
defaultMessage="Policy {policyName} is configured for rollover,
|
||||
but index {indexName} does not have an alias, which is required for rollover."
|
||||
values={{
|
||||
policyName: selectedPolicy.name,
|
||||
policyName: selectedPolicy?.name,
|
||||
indexName: index.name,
|
||||
}}
|
||||
/>
|
||||
|
@ -117,7 +135,7 @@ export class AddLifecyclePolicyConfirmModal extends Component {
|
|||
</Fragment>
|
||||
);
|
||||
}
|
||||
const aliasOptions = aliases.map((alias) => {
|
||||
const aliasOptions = (aliases as string[]).map((alias: string) => {
|
||||
return {
|
||||
text: alias,
|
||||
value: alias,
|
||||
|
@ -152,10 +170,10 @@ export class AddLifecyclePolicyConfirmModal extends Component {
|
|||
);
|
||||
};
|
||||
renderForm() {
|
||||
const { policies, selectedPolicyName, policyError } = this.state;
|
||||
const { policies, selectedPolicyName, policyErrorMessage } = this.state;
|
||||
const selectedPolicy = selectedPolicyName
|
||||
? policies.find((policy) => policy.name === selectedPolicyName)
|
||||
: null;
|
||||
: undefined;
|
||||
|
||||
const options = policies.map(({ name }) => {
|
||||
return {
|
||||
|
@ -175,8 +193,8 @@ export class AddLifecyclePolicyConfirmModal extends Component {
|
|||
return (
|
||||
<EuiForm>
|
||||
<EuiFormRow
|
||||
isInvalid={!!policyError}
|
||||
error={policyError}
|
||||
isInvalid={!!policyErrorMessage}
|
||||
error={policyErrorMessage}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.indexLifecycleMgmt.indexManagementTable.addLifecyclePolicyConfirmModal.choosePolicyLabel"
|
||||
|
@ -188,7 +206,7 @@ export class AddLifecyclePolicyConfirmModal extends Component {
|
|||
options={options}
|
||||
value={selectedPolicyName}
|
||||
onChange={(e) => {
|
||||
this.setState({ policyError: null, selectedPolicyName: e.target.value });
|
||||
this.setState({ policyErrorMessage: undefined, selectedPolicyName: e.target.value });
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
@ -198,7 +216,7 @@ export class AddLifecyclePolicyConfirmModal extends Component {
|
|||
}
|
||||
async componentDidMount() {
|
||||
try {
|
||||
const policies = await loadPolicies(false, this.props.httpClient);
|
||||
const policies = await loadPolicies(false);
|
||||
this.setState({ policies });
|
||||
} catch (err) {
|
||||
showApiError(
|
|
@ -24,44 +24,71 @@ import {
|
|||
EuiPopoverTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { ApplicationStart } from 'kibana/public';
|
||||
import { getPolicyPath } from '../../application/services/navigation';
|
||||
import { Index, IndexLifecyclePolicy } from '../../application/services/policies/types';
|
||||
|
||||
const getHeaders = () => {
|
||||
return {
|
||||
policy: i18n.translate(
|
||||
'xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.lifecyclePolicyHeader',
|
||||
{
|
||||
defaultMessage: 'Lifecycle policy',
|
||||
}
|
||||
),
|
||||
phase: i18n.translate(
|
||||
'xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.currentPhaseHeader',
|
||||
{
|
||||
defaultMessage: 'Current phase',
|
||||
}
|
||||
),
|
||||
action: i18n.translate(
|
||||
'xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.currentActionHeader',
|
||||
{
|
||||
defaultMessage: 'Current action',
|
||||
}
|
||||
),
|
||||
action_time_millis: i18n.translate(
|
||||
'xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.currentActionTimeHeader',
|
||||
{
|
||||
defaultMessage: 'Current action time',
|
||||
}
|
||||
),
|
||||
failed_step: i18n.translate(
|
||||
'xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.failedStepHeader',
|
||||
{
|
||||
defaultMessage: 'Failed step',
|
||||
}
|
||||
),
|
||||
};
|
||||
const getHeaders = (): Array<[keyof IndexLifecyclePolicy, string]> => {
|
||||
return [
|
||||
[
|
||||
'policy',
|
||||
i18n.translate(
|
||||
'xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.lifecyclePolicyHeader',
|
||||
{
|
||||
defaultMessage: 'Lifecycle policy',
|
||||
}
|
||||
),
|
||||
],
|
||||
[
|
||||
'phase',
|
||||
i18n.translate(
|
||||
'xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.currentPhaseHeader',
|
||||
{
|
||||
defaultMessage: 'Current phase',
|
||||
}
|
||||
),
|
||||
],
|
||||
[
|
||||
'action',
|
||||
i18n.translate(
|
||||
'xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.currentActionHeader',
|
||||
{
|
||||
defaultMessage: 'Current action',
|
||||
}
|
||||
),
|
||||
],
|
||||
[
|
||||
'action_time_millis',
|
||||
i18n.translate(
|
||||
'xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.currentActionTimeHeader',
|
||||
{
|
||||
defaultMessage: 'Current action time',
|
||||
}
|
||||
),
|
||||
],
|
||||
[
|
||||
'failed_step',
|
||||
i18n.translate(
|
||||
'xpack.indexLifecycleMgmt.indexLifecycleMgmtSummary.headers.failedStepHeader',
|
||||
{
|
||||
defaultMessage: 'Failed step',
|
||||
}
|
||||
),
|
||||
],
|
||||
];
|
||||
};
|
||||
export class IndexLifecycleSummary extends Component {
|
||||
constructor(props) {
|
||||
|
||||
interface Props {
|
||||
index: Index;
|
||||
getUrlForApp: ApplicationStart['getUrlForApp'];
|
||||
}
|
||||
interface State {
|
||||
showStackPopover: boolean;
|
||||
showPhaseExecutionPopover: boolean;
|
||||
}
|
||||
|
||||
export class IndexLifecycleSummary extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
showStackPopover: false,
|
||||
|
@ -80,8 +107,8 @@ export class IndexLifecycleSummary extends Component {
|
|||
closePhaseExecutionPopover = () => {
|
||||
this.setState({ showPhaseExecutionPopover: false });
|
||||
};
|
||||
renderStackPopoverButton(ilm) {
|
||||
if (!ilm.stack_trace) {
|
||||
renderStackPopoverButton(ilm: IndexLifecyclePolicy) {
|
||||
if (!ilm.step_info!.stack_trace) {
|
||||
return null;
|
||||
}
|
||||
const button = (
|
||||
|
@ -100,15 +127,12 @@ export class IndexLifecycleSummary extends Component {
|
|||
closePopover={this.closeStackPopover}
|
||||
>
|
||||
<div style={{ maxHeight: '400px', width: '900px', overflowY: 'scroll' }}>
|
||||
<pre>{ilm.step_info.stack_trace}</pre>
|
||||
<pre>{ilm.step_info!.stack_trace}</pre>
|
||||
</div>
|
||||
</EuiPopover>
|
||||
);
|
||||
}
|
||||
renderPhaseExecutionPopoverButton(ilm) {
|
||||
if (!ilm.phase_execution) {
|
||||
return null;
|
||||
}
|
||||
renderPhaseExecutionPopoverButton(ilm: IndexLifecyclePolicy) {
|
||||
const button = (
|
||||
<EuiLink onClick={this.togglePhaseExecutionPopover}>
|
||||
<FormattedMessage
|
||||
|
@ -150,15 +174,18 @@ export class IndexLifecycleSummary extends Component {
|
|||
}
|
||||
buildRows() {
|
||||
const {
|
||||
index: { ilm = {} },
|
||||
index: { ilm },
|
||||
} = this.props;
|
||||
const headers = getHeaders();
|
||||
const rows = {
|
||||
const rows: {
|
||||
left: JSX.Element[];
|
||||
right: JSX.Element[];
|
||||
} = {
|
||||
left: [],
|
||||
right: [],
|
||||
};
|
||||
Object.keys(headers).forEach((fieldName, arrayIndex) => {
|
||||
const value = ilm[fieldName];
|
||||
headers.forEach(([fieldName, label], arrayIndex) => {
|
||||
const value: any = ilm[fieldName];
|
||||
let content;
|
||||
if (fieldName === 'action_time_millis') {
|
||||
content = moment(value).format('YYYY-MM-DD HH:mm:ss');
|
||||
|
@ -176,34 +203,38 @@ export class IndexLifecycleSummary extends Component {
|
|||
content = value;
|
||||
}
|
||||
content = content || '-';
|
||||
const cell = [
|
||||
<EuiDescriptionListTitle key={fieldName}>
|
||||
<strong>{headers[fieldName]}</strong>
|
||||
</EuiDescriptionListTitle>,
|
||||
<EuiDescriptionListDescription key={fieldName + '_desc'}>
|
||||
{content}
|
||||
</EuiDescriptionListDescription>,
|
||||
];
|
||||
const cell = (
|
||||
<>
|
||||
<EuiDescriptionListTitle key={fieldName}>
|
||||
<strong>{label}</strong>
|
||||
</EuiDescriptionListTitle>
|
||||
<EuiDescriptionListDescription key={fieldName + '_desc'}>
|
||||
{content}
|
||||
</EuiDescriptionListDescription>
|
||||
</>
|
||||
);
|
||||
if (arrayIndex % 2 === 0) {
|
||||
rows.left.push(cell);
|
||||
} else {
|
||||
rows.right.push(cell);
|
||||
}
|
||||
});
|
||||
rows.right.push(this.renderPhaseExecutionPopoverButton(ilm));
|
||||
if (ilm.phase_execution) {
|
||||
rows.right.push(this.renderPhaseExecutionPopoverButton(ilm));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
index: { ilm = {} },
|
||||
index: { ilm },
|
||||
} = this.props;
|
||||
if (!ilm.managed) {
|
||||
return null;
|
||||
}
|
||||
const { left, right } = this.buildRows();
|
||||
return (
|
||||
<Fragment>
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
|
@ -213,7 +244,7 @@ export class IndexLifecycleSummary extends Component {
|
|||
</h3>
|
||||
</EuiTitle>
|
||||
{ilm.step_info && ilm.step_info.type ? (
|
||||
<Fragment>
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiCallOut
|
||||
color="danger"
|
||||
|
@ -229,10 +260,10 @@ export class IndexLifecycleSummary extends Component {
|
|||
<EuiSpacer size="s" />
|
||||
{this.renderStackPopoverButton(ilm)}
|
||||
</EuiCallOut>
|
||||
</Fragment>
|
||||
</>
|
||||
) : null}
|
||||
{ilm.step_info && ilm.step_info.message && !ilm.step_info.stack_trace ? (
|
||||
<Fragment>
|
||||
{ilm.step_info && ilm.step_info!.message && !ilm.step_info!.stack_trace ? (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiCallOut
|
||||
color="primary"
|
||||
|
@ -243,9 +274,9 @@ export class IndexLifecycleSummary extends Component {
|
|||
/>
|
||||
}
|
||||
>
|
||||
{ilm.step_info.message}
|
||||
{ilm.step_info!.message}
|
||||
</EuiCallOut>
|
||||
</Fragment>
|
||||
</>
|
||||
) : null}
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup>
|
||||
|
@ -256,7 +287,7 @@ export class IndexLifecycleSummary extends Component {
|
|||
<EuiDescriptionList type="column">{right}</EuiDescriptionList>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</Fragment>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,7 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export declare const addAllExtensions: any;
|
|
@ -8,22 +8,27 @@ import React from 'react';
|
|||
import { get, every, some } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiSearchBar } from '@elastic/eui';
|
||||
import { ApplicationStart } from 'kibana/public';
|
||||
|
||||
import { IndexManagementPluginSetup } from '../../../index_management/public';
|
||||
|
||||
import { retryLifecycleForIndex } from '../application/services/api';
|
||||
import { IndexLifecycleSummary } from './components/index_lifecycle_summary';
|
||||
|
||||
import { AddLifecyclePolicyConfirmModal } from './components/add_lifecycle_confirm_modal';
|
||||
import { RemoveLifecyclePolicyConfirmModal } from './components/remove_lifecycle_confirm_modal';
|
||||
import { Index } from '../application/services/policies/types';
|
||||
|
||||
const stepPath = 'ilm.step';
|
||||
|
||||
export const retryLifecycleActionExtension = ({ indices }) => {
|
||||
export const retryLifecycleActionExtension = ({ indices }: { indices: Index[] }) => {
|
||||
const allHaveErrors = every(indices, (index) => {
|
||||
return index.ilm && index.ilm.failed_step;
|
||||
});
|
||||
if (!allHaveErrors) {
|
||||
return null;
|
||||
}
|
||||
const indexNames = indices.map(({ name }) => name);
|
||||
const indexNames = indices.map(({ name }: Index) => name);
|
||||
return {
|
||||
requestMethod: retryLifecycleForIndex,
|
||||
icon: 'play',
|
||||
|
@ -35,22 +40,28 @@ export const retryLifecycleActionExtension = ({ indices }) => {
|
|||
'xpack.indexLifecycleMgmt.retryIndexLifecycleAction.retriedLifecycleMessage',
|
||||
{
|
||||
defaultMessage: 'Called retry lifecycle step for: {indexNames}',
|
||||
values: { indexNames: indexNames.map((indexName) => `"${indexName}"`).join(', ') },
|
||||
values: { indexNames: indexNames.map((indexName: string) => `"${indexName}"`).join(', ') },
|
||||
}
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
export const removeLifecyclePolicyActionExtension = ({ indices, reloadIndices }) => {
|
||||
export const removeLifecyclePolicyActionExtension = ({
|
||||
indices,
|
||||
reloadIndices,
|
||||
}: {
|
||||
indices: Index[];
|
||||
reloadIndices: () => void;
|
||||
}) => {
|
||||
const allHaveIlm = every(indices, (index) => {
|
||||
return index.ilm && index.ilm.managed;
|
||||
});
|
||||
if (!allHaveIlm) {
|
||||
return null;
|
||||
}
|
||||
const indexNames = indices.map(({ name }) => name);
|
||||
const indexNames = indices.map(({ name }: Index) => name);
|
||||
return {
|
||||
renderConfirmModal: (closeModal) => {
|
||||
renderConfirmModal: (closeModal: () => void) => {
|
||||
return (
|
||||
<RemoveLifecyclePolicyConfirmModal
|
||||
indexNames={indexNames}
|
||||
|
@ -67,7 +78,15 @@ export const removeLifecyclePolicyActionExtension = ({ indices, reloadIndices })
|
|||
};
|
||||
};
|
||||
|
||||
export const addLifecyclePolicyActionExtension = ({ indices, reloadIndices, getUrlForApp }) => {
|
||||
export const addLifecyclePolicyActionExtension = ({
|
||||
indices,
|
||||
reloadIndices,
|
||||
getUrlForApp,
|
||||
}: {
|
||||
indices: Index[];
|
||||
reloadIndices: () => void;
|
||||
getUrlForApp: ApplicationStart['getUrlForApp'];
|
||||
}) => {
|
||||
if (indices.length !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
@ -79,7 +98,7 @@ export const addLifecyclePolicyActionExtension = ({ indices, reloadIndices, getU
|
|||
}
|
||||
const indexName = index.name;
|
||||
return {
|
||||
renderConfirmModal: (closeModal) => {
|
||||
renderConfirmModal: (closeModal: () => void) => {
|
||||
return (
|
||||
<AddLifecyclePolicyConfirmModal
|
||||
indexName={indexName}
|
||||
|
@ -97,12 +116,12 @@ export const addLifecyclePolicyActionExtension = ({ indices, reloadIndices, getU
|
|||
};
|
||||
};
|
||||
|
||||
export const ilmBannerExtension = (indices) => {
|
||||
export const ilmBannerExtension = (indices: Index[]) => {
|
||||
const { Query } = EuiSearchBar;
|
||||
if (!indices.length) {
|
||||
return null;
|
||||
}
|
||||
const indicesWithLifecycleErrors = indices.filter((index) => {
|
||||
const indicesWithLifecycleErrors = indices.filter((index: Index) => {
|
||||
return get(index, stepPath) === 'ERROR';
|
||||
});
|
||||
const numIndicesWithLifecycleErrors = indicesWithLifecycleErrors.length;
|
||||
|
@ -124,11 +143,14 @@ export const ilmBannerExtension = (indices) => {
|
|||
};
|
||||
};
|
||||
|
||||
export const ilmSummaryExtension = (index, getUrlForApp) => {
|
||||
export const ilmSummaryExtension = (
|
||||
index: Index,
|
||||
getUrlForApp: ApplicationStart['getUrlForApp']
|
||||
) => {
|
||||
return <IndexLifecycleSummary index={index} getUrlForApp={getUrlForApp} />;
|
||||
};
|
||||
|
||||
export const ilmFilterExtension = (indices) => {
|
||||
export const ilmFilterExtension = (indices: Index[]) => {
|
||||
const hasIlm = some(indices, (index) => index.ilm && index.ilm.managed);
|
||||
if (!hasIlm) {
|
||||
return [];
|
||||
|
@ -200,7 +222,9 @@ export const ilmFilterExtension = (indices) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const addAllExtensions = (extensionsService) => {
|
||||
export const addAllExtensions = (
|
||||
extensionsService: IndexManagementPluginSetup['extensionsService']
|
||||
) => {
|
||||
extensionsService.addAction(retryLifecycleActionExtension);
|
||||
extensionsService.addAction(removeLifecyclePolicyActionExtension);
|
||||
extensionsService.addAction(addLifecyclePolicyActionExtension);
|
|
@ -41,3 +41,18 @@ export interface IndexSettings {
|
|||
analysis?: AnalysisModule;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface Index {
|
||||
health: string;
|
||||
status: string;
|
||||
name: string;
|
||||
uuid: string;
|
||||
primary: string;
|
||||
replica: string;
|
||||
documents: any;
|
||||
size: any;
|
||||
isFrozen: boolean;
|
||||
aliases: string | string[];
|
||||
data_stream?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
|
|
@ -14,3 +14,5 @@ export const plugin = () => {
|
|||
export { IndexManagementPluginSetup };
|
||||
|
||||
export { getIndexListUri } from './application/services/routing';
|
||||
|
||||
export { Index } from '../common';
|
||||
|
|
|
@ -18,5 +18,5 @@ export const config = {
|
|||
/** @public */
|
||||
export { Dependencies } from './types';
|
||||
export { IndexManagementPluginSetup } from './plugin';
|
||||
export { Index } from './types';
|
||||
export { Index } from '../common';
|
||||
export { IndexManagementConfig } from './config';
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
*/
|
||||
import { CatIndicesParams } from 'elasticsearch';
|
||||
import { IndexDataEnricher } from '../services';
|
||||
import { Index, CallAsCurrentUser } from '../types';
|
||||
import { CallAsCurrentUser } from '../types';
|
||||
import { Index } from '../index';
|
||||
|
||||
interface Hit {
|
||||
health: string;
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { Index, CallAsCurrentUser } from '../types';
|
||||
import { CallAsCurrentUser } from '../types';
|
||||
import { Index } from '../index';
|
||||
|
||||
export type Enricher = (indices: Index[], callAsCurrentUser: CallAsCurrentUser) => Promise<Index[]>;
|
||||
|
||||
|
|
|
@ -26,19 +26,4 @@ export interface RouteDependencies {
|
|||
};
|
||||
}
|
||||
|
||||
export interface Index {
|
||||
health: string;
|
||||
status: string;
|
||||
name: string;
|
||||
uuid: string;
|
||||
primary: string;
|
||||
replica: string;
|
||||
documents: any;
|
||||
size: any;
|
||||
isFrozen: boolean;
|
||||
aliases: string | string[];
|
||||
data_stream?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export type CallAsCurrentUser = LegacyScopedClusterClient['callAsCurrentUser'];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue