foreman-tasks 2.0.0 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/js_tests.yml +31 -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/app/controllers/foreman_tasks/api/tasks_controller.rb +36 -60
  8. data/app/controllers/foreman_tasks/concerns/parameters/triggering.rb +1 -1
  9. data/app/controllers/foreman_tasks/recurring_logics_controller.rb +7 -0
  10. data/app/controllers/foreman_tasks/tasks_controller.rb +6 -3
  11. data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +3 -3
  12. data/app/lib/actions/proxy_action.rb +1 -1
  13. data/app/models/foreman_tasks/recurring_logic.rb +1 -1
  14. data/app/models/foreman_tasks/task.rb +11 -0
  15. data/app/models/foreman_tasks/task/dynflow_task.rb +29 -33
  16. data/app/models/foreman_tasks/task/status_explicator.rb +1 -1
  17. data/app/models/foreman_tasks/triggering.rb +1 -1
  18. data/app/models/setting/foreman_tasks.rb +9 -9
  19. data/app/services/foreman_tasks/dashboard_table_filter.rb +5 -1
  20. data/app/views/foreman_tasks/api/tasks/index.json.rabl +2 -0
  21. data/app/views/foreman_tasks/api/tasks/show.json.rabl +2 -0
  22. data/app/views/foreman_tasks/layouts/react.html.erb +1 -2
  23. data/app/views/foreman_tasks/recurring_logics/index.html.erb +3 -1
  24. data/app/views/foreman_tasks/tasks/show.html.erb +1 -6
  25. data/config/routes.rb +2 -1
  26. data/db/migrate/20200517215015_rename_bookmarks_controller.rb +2 -2
  27. data/db/migrate/20200611090846_add_task_lock_index_on_resource_type_and_task_id.rb +9 -0
  28. data/db/seeds.d/30-notification_blueprints.rb +7 -7
  29. data/db/seeds.d/61-foreman_tasks_bookmarks.rb +1 -1
  30. data/foreman-tasks.gemspec +1 -0
  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 +2 -7
  35. data/lib/foreman_tasks/tasks/cleanup.rake +2 -2
  36. data/lib/foreman_tasks/tasks/dynflow.rake +6 -0
  37. data/lib/foreman_tasks/tasks/export_tasks.rake +1 -1
  38. data/lib/foreman_tasks/version.rb +1 -1
  39. data/locale/en/LC_MESSAGES/foreman_tasks.mo +0 -0
  40. data/locale/en/foreman_tasks.po +50 -20
  41. data/locale/foreman_tasks.pot +173 -126
  42. data/locale/fr/LC_MESSAGES/foreman_tasks.mo +0 -0
  43. data/locale/fr/foreman_tasks.po +817 -0
  44. data/locale/ja/LC_MESSAGES/foreman_tasks.mo +0 -0
  45. data/locale/ja/foreman_tasks.po +817 -0
  46. data/locale/zh_CN/LC_MESSAGES/foreman_tasks.mo +0 -0
  47. data/locale/zh_CN/foreman_tasks.po +816 -0
  48. data/package.json +1 -1
  49. data/script/npm_link_foreman_js.sh +26 -0
  50. data/test/controllers/api/recurring_logics_controller_test.rb +1 -1
  51. data/test/controllers/api/tasks_controller_test.rb +17 -7
  52. data/test/controllers/tasks_controller_test.rb +6 -6
  53. data/test/core/unit/runner_test.rb +20 -20
  54. data/test/core/unit/task_launcher_test.rb +8 -8
  55. data/test/helpers/foreman_tasks/foreman_tasks_helper_test.rb +7 -7
  56. data/test/helpers/foreman_tasks/tasks_helper_test.rb +3 -3
  57. data/test/lib/actions/middleware/keep_current_request_id_test.rb +3 -3
  58. data/test/support/history_tasks_builder.rb +1 -1
  59. data/test/tasks/generate_task_actions_test.rb +1 -1
  60. data/test/unit/actions/action_with_sub_plans_test.rb +2 -2
  61. data/test/unit/actions/bulk_action_test.rb +6 -6
  62. data/test/unit/actions/proxy_action_test.rb +20 -20
  63. data/test/unit/actions/recurring_action_test.rb +30 -32
  64. data/test/unit/cleaner_test.rb +24 -24
  65. data/test/unit/dashboard_table_filter_test.rb +5 -5
  66. data/test/unit/otp_manager_test.rb +2 -2
  67. data/test/unit/proxy_selector_test.rb +9 -9
  68. data/test/unit/recurring_logic_test.rb +32 -32
  69. data/test/unit/remote_task_test.rb +2 -2
  70. data/test/unit/task_groups_test.rb +4 -4
  71. data/test/unit/task_test.rb +18 -18
  72. data/test/unit/triggering_test.rb +8 -8
  73. data/test/unit/troubleshooting_help_generator_test.rb +6 -6
  74. data/test/unit/ui_notifications_test.rb +11 -11
  75. data/webpack/ForemanTasks/Components/TaskActions/TaskAction.test.js +2 -2
  76. data/webpack/ForemanTasks/Components/TaskActions/index.js +1 -1
  77. data/webpack/ForemanTasks/Components/TaskDetails/Components/RunningSteps.js +17 -3
  78. data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +8 -153
  79. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskButtons.js +168 -0
  80. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +6 -7
  81. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskSkeleton.js +48 -0
  82. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +8 -1
  83. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +13 -70
  84. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskButtons.test.js +95 -0
  85. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/RunningSteps.test.js.snap +1 -1
  86. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +78 -208
  87. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskButtons.test.js.snap +212 -0
  88. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +8 -4
  89. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +100 -53
  90. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.scss +13 -14
  91. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +57 -95
  92. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsConstants.js +3 -12
  93. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +57 -28
  94. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.fixtures.js +8 -0
  95. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +8 -1
  96. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +6 -6
  97. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +84 -12
  98. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap +25 -21
  99. data/webpack/ForemanTasks/Components/TaskDetails/index.js +8 -3
  100. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.scss +4 -0
  101. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.js +53 -0
  102. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.test.js +14 -0
  103. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js +27 -19
  104. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.scss +14 -0
  105. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.test.js +1 -34
  106. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/{StoppedTasksCardHelper.js → StoppedTasksCardTable.js} +28 -1
  107. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCardTable.test.js +54 -0
  108. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/OtherInfo.test.js.snap +48 -0
  109. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCard.test.js.snap +60 -1367
  110. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCardTable.test.js.snap +960 -0
  111. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/__snapshots__/TasksCardsGrid.test.js.snap +14 -11
  112. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardActions.js +1 -1
  113. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardConstants.js +2 -0
  114. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardSelectors.js +17 -11
  115. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardActions.test.js +2 -2
  116. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardSelectors.test.js +26 -14
  117. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboard.test.js.snap +14 -11
  118. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboardSelectors.test.js.snap +38 -22
  119. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalSelectors.js +1 -0
  120. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalSelectors.test.js +1 -0
  121. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalSelectors.test.js.snap +2 -0
  122. data/webpack/ForemanTasks/Components/TasksTable/TasksBulkActions.js +25 -8
  123. data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +3 -3
  124. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +6 -3
  125. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.scss +0 -10
  126. data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +1 -0
  127. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksBulkActions.test.js +15 -2
  128. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +1 -0
  129. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTablePage.test.js +2 -1
  130. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +1 -0
  131. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksBulkActions.test.js.snap +48 -0
  132. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +1 -0
  133. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +39 -7
  134. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/__snapshots__/actionCellFormatter.test.js.snap +1 -0
  135. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/__snapshots__/selectionCellFormatter.test.js.snap +2 -0
  136. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/actionCellFormatter.test.js +1 -1
  137. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/selectionCellFormatter.test.js +1 -1
  138. data/webpack/ForemanTasks/Components/TasksTable/formatters/actionCellFormatter.js +10 -7
  139. data/webpack/ForemanTasks/Components/TasksTable/formatters/selectionCellFormatter.js +7 -0
  140. data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.js +39 -31
  141. data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.test.js +17 -8
  142. data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ActionButton.test.js.snap +8 -0
  143. data/webpack/ForemanTasks/Components/common/urlHelpers.js +7 -0
  144. data/webpack/ForemanTasks/ForemanTasksReducers.js +0 -2
  145. data/webpack/__mocks__/foremanReact/common/helpers.js +2 -0
  146. data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +10 -0
  147. data/webpack/__mocks__/foremanReact/redux/API/index.js +10 -0
  148. data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware.js +5 -0
  149. metadata +35 -17
  150. data/.travis.yml +0 -5
  151. data/app/assets/stylesheets/foreman_tasks/tasks.scss +0 -9
  152. data/script/travis_run_js_tests.sh +0 -7
  153. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsReducer.js +0 -38
  154. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsReducer.test.js +0 -33
  155. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsReducer.test.js.snap +0 -26
  156. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/integration.test.js.snap +0 -122
  157. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/integration.test.js +0 -67
  158. data/webpack/__mocks__/foremanReact/API.js +0 -7
