Skip to content

Commit 996e151

Browse files
committed
[ML] Refactor analytics list actions.
1 parent bb91e7d commit 996e151

File tree

23 files changed

+793
-583
lines changed

23 files changed

+793
-583
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import { isAdvancedConfig } from './action_clone';
7+
import { isAdvancedConfig } from './clone_button';
88

99
describe('Analytics job clone action', () => {
1010
describe('isAdvancedConfig', () => {
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
DEFAULT_NUM_TOP_FEATURE_IMPORTANCE_VALUES,
2020
} from '../../hooks/use_create_analytics_form';
2121
import { State } from '../../hooks/use_create_analytics_form/state';
22-
import { DataFrameAnalyticsListRow } from './common';
22+
import { DataFrameAnalyticsListRow } from '../analytics_list/common';
2323
import { checkPermission } from '../../../../../capabilities/check_capabilities';
2424
import { extractErrorMessage } from '../../../../../../../common/util/errors';
2525

@@ -343,7 +343,7 @@ export function getCloneAction(createAnalyticsForm: CreateAnalyticsFormProps) {
343343
};
344344
}
345345

346-
interface CloneActionProps {
346+
interface CloneButtonProps {
347347
item: DataFrameAnalyticsListRow;
348348
createAnalyticsForm: CreateAnalyticsFormProps;
349349
}
@@ -353,7 +353,7 @@ interface CloneActionProps {
353353
* Replace with {@link getCloneAction} as soon as all the actions are refactored
354354
* to support EuiContext with a valid DOM structure without nested buttons.
355355
*/
356-
export const CloneAction: FC<CloneActionProps> = ({ createAnalyticsForm, item }) => {
356+
export const CloneButton: FC<CloneButtonProps> = ({ createAnalyticsForm, item }) => {
357357
const canCreateDataFrameAnalytics: boolean = checkPermission('canCreateDataFrameAnalytics');
358358

359359
const buttonText = i18n.translate('xpack.ml.dataframe.analyticsList.cloneJobButtonLabel', {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
export { CloneButton } from './clone_button';
Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import React from 'react';
88
import { fireEvent, render } from '@testing-library/react';
99
import * as CheckPrivilige from '../../../../../capabilities/check_capabilities';
1010
import mockAnalyticsListItem from './__mocks__/analytics_list_item.json';
11-
import { DeleteAction } from './action_delete';
11+
import { DeleteButton } from './delete_button';
1212
import { I18nProvider } from '@kbn/i18n/react';
1313
import {
1414
coreMock as mockCoreServices,
@@ -41,14 +41,18 @@ describe('DeleteAction', () => {
4141
});
4242

4343
test('When canDeleteDataFrameAnalytics permission is false, button should be disabled.', () => {
44-
const { getByTestId } = render(<DeleteAction item={mockAnalyticsListItem} />);
44+
const { getByTestId } = render(
45+
<DeleteButton item={mockAnalyticsListItem} onClick={() => {}} />
46+
);
4547
expect(getByTestId('mlAnalyticsJobDeleteButton')).toHaveAttribute('disabled');
4648
});
4749

4850
test('When canDeleteDataFrameAnalytics permission is true, button should not be disabled.', () => {
4951
const mock = jest.spyOn(CheckPrivilige, 'checkPermission');
5052
mock.mockImplementation((p) => p === 'canDeleteDataFrameAnalytics');
51-
const { getByTestId } = render(<DeleteAction item={mockAnalyticsListItem} />);
53+
const { getByTestId } = render(
54+
<DeleteButton item={mockAnalyticsListItem} onClick={() => {}} />
55+
);
5256

5357
expect(getByTestId('mlAnalyticsJobDeleteButton')).not.toHaveAttribute('disabled');
5458

@@ -57,11 +61,12 @@ describe('DeleteAction', () => {
5761

5862
test('When job is running, delete button should be disabled.', () => {
5963
const { getByTestId } = render(
60-
<DeleteAction
64+
<DeleteButton
6165
item={{
6266
...mockAnalyticsListItem,
6367
stats: { state: 'started' },
6468
}}
69+
onClick={() => {}}
6570
/>
6671
);
6772

@@ -74,7 +79,7 @@ describe('DeleteAction', () => {
7479
mock.mockImplementation((p) => p === 'canDeleteDataFrameAnalytics');
7580
const { getByTestId, queryByTestId } = render(
7681
<I18nProvider>
77-
<DeleteAction item={mockAnalyticsListItem} />
82+
<DeleteButton item={mockAnalyticsListItem} onClick={() => {}} />
7883
</I18nProvider>
7984
);
8085
const deleteButton = getByTestId('mlAnalyticsJobDeleteButton');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import React, { FC } from 'react';
8+
import { i18n } from '@kbn/i18n';
9+
import { EuiIcon, EuiLink, EuiToolTip } from '@elastic/eui';
10+
import {
11+
checkPermission,
12+
createPermissionFailureMessage,
13+
} from '../../../../../capabilities/check_capabilities';
14+
import { isDataFrameAnalyticsRunning, DataFrameAnalyticsListRow } from '../analytics_list/common';
15+
16+
interface DeleteButtonProps {
17+
item: DataFrameAnalyticsListRow;
18+
onClick: (item: DataFrameAnalyticsListRow) => void;
19+
}
20+
21+
export const DeleteButton: FC<DeleteButtonProps> = ({ item, onClick }) => {
22+
const disabled = isDataFrameAnalyticsRunning(item.stats.state);
23+
const canDeleteDataFrameAnalytics: boolean = checkPermission('canDeleteDataFrameAnalytics');
24+
25+
const buttonDeleteText = i18n.translate('xpack.ml.dataframe.analyticsList.deleteActionName', {
26+
defaultMessage: 'Delete',
27+
});
28+
29+
const buttonDisabled = disabled || !canDeleteDataFrameAnalytics;
30+
let deleteButton = (
31+
<EuiLink
32+
data-test-subj="mlAnalyticsJobDeleteButton"
33+
color={buttonDisabled ? 'subdued' : 'text'}
34+
disabled={buttonDisabled}
35+
onClick={buttonDisabled ? undefined : () => onClick(item)}
36+
aria-label={buttonDeleteText}
37+
style={{ padding: 0 }}
38+
>
39+
<EuiIcon type="trash" /> {buttonDeleteText}
40+
</EuiLink>
41+
);
42+
43+
if (disabled || !canDeleteDataFrameAnalytics) {
44+
deleteButton = (
45+
<EuiToolTip
46+
position="top"
47+
content={
48+
disabled
49+
? i18n.translate(
50+
'xpack.ml.dataframe.analyticsList.deleteActionDisabledToolTipContent',
51+
{
52+
defaultMessage: 'Stop the data frame analytics in order to delete it.',
53+
}
54+
)
55+
: createPermissionFailureMessage('canStartStopDataFrameAnalytics')
56+
}
57+
>
58+
{deleteButton}
59+
</EuiToolTip>
60+
);
61+
}
62+
63+
return deleteButton;
64+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import React, { FC } from 'react';
8+
import { i18n } from '@kbn/i18n';
9+
import {
10+
EuiConfirmModal,
11+
EuiOverlayMask,
12+
EuiSwitch,
13+
EuiFlexGroup,
14+
EuiFlexItem,
15+
EUI_MODAL_CONFIRM_BUTTON,
16+
} from '@elastic/eui';
17+
import { FormattedMessage } from '@kbn/i18n/react';
18+
19+
import { DeleteAction } from './use_delete_action';
20+
21+
type DeleteButtonModalProps = Pick<
22+
DeleteAction,
23+
| 'closeModal'
24+
| 'deleteAndCloseModal'
25+
| 'deleteTargetIndex'
26+
| 'deleteIndexPattern'
27+
| 'indexPatternExists'
28+
| 'isModalVisible'
29+
| 'item'
30+
| 'toggleDeleteIndex'
31+
| 'toggleDeleteIndexPattern'
32+
| 'userCanDeleteIndex'
33+
>;
34+
export const DeleteButtonModal: FC<DeleteButtonModalProps> = ({
35+
closeModal,
36+
deleteAndCloseModal,
37+
deleteTargetIndex,
38+
deleteIndexPattern,
39+
indexPatternExists,
40+
isModalVisible,
41+
item,
42+
toggleDeleteIndex,
43+
toggleDeleteIndexPattern,
44+
userCanDeleteIndex,
45+
}) => {
46+
if (item === undefined) {
47+
return null;
48+
}
49+
50+
const indexName = item.config.dest.index;
51+
52+
return (
53+
<>
54+
{isModalVisible && (
55+
<EuiOverlayMask data-test-subj="mlAnalyticsJobDeleteOverlay">
56+
<EuiConfirmModal
57+
data-test-subj="mlAnalyticsJobDeleteModal"
58+
title={i18n.translate('xpack.ml.dataframe.analyticsList.deleteModalTitle', {
59+
defaultMessage: 'Delete {analyticsId}',
60+
values: { analyticsId: item.config.id },
61+
})}
62+
onCancel={closeModal}
63+
onConfirm={deleteAndCloseModal}
64+
cancelButtonText={i18n.translate(
65+
'xpack.ml.dataframe.analyticsList.deleteModalCancelButton',
66+
{
67+
defaultMessage: 'Cancel',
68+
}
69+
)}
70+
confirmButtonText={i18n.translate(
71+
'xpack.ml.dataframe.analyticsList.deleteModalDeleteButton',
72+
{
73+
defaultMessage: 'Delete',
74+
}
75+
)}
76+
defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON}
77+
buttonColor="danger"
78+
>
79+
<p>
80+
<FormattedMessage
81+
id="xpack.ml.dataframe.analyticsList.deleteModalBody"
82+
defaultMessage="Are you sure you want to delete this analytics job?"
83+
/>
84+
</p>
85+
86+
<EuiFlexGroup direction="column" gutterSize="none">
87+
<EuiFlexItem>
88+
{userCanDeleteIndex && (
89+
<EuiSwitch
90+
data-test-subj="mlAnalyticsJobDeleteIndexSwitch"
91+
style={{ paddingBottom: 10 }}
92+
label={i18n.translate(
93+
'xpack.ml.dataframe.analyticsList.deleteDestinationIndexTitle',
94+
{
95+
defaultMessage: 'Delete destination index {indexName}',
96+
values: { indexName },
97+
}
98+
)}
99+
checked={deleteTargetIndex}
100+
onChange={toggleDeleteIndex}
101+
/>
102+
)}
103+
</EuiFlexItem>
104+
<EuiFlexItem>
105+
{userCanDeleteIndex && indexPatternExists && (
106+
<EuiSwitch
107+
data-test-subj="mlAnalyticsJobDeleteIndexPatternSwitch"
108+
label={i18n.translate(
109+
'xpack.ml.dataframe.analyticsList.deleteTargetIndexPatternTitle',
110+
{
111+
defaultMessage: 'Delete index pattern {indexPattern}',
112+
values: { indexPattern: indexName },
113+
}
114+
)}
115+
checked={deleteIndexPattern}
116+
onChange={toggleDeleteIndexPattern}
117+
/>
118+
)}
119+
</EuiFlexItem>
120+
</EuiFlexGroup>
121+
</EuiConfirmModal>
122+
</EuiOverlayMask>
123+
)}
124+
</>
125+
);
126+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
export { DeleteButton } from './delete_button';
8+
export { DeleteButtonModal } from './delete_button_modal';
9+
export { useDeleteAction } from './use_delete_action';

0 commit comments

Comments
 (0)