foreman-tasks 1.1.3 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/js_tests.yml +27 -0
  3. data/.github/workflows/ruby_tests.yml +74 -0
  4. data/.rubocop.yml +12 -4
  5. data/.rubocop_todo.yml +32 -25
  6. data/Gemfile +5 -0
  7. data/README.md +2 -0
  8. data/app/controllers/foreman_tasks/api/tasks_controller.rb +63 -58
  9. data/app/controllers/foreman_tasks/concerns/parameters/triggering.rb +1 -1
  10. data/app/controllers/foreman_tasks/recurring_logics_controller.rb +7 -0
  11. data/app/controllers/foreman_tasks/tasks_controller.rb +9 -14
  12. data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +3 -3
  13. data/app/lib/actions/proxy_action.rb +1 -1
  14. data/app/models/foreman_tasks/recurring_logic.rb +1 -1
  15. data/app/models/foreman_tasks/task.rb +15 -0
  16. data/app/models/foreman_tasks/task/dynflow_task.rb +29 -33
  17. data/app/models/foreman_tasks/task/status_explicator.rb +1 -1
  18. data/app/models/foreman_tasks/triggering.rb +1 -1
  19. data/app/models/setting/foreman_tasks.rb +2 -2
  20. data/app/services/ui_notifications/tasks/task_bulk_stop.rb +36 -0
  21. data/app/views/foreman_tasks/api/tasks/details.json.rabl +0 -1
  22. data/app/views/foreman_tasks/api/tasks/index.json.rabl +2 -0
  23. data/app/views/foreman_tasks/api/tasks/show.json.rabl +2 -0
  24. data/app/views/foreman_tasks/recurring_logics/index.html.erb +3 -1
  25. data/config/routes.rb +3 -1
  26. data/db/migrate/20200517215015_rename_bookmarks_controller.rb +35 -0
  27. data/db/migrate/20200519093217_drop_dynflow_allow_dangerous_actions_setting.foreman_tasks.rb +5 -0
  28. data/db/migrate/20200611090846_add_task_lock_index_on_resource_type_and_task_id.rb +1 -1
  29. data/db/seeds.d/30-notification_blueprints.rb +14 -7
  30. data/db/seeds.d/61-foreman_tasks_bookmarks.rb +1 -1
  31. data/lib/foreman_tasks/cleaner.rb +4 -6
  32. data/lib/foreman_tasks/dynflow/configuration.rb +1 -1
  33. data/lib/foreman_tasks/dynflow/persistence.rb +4 -6
  34. data/lib/foreman_tasks/engine.rb +3 -8
  35. data/lib/foreman_tasks/version.rb +1 -1
  36. data/locale/action_names.rb +1 -1
  37. data/locale/en/LC_MESSAGES/foreman_tasks.mo +0 -0
  38. data/locale/en/foreman_tasks.po +270 -54
  39. data/locale/foreman_tasks.pot +630 -292
  40. data/locale/fr/LC_MESSAGES/foreman_tasks.mo +0 -0
  41. data/locale/fr/foreman_tasks.po +817 -0
  42. data/locale/ja/LC_MESSAGES/foreman_tasks.mo +0 -0
  43. data/locale/ja/foreman_tasks.po +817 -0
  44. data/locale/zh_CN/LC_MESSAGES/foreman_tasks.mo +0 -0
  45. data/locale/zh_CN/foreman_tasks.po +816 -0
  46. data/package.json +1 -1
  47. data/script/npm_link_foreman_js.sh +26 -0
  48. data/test/controllers/api/recurring_logics_controller_test.rb +1 -1
  49. data/test/controllers/api/tasks_controller_test.rb +7 -7
  50. data/test/controllers/tasks_controller_test.rb +6 -6
  51. data/test/core/unit/runner_test.rb +20 -20
  52. data/test/core/unit/task_launcher_test.rb +8 -8
  53. data/test/helpers/foreman_tasks/foreman_tasks_helper_test.rb +7 -7
  54. data/test/helpers/foreman_tasks/tasks_helper_test.rb +3 -3
  55. data/test/lib/actions/middleware/keep_current_request_id_test.rb +3 -3
  56. data/test/support/history_tasks_builder.rb +1 -1
  57. data/test/tasks/generate_task_actions_test.rb +1 -1
  58. data/test/unit/actions/action_with_sub_plans_test.rb +2 -2
  59. data/test/unit/actions/bulk_action_test.rb +6 -6
  60. data/test/unit/actions/proxy_action_test.rb +20 -20
  61. data/test/unit/actions/recurring_action_test.rb +30 -32
  62. data/test/unit/cleaner_test.rb +24 -24
  63. data/test/unit/dashboard_table_filter_test.rb +5 -5
  64. data/test/unit/otp_manager_test.rb +2 -2
  65. data/test/unit/proxy_selector_test.rb +9 -9
  66. data/test/unit/recurring_logic_test.rb +32 -32
  67. data/test/unit/remote_task_test.rb +2 -2
  68. data/test/unit/task_groups_test.rb +4 -4
  69. data/test/unit/task_test.rb +18 -18
  70. data/test/unit/triggering_test.rb +8 -8
  71. data/test/unit/troubleshooting_help_generator_test.rb +6 -6
  72. data/test/unit/ui_notifications_test.rb +11 -11
  73. data/webpack/ForemanTasks/Components/TaskActions/TaskAction.test.js +60 -0
  74. data/webpack/ForemanTasks/Components/{TasksTable/TasksTableActionHelpers.js → TaskActions/TaskActionHelpers.js} +21 -6
  75. data/webpack/ForemanTasks/Components/{TasksTable/__tests__/TasksTableActionHelpers.test.js → TaskActions/TaskActionHelpers.test.js} +2 -2
  76. data/webpack/ForemanTasks/Components/TaskActions/TaskActionsConstants.js +16 -0
  77. data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.js +60 -0
  78. data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.test.js +14 -0
  79. data/webpack/ForemanTasks/Components/TaskActions/__snapshots__/TaskAction.test.js.snap +233 -0
  80. data/webpack/ForemanTasks/Components/TaskActions/__snapshots__/UnlockModals.test.js.snap +25 -0
  81. data/webpack/ForemanTasks/Components/TaskActions/index.js +115 -0
  82. data/webpack/ForemanTasks/Components/TaskDetails/Components/RunningSteps.js +17 -3
  83. data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +38 -205
  84. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskButtons.js +168 -0
  85. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +6 -7
  86. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskSkeleton.js +48 -0
  87. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +8 -1
  88. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +14 -7
  89. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskButtons.test.js +95 -0
  90. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskInfo.test.js +0 -1
  91. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/RunningSteps.test.js.snap +1 -1
  92. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +90 -189
  93. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskButtons.test.js.snap +212 -0
  94. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +8 -4
  95. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +100 -53
  96. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.scss +3 -14
  97. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +57 -110
  98. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsConstants.js +3 -17
  99. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +57 -37
  100. data/webpack/ForemanTasks/Components/TaskDetails/TasksDetailsHelper.js +6 -1
  101. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.fixtures.js +8 -0
  102. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +13 -1
  103. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +6 -6
  104. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +86 -19
  105. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap +25 -21
  106. data/webpack/ForemanTasks/Components/TaskDetails/index.js +12 -11
  107. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardActions.js +1 -1
  108. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardActions.test.js +2 -2
  109. data/webpack/ForemanTasks/Components/TasksTable/Components/ActionSelectButton.js +14 -1
  110. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModal.js +83 -0
  111. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalActions.js +106 -0
  112. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalReducer.js +38 -0
  113. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalSelectors.js +46 -0
  114. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModal.test.js +36 -0
  115. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalActions.test.js +205 -0
  116. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalReducer.test.js +27 -0
  117. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalSelectors.test.js +55 -0
  118. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModal.test.js.snap +41 -0
  119. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalReducer.test.js.snap +19 -0
  120. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalSelectors.test.js.snap +32 -0
  121. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/index.js +29 -0
  122. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ActionSelectButton.test.js +1 -0
  123. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ActionSelectButton.test.js.snap +11 -0
  124. data/webpack/ForemanTasks/Components/TasksTable/TasksBulkActions.js +135 -35
  125. data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +13 -9
  126. data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +26 -66
  127. data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +10 -12
  128. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +30 -96
  129. data/webpack/ForemanTasks/Components/TasksTable/TasksTableSchema.js +2 -2
  130. data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +8 -4
  131. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksBulkActions.test.js +50 -2
  132. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +3 -12
  133. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActions.test.js +22 -26
  134. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTablePage.test.js +2 -1
  135. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +3 -14
  136. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksBulkActions.test.js.snap +155 -0
  137. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +3 -14
  138. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableActions.test.js.snap +17 -124
  139. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +63 -133
  140. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/__snapshots__/actionCellFormatter.test.js.snap +1 -0
  141. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/__snapshots__/selectionCellFormatter.test.js.snap +2 -0
  142. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/actionCellFormatter.test.js +1 -1
  143. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/selectionCellFormatter.test.js +1 -1
  144. data/webpack/ForemanTasks/Components/TasksTable/formatters/actionCellFormatter.js +10 -7
  145. data/webpack/ForemanTasks/Components/TasksTable/formatters/selectionCellFormatter.js +7 -0
  146. data/webpack/ForemanTasks/Components/TasksTable/index.js +2 -2
  147. data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.js +55 -19
  148. data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.test.js +75 -19
  149. data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ActionButton.test.js.snap +88 -21
  150. data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.scss +9 -0
  151. data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.test.js +44 -0
  152. data/webpack/ForemanTasks/Components/common/ClickConfirmation/__snapshots__/ClickConfirmation.test.js.snap +52 -0
  153. data/webpack/ForemanTasks/Components/common/ClickConfirmation/index.js +59 -66
  154. data/webpack/ForemanTasks/Components/common/{ToastTypesConstants.js → ToastsHelpers/ToastTypesConstants.js} +0 -0
  155. data/webpack/ForemanTasks/Components/common/ToastsHelpers/index.js +15 -0
  156. data/webpack/ForemanTasks/Components/common/urlHelpers.js +7 -0
  157. data/webpack/ForemanTasks/ForemanTasksReducers.js +2 -2
  158. data/webpack/ForemanTasks/Routes/ForemanTasksRoutes.test.js +2 -1
  159. data/webpack/__mocks__/foremanReact/common/helpers.js +2 -0
  160. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js +2 -2
  161. data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +17 -3
  162. data/webpack/__mocks__/foremanReact/components/common/ActionButtons/ActionButtons.js +3 -0
  163. data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +10 -0
  164. data/webpack/__mocks__/foremanReact/redux/API/index.js +10 -0
  165. data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware.js +5 -0
  166. metadata +51 -28
  167. data/.travis.yml +0 -5
  168. data/script/travis_run_js_tests.sh +0 -7
  169. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsReducer.js +0 -44
  170. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsReducer.test.js +0 -33
  171. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsReducer.test.js.snap +0 -26
  172. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/integration.test.js.snap +0 -122
  173. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/integration.test.js +0 -63
  174. data/webpack/ForemanTasks/Components/TasksTable/Components/CancelConfirm.js +0 -53
  175. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmationModals.js +0 -56
  176. data/webpack/ForemanTasks/Components/TasksTable/Components/ResumeConfirm.js +0 -52
  177. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/CancelConfirm.test.js +0 -26
  178. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ConfirmationModals.test.js +0 -24
  179. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ResumeConfirm.test.js +0 -26
  180. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/CancelConfirm.test.js.snap +0 -65
  181. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ConfirmationModals.test.js.snap +0 -30
  182. data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ResumeConfirm.test.js.snap +0 -63
  183. data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.js +0 -23
  184. data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.test.js +0 -26
  185. data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.js +0 -23
  186. data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.test.js +0 -27
  187. data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/CancelButton.test.js.snap +0 -15
  188. data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ResumeButton.test.js.snap +0 -15
  189. data/webpack/__mocks__/foremanReact/API.js +0 -7