@@ -290,10 +290,14 @@ exports[`TaskInfo rendering render with Props 1`] = `
290
290
  </b>
291
291
  </span>
292
292
  </p>
293
- <p>
294
- A paused task represents a process that has not finished properly. Any task in paused state can lead to potential inconsistency and needs to be resolved.
295
- The recommended approach is to investigate the error messages below and in 'errors' tab, address the primary cause of the issue and resume the task.
296
- </p>
293
+ <p
294
+ dangerouslySetInnerHTML={
295
+ Object {
296
+ "__html": "A paused task represents a process that has not finished properly. Any task in paused state can lead to potential inconsistency and needs to be resolved.
297
+ The recommended approach is to investigate the error messages below and in 'errors' tab, address the primary cause of the issue and resume the task.",
298
+ }
299
+ }
300
+ />
297
301
  </Col>
298
302
  </Row>
299
303
  </Grid>
@@ -1,82 +1,129 @@
1
- import React, { Component } from 'react';
1
+ import React, { useEffect } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { Tab, Tabs } from 'patternfly-react';
4
4
  import { translate as __ } from 'foremanReact/common/I18n';
5
+ import { STATUS } from 'foremanReact/constants';
6
+ import MessageBox from 'foremanReact/components/common/MessageBox';
5
7
  import Task from './Components/Task';
6
8
  import RunningSteps from './Components/RunningSteps';
7
9
  import Errors from './Components/Errors';
8
10
  import Locks from './Components/Locks';
9
11
  import Raw from './Components/Raw';
10
12
  import { getTaskID } from './TasksDetailsHelper';
13
+ import { TaskSkeleton } from './Components/TaskSkeleton';
11
14
 
12
15
  import './TaskDetails.scss';
13
16
 
14
- class TaskDetails extends Component {
15
- componentDidMount() {
16
- const { timeoutId, refetchTaskDetails, fetchTaskDetails } = this.props;
17
+ const TaskDetails = ({
18
+ executionPlan,
19
+ failedSteps,
20
+ runningSteps,
21
+ locks,
22
+ cancelStep,
23
+ taskReloadStart,
24
+ taskReloadStop,
25
+ APIerror,
26
+ ...props
27
+ }) => {
28
+ const id = getTaskID();
29
+ const { taskReload, status, isLoading } = props;
17
30
 
18
- fetchTaskDetails(getTaskID(), timeoutId, refetchTaskDetails);
19
- }
20
- componentWillUnmount() {
21
- this.props.taskReloadStop(this.props.timeoutId);
22
- }
23
- render() {
24
- const {
25
- externalId,
26
- startedAt,
27
- endedAt,
28
- label,
29
- input,
30
- output,
31
- executionPlan,
32
- failedSteps,
33
- runningSteps,
34
- locks,
35
- } = this.props;
36
- const id = getTaskID();
37
- const resumable = executionPlan ? executionPlan.state === 'paused' : false;
38
- const cancellable = executionPlan ? executionPlan.cancellable : false;
31
+ useEffect(() => {
32
+ taskReloadStart(id);
33
+ return () => {
34
+ taskReloadStop();
35
+ };
36
+ }, [id, taskReloadStart, taskReloadStop]);
37
+
38
+ const taskProgressToggle = () => {
39
+ if (taskReload) {
40
+ taskReloadStop();
41
+ } else {
42
+ taskReloadStart(id);
43
+ }
44
+ };
45
+
46
+ if (status === STATUS.ERROR) {
39
47
  return (
40
- <div className="task-details-react well">
41
- <Tabs defaultActiveKey={1} animation={false} id="task-details-tabs">
42
- <Tab eventKey={1} title={__('Task')}>
43
- <Task {...{ ...this.props, cancellable, resumable, id }} />
44
- </Tab>
45
- <Tab eventKey={2} title={__('Running Steps')}>
46
- <RunningSteps
47
- executionPlan={executionPlan}
48
- runningSteps={runningSteps}
49
- />
50
- </Tab>
51
- <Tab eventKey={3} title={__('Errors')}>
52
- <Errors executionPlan={executionPlan} failedSteps={failedSteps} />
53
- </Tab>
54
- <Tab eventKey={4} title={__('Locks')}>
55
- <Locks locks={locks} />
56
- </Tab>
57
- <Tab eventKey={5} title={__('Raw')}>
58
- <Raw
59
- {...{ id, label, startedAt, endedAt, input, output, externalId }}
60
- />
61
- </Tab>
62
- </Tabs>
63
- </div>
48
+ <MessageBox
49
+ key="task-details-error"
50
+ icontype="error-circle-o"
51
+ msg={__(`Could not receive data: ${APIerror && APIerror.message}`)}
52
+ />
64
53
  );
65
54
  }
66
- }
55
+ const resumable = executionPlan ? executionPlan.state === 'paused' : false;
56
+ const cancellable = executionPlan ? executionPlan.cancellable : false;
57
+ return (
58
+ <div className="task-details-react well">
59
+ <Tabs defaultActiveKey={1} animation={false} id="task-details-tabs">
60
+ <Tab eventKey={1} title={__('Task')}>
61
+ {isLoading ? (
62
+ <TaskSkeleton />
63
+ ) : (
64
+ <Task
65
+ {...{
66
+ ...props,
67
+ cancellable,
68
+ resumable,
69
+ id,
70
+ status,
71
+ taskProgressToggle,
72
+ taskReloadStart,
73
+ }}
74
+ />
75
+ )}
76
+ </Tab>
77
+ <Tab eventKey={2} disabled={isLoading} title={__('Running Steps')}>
78
+ <RunningSteps
79
+ runningSteps={runningSteps}
80
+ id={id}
81
+ cancelStep={cancelStep}
82
+ taskReload={taskReload}
83
+ taskReloadStart={taskReloadStart}
84
+ />
85
+ </Tab>
86
+ <Tab eventKey={3} disabled={isLoading} title={__('Errors')}>
87
+ <Errors executionPlan={executionPlan} failedSteps={failedSteps} />
88
+ </Tab>
89
+ <Tab eventKey={4} disabled={isLoading} title={__('Locks')}>
90
+ <Locks locks={locks} />
91
+ </Tab>
92
+ <Tab eventKey={5} disabled={isLoading} title={__('Raw')}>
93
+ <Raw
94
+ id={id}
95
+ label={props.label}
96
+ startedAt={props.startedAt}
97
+ endedAt={props.endedAt}
98
+ input={props.input}
99
+ output={props.output}
100
+ externalId={props.externalId}
101
+ />
102
+ </Tab>
103
+ </Tabs>
104
+ </div>
105
+ );
106
+ };
67
107
 
68
108
  TaskDetails.propTypes = {
69
109
  label: PropTypes.string,
70
- fetchTaskDetails: PropTypes.func,
110
+ runningSteps: PropTypes.array,
111
+ cancelStep: PropTypes.func.isRequired,
112
+ taskReload: PropTypes.bool.isRequired,
113
+ status: PropTypes.oneOf(Object.keys(STATUS)),
114
+ APIerror: PropTypes.object,
115
+ taskReloadStop: PropTypes.func.isRequired,
116
+ taskReloadStart: PropTypes.func.isRequired,
71
117
  ...Task.propTypes,
72
- ...RunningSteps.propTypes,
73
118
  ...Errors.propTypes,
74
119
  ...Locks.propTypes,
75
120
  ...Raw.propTypes,
76
121
  };
77
122
  TaskDetails.defaultProps = {
78
123
  label: '',
79
- fetchTaskDetails: () => null,
124
+ runningSteps: [],
125
+ APIerror: null,
126
+ status: STATUS.PENDING,
80
127
  ...Task.defaultProps,
81
128
  ...RunningSteps.defaultProps,
82
129
  ...Errors.defaultProps,
@@ -10,20 +10,6 @@
10
10
  .container {
11
11
  margin: 0;
12
12
  }
13
- /*
14
- * This is a manifest file that'll be compiled into application.css, which will include all the files
15
- * listed below.
16
- *
17
- * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
18
- * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
19
- *
20
- * You're free to add application-wide styles to this file and they'll appear at the top of the
21
- * compiled file, but it's generally better to create a new file per style scope.
22
- *
23
- *= require_self
24
- *= require_tree .
25
- */
26
-
27
13
  .spin {
28
14
  -webkit-animation: spin 1s infinite linear;
29
15
  -moz-animation: spin 1s infinite linear;
@@ -60,4 +46,17 @@
60
46
  transform: rotate(360deg);
61
47
  }
62
48
  }
49
+ .dynflow-button > span {
50
+ pointer-events: auto;
51
+ }
52
+
53
+ pre {
54
+ white-space: pre;
55
+ word-break: normal;
56
+ }
57
+
58
+ .param-name {
59
+ display: inline-block;
60
+ width: 10em;
61
+ }
63
62
  }
@@ -1,100 +1,62 @@
1
- import API from 'foremanReact/API';
1
+ import { post, get } from 'foremanReact/redux/API';
2
+ import { addToast } from 'foremanReact/redux/actions/toasts';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
2
4
  import {
3
- showLoading,
4
- hideLoading,
5
- } from 'foremanReact/components/Layout/LayoutActions';
5
+ withInterval,
6
+ stopInterval,
7
+ } from 'foremanReact/redux/middlewares/IntervalMiddleware';
8
+ import { foremanTasksApiPath, foremanTasksPath } from '../common/urlHelpers';
9
+ import { TASK_STEP_CANCEL, FOREMAN_TASK_DETAILS } from './TaskDetailsConstants';
6
10
  import {
7
- FOREMAN_TASK_DETAILS_FETCH_TASK_REQUEST,
8
- FOREMAN_TASK_DETAILS_FETCH_TASK_SUCCESS,
9
- FOREMAN_TASK_DETAILS_FETCH_TASK_FAILURE,
10
- FOREMAN_TASK_DETAILS_STOP_POLLING,
11
- FOREMAN_TASK_DETAILS_START_POLLING,
12
- } from './TaskDetailsConstants';
13
-
14
- export const taskReloadStop = timeoutId => {
15
- if (timeoutId) {
16
- clearTimeout(timeoutId);
17
- }
18
- return {
19
- type: FOREMAN_TASK_DETAILS_STOP_POLLING,
20
- payload: { timeoutId },
21
- };
22
- };
23
-
24
- export const taskReloadStart = (
25
- timeoutId,
26
- refetchTaskDetails,
27
- id,
28
- loading = false
29
- ) => {
30
- if (!timeoutId) {
31
- timeoutId = setInterval(() => refetchTaskDetails(id, loading), 5000);
32
- }
33
- return {
34
- type: FOREMAN_TASK_DETAILS_START_POLLING,
35
- payload: { timeoutId },
36
- };
37
- };
38
-
39
- export const refetchTaskDetails = (id, loading) => dispatch => {
40
- if (!loading) {
41
- showLoading();
42
- dispatch(startRequest());
43
- reloadTasksDetails(id, dispatch);
44
- }
45
- };
46
-
47
- const reloadTasksDetails = async (id, dispatch) => {
48
- try {
49
- const { data } = await API.get(`/foreman_tasks/api/tasks/${id}/details`);
50
- dispatch(requestSuccess(data));
51
- } catch (error) {
52
- dispatch(requestFailure(error));
53
- document.location.reload();
54
- } finally {
55
- hideLoading();
56
- }
57
- };
58
-
59
- export const fetchTaskDetails = (
60
- id,
61
- timeoutId,
62
- refetchTaskDetailsAction
63
- ) => async dispatch => {
64
- showLoading();
65
- dispatch(startRequest());
66
- await getTasksDetails(id, dispatch, timeoutId, refetchTaskDetailsAction);
11
+ errorToastData,
12
+ infoToastData,
13
+ successToastData,
14
+ } from '../common/ToastsHelpers';
15
+
16
+ export const taskReloadStop = () => stopInterval(FOREMAN_TASK_DETAILS);
17
+
18
+ export const taskReloadStart = id => dispatch => {
19
+ dispatch(
20
+ withInterval(
21
+ get({
22
+ key: FOREMAN_TASK_DETAILS,
23
+ url: foremanTasksApiPath(`${id}/details?include_permissions`),
24
+ handleSuccess: ({ data }) => {
25
+ if (data.state === 'stopped') {
26
+ dispatch(stopInterval(FOREMAN_TASK_DETAILS));
27
+ }
28
+ },
29
+ handleError: () => {
30
+ dispatch(stopInterval(FOREMAN_TASK_DETAILS));
31
+ },
32
+ }),
33
+ 5000
34
+ )
35
+ );
67
36
  };
68
37
 
69
- const getTasksDetails = async (
70
- id,
71
- dispatch,
72
- timeoutId,
73
- refetchTaskDetailsAction
74
- ) => {
75
- try {
76
- const { data } = await API.get(`/foreman_tasks/api/tasks/${id}/details`);
77
- dispatch(requestSuccess(data));
78
- if (data.state !== 'stopped') {
79
- dispatch(taskReloadStart(timeoutId, refetchTaskDetailsAction, id));
80
- }
81
- } catch (error) {
82
- dispatch(requestFailure(error));
83
- } finally {
84
- hideLoading();
85
- }
38
+ export const cancelStep = (taskId, stepId) => async dispatch => {
39
+ dispatch(addToast(infoToastData(`${__('Trying to cancel step')} ${stepId}`)));
40
+ dispatch(
41
+ post({
42
+ key: TASK_STEP_CANCEL,
43
+ url: foremanTasksPath(`${taskId}/cancel_step?step_id=${stepId}`),
44
+ handleSuccess: () => {
45
+ dispatch(addToast(successToastData(`${stepId} {__('Step Canceled')}`)));
46
+ },
47
+ handleError: error => {
48
+ dispatch(
49
+ addToast(
50
+ errorToastData(
51
+ `${__('Could not cancel step.')} ${__(
52
+ 'Error:'
53
+ )} ${stepId} ${error.response &&
54
+ error.response.data &&
55
+ error.response.data.error}`
56
+ )
57
+ )
58
+ );
59
+ },
60
+ })
61
+ );
86
62
  };
87
-
88
- const startRequest = () => ({
89
- type: FOREMAN_TASK_DETAILS_FETCH_TASK_REQUEST,
90
- });
91
-
92
- const requestSuccess = data => ({
93
- type: FOREMAN_TASK_DETAILS_FETCH_TASK_SUCCESS,
94
- payload: data,
95
- });
96
-
97
- const requestFailure = error => ({
98
- type: FOREMAN_TASK_DETAILS_FETCH_TASK_FAILURE,
99
- payload: error,
100
- });
@@ -1,13 +1,4 @@
1
- export const FOREMAN_TASK_DETAILS_INIT = 'FOREMAN_TASK_DETAILS_INIT';
1
+ export const FOREMAN_TASK_DETAILS = 'FOREMAN_TASK_DETAILS';
2
+ export const FOREMAN_TASK_DETAILS_SUCCESS = 'FOREMAN_TASK_DETAILS_SUCCESS';
2
3
 
3
- export const FOREMAN_TASK_DETAILS_FETCH_TASK_REQUEST =
4
- 'FOREMAN_TASK_DETAILS_FETCH_TASK_REQUEST';
5
- export const FOREMAN_TASK_DETAILS_FETCH_TASK_SUCCESS =
6
- 'FOREMAN_TASK_DETAILS_FETCH_TASK_SUCCESS';
7
- export const FOREMAN_TASK_DETAILS_FETCH_TASK_FAILURE =
8
- 'FOREMAN_TASK_DETAILS_FETCH_TASK_FAILURE';
9
-
10
- export const FOREMAN_TASK_DETAILS_STOP_POLLING =
11
- 'FOREMAN_TASK_DETAILS_STOP_POLLING';
12
- export const FOREMAN_TASK_DETAILS_START_POLLING =
13
- 'FOREMAN_TASK_DETAILS_START_POLLING';
4
+ export const TASK_STEP_CANCEL = 'TASK_STEP_CANCEL';
@@ -1,79 +1,108 @@
1
+ /* eslint-disable camelcase */
2
+ import {
3
+ selectAPIResponse,
4
+ selectAPIByKey,
5
+ } from 'foremanReact/redux/API/APISelectors';
6
+ import { selectDoesIntervalExist } from 'foremanReact/redux/middlewares/IntervalMiddleware/IntervalSelectors';
7
+ import { STATUS } from 'foremanReact/constants';
1
8
  import { selectForemanTasks } from '../../ForemanTasksSelectors';
9
+ import { FOREMAN_TASK_DETAILS } from './TaskDetailsConstants';
2
10
 
3
11
  export const selectTaskDetails = state =>
4
12
  selectForemanTasks(state).taskDetails || {};
5
13
 
6
- export const selectStartAt = state => selectTaskDetails(state).start_at || null;
14
+ export const selectTaskDetailsResponse = state =>
15
+ selectAPIResponse(state, FOREMAN_TASK_DETAILS);
16
+
17
+ export const selectStartAt = state =>
18
+ selectTaskDetailsResponse(state)?.start_at;
7
19
 
8
20
  export const selectStartBefore = state =>
9
- selectTaskDetails(state).start_before || null;
21
+ selectTaskDetailsResponse(state)?.start_before;
10
22
 
11
23
  export const selectStartedAt = state =>
12
- selectTaskDetails(state).started_at || null;
24
+ selectTaskDetailsResponse(state)?.started_at;
13
25
 
14
- export const selectEndedAt = state => selectTaskDetails(state).ended_at || null;
26
+ export const selectEndedAt = state =>
27
+ selectTaskDetailsResponse(state)?.ended_at;
15
28
 
16
- export const selectInput = state => selectTaskDetails(state).input || [];
29
+ export const selectInput = state =>
30
+ selectTaskDetailsResponse(state).input || [];
17
31
 
18
- export const selectOutput = state => selectTaskDetails(state).output || {};
32
+ export const selectOutput = state =>
33
+ selectTaskDetailsResponse(state).output || {};
19
34
 
20
35
  export const selectResumable = state =>
21
- selectTaskDetails(state).resumable || false;
36
+ selectTaskDetailsResponse(state).resumable || false;
22
37
 
23
38
  export const selectCancellable = state =>
24
- selectTaskDetails(state).cancellable || false;
39
+ selectTaskDetailsResponse(state).cancellable || false;
25
40
 
26
41
  export const selectErrors = state => {
27
- const { humanized } = selectTaskDetails(state);
42
+ const { humanized } = selectTaskDetailsResponse(state);
28
43
  return humanized ? humanized.errors : [];
29
44
  };
30
45
 
31
46
  export const selectProgress = state =>
32
- selectTaskDetails(state).progress
33
- ? parseFloat((selectTaskDetails(state).progress * 100).toFixed(2))
47
+ selectTaskDetailsResponse(state).progress
48
+ ? Math.trunc(selectTaskDetailsResponse(state).progress * 100)
34
49
  : 0;
35
50
 
36
51
  export const selectUsername = state =>
37
- selectTaskDetails(state).username || null;
52
+ selectTaskDetailsResponse(state)?.username;
38
53
 
39
- export const selectLabel = state => selectTaskDetails(state).label || null;
54
+ export const selectLabel = state => selectTaskDetailsResponse(state)?.label;
40
55
 
41
56
  export const selectExecutionPlan = state =>
42
- selectTaskDetails(state).execution_plan || {};
57
+ selectTaskDetailsResponse(state).execution_plan || {};
43
58
 
44
59
  export const selectFailedSteps = state =>
45
- selectTaskDetails(state).failed_steps || [];
60
+ selectTaskDetailsResponse(state).failed_steps || [];
46
61
 
47
62
  export const selectRunningSteps = state =>
48
- selectTaskDetails(state).running_steps || [];
63
+ selectTaskDetailsResponse(state).running_steps || [];
49
64
 
50
- export const selectHelp = state => selectTaskDetails(state).help || null;
65
+ export const selectHelp = state => selectTaskDetailsResponse(state)?.help;
51
66
 
52
67
  export const selectHasSubTasks = state =>
53
- selectTaskDetails(state).has_sub_tasks || false;
68
+ selectTaskDetailsResponse(state).has_sub_tasks || false;
54
69
 
55
- export const selectLocks = state => selectTaskDetails(state).locks || [];
70
+ export const selectLocks = state =>
71
+ selectTaskDetailsResponse(state).locks || [];
56
72
 
57
73
  export const selectUsernamePath = state =>
58
- selectTaskDetails(state).username_path || null;
74
+ selectTaskDetailsResponse(state)?.username_path;
59
75
 
60
- export const selectAction = state => selectTaskDetails(state).action || '';
76
+ export const selectAction = state =>
77
+ selectTaskDetailsResponse(state).action || '';
61
78
 
62
- export const selectState = state => selectTaskDetails(state).state || null;
79
+ export const selectState = state => selectTaskDetailsResponse(state)?.state;
63
80
 
64
- export const selectResult = state => selectTaskDetails(state).result || null;
81
+ export const selectResult = state => selectTaskDetailsResponse(state)?.result;
65
82
 
66
83
  export const selectTimeoutId = state =>
67
- selectTaskDetails(state).timeoutId || null;
84
+ selectTaskDetailsResponse(state)?.timeoutId;
68
85
 
69
86
  export const selectTaskReload = state =>
70
- selectTaskDetails(state).taskReload || false;
87
+ !!selectDoesIntervalExist(state, FOREMAN_TASK_DETAILS);
71
88
 
72
89
  export const selectParentTask = state =>
73
- selectTaskDetails(state).parent_task_id || '';
90
+ selectTaskDetailsResponse(state).parent_task_id || '';
74
91
 
75
92
  export const selectExternalId = state =>
76
- selectTaskDetails(state).external_id || null;
93
+ selectTaskDetailsResponse(state)?.external_id;
77
94
 
78
95
  export const selectDynflowEnableConsole = state =>
79
- selectTaskDetails(state).dynflow_enable_console || false;
96
+ selectTaskDetailsResponse(state).dynflow_enable_console || false;
97
+
98
+ export const selectCanEdit = state =>
99
+ selectTaskDetailsResponse(state).can_edit || false;
100
+
101
+ export const selectStatus = state => selectTaskDetailsResponse(state).status;
102
+
103
+ export const selectAPIError = state =>
104
+ selectTaskDetailsResponse(state)?.APIerror;
105
+
106
+ export const selectIsLoading = state =>
107
+ !!selectAPIByKey(state, FOREMAN_TASK_DETAILS).response &&
108
+ selectStatus(state) === STATUS.PENDING;