foreman-tasks 2.0.0 → 3.0.2

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 (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;