foreman-tasks 1.1.3 → 1.2.0

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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/foreman_tasks/api/tasks_controller.rb +29 -1
  3. data/app/controllers/foreman_tasks/tasks_controller.rb +3 -11
  4. data/app/models/foreman_tasks/task.rb +4 -0
  5. data/app/models/setting/foreman_tasks.rb +1 -1
  6. data/app/services/ui_notifications/tasks/task_bulk_stop.rb +36 -0
  7. data/app/views/foreman_tasks/api/tasks/details.json.rabl +0 -1
  8. data/config/routes.rb +1 -0
  9. data/db/migrate/20200517215015_rename_bookmarks_controller.rb +35 -0
  10. data/db/migrate/20200519093217_drop_dynflow_allow_dangerous_actions_setting.foreman_tasks.rb +5 -0
  11. data/db/seeds.d/30-notification_blueprints.rb +7 -0
  12. data/lib/foreman_tasks/engine.rb +1 -1
  13. data/lib/foreman_tasks/tasks/cleanup.rake +2 -2
  14. data/lib/foreman_tasks/tasks/export_tasks.rake +1 -1
  15. data/lib/foreman_tasks/version.rb +1 -1
  16. data/locale/action_names.rb +1 -1
  17. data/locale/en/foreman_tasks.po +227 -41
  18. data/locale/foreman_tasks.pot +579 -288
  19. data/webpack/ForemanTasks/Components/TaskActions/TaskAction.test.js +60 -0
  20. data/webpack/ForemanTasks/Components/{TasksTable/TasksTableActionHelpers.js → TaskActions/TaskActionHelpers.js} +21 -6
  21. data/webpack/ForemanTasks/Components/{TasksTable/__tests__/TasksTableActionHelpers.test.js → TaskActions/TaskActionHelpers.test.js} +2 -2
  22. data/webpack/ForemanTasks/Components/TaskActions/TaskActionsConstants.js +16 -0
  23. data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.js +60 -0
  24. data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.test.js +14 -0
  25. data/webpack/ForemanTasks/Components/TaskActions/__snapshots__/TaskAction.test.js.snap +233 -0
  26. data/webpack/ForemanTasks/Components/TaskActions/__snapshots__/UnlockModals.test.js.snap +25 -0
  27. data/webpack/ForemanTasks/Components/TaskActions/index.js +115 -0
  28. data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +130 -152
  29. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +67 -3
  30. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskInfo.test.js +0 -1
  31. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +101 -70
  32. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +0 -15
  33. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsConstants.js +0 -5
  34. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsReducer.js +0 -6
  35. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +0 -9
  36. data/webpack/ForemanTasks/Components/TaskDetails/TasksDetailsHelper.js +6 -1
  37. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +5 -0
  38. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +2 -7
  39. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/integration.test.js +4 -0
  40. data/webpack/ForemanTasks/Components/TaskDetails/index.js +4 -8
  41. data/webpack/ForemanTasks/Components/TasksTable/Components/ActionSelectButton.js +14 -1
  42. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModal.js +83 -0
  43. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalActions.js +106 -0
  44. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalReducer.js +38 -0
  45. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalSelectors.js +45 -0
  46. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModal.test.js +36 -0
  47. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalActions.test.js +205 -0
  48. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalReducer.test.js +27 -0
  49. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalSelectors.test.js +54 -0
  50. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModal.test.js.snap +41 -0
  51. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalReducer.test.js.snap +19 -0
  52. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalSelectors.test.js.snap +30 -0
  53. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/index.js +29 -0
  54. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ActionSelectButton.test.js +1 -0
  55. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ActionSelectButton.test.js.snap +11 -0
  56. data/webpack/ForemanTasks/Components/TasksTable/TasksBulkActions.js +113 -30
  57. data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +13 -9
  58. data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +23 -63
  59. data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +10 -12
  60. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +24 -94
  61. data/webpack/ForemanTasks/Components/TasksTable/TasksTableSchema.js +2 -2
  62. data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +7 -4
  63. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksBulkActions.test.js +35 -0
  64. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +2 -12
  65. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActions.test.js +22 -26
  66. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +2 -14
  67. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksBulkActions.test.js.snap +107 -0
  68. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +2 -14
  69. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableActions.test.js.snap +17 -124
  70. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +24 -128
  71. data/webpack/ForemanTasks/Components/TasksTable/index.js +2 -2
  72. data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.js +47 -19
  73. data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.test.js +61 -14
  74. data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ActionButton.test.js.snap +80 -21
  75. data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.scss +9 -0
  76. data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.test.js +44 -0
  77. data/webpack/ForemanTasks/Components/common/ClickConfirmation/__snapshots__/ClickConfirmation.test.js.snap +52 -0
  78. data/webpack/ForemanTasks/Components/common/ClickConfirmation/index.js +59 -66
  79. data/webpack/ForemanTasks/Components/common/{ToastTypesConstants.js → ToastsHelpers/ToastTypesConstants.js} +0 -0
  80. data/webpack/ForemanTasks/Components/common/ToastsHelpers/index.js +15 -0
  81. data/webpack/ForemanTasks/ForemanTasksReducers.js +2 -0
  82. data/webpack/ForemanTasks/Routes/ForemanTasksRoutes.test.js +2 -1
  83. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js +2 -2
  84. data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +17 -3
  85. data/webpack/__mocks__/foremanReact/components/common/ActionButtons/ActionButtons.js +3 -0
  86. metadata +32 -22
  87. data/db/migrate/20200611090846_add_task_lock_index_on_resource_type_and_task_id.rb +0 -9
  88. data/lib/foreman_tasks/tasks/dynflow.rake +0 -6
  89. data/webpack/ForemanTasks/Components/TasksTable/Components/CancelConfirm.js +0 -53
  90. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmationModals.js +0 -56
  91. data/webpack/ForemanTasks/Components/TasksTable/Components/ResumeConfirm.js +0 -52
  92. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/CancelConfirm.test.js +0 -26
  93. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ConfirmationModals.test.js +0 -24
  94. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ResumeConfirm.test.js +0 -26
  95. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/CancelConfirm.test.js.snap +0 -65
  96. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ConfirmationModals.test.js.snap +0 -30
  97. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ResumeConfirm.test.js.snap +0 -63
  98. data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.js +0 -23
  99. data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.test.js +0 -26
  100. data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.js +0 -23
  101. data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.test.js +0 -27
  102. data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/CancelButton.test.js.snap +0 -15
  103. data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ResumeButton.test.js.snap +0 -15
