foreman-tasks 11.0.6 → 11.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/foreman_tasks/version.rb +1 -1
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +37 -9
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskButtons.js +19 -16
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskButtons.test.js +197 -71
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +24 -40
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +2 -16
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalSelectors.js +0 -16
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/GenericConfirmModal.js +70 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalSelectors.test.js +25 -14
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalSelectors.test.js.snap +8 -7
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/index.test.js +409 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/createBulkTaskModal.js +67 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/createTaskModal.js +51 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/index.js +73 -23
- data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +5 -2
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +1 -1
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +67 -11
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +86 -6
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.test.js +225 -39
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/index.js +136 -37
- metadata +6 -19
- data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.js +0 -60
- data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.test.js +0 -14
- data/webpack/ForemanTasks/Components/TaskActions/__snapshots__/UnlockModals.test.js.snap +0 -25
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskButtons.test.js.snap +0 -212
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModal.js +0 -83
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalActions.js +0 -106
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalReducer.js +0 -38
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModal.test.js +0 -36
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalActions.test.js +0 -205
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalReducer.test.js +0 -27
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModal.test.js.snap +0 -41
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalReducer.test.js.snap +0 -19
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.scss +0 -9
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/__snapshots__/ClickConfirmation.test.js.snap +0 -52
- data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +0 -2
- data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js +0 -10
- data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +0 -18
data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalSelectors.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { selectForemanTasks } from '../../../../ForemanTasksSelectors';
|
|
2
1
|
import {
|
|
3
2
|
selectTasksTableQuery,
|
|
4
3
|
selectResults,
|
|
@@ -6,15 +5,7 @@ import {
|
|
|
6
5
|
selectItemCount,
|
|
7
6
|
selectAllRowsSelected,
|
|
8
7
|
} from '../../TasksTableSelectors';
|
|
9
|
-
import { RESUME_MODAL, CANCEL_MODAL } from '../../TasksTableConstants';
|
|
10
|
-
import { FORCE_UNLOCK_MODAL } from '../../../TaskActions/TaskActionsConstants';
|
|
11
8
|
|
|
12
|
-
export const selectCofirmModal = state =>
|
|
13
|
-
selectForemanTasks(state).confirmModal || {};
|
|
14
|
-
|
|
15
|
-
export const selectActionType = state => selectCofirmModal(state).actionType;
|
|
16
|
-
export const selectActionText = state => selectCofirmModal(state).actionText;
|
|
17
|
-
export const selectActionState = state => selectCofirmModal(state).actionState;
|
|
18
9
|
export const selectClicked = state =>
|
|
19
10
|
selectTasksTableQuery(state).clicked || {};
|
|
20
11
|
|
|
@@ -32,13 +23,6 @@ export const selectSelectedTasks = state => {
|
|
|
32
23
|
};
|
|
33
24
|
|
|
34
25
|
export const selectSelectedRowsLen = state => {
|
|
35
|
-
if (
|
|
36
|
-
[CANCEL_MODAL, RESUME_MODAL, FORCE_UNLOCK_MODAL].includes(
|
|
37
|
-
selectActionType(state)
|
|
38
|
-
)
|
|
39
|
-
) {
|
|
40
|
-
return 1;
|
|
41
|
-
}
|
|
42
26
|
if (selectAllRowsSelected(state)) {
|
|
43
27
|
return selectItemCount(state);
|
|
44
28
|
}
|
data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/GenericConfirmModal.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { useDispatch } from 'react-redux';
|
|
4
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
|
5
|
+
import { Button, Modal, ModalVariant } from '@patternfly/react-core';
|
|
6
|
+
|
|
7
|
+
export const GenericConfirmModal = ({
|
|
8
|
+
isModalOpen,
|
|
9
|
+
setIsModalOpen,
|
|
10
|
+
title,
|
|
11
|
+
message,
|
|
12
|
+
onConfirm,
|
|
13
|
+
confirmButtonVariant,
|
|
14
|
+
ouiaIdPrefix,
|
|
15
|
+
}) => {
|
|
16
|
+
const dispatch = useDispatch();
|
|
17
|
+
|
|
18
|
+
const handleConfirm = () => {
|
|
19
|
+
const action = onConfirm();
|
|
20
|
+
if (action) {
|
|
21
|
+
dispatch(action);
|
|
22
|
+
}
|
|
23
|
+
setIsModalOpen(false);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Modal
|
|
28
|
+
title={title}
|
|
29
|
+
variant={ModalVariant.small}
|
|
30
|
+
isOpen={isModalOpen}
|
|
31
|
+
onClose={() => setIsModalOpen(false)}
|
|
32
|
+
ouiaId={`${ouiaIdPrefix}-modal`}
|
|
33
|
+
actions={[
|
|
34
|
+
<Button
|
|
35
|
+
ouiaId={`${ouiaIdPrefix}-modal-confirm-button`}
|
|
36
|
+
key="confirm"
|
|
37
|
+
className="confirm-button"
|
|
38
|
+
variant={confirmButtonVariant}
|
|
39
|
+
onClick={handleConfirm}
|
|
40
|
+
>
|
|
41
|
+
{__('Yes')}
|
|
42
|
+
</Button>,
|
|
43
|
+
<Button
|
|
44
|
+
ouiaId={`${ouiaIdPrefix}-modal-cancel-button`}
|
|
45
|
+
key="cancel"
|
|
46
|
+
variant="secondary"
|
|
47
|
+
onClick={() => setIsModalOpen(false)}
|
|
48
|
+
>
|
|
49
|
+
{__('No')}
|
|
50
|
+
</Button>,
|
|
51
|
+
]}
|
|
52
|
+
>
|
|
53
|
+
{message}
|
|
54
|
+
</Modal>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
GenericConfirmModal.propTypes = {
|
|
59
|
+
isModalOpen: PropTypes.bool.isRequired,
|
|
60
|
+
setIsModalOpen: PropTypes.func.isRequired,
|
|
61
|
+
title: PropTypes.string.isRequired,
|
|
62
|
+
message: PropTypes.string.isRequired,
|
|
63
|
+
onConfirm: PropTypes.func.isRequired,
|
|
64
|
+
confirmButtonVariant: PropTypes.string,
|
|
65
|
+
ouiaIdPrefix: PropTypes.string.isRequired,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
GenericConfirmModal.defaultProps = {
|
|
69
|
+
confirmButtonVariant: 'primary',
|
|
70
|
+
};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { testSelectorsSnapshotWithFixtures } from '@theforeman/test';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
selectActionState,
|
|
5
|
-
selectActionType,
|
|
3
|
+
selectClicked,
|
|
6
4
|
selectSelectedTasks,
|
|
7
5
|
selectSelectedRowsLen,
|
|
8
6
|
} from '../ConfirmModalSelectors';
|
|
@@ -10,11 +8,6 @@ import { CANCEL_MODAL } from '../../../TasksTableConstants';
|
|
|
10
8
|
|
|
11
9
|
const state = {
|
|
12
10
|
foremanTasks: {
|
|
13
|
-
confirmModal: {
|
|
14
|
-
actionText: 'some-text',
|
|
15
|
-
actionState: 'some-state',
|
|
16
|
-
actionType: 'some-type',
|
|
17
|
-
},
|
|
18
11
|
tasksTable: {
|
|
19
12
|
tasksTableContent: {
|
|
20
13
|
results: [
|
|
@@ -28,26 +21,44 @@ const state = {
|
|
|
28
21
|
],
|
|
29
22
|
itemCount: 10,
|
|
30
23
|
},
|
|
31
|
-
tasksTableQuery: {
|
|
24
|
+
tasksTableQuery: {
|
|
25
|
+
selectedRows: [1, 2, 3],
|
|
26
|
+
clicked: { taskId: '1', taskName: 'test-task' },
|
|
27
|
+
allRowsSelected: false,
|
|
28
|
+
},
|
|
32
29
|
},
|
|
33
30
|
},
|
|
34
31
|
};
|
|
35
32
|
|
|
36
33
|
const fixtures = {
|
|
37
|
-
'should select
|
|
38
|
-
'should select actionState': () => selectActionState(state),
|
|
39
|
-
'should select actionType': () => selectActionType(state),
|
|
34
|
+
'should select clicked': () => selectClicked(state),
|
|
40
35
|
'should select selectedTasks': () => selectSelectedTasks(state),
|
|
41
36
|
'should select selectedRowsLen 1': () =>
|
|
42
37
|
selectSelectedRowsLen({
|
|
43
38
|
...state,
|
|
44
|
-
foremanTasks: {
|
|
39
|
+
foremanTasks: {
|
|
40
|
+
tasksTable: {
|
|
41
|
+
...state.foremanTasks.tasksTable,
|
|
42
|
+
tasksTableQuery: {
|
|
43
|
+
...state.foremanTasks.tasksTable.tasksTableQuery,
|
|
44
|
+
clicked: { modalType: CANCEL_MODAL },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
45
48
|
}),
|
|
46
49
|
'should select selectedRowsLen all': () => selectSelectedRowsLen(state),
|
|
47
50
|
'should select selectedRowsLen some': () =>
|
|
48
51
|
selectSelectedRowsLen({
|
|
49
52
|
...state,
|
|
50
|
-
|
|
53
|
+
foremanTasks: {
|
|
54
|
+
tasksTable: {
|
|
55
|
+
...state.foremanTasks.tasksTable,
|
|
56
|
+
tasksTableQuery: {
|
|
57
|
+
...state.foremanTasks.tasksTable.tasksTableQuery,
|
|
58
|
+
allRowsSelected: true,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
51
62
|
}),
|
|
52
63
|
};
|
|
53
64
|
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
-
exports[`TasksDashboard - Selectors should select
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
exports[`TasksDashboard - Selectors should select clicked 1`] = `
|
|
4
|
+
Object {
|
|
5
|
+
"taskId": "1",
|
|
6
|
+
"taskName": "test-task",
|
|
7
|
+
}
|
|
8
|
+
`;
|
|
8
9
|
|
|
9
|
-
exports[`TasksDashboard - Selectors should select selectedRowsLen 1 1`] = `
|
|
10
|
+
exports[`TasksDashboard - Selectors should select selectedRowsLen 1 1`] = `3`;
|
|
10
11
|
|
|
11
12
|
exports[`TasksDashboard - Selectors should select selectedRowsLen all 1`] = `3`;
|
|
12
13
|
|
|
13
|
-
exports[`TasksDashboard - Selectors should select selectedRowsLen some 1`] = `
|
|
14
|
+
exports[`TasksDashboard - Selectors should select selectedRowsLen some 1`] = `0`;
|
|
14
15
|
|
|
15
16
|
exports[`TasksDashboard - Selectors should select selectedTasks 1`] = `
|
|
16
17
|
Array [
|
data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/index.test.js
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
import { Provider } from 'react-redux';
|
|
5
|
+
import { configureStore } from '@reduxjs/toolkit';
|
|
6
|
+
import {
|
|
7
|
+
CancelModal,
|
|
8
|
+
ResumeModal,
|
|
9
|
+
CancelSelectedModal,
|
|
10
|
+
ResumeSelectedModal,
|
|
11
|
+
ForceUnlockModal,
|
|
12
|
+
ForceUnlockSelectedModal,
|
|
13
|
+
} from '../index';
|
|
14
|
+
|
|
15
|
+
// Mock the action creators
|
|
16
|
+
jest.mock('../../../TasksTableActions', () => ({
|
|
17
|
+
cancelTask: jest.fn(() => ({ type: 'CANCEL_TASK' })),
|
|
18
|
+
resumeTask: jest.fn(() => ({ type: 'RESUME_TASK' })),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
jest.mock('../../../TasksBulkActions', () => ({
|
|
22
|
+
bulkCancelBySearch: jest.fn(() => ({ type: 'BULK_CANCEL_BY_SEARCH' })),
|
|
23
|
+
bulkCancelById: jest.fn(() => ({ type: 'BULK_CANCEL_BY_ID' })),
|
|
24
|
+
bulkResumeBySearch: jest.fn(() => ({ type: 'BULK_RESUME_BY_SEARCH' })),
|
|
25
|
+
bulkResumeById: jest.fn(() => ({ type: 'BULK_RESUME_BY_ID' })),
|
|
26
|
+
bulkForceUnlockBySearch: jest.fn(() => ({
|
|
27
|
+
type: 'BULK_FORCE_UNLOCK_BY_SEARCH',
|
|
28
|
+
})),
|
|
29
|
+
bulkForceUnlockById: jest.fn(() => ({ type: 'BULK_FORCE_UNLOCK_BY_ID' })),
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
// Mock the selectors
|
|
33
|
+
jest.mock('../ConfirmModalSelectors', () => ({
|
|
34
|
+
selectClicked: jest.fn(() => ({ taskId: '123', taskName: 'Test Task' })),
|
|
35
|
+
selectSelectedTasks: jest.fn(() => [
|
|
36
|
+
{ id: 1, name: 'Task 1' },
|
|
37
|
+
{ id: 2, name: 'Task 2' },
|
|
38
|
+
]),
|
|
39
|
+
selectSelectedRowsLen: jest.fn(() => 2),
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
jest.mock('../../../TasksTableSelectors', () => ({
|
|
43
|
+
selectAllRowsSelected: jest.fn(() => false),
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
// Create a mock store
|
|
47
|
+
const createMockStore = (initialState = {}) => {
|
|
48
|
+
return configureStore({
|
|
49
|
+
reducer: {
|
|
50
|
+
foremanTasks: (state = initialState, action) => state,
|
|
51
|
+
},
|
|
52
|
+
preloadedState: {
|
|
53
|
+
foremanTasks: initialState,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Test wrapper component
|
|
59
|
+
const TestWrapper = ({ children, store }) => (
|
|
60
|
+
<Provider store={store}>{children}</Provider>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
describe('ConfirmModal Components', () => {
|
|
64
|
+
const defaultProps = {
|
|
65
|
+
isModalOpen: true,
|
|
66
|
+
setIsModalOpen: jest.fn(),
|
|
67
|
+
url: '/api/tasks',
|
|
68
|
+
parentTaskID: 'parent-123',
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const mockStore = createMockStore();
|
|
72
|
+
|
|
73
|
+
beforeEach(() => {
|
|
74
|
+
jest.clearAllMocks();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('CancelModal', () => {
|
|
78
|
+
it('renders with correct title and content', () => {
|
|
79
|
+
render(
|
|
80
|
+
<TestWrapper store={mockStore}>
|
|
81
|
+
<CancelModal {...defaultProps} />
|
|
82
|
+
</TestWrapper>
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(screen.getByText('Cancel Task')).toBeInTheDocument();
|
|
86
|
+
expect(
|
|
87
|
+
screen.getByText(
|
|
88
|
+
/This will cancel task "Test Task", putting it in the stopped state/
|
|
89
|
+
)
|
|
90
|
+
).toBeInTheDocument();
|
|
91
|
+
expect(screen.getByText('No')).toBeInTheDocument();
|
|
92
|
+
expect(screen.getByText('Yes')).toBeInTheDocument();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('calls setIsModalOpen when cancel button is clicked', () => {
|
|
96
|
+
const setIsModalOpen = jest.fn();
|
|
97
|
+
|
|
98
|
+
render(
|
|
99
|
+
<TestWrapper store={mockStore}>
|
|
100
|
+
<CancelModal {...defaultProps} setIsModalOpen={setIsModalOpen} />
|
|
101
|
+
</TestWrapper>
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const cancelButton = screen.getByRole('button', { name: 'No' });
|
|
105
|
+
fireEvent.click(cancelButton);
|
|
106
|
+
|
|
107
|
+
expect(setIsModalOpen).toHaveBeenCalledWith(false);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('calls setIsModalOpen when confirm button is clicked', () => {
|
|
111
|
+
const setIsModalOpen = jest.fn();
|
|
112
|
+
|
|
113
|
+
render(
|
|
114
|
+
<TestWrapper store={mockStore}>
|
|
115
|
+
<CancelModal {...defaultProps} setIsModalOpen={setIsModalOpen} />
|
|
116
|
+
</TestWrapper>
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const confirmButton = screen.getByRole('button', { name: 'Yes' });
|
|
120
|
+
fireEvent.click(confirmButton);
|
|
121
|
+
|
|
122
|
+
expect(setIsModalOpen).toHaveBeenCalledWith(false);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('does not render when isModalOpen is false', () => {
|
|
126
|
+
render(
|
|
127
|
+
<TestWrapper store={mockStore}>
|
|
128
|
+
<CancelModal {...defaultProps} isModalOpen={false} />
|
|
129
|
+
</TestWrapper>
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(screen.queryByText('Cancel Task')).not.toBeInTheDocument();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('ResumeModal', () => {
|
|
137
|
+
it('renders with correct title and content', () => {
|
|
138
|
+
render(
|
|
139
|
+
<TestWrapper store={mockStore}>
|
|
140
|
+
<ResumeModal {...defaultProps} />
|
|
141
|
+
</TestWrapper>
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
expect(screen.getByText('Resume Task')).toBeInTheDocument();
|
|
145
|
+
expect(
|
|
146
|
+
screen.getByText(
|
|
147
|
+
/This will resume task "Test Task", putting it in the running state/
|
|
148
|
+
)
|
|
149
|
+
).toBeInTheDocument();
|
|
150
|
+
expect(screen.getByText('No')).toBeInTheDocument();
|
|
151
|
+
expect(screen.getByText('Yes')).toBeInTheDocument();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('calls setIsModalOpen when cancel button is clicked', () => {
|
|
155
|
+
const setIsModalOpen = jest.fn();
|
|
156
|
+
|
|
157
|
+
render(
|
|
158
|
+
<TestWrapper store={mockStore}>
|
|
159
|
+
<ResumeModal {...defaultProps} setIsModalOpen={setIsModalOpen} />
|
|
160
|
+
</TestWrapper>
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
const cancelButton = screen.getByRole('button', { name: 'No' });
|
|
164
|
+
fireEvent.click(cancelButton);
|
|
165
|
+
|
|
166
|
+
expect(setIsModalOpen).toHaveBeenCalledWith(false);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('calls setIsModalOpen when confirm button is clicked', () => {
|
|
170
|
+
const setIsModalOpen = jest.fn();
|
|
171
|
+
|
|
172
|
+
render(
|
|
173
|
+
<TestWrapper store={mockStore}>
|
|
174
|
+
<ResumeModal {...defaultProps} setIsModalOpen={setIsModalOpen} />
|
|
175
|
+
</TestWrapper>
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
const confirmButton = screen.getByRole('button', { name: 'Yes' });
|
|
179
|
+
fireEvent.click(confirmButton);
|
|
180
|
+
|
|
181
|
+
expect(setIsModalOpen).toHaveBeenCalledWith(false);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe('CancelSelectedModal', () => {
|
|
186
|
+
const selectedProps = {
|
|
187
|
+
...defaultProps,
|
|
188
|
+
uriQuery: { search: 'test' },
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
it('renders with correct title and content', () => {
|
|
192
|
+
render(
|
|
193
|
+
<TestWrapper store={mockStore}>
|
|
194
|
+
<CancelSelectedModal {...selectedProps} />
|
|
195
|
+
</TestWrapper>
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
expect(screen.getByText('Cancel Selected Tasks')).toBeInTheDocument();
|
|
199
|
+
expect(
|
|
200
|
+
screen.getByText(
|
|
201
|
+
/This will cancel 2 task\(s\), putting them in the stopped state/
|
|
202
|
+
)
|
|
203
|
+
).toBeInTheDocument();
|
|
204
|
+
expect(screen.getByText('No')).toBeInTheDocument();
|
|
205
|
+
expect(screen.getByText('Yes')).toBeInTheDocument();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('calls setIsModalOpen when cancel button is clicked', () => {
|
|
209
|
+
const setIsModalOpen = jest.fn();
|
|
210
|
+
|
|
211
|
+
render(
|
|
212
|
+
<TestWrapper store={mockStore}>
|
|
213
|
+
<CancelSelectedModal
|
|
214
|
+
{...selectedProps}
|
|
215
|
+
setIsModalOpen={setIsModalOpen}
|
|
216
|
+
/>
|
|
217
|
+
</TestWrapper>
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
const cancelButton = screen.getByRole('button', { name: 'No' });
|
|
221
|
+
fireEvent.click(cancelButton);
|
|
222
|
+
|
|
223
|
+
expect(setIsModalOpen).toHaveBeenCalledWith(false);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('calls setIsModalOpen when confirm button is clicked', () => {
|
|
227
|
+
const setIsModalOpen = jest.fn();
|
|
228
|
+
|
|
229
|
+
render(
|
|
230
|
+
<TestWrapper store={mockStore}>
|
|
231
|
+
<CancelSelectedModal
|
|
232
|
+
{...selectedProps}
|
|
233
|
+
setIsModalOpen={setIsModalOpen}
|
|
234
|
+
/>
|
|
235
|
+
</TestWrapper>
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
const confirmButton = screen.getByRole('button', { name: 'Yes' });
|
|
239
|
+
fireEvent.click(confirmButton);
|
|
240
|
+
|
|
241
|
+
expect(setIsModalOpen).toHaveBeenCalledWith(false);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe('ResumeSelectedModal', () => {
|
|
246
|
+
const selectedProps = {
|
|
247
|
+
...defaultProps,
|
|
248
|
+
uriQuery: { search: 'test' },
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
it('renders with correct title and content', () => {
|
|
252
|
+
render(
|
|
253
|
+
<TestWrapper store={mockStore}>
|
|
254
|
+
<ResumeSelectedModal {...selectedProps} />
|
|
255
|
+
</TestWrapper>
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
expect(screen.getByText('Resume Selected Tasks')).toBeInTheDocument();
|
|
259
|
+
expect(
|
|
260
|
+
screen.getByText(
|
|
261
|
+
/This will resume 2 task\(s\), putting them in the running state/
|
|
262
|
+
)
|
|
263
|
+
).toBeInTheDocument();
|
|
264
|
+
expect(screen.getByText('No')).toBeInTheDocument();
|
|
265
|
+
expect(screen.getByText('Yes')).toBeInTheDocument();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('calls setIsModalOpen when cancel button is clicked', () => {
|
|
269
|
+
const setIsModalOpen = jest.fn();
|
|
270
|
+
|
|
271
|
+
render(
|
|
272
|
+
<TestWrapper store={mockStore}>
|
|
273
|
+
<ResumeSelectedModal
|
|
274
|
+
{...selectedProps}
|
|
275
|
+
setIsModalOpen={setIsModalOpen}
|
|
276
|
+
/>
|
|
277
|
+
</TestWrapper>
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
const cancelButton = screen.getByRole('button', { name: 'No' });
|
|
281
|
+
fireEvent.click(cancelButton);
|
|
282
|
+
|
|
283
|
+
expect(setIsModalOpen).toHaveBeenCalledWith(false);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
describe('ForceUnlockModal', () => {
|
|
288
|
+
it('renders with correct title and content', () => {
|
|
289
|
+
render(
|
|
290
|
+
<TestWrapper store={mockStore}>
|
|
291
|
+
<ForceUnlockModal {...defaultProps} />
|
|
292
|
+
</TestWrapper>
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
expect(screen.getByText('Force Unlock Task')).toBeInTheDocument();
|
|
296
|
+
expect(
|
|
297
|
+
screen.getByText(
|
|
298
|
+
/This will force unlock task "Test Task". This may cause harm and should be used with caution/
|
|
299
|
+
)
|
|
300
|
+
).toBeInTheDocument();
|
|
301
|
+
expect(screen.getByText('No')).toBeInTheDocument();
|
|
302
|
+
expect(screen.getByText('Yes')).toBeInTheDocument();
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('calls setIsModalOpen when cancel button is clicked', () => {
|
|
306
|
+
const setIsModalOpen = jest.fn();
|
|
307
|
+
|
|
308
|
+
render(
|
|
309
|
+
<TestWrapper store={mockStore}>
|
|
310
|
+
<ForceUnlockModal {...defaultProps} setIsModalOpen={setIsModalOpen} />
|
|
311
|
+
</TestWrapper>
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
const cancelButton = screen.getByRole('button', { name: 'No' });
|
|
315
|
+
fireEvent.click(cancelButton);
|
|
316
|
+
|
|
317
|
+
expect(setIsModalOpen).toHaveBeenCalledWith(false);
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
describe('ForceUnlockSelectedModal', () => {
|
|
322
|
+
const selectedProps = {
|
|
323
|
+
...defaultProps,
|
|
324
|
+
uriQuery: { search: 'test' },
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
it('renders with correct title and content', () => {
|
|
328
|
+
render(
|
|
329
|
+
<TestWrapper store={mockStore}>
|
|
330
|
+
<ForceUnlockSelectedModal {...selectedProps} />
|
|
331
|
+
</TestWrapper>
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
expect(
|
|
335
|
+
screen.getByText('Force Unlock Selected Tasks')
|
|
336
|
+
).toBeInTheDocument();
|
|
337
|
+
expect(
|
|
338
|
+
screen.getByText(
|
|
339
|
+
/This will force unlock 2 task\(s\). This may cause harm and should be used with caution/
|
|
340
|
+
)
|
|
341
|
+
).toBeInTheDocument();
|
|
342
|
+
expect(screen.getByText('No')).toBeInTheDocument();
|
|
343
|
+
expect(screen.getByText('Yes')).toBeInTheDocument();
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('calls setIsModalOpen when cancel button is clicked', () => {
|
|
347
|
+
const setIsModalOpen = jest.fn();
|
|
348
|
+
|
|
349
|
+
render(
|
|
350
|
+
<TestWrapper store={mockStore}>
|
|
351
|
+
<ForceUnlockSelectedModal
|
|
352
|
+
{...selectedProps}
|
|
353
|
+
setIsModalOpen={setIsModalOpen}
|
|
354
|
+
/>
|
|
355
|
+
</TestWrapper>
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
const cancelButton = screen.getByRole('button', { name: 'No' });
|
|
359
|
+
fireEvent.click(cancelButton);
|
|
360
|
+
|
|
361
|
+
expect(setIsModalOpen).toHaveBeenCalledWith(false);
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
describe('Accessibility', () => {
|
|
366
|
+
it('has proper ARIA attributes for all modals', () => {
|
|
367
|
+
const { rerender } = render(
|
|
368
|
+
<TestWrapper store={mockStore}>
|
|
369
|
+
<CancelModal {...defaultProps} />
|
|
370
|
+
</TestWrapper>
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
374
|
+
expect(screen.getByRole('button', { name: 'No' })).toBeInTheDocument();
|
|
375
|
+
expect(screen.getByRole('button', { name: 'Yes' })).toBeInTheDocument();
|
|
376
|
+
|
|
377
|
+
// Test other modals
|
|
378
|
+
rerender(
|
|
379
|
+
<TestWrapper store={mockStore}>
|
|
380
|
+
<ResumeModal {...defaultProps} />
|
|
381
|
+
</TestWrapper>
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
385
|
+
expect(screen.getByRole('button', { name: 'No' })).toBeInTheDocument();
|
|
386
|
+
expect(screen.getByRole('button', { name: 'Yes' })).toBeInTheDocument();
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
describe('Modal Visibility', () => {
|
|
391
|
+
it('handles modal visibility correctly for all components', () => {
|
|
392
|
+
const { rerender } = render(
|
|
393
|
+
<TestWrapper store={mockStore}>
|
|
394
|
+
<CancelModal {...defaultProps} isModalOpen={false} />
|
|
395
|
+
</TestWrapper>
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
399
|
+
|
|
400
|
+
rerender(
|
|
401
|
+
<TestWrapper store={mockStore}>
|
|
402
|
+
<ResumeModal {...defaultProps} isModalOpen={false} />
|
|
403
|
+
</TestWrapper>
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
});
|
data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/createBulkTaskModal.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { useSelector } from 'react-redux';
|
|
4
|
+
import { sprintf } from 'foremanReact/common/I18n';
|
|
5
|
+
import {
|
|
6
|
+
selectSelectedTasks,
|
|
7
|
+
selectSelectedRowsLen,
|
|
8
|
+
} from './ConfirmModalSelectors';
|
|
9
|
+
import { selectAllRowsSelected } from '../../TasksTableSelectors';
|
|
10
|
+
import { GenericConfirmModal } from './GenericConfirmModal';
|
|
11
|
+
|
|
12
|
+
export const createBulkTaskModal = ({
|
|
13
|
+
bulkActionBySearch,
|
|
14
|
+
bulkActionById,
|
|
15
|
+
title,
|
|
16
|
+
messageTemplate,
|
|
17
|
+
confirmButtonVariant = 'primary',
|
|
18
|
+
ouiaIdPrefix,
|
|
19
|
+
}) => {
|
|
20
|
+
const BulkTaskModal = ({
|
|
21
|
+
isModalOpen,
|
|
22
|
+
setIsModalOpen,
|
|
23
|
+
url,
|
|
24
|
+
uriQuery,
|
|
25
|
+
parentTaskID,
|
|
26
|
+
}) => {
|
|
27
|
+
const allRowsSelected = useSelector(selectAllRowsSelected);
|
|
28
|
+
const selectedTasks = useSelector(selectSelectedTasks);
|
|
29
|
+
const selectedRowsLen = useSelector(selectSelectedRowsLen);
|
|
30
|
+
|
|
31
|
+
const handleConfirm = () =>
|
|
32
|
+
allRowsSelected
|
|
33
|
+
? bulkActionBySearch({ query: uriQuery, parentTaskID })
|
|
34
|
+
: bulkActionById({
|
|
35
|
+
selected: selectedTasks,
|
|
36
|
+
url,
|
|
37
|
+
parentTaskID,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<GenericConfirmModal
|
|
42
|
+
isModalOpen={isModalOpen}
|
|
43
|
+
setIsModalOpen={setIsModalOpen}
|
|
44
|
+
title={title}
|
|
45
|
+
message={sprintf(messageTemplate, { number: selectedRowsLen })}
|
|
46
|
+
onConfirm={handleConfirm}
|
|
47
|
+
confirmButtonVariant={confirmButtonVariant}
|
|
48
|
+
ouiaIdPrefix={ouiaIdPrefix}
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
BulkTaskModal.propTypes = {
|
|
54
|
+
isModalOpen: PropTypes.bool.isRequired,
|
|
55
|
+
setIsModalOpen: PropTypes.func.isRequired,
|
|
56
|
+
url: PropTypes.string.isRequired,
|
|
57
|
+
uriQuery: PropTypes.object,
|
|
58
|
+
parentTaskID: PropTypes.string,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
BulkTaskModal.defaultProps = {
|
|
62
|
+
uriQuery: {},
|
|
63
|
+
parentTaskID: null,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return BulkTaskModal;
|
|
67
|
+
};
|