foreman-tasks 11.0.5 → 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/app/assets/javascripts/foreman-tasks/locale/de/foreman_tasks.js +5 -2
- data/app/assets/javascripts/foreman-tasks/locale/en/foreman_tasks.js +4 -1
- data/app/assets/javascripts/foreman-tasks/locale/es/foreman_tasks.js +5 -2
- data/app/assets/javascripts/foreman-tasks/locale/fr/foreman_tasks.js +11 -8
- data/app/assets/javascripts/foreman-tasks/locale/ja/foreman_tasks.js +12 -9
- data/app/assets/javascripts/foreman-tasks/locale/ka/foreman_tasks.js +5 -2
- data/app/assets/javascripts/foreman-tasks/locale/ko/foreman_tasks.js +167 -165
- data/app/assets/javascripts/foreman-tasks/locale/pt_BR/foreman_tasks.js +5 -2
- data/app/assets/javascripts/foreman-tasks/locale/ru/foreman_tasks.js +5 -2
- data/app/assets/javascripts/foreman-tasks/locale/zh_CN/foreman_tasks.js +11 -8
- data/app/assets/javascripts/foreman-tasks/locale/zh_TW/foreman_tasks.js +5 -2
- data/lib/foreman_tasks/dynflow/console_authorizer.rb +1 -3
- data/lib/foreman_tasks/version.rb +1 -1
- data/locale/Makefile +18 -7
- data/locale/de/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/de/foreman_tasks.po +5 -2
- data/locale/en/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/en/foreman_tasks.po +4 -1
- data/locale/es/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/es/foreman_tasks.po +5 -2
- data/locale/foreman_tasks.pot +10 -6
- data/locale/fr/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/fr/foreman_tasks.po +11 -8
- data/locale/ja/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/ja/foreman_tasks.po +12 -9
- data/locale/ka/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/ka/foreman_tasks.po +5 -2
- data/locale/ko/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/ko/foreman_tasks.po +167 -165
- data/locale/pt_BR/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/pt_BR/foreman_tasks.po +5 -2
- data/locale/ru/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/ru/foreman_tasks.po +5 -2
- data/locale/zh_CN/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/zh_CN/foreman_tasks.po +11 -8
- data/locale/zh_TW/LC_MESSAGES/foreman_tasks.mo +0 -0
- data/locale/zh_TW/foreman_tasks.po +5 -2
- 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/__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
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
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 { selectClicked } from './ConfirmModalSelectors';
|
|
6
|
+
import { GenericConfirmModal } from './GenericConfirmModal';
|
|
7
|
+
|
|
8
|
+
export const createTaskModal = ({
|
|
9
|
+
actionCreator,
|
|
10
|
+
title,
|
|
11
|
+
messageTemplate,
|
|
12
|
+
confirmButtonVariant = 'primary',
|
|
13
|
+
ouiaIdPrefix,
|
|
14
|
+
}) => {
|
|
15
|
+
const TaskModal = ({ isModalOpen, setIsModalOpen, url, parentTaskID }) => {
|
|
16
|
+
const { taskId, taskName } = useSelector(selectClicked);
|
|
17
|
+
|
|
18
|
+
const handleConfirm = () =>
|
|
19
|
+
actionCreator({
|
|
20
|
+
taskId,
|
|
21
|
+
taskName,
|
|
22
|
+
url,
|
|
23
|
+
parentTaskID,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<GenericConfirmModal
|
|
28
|
+
isModalOpen={isModalOpen}
|
|
29
|
+
setIsModalOpen={setIsModalOpen}
|
|
30
|
+
title={title}
|
|
31
|
+
message={sprintf(messageTemplate, { taskName })}
|
|
32
|
+
onConfirm={handleConfirm}
|
|
33
|
+
confirmButtonVariant={confirmButtonVariant}
|
|
34
|
+
ouiaIdPrefix={ouiaIdPrefix}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
TaskModal.propTypes = {
|
|
40
|
+
isModalOpen: PropTypes.bool.isRequired,
|
|
41
|
+
setIsModalOpen: PropTypes.func.isRequired,
|
|
42
|
+
url: PropTypes.string.isRequired,
|
|
43
|
+
parentTaskID: PropTypes.string,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
TaskModal.defaultProps = {
|
|
47
|
+
parentTaskID: null,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return TaskModal;
|
|
51
|
+
};
|
|
@@ -1,29 +1,79 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import reducer from './ConfirmModalReducer';
|
|
5
|
-
import tasksActions from './ConfirmModalActions';
|
|
1
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
|
2
|
+
import { createTaskModal } from './createTaskModal';
|
|
3
|
+
import { createBulkTaskModal } from './createBulkTaskModal';
|
|
6
4
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
cancelTask,
|
|
6
|
+
forceCancelTask,
|
|
7
|
+
resumeTask,
|
|
8
|
+
} from '../../TasksTableActions';
|
|
9
|
+
import {
|
|
10
|
+
bulkCancelBySearch,
|
|
11
|
+
bulkCancelById,
|
|
12
|
+
bulkForceCancelBySearch,
|
|
13
|
+
bulkForceCancelById,
|
|
14
|
+
bulkResumeBySearch,
|
|
15
|
+
bulkResumeById,
|
|
16
|
+
} from '../../TasksBulkActions';
|
|
17
|
+
|
|
18
|
+
export const CancelModal = createTaskModal({
|
|
19
|
+
actionCreator: cancelTask,
|
|
20
|
+
title: __('Cancel Task'),
|
|
21
|
+
messageTemplate: __(
|
|
22
|
+
'This will cancel task "%(taskName)s", putting it in the stopped state. Are you sure?'
|
|
23
|
+
),
|
|
24
|
+
confirmButtonVariant: 'primary',
|
|
25
|
+
ouiaIdPrefix: 'cancel',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const CancelSelectedModal = createBulkTaskModal({
|
|
29
|
+
bulkActionBySearch: bulkCancelBySearch,
|
|
30
|
+
bulkActionById: bulkCancelById,
|
|
31
|
+
title: __('Cancel Selected Tasks'),
|
|
32
|
+
messageTemplate: __(
|
|
33
|
+
'This will cancel %(number)s task(s), putting them in the stopped state. Are you sure?'
|
|
34
|
+
),
|
|
35
|
+
confirmButtonVariant: 'primary',
|
|
36
|
+
ouiaIdPrefix: 'cancel-selected',
|
|
37
|
+
});
|
|
14
38
|
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
39
|
+
export const ForceUnlockModal = createTaskModal({
|
|
40
|
+
actionCreator: forceCancelTask,
|
|
41
|
+
title: __('Force Unlock Task'),
|
|
42
|
+
messageTemplate: __(
|
|
43
|
+
'This will force unlock task "%(taskName)s". This may cause harm and should be used with caution. Are you sure?'
|
|
44
|
+
),
|
|
45
|
+
confirmButtonVariant: 'danger',
|
|
46
|
+
ouiaIdPrefix: 'force-unlock',
|
|
22
47
|
});
|
|
23
48
|
|
|
24
|
-
const
|
|
25
|
-
|
|
49
|
+
export const ForceUnlockSelectedModal = createBulkTaskModal({
|
|
50
|
+
bulkActionBySearch: bulkForceCancelBySearch,
|
|
51
|
+
bulkActionById: bulkForceCancelById,
|
|
52
|
+
title: __('Force Unlock Selected Tasks'),
|
|
53
|
+
messageTemplate: __(
|
|
54
|
+
'This will force unlock %(number)s task(s). This may cause harm and should be used with caution. Are you sure?'
|
|
55
|
+
),
|
|
56
|
+
confirmButtonVariant: 'danger',
|
|
57
|
+
ouiaIdPrefix: 'force-unlock-selected',
|
|
58
|
+
});
|
|
26
59
|
|
|
27
|
-
export const
|
|
60
|
+
export const ResumeModal = createTaskModal({
|
|
61
|
+
actionCreator: resumeTask,
|
|
62
|
+
title: __('Resume Task'),
|
|
63
|
+
messageTemplate: __(
|
|
64
|
+
'This will resume task "%(taskName)s", putting it in the running state. Are you sure?'
|
|
65
|
+
),
|
|
66
|
+
confirmButtonVariant: 'primary',
|
|
67
|
+
ouiaIdPrefix: 'resume',
|
|
68
|
+
});
|
|
28
69
|
|
|
29
|
-
export
|
|
70
|
+
export const ResumeSelectedModal = createBulkTaskModal({
|
|
71
|
+
bulkActionBySearch: bulkResumeBySearch,
|
|
72
|
+
bulkActionById: bulkResumeById,
|
|
73
|
+
title: __('Resume Selected Tasks'),
|
|
74
|
+
messageTemplate: __(
|
|
75
|
+
'This will resume %(number)s task(s), putting them in the running state. Are you sure?'
|
|
76
|
+
),
|
|
77
|
+
confirmButtonVariant: 'primary',
|
|
78
|
+
ouiaIdPrefix: 'resume-selected',
|
|
79
|
+
});
|
|
@@ -8,8 +8,11 @@ import Pagination from 'foremanReact/components/Pagination';
|
|
|
8
8
|
import { getURIQuery } from 'foremanReact/common/helpers';
|
|
9
9
|
import createTasksTableSchema from './TasksTableSchema';
|
|
10
10
|
import { updateURlQuery } from './TasksTableHelpers';
|
|
11
|
-
import {
|
|
12
|
-
|
|
11
|
+
import {
|
|
12
|
+
RESUME_MODAL,
|
|
13
|
+
CANCEL_MODAL,
|
|
14
|
+
FORCE_UNLOCK_MODAL,
|
|
15
|
+
} from './TasksTableConstants';
|
|
13
16
|
|
|
14
17
|
const TasksTable = ({
|
|
15
18
|
getTableItems,
|
|
@@ -16,7 +16,7 @@ export const CANCEL_MODAL = 'cancelConfirmModal';
|
|
|
16
16
|
export const RESUME_MODAL = 'resumeConfirmModal';
|
|
17
17
|
export const CANCEL_SELECTED_MODAL = 'cancelSelectedConfirmModal';
|
|
18
18
|
export const RESUME_SELECTED_MODAL = 'resumeSelectedConfirmModal';
|
|
19
|
-
export const
|
|
19
|
+
export const FORCE_UNLOCK_MODAL = 'forceUnlockConfirmModal';
|
|
20
20
|
export const FORCE_UNLOCK_SELECTED_MODAL = 'forceUnlockSelectedConfirmModal';
|
|
21
21
|
|
|
22
22
|
export const UPDATE_CLICKED = 'UPDATE_CLICKED';
|