@@ -0,0 +1,205 @@
1
+ import taskActions from '../ConfirmModalActions';
2
+ import {
3
+ CANCEL_MODAL,
4
+ RESUME_MODAL,
5
+ CANCEL_SELECTED_MODAL,
6
+ RESUME_SELECTED_MODAL,
7
+ FORCE_UNLOCK_SELECTED_MODAL,
8
+ } from '../../../TasksTableConstants';
9
+
10
+ import { FORCE_UNLOCK_MODAL } from '../../../../TaskActions/TaskActionsConstants';
11
+
12
+ import {
13
+ resumeTask,
14
+ cancelTask,
15
+ forceCancelTask,
16
+ } from '../../../TasksTableActions';
17
+ import {
18
+ bulkCancelBySearch,
19
+ bulkCancelById,
20
+ bulkResumeBySearch,
21
+ bulkResumeById,
22
+ bulkForceCancelBySearch,
23
+ bulkForceCancelById,
24
+ } from '../../../TasksBulkActions';
25
+
26
+ jest.mock('../../../TasksBulkActions');
27
+ jest.mock('../../../TasksTableActions');
28
+
29
+ const bulkCancelBySearchMock = 'bulkCancelBySearchMock';
30
+ const bulkCancelByIdMock = 'bulkCancelByIdMock';
31
+ const bulkResumeBySearchMock = 'bulkResumeBySearchMock';
32
+ const bulkResumeByIdMock = 'bulkResumeByIdMock';
33
+ const bulkForceCancelBySearchMock = 'bulkForceCancelBySearchMock';
34
+ const bulkForceCancelByIdMock = 'bulkForceCancelByIdMock';
35
+ const resumeTaskMock = 'resumeTaskMock';
36
+ const cancelTaskMock = 'cancelTaskMock';
37
+ const forceCancelTaskMock = 'forceCancelTaskMock';
38
+
39
+ bulkCancelBySearch.mockImplementation(() => bulkCancelBySearchMock);
40
+ bulkCancelById.mockImplementation(() => bulkCancelByIdMock);
41
+ bulkResumeBySearch.mockImplementation(() => bulkResumeBySearchMock);
42
+ bulkResumeById.mockImplementation(() => bulkResumeByIdMock);
43
+ bulkForceCancelBySearch.mockImplementation(() => bulkForceCancelBySearchMock);
44
+ bulkForceCancelById.mockImplementation(() => bulkForceCancelByIdMock);
45
+ resumeTask.mockImplementation(() => resumeTaskMock);
46
+ cancelTask.mockImplementation(() => cancelTaskMock);
47
+ forceCancelTask.mockImplementation(() => forceCancelTaskMock);
48
+
49
+ const url = 'some-url';
50
+ const query = 'some-query';
51
+ const parentTaskID = 'some-parentTaskID';
52
+
53
+ const runWithGetState = (state, action, dispatch, ...params) => {
54
+ const getState = () => state;
55
+ action(...params)(dispatch, getState);
56
+ };
57
+
58
+ const clickedState = {
59
+ foremanTasks: {
60
+ tasksTable: {
61
+ tasksTableQuery: {
62
+ clicked: { taskId: 'some-id', taskName: 'some-name' },
63
+ },
64
+ },
65
+ },
66
+ };
67
+
68
+ const selectedState = {
69
+ foremanTasks: {
70
+ tasksTable: {
71
+ tasksTableQuery: {
72
+ allRowsSelected: false,
73
+ selectedRows: [1, 2, 3],
74
+ },
75
+ tasksTableContent: {
76
+ results: [
77
+ {
78
+ id: 1,
79
+ action: 'action1',
80
+ available_actions: { cancellable: true },
81
+ },
82
+ {
83
+ id: 2,
84
+ action: 'action2',
85
+ available_actions: { resumable: true },
86
+ },
87
+ ],
88
+ },
89
+ },
90
+ },
91
+ };
92
+ const allRowsState = {
93
+ foremanTasks: {
94
+ tasksTable: {
95
+ tasksTableQuery: {
96
+ allRowsSelected: true,
97
+ },
98
+ },
99
+ },
100
+ };
101
+ describe('ConfirmModalActions', () => {
102
+ const dispatch = jest.fn();
103
+
104
+ beforeEach(() => dispatch.mockClear());
105
+ it('run CANCEL_MODAL', () => {
106
+ runWithGetState(clickedState, taskActions[CANCEL_MODAL], dispatch, {
107
+ url,
108
+ parentTaskID,
109
+ });
110
+ expect(dispatch).toBeCalledWith(cancelTaskMock);
111
+ });
112
+ it('run RESUME_MODAL', () => {
113
+ runWithGetState(clickedState, taskActions[RESUME_MODAL], dispatch, {
114
+ url,
115
+ parentTaskID,
116
+ });
117
+ expect(dispatch).toBeCalledWith(resumeTaskMock);
118
+ });
119
+ it('run FORCE_UNLOCK_MODAL', () => {
120
+ runWithGetState(clickedState, taskActions[FORCE_UNLOCK_MODAL], dispatch, {
121
+ url,
122
+ parentTaskID,
123
+ });
124
+ expect(dispatch).toBeCalledWith(forceCancelTaskMock);
125
+ });
126
+ it('run CANCEL_SELECTED_MODAL by id', () => {
127
+ runWithGetState(
128
+ selectedState,
129
+ taskActions[CANCEL_SELECTED_MODAL],
130
+ dispatch,
131
+ {
132
+ url,
133
+ query,
134
+ parentTaskID,
135
+ }
136
+ );
137
+ expect(dispatch).toBeCalledWith(bulkCancelByIdMock);
138
+ });
139
+
140
+ it('run CANCEL_SELECTED_MODAL by search', () => {
141
+ runWithGetState(
142
+ allRowsState,
143
+ taskActions[CANCEL_SELECTED_MODAL],
144
+ dispatch,
145
+ {
146
+ url,
147
+ query,
148
+ parentTaskID,
149
+ }
150
+ );
151
+ expect(dispatch).toBeCalledWith(bulkCancelBySearchMock);
152
+ });
153
+ it('run RESUME_SELECTED_MODAL by id', () => {
154
+ runWithGetState(
155
+ selectedState,
156
+ taskActions[RESUME_SELECTED_MODAL],
157
+ dispatch,
158
+ {
159
+ url,
160
+ query,
161
+ parentTaskID,
162
+ }
163
+ );
164
+ expect(dispatch).toBeCalledWith(bulkResumeByIdMock);
165
+ });
166
+ it('run RESUME_SELECTED_MODAL by search', () => {
167
+ runWithGetState(
168
+ allRowsState,
169
+ taskActions[RESUME_SELECTED_MODAL],
170
+ dispatch,
171
+ {
172
+ url,
173
+ query,
174
+ parentTaskID,
175
+ }
176
+ );
177
+ expect(dispatch).toBeCalledWith(bulkResumeBySearchMock);
178
+ });
179
+ it('run FORCE_UNLOCK_SELECTED_MODAL by id', () => {
180
+ runWithGetState(
181
+ selectedState,
182
+ taskActions[FORCE_UNLOCK_SELECTED_MODAL],
183
+ dispatch,
184
+ {
185
+ url,
186
+ query,
187
+ parentTaskID,
188
+ }
189
+ );
190
+ expect(dispatch).toBeCalledWith(bulkForceCancelByIdMock);
191
+ });
192
+ it('run FORCE_UNLOCK_SELECTED_MODAL by search', () => {
193
+ runWithGetState(
194
+ allRowsState,
195
+ taskActions[FORCE_UNLOCK_SELECTED_MODAL],
196
+ dispatch,
197
+ {
198
+ url,
199
+ query,
200
+ parentTaskID,
201
+ }
202
+ );
203
+ expect(dispatch).toBeCalledWith(bulkForceCancelBySearchMock);
204
+ });
205
+ });
@@ -0,0 +1,27 @@
1
+ import { testReducerSnapshotWithFixtures } from '@theforeman/test';
2
+ import {
3
+ UPDATE_MODAL,
4
+ CANCEL_MODAL,
5
+ RESUME_SELECTED_MODAL,
6
+ } from '../../../TasksTableConstants';
7
+
8
+ import reducer from '../ConfirmModalReducer';
9
+
10
+ const fixtures = {
11
+ 'should return the initial state': {},
12
+ 'should handle UPDATE_MODAL to cancel': {
13
+ action: {
14
+ type: UPDATE_MODAL,
15
+ payload: { modalID: CANCEL_MODAL },
16
+ },
17
+ },
18
+ 'should handle UPDATE_MODAL to resume': {
19
+ action: {
20
+ type: UPDATE_MODAL,
21
+ payload: { modalID: RESUME_SELECTED_MODAL },
22
+ },
23
+ },
24
+ };
25
+
26
+ describe('ConfirmModalReducer reducer', () =>
27
+ testReducerSnapshotWithFixtures(reducer, fixtures));
@@ -0,0 +1,54 @@
1
+ import { testSelectorsSnapshotWithFixtures } from '@theforeman/test';
2
+ import {
3
+ selectActionText,
4
+ selectActionState,
5
+ selectActionType,
6
+ selectSelectedTasks,
7
+ selectSelectedRowsLen,
8
+ } from '../ConfirmModalSelectors';
9
+ import { CANCEL_MODAL } from '../../../TasksTableConstants';
10
+
11
+ const state = {
12
+ foremanTasks: {
13
+ confirmModal: {
14
+ actionText: 'some-text',
15
+ actionState: 'some-state',
16
+ actionType: 'some-type',
17
+ },
18
+ tasksTable: {
19
+ tasksTableContent: {
20
+ results: [
21
+ {
22
+ id: 1,
23
+ action: 'action1',
24
+ available_actions: { cancellable: true },
25
+ },
26
+ { id: 2, action: 'action2', available_actions: { resumable: true } },
27
+ ],
28
+ itemCount: 10,
29
+ },
30
+ tasksTableQuery: { selectedRows: [1, 2, 3] },
31
+ },
32
+ },
33
+ };
34
+
35
+ const fixtures = {
36
+ 'should select actionText': () => selectActionText(state),
37
+ 'should select actionState': () => selectActionState(state),
38
+ 'should select actionType': () => selectActionType(state),
39
+ 'should select selectedTasks': () => selectSelectedTasks(state),
40
+ 'should select selectedRowsLen 1': () =>
41
+ selectSelectedRowsLen({
42
+ ...state,
43
+ foremanTasks: { confirmModal: { actionType: CANCEL_MODAL } },
44
+ }),
45
+ 'should select selectedRowsLen all': () => selectSelectedRowsLen(state),
46
+ 'should select selectedRowsLen some': () =>
47
+ selectSelectedRowsLen({
48
+ ...state,
49
+ tasksTable: { tasksTableQuery: { allRowsSelected: true } },
50
+ }),
51
+ };
52
+
53
+ describe('TasksDashboard - Selectors', () =>
54
+ testSelectorsSnapshotWithFixtures(fixtures));
@@ -0,0 +1,41 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`ConfirmModal renders ConfirmModal 1`] = `
4
+ <ForemanModal
5
+ id="modalID"
6
+ title="Some Text Selected Tasks"
7
+ >
8
+ This will some text 1 task(s), putting them in the some state state. Are you sure?
9
+ <Component>
10
+ <Button
11
+ active={false}
12
+ block={false}
13
+ bsClass="btn"
14
+ bsStyle="default"
15
+ disabled={false}
16
+ onClick={[MockFunction]}
17
+ >
18
+ No
19
+ </Button>
20
+ <Button
21
+ active={false}
22
+ block={false}
23
+ bsClass="btn"
24
+ bsStyle="primary"
25
+ className="confirm-button"
26
+ disabled={false}
27
+ onClick={[Function]}
28
+ >
29
+ Yes
30
+ </Button>
31
+ </Component>
32
+ </ForemanModal>
33
+ `;
34
+
35
+ exports[`ConfirmModal renders ConfirmModal for unlock 1`] = `
36
+ <ForceUnlockModal
37
+ id="modalID"
38
+ onClick={[Function]}
39
+ selectedRowsLen={1}
40
+ />
41
+ `;
@@ -0,0 +1,19 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`ConfirmModalReducer reducer should handle UPDATE_MODAL to cancel 1`] = `
4
+ Object {
5
+ "actionState": "stopped",
6
+ "actionText": "cancel",
7
+ "actionType": "cancelConfirmModal",
8
+ }
9
+ `;
10
+
11
+ exports[`ConfirmModalReducer reducer should handle UPDATE_MODAL to resume 1`] = `
12
+ Object {
13
+ "actionState": "running",
14
+ "actionText": "resume",
15
+ "actionType": "resumeSelectedConfirmModal",
16
+ }
17
+ `;
18
+
19
+ exports[`ConfirmModalReducer reducer should return the initial state 1`] = `Object {}`;
@@ -0,0 +1,30 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`TasksDashboard - Selectors should select actionState 1`] = `"some-state"`;
4
+
5
+ exports[`TasksDashboard - Selectors should select actionText 1`] = `"some-text"`;
6
+
7
+ exports[`TasksDashboard - Selectors should select actionType 1`] = `"some-type"`;
8
+
9
+ exports[`TasksDashboard - Selectors should select selectedRowsLen 1 1`] = `1`;
10
+
11
+ exports[`TasksDashboard - Selectors should select selectedRowsLen all 1`] = `3`;
12
+
13
+ exports[`TasksDashboard - Selectors should select selectedRowsLen some 1`] = `3`;
14
+
15
+ exports[`TasksDashboard - Selectors should select selectedTasks 1`] = `
16
+ Array [
17
+ Object {
18
+ "id": 1,
19
+ "isCancellable": true,
20
+ "isResumable": undefined,
21
+ "name": "action1",
22
+ },
23
+ Object {
24
+ "id": 2,
25
+ "isCancellable": undefined,
26
+ "isResumable": true,
27
+ "name": "action2",
28
+ },
29
+ ]
30
+ `;
@@ -0,0 +1,29 @@
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';
6
+ import {
7
+ selectActionText,
8
+ selectActionState,
9
+ selectActionType,
10
+ selectClicked,
11
+ selectSelectedRowsLen,
12
+ } from './ConfirmModalSelectors';
13
+ import { selectAllRowsSelected } from '../../TasksTableSelectors';
14
+
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),
22
+ });
23
+
24
+ const mapDispatchToProps = dispatch =>
25
+ bindActionCreators(tasksActions, dispatch);
26
+
27
+ export const reducers = { confirmModal: reducer };
28
+
29
+ export default connect(mapStateToProps, mapDispatchToProps)(ConfirmModal);
@@ -6,6 +6,7 @@ const fixtures = {
6
6
  'renders with minimal props': {
7
7
  onCancel: jest.fn(),
8
8
  onResume: jest.fn(),
9
+ onForceCancel: jest.fn(),
9
10
  },
10
11
  };
11
12
 
@@ -28,5 +28,16 @@ exports[`ActionSelectButton renders with minimal props 1`] = `
28
28
  >
29
29
  Resume Selected
30
30
  </MenuItem>
31
+ <MenuItem
32
+ bsClass="dropdown"
33
+ disabled={false}
34
+ divider={false}
35
+ eventKey="3"
36
+ header={false}
37
+ onClick={[MockFunction]}
38
+ title="Force Cancel selected tasks"
39
+ >
40
+ Force Cancel Selected
41
+ </MenuItem>
31
42
  </DropdownButton>
32
43
  `;
@@ -1,7 +1,11 @@
1
1
  import API from 'foremanReact/API';
2
2
  import { addToast } from 'foremanReact/redux/actions/toasts';
3
- import { translate as __ } from 'foremanReact/common/I18n';
4
- import { TOAST_TYPES } from '../common/ToastTypesConstants';
3
+ import { translate as __, sprintf } from 'foremanReact/common/I18n';
4
+ import {
5
+ BULK_CANCEL_PATH,
6
+ BULK_RESUME_PATH,
7
+ BULK_FORCE_CANCEL_PATH,
8
+ } from './TasksTableConstants';
5
9
  import {
6
10
  TASKS_RESUME_REQUEST,
7
11
  TASKS_RESUME_SUCCESS,
@@ -9,16 +13,23 @@ import {
9
13
  TASKS_CANCEL_REQUEST,
10
14
  TASKS_CANCEL_SUCCESS,
11
15
  TASKS_CANCEL_FAILURE,
12
- BULK_CANCEL_PATH,
13
- BULK_RESUME_PATH,
14
- } from './TasksTableConstants';
16
+ TASKS_FORCE_CANCEL_REQUEST,
17
+ TASKS_FORCE_CANCEL_SUCCESS,
18
+ TASKS_FORCE_CANCEL_FAILURE,
19
+ } from '../TaskActions/TaskActionsConstants';
15
20
  import { reloadPage } from './TasksTableActions';