@@ -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,55 @@
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
+ can_edit: true,
26
+ },
27
+ { id: 2, action: 'action2', available_actions: { resumable: true } },
28
+ ],
29
+ itemCount: 10,
30
+ },
31
+ tasksTableQuery: { selectedRows: [1, 2, 3] },
32
+ },
33
+ },
34
+ };
35
+
36
+ const fixtures = {
37
+ 'should select actionText': () => selectActionText(state),
38
+ 'should select actionState': () => selectActionState(state),
39
+ 'should select actionType': () => selectActionType(state),
40
+ 'should select selectedTasks': () => selectSelectedTasks(state),
41
+ 'should select selectedRowsLen 1': () =>
42
+ selectSelectedRowsLen({
43
+ ...state,
44
+ foremanTasks: { confirmModal: { actionType: CANCEL_MODAL } },
45
+ }),
46
+ 'should select selectedRowsLen all': () => selectSelectedRowsLen(state),
47
+ 'should select selectedRowsLen some': () =>
48
+ selectSelectedRowsLen({
49
+ ...state,
50
+ tasksTable: { tasksTableQuery: { allRowsSelected: true } },
51
+ }),
52
+ };
53
+
54
+ describe('TasksDashboard - Selectors', () =>
55
+ 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,32 @@
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
+ "canEdit": true,
19
+ "id": 1,
20
+ "isCancellable": true,
21
+ "isResumable": undefined,
22
+ "name": "action1",
23
+ },
24
+ Object {
25
+ "canEdit": undefined,
26
+ "id": 2,
27
+ "isCancellable": undefined,
28
+ "isResumable": true,
29
+ "name": "action2",
30
+ },
31
+ ]
32
+ `;
@@ -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
- import API from 'foremanReact/API';
1
+ import { API } from 'foremanReact/redux/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
 
@@ -53,13 +63,12 @@ export const bulkResumeById = ({
53
63
  url,
54
64
  parentTaskID,
55
65
  }) => async dispatch => {
56
- const resumeTasks = selected.filter(task => task.isResumable);
66
+ const resumeTasks = selected.filter(task => task.isResumable && task.canEdit);
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 });
@@ -78,7 +87,7 @@ export const bulkResumeById = ({
78
87
  });
79
88
  });
80
89
  if (data.resumed) {
81
- reloadPage(url, parentTaskID, dispatch);
90
+ reloadPage(url, parentTaskID)(dispatch);
82
91
  }
83
92
  } catch (error) {
84
93
  handleErrorResume(error, dispatch);
@@ -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
  };
@@ -129,13 +135,14 @@ export const bulkCancelById = ({
129
135
  url,
130
136
  parentTaskID,
131
137
  }) => async dispatch => {
132
- const cancelTasks = selected.filter(task => task.isCancellable);
138
+ const cancelTasks = selected.filter(
139
+ task => task.isCancellable && task.canEdit
140
+ );
133
141
  if (cancelTasks.length < selected.length)
134
142
  dispatch(
135
- addToast({
136
- type: TOAST_TYPES.WARNING,
137
- message: __('Not all the selected tasks can be cancelled'),
138
- })
143
+ addToast(
144
+ warningToastData(__('Not all the selected tasks can be cancelled'))
145
+ )
139
146
  );
140
147
  if (cancelTasks.length) {
141
148
  dispatch({ type: TASKS_CANCEL_REQUEST });
@@ -155,10 +162,103 @@ export const bulkCancelById = ({
155
162
  });
156
163
  });
157
164
  if (data.cancelled) {
158
- reloadPage(url, parentTaskID, dispatch);
165
+ reloadPage(url, parentTaskID)(dispatch);
159
166
  }
160
167
  } catch (error) {
161
168
  handleErrorCancel(error, dispatch);
162
169
  }
163
170
  }
164
171
  };
172
+
173
+ const handleErrorForceCancel = (error, dispatch) => {
174
+ dispatch({ type: TASKS_FORCE_CANCEL_FAILURE, error });
175
+ dispatch(
176
+ addToast(
177
+ errorToastData(
178
+ `${__(`Cannot force cancel tasks at the moment`)} ${error}`
179
+ )
180
+ )
181
+ );
182
+ };
183
+
184
+ export const bulkForceCancelById = ({
185
+ selected,
186
+ url,
187
+ parentTaskID,
188
+ }) => async dispatch => {
189
+ const stopTasks = selected.filter(task => task.state !== 'stopped');
190
+ const authorisedTasks = stopTasks.filter(task => task.canEdit);
191
+ if (authorisedTasks.length < stopTasks.length)
192
+ dispatch(
193
+ addToast(
194
+ warningToastData(
195
+ sprintf(
196
+ 'User has no permission for %s task(s)',
197
+ stopTasks.length - authorisedTasks.length
198
+ )
199
+ )
200
+ )
201
+ );
202
+ if (stopTasks.length < selected.length)
203
+ dispatch(
204
+ addToast(
205
+ warningToastData(
206
+ sprintf(
207
+ '%s task(s) are already stopped',
208
+ selected.length - stopTasks.length
209
+ )
210
+ )
211
+ )
212
+ );
213
+ if (authorisedTasks.length > 0) {
214
+ dispatch({ type: TASKS_FORCE_CANCEL_REQUEST });
215
+ try {
216
+ const { data } = await bulkByIdRequest(
217
+ authorisedTasks,
218
+ BULK_FORCE_CANCEL_PATH
219
+ );
220
+ dispatch({ type: TASKS_FORCE_CANCEL_SUCCESS });
221
+ if (data.stopped_length) {
222
+ dispatch(
223
+ addToast(
224
+ successToastData(
225
+ sprintf('%s task(s) cancelled with force', data.stopped_length)
226
+ )
227
+ )
228
+ );
229
+ }
230
+ if (data.skipped_length > 0)
231
+ dispatch(
232
+ addToast(
233
+ warningToastData(
234
+ sprintf('%s task(s) are already stopped', data.skipped_length)
235
+ )
236
+ )
237
+ );
238
+ if (data.stopped_length > 0) {
239
+ reloadPage(url, parentTaskID)(dispatch);
240
+ }
241
+ } catch (error) {
242
+ handleErrorForceCancel(error, dispatch);
243
+ }
244
+ }
245
+ };
246
+
247
+ export const bulkForceCancelBySearch = ({
248
+ query,
249
+ parentTaskID,
250
+ }) => async dispatch => {
251
+ dispatch({ type: TASKS_FORCE_CANCEL_REQUEST });
252
+ dispatch(
253
+ addToast(
254
+ infoToastData(
255
+ __('Canceling with force selected tasks, this might take a while')
256
+ )
257
+ )
258
+ );
259
+ await bulkBySearchRequest({
260
+ query,
261
+ path: BULK_FORCE_CANCEL_PATH,
262
+ parentTaskID,
263
+ });
264
+ };