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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman-tasks/locale/de/foreman_tasks.js +5 -2
  3. data/app/assets/javascripts/foreman-tasks/locale/en/foreman_tasks.js +4 -1
  4. data/app/assets/javascripts/foreman-tasks/locale/es/foreman_tasks.js +5 -2
  5. data/app/assets/javascripts/foreman-tasks/locale/fr/foreman_tasks.js +11 -8
  6. data/app/assets/javascripts/foreman-tasks/locale/ja/foreman_tasks.js +12 -9
  7. data/app/assets/javascripts/foreman-tasks/locale/ka/foreman_tasks.js +5 -2
  8. data/app/assets/javascripts/foreman-tasks/locale/ko/foreman_tasks.js +167 -165
  9. data/app/assets/javascripts/foreman-tasks/locale/pt_BR/foreman_tasks.js +5 -2
  10. data/app/assets/javascripts/foreman-tasks/locale/ru/foreman_tasks.js +5 -2
  11. data/app/assets/javascripts/foreman-tasks/locale/zh_CN/foreman_tasks.js +11 -8
  12. data/app/assets/javascripts/foreman-tasks/locale/zh_TW/foreman_tasks.js +5 -2
  13. data/lib/foreman_tasks/dynflow/console_authorizer.rb +1 -3
  14. data/lib/foreman_tasks/version.rb +1 -1
  15. data/locale/Makefile +18 -7
  16. data/locale/de/LC_MESSAGES/foreman_tasks.mo +0 -0
  17. data/locale/de/foreman_tasks.po +5 -2
  18. data/locale/en/LC_MESSAGES/foreman_tasks.mo +0 -0
  19. data/locale/en/foreman_tasks.po +4 -1
  20. data/locale/es/LC_MESSAGES/foreman_tasks.mo +0 -0
  21. data/locale/es/foreman_tasks.po +5 -2
  22. data/locale/foreman_tasks.pot +10 -6
  23. data/locale/fr/LC_MESSAGES/foreman_tasks.mo +0 -0
  24. data/locale/fr/foreman_tasks.po +11 -8
  25. data/locale/ja/LC_MESSAGES/foreman_tasks.mo +0 -0
  26. data/locale/ja/foreman_tasks.po +12 -9
  27. data/locale/ka/LC_MESSAGES/foreman_tasks.mo +0 -0
  28. data/locale/ka/foreman_tasks.po +5 -2
  29. data/locale/ko/LC_MESSAGES/foreman_tasks.mo +0 -0
  30. data/locale/ko/foreman_tasks.po +167 -165
  31. data/locale/pt_BR/LC_MESSAGES/foreman_tasks.mo +0 -0
  32. data/locale/pt_BR/foreman_tasks.po +5 -2
  33. data/locale/ru/LC_MESSAGES/foreman_tasks.mo +0 -0
  34. data/locale/ru/foreman_tasks.po +5 -2
  35. data/locale/zh_CN/LC_MESSAGES/foreman_tasks.mo +0 -0
  36. data/locale/zh_CN/foreman_tasks.po +11 -8
  37. data/locale/zh_TW/LC_MESSAGES/foreman_tasks.mo +0 -0
  38. data/locale/zh_TW/foreman_tasks.po +5 -2
  39. data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +37 -9
  40. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskButtons.js +19 -16
  41. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskButtons.test.js +197 -71
  42. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +24 -40
  43. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +2 -16
  44. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalSelectors.js +0 -16
  45. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/GenericConfirmModal.js +70 -0
  46. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalSelectors.test.js +25 -14
  47. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalSelectors.test.js.snap +8 -7
  48. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/index.test.js +409 -0
  49. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/createBulkTaskModal.js +67 -0
  50. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/createTaskModal.js +51 -0
  51. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/index.js +73 -23
  52. data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +5 -2
  53. data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +1 -1
  54. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +67 -11
  55. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +86 -6
  56. data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.test.js +225 -39
  57. data/webpack/ForemanTasks/Components/common/ClickConfirmation/index.js +136 -37
  58. metadata +6 -19
  59. data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.js +0 -60
  60. data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.test.js +0 -14
  61. data/webpack/ForemanTasks/Components/TaskActions/__snapshots__/UnlockModals.test.js.snap +0 -25
  62. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskButtons.test.js.snap +0 -212
  63. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModal.js +0 -83
  64. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalActions.js +0 -106
  65. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalReducer.js +0 -38
  66. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModal.test.js +0 -36
  67. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalActions.test.js +0 -205
  68. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalReducer.test.js +0 -27
  69. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModal.test.js.snap +0 -41
  70. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalReducer.test.js.snap +0 -19
  71. data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.scss +0 -9
  72. data/webpack/ForemanTasks/Components/common/ClickConfirmation/__snapshots__/ClickConfirmation.test.js.snap +0 -52
  73. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +0 -2
  74. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js +0 -10
  75. data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +0 -18
@@ -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
+ });
@@ -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 { connect } from 'react-redux';
2
- import { bindActionCreators } from 'redux';
3
- import { ConfirmModal } from './ConfirmModal';
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
- selectActionText,
8
- selectActionState,
9
- selectActionType,
10
- selectClicked,
11
- selectSelectedRowsLen,
12
- } from './ConfirmModalSelectors';
13
- import { selectAllRowsSelected } from '../../TasksTableSelectors';
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 mapStateToProps = state => ({
16
- actionText: selectActionText(state),
17
- actionType: selectActionType(state),
18
- actionState: selectActionState(state),
19
- allRowsSelected: selectAllRowsSelected(state),
20
- clicked: selectClicked(state),
21
- selectedRowsLen: selectSelectedRowsLen(state),
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 mapDispatchToProps = dispatch =>
25
- bindActionCreators(tasksActions, dispatch);
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 reducers = { confirmModal: reducer };
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 default connect(mapStateToProps, mapDispatchToProps)(ConfirmModal);
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 { RESUME_MODAL, CANCEL_MODAL } from './TasksTableConstants';
12
- import { FORCE_UNLOCK_MODAL } from '../TaskActions/TaskActionsConstants';
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 CONFIRM_MODAL = 'ConfirmModal';
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';