16
21
  import {
17
22
  convertDashboardQuery,
18
23
  resumeToastInfo,
19
24
  cancelToastInfo,
20
25
  toastDispatch,
21
- } from './TasksTableActionHelpers';
26
+ } from '../TaskActions/TaskActionHelpers';
27
+ import {
28
+ successToastData,
29
+ errorToastData,
30
+ warningToastData,
31
+ infoToastData,
32
+ } from '../common/ToastsHelpers';
22
33
 
23
34
  export const bulkByIdRequest = (resumeTasks, path) => {
24
35
  const ids = resumeTasks.map(task => task.id);
@@ -41,10 +52,9 @@ export const bulkBySearchRequest = ({ query, parentTaskID, path }) => {
41
52
  const handleErrorResume = (error, dispatch) => {
42
53
  dispatch({ type: TASKS_RESUME_FAILURE, error });
43
54
  dispatch(
44
- addToast({
45
- type: TOAST_TYPES.ERROR,
46
- message: `${__(`Cannot resume tasks at the moment`)} ${error}`,
47
- })
55
+ addToast(
56
+ errorToastData(`${__(`Cannot resume tasks at the moment`)} ${error}`)
57
+ )
48
58
  );
49
59
  };
50
60
 
@@ -56,10 +66,9 @@ export const bulkResumeById = ({
56
66
  const resumeTasks = selected.filter(task => task.isResumable);
57
67
  if (resumeTasks.length < selected.length)
58
68
  dispatch(
59
- addToast({
60
- type: TOAST_TYPES.WARNING,
61
- message: __('Not all the selected tasks can be resumed'),
62
- })
69
+ addToast(
70
+ warningToastData(__('Not all the selected tasks can be resumed'))
71
+ )
63
72
  );
64
73
  if (resumeTasks.length) {
65
74
  dispatch({ type: TASKS_RESUME_REQUEST });
@@ -92,10 +101,9 @@ export const bulkResumeBySearch = ({
92
101
  }) => async dispatch => {
93
102
  dispatch({ type: TASKS_RESUME_REQUEST });
94
103
  dispatch(
95
- addToast({
96
- type: 'info',
97
- message: __('Resuming selected tasks, this might take a while'),
98
- })
104
+ addToast(
105
+ infoToastData(__('Resuming selected tasks, this might take a while'))
106
+ )
99
107
  );
100
108
  await bulkBySearchRequest({ query, path: BULK_RESUME_PATH, parentTaskID });
101
109
  };
@@ -103,10 +111,9 @@ export const bulkResumeBySearch = ({
103
111
  const handleErrorCancel = (error, dispatch) => {
104
112
  dispatch({ type: TASKS_CANCEL_FAILURE, error });
105
113
  dispatch(
106
- addToast({
107
- type: TOAST_TYPES.ERROR,
108
- message: `${__(`Cannot cancel tasks at the moment`)} ${error}`,
109
- })
114
+ addToast(
115
+ errorToastData(`${__(`Cannot cancel tasks at the moment`)} ${error}`)
116
+ )
110
117
  );
111
118
  };
112
119
 
@@ -116,10 +123,9 @@ export const bulkCancelBySearch = ({
116
123
  }) => async dispatch => {
117
124
  dispatch({ type: TASKS_CANCEL_REQUEST });
118
125
  dispatch(
119
- addToast({
120
- type: 'info',
121
- message: __('Canceling selected tasks, this might take a while'),
122
- })
126
+ addToast(
127
+ infoToastData(__('Canceling selected tasks, this might take a while'))
128
+ )
123
129
  );
124
130
  await bulkBySearchRequest({ query, path: BULK_CANCEL_PATH, parentTaskID });
125
131
  };
@@ -132,10 +138,9 @@ export const bulkCancelById = ({
132
138
  const cancelTasks = selected.filter(task => task.isCancellable);
133
139
  if (cancelTasks.length < selected.length)
134
140
  dispatch(
135
- addToast({
136
- type: TOAST_TYPES.WARNING,
137
- message: __('Not all the selected tasks can be cancelled'),
138
- })
141
+ addToast(
142
+ warningToastData(__('Not all the selected tasks can be cancelled'))
143
+ )
139
144
  );
140
145
  if (cancelTasks.length) {
141
146
  dispatch({ type: TASKS_CANCEL_REQUEST });
@@ -162,3 +167,81 @@ export const bulkCancelById = ({
162
167
  }
163
168
  }
164
169
  };
170
+
171
+ const handleErrorForceCancel = (error, dispatch) => {
172
+ dispatch({ type: TASKS_FORCE_CANCEL_FAILURE, error });
173
+ dispatch(
174
+ addToast(
175
+ errorToastData(
176
+ `${__(`Cannot force cancel tasks at the moment`)} ${error}`
177
+ )
178
+ )
179
+ );
180
+ };
181
+
182
+ export const bulkForceCancelById = ({
183
+ selected,
184
+ url,
185
+ parentTaskID,
186
+ }) => async dispatch => {
187
+ const stopTasks = selected.filter(task => task.state !== 'stopped');
188
+ if (stopTasks.length < selected.length)
189
+ dispatch(
190
+ addToast(
191
+ warningToastData(
192
+ sprintf(
193
+ '%s task(s) are already stopped',
194
+ selected.length - stopTasks.length
195
+ )
196
+ )
197
+ )
198
+ );
199
+ if (stopTasks.length > 0) {
200
+ dispatch({ type: TASKS_FORCE_CANCEL_REQUEST });
201
+ try {
202
+ const { data } = await bulkByIdRequest(stopTasks, BULK_FORCE_CANCEL_PATH);
203
+ dispatch({ type: TASKS_FORCE_CANCEL_SUCCESS });
204
+ if (data.stopped_length) {
205
+ dispatch(
206
+ addToast(
207
+ successToastData(
208
+ sprintf('%s task(s) cancelled with force', data.stopped_length)
209
+ )
210
+ )
211
+ );
212
+ }
213
+ if (data.skipped_length > 0)
214
+ dispatch(
215
+ addToast(
216
+ warningToastData(
217
+ sprintf('%s task(s) are already stopped', data.skipped_length)
218
+ )
219
+ )
220
+ );
221
+ if (data.stopped_length > 0) {
222
+ reloadPage(url, parentTaskID, dispatch);
223
+ }
224
+ } catch (error) {
225
+ handleErrorForceCancel(error, dispatch);
226
+ }
227
+ }
228
+ };
229
+
230
+ export const bulkForceCancelBySearch = ({
231
+ query,
232
+ parentTaskID,
233
+ }) => async dispatch => {
234
+ dispatch({ type: TASKS_FORCE_CANCEL_REQUEST });
235
+ dispatch(
236
+ addToast(
237
+ infoToastData(
238
+ __('Canceling with force selected tasks, this might take a while')
239
+ )
240
+ )
241
+ );
242
+ await bulkBySearchRequest({
243
+ query,
244
+ path: BULK_FORCE_CANCEL_PATH,
245
+ parentTaskID,
246
+ });
247
+ };