foreman-tasks 0.16.0 → 0.16.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.babelrc +4 -1
- data/.eslintrc +4 -13
- data/app/assets/stylesheets/foreman_tasks/application.css.scss +0 -37
- data/app/controllers/foreman_tasks/api/tasks_controller.rb +9 -5
- data/app/controllers/foreman_tasks/tasks_controller.rb +23 -19
- data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +28 -29
- data/app/lib/actions/bulk_action.rb +1 -1
- data/app/models/foreman_tasks/task.rb +1 -1
- data/app/models/foreman_tasks/task/dynflow_task.rb +30 -0
- data/app/services/foreman_tasks/troubleshooting_help_generator.rb +4 -0
- data/app/views/foreman_tasks/api/tasks/details.json.rabl +18 -0
- data/app/views/foreman_tasks/layouts/react.html.erb +1 -1
- data/app/views/foreman_tasks/tasks/index.html.erb +3 -0
- data/app/views/foreman_tasks/tasks/show.html.erb +10 -134
- data/config/routes.rb +3 -0
- data/lib/foreman_tasks/engine.rb +1 -1
- data/lib/foreman_tasks/tasks/export_tasks.rake +1 -2
- data/lib/foreman_tasks/version.rb +1 -1
- data/package.json +6 -20
- data/test/controllers/tasks_controller_test.rb +11 -0
- data/test/helpers/foreman_tasks/foreman_tasks_helper_test.rb +39 -0
- data/test/unit/actions/bulk_action_test.rb +2 -0
- data/test/unit/task_test.rb +4 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Errors.js +60 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Locks.js +46 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Raw.js +73 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/RunningSteps.js +55 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +202 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskHelper.js +38 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +238 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Errors.test.js +36 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Locks.test.js +28 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Raw.test.js +27 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +29 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +18 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskHelper.test.js +77 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskInfo.test.js +60 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Errors.test.js.snap +77 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Locks.test.js.snap +108 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Raw.test.js.snap +174 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/RunningSteps.test.js.snap +62 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +282 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskHelper.test.js.snap +37 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +568 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +87 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.scss +63 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.stories.js +5 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +109 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsConstants.js +18 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsReducer.js +44 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +83 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TasksDetailsHelper.js +1 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +12 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +20 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsReducer.test.js +33 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +97 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap +43 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsReducer.test.js.snap +26 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/integration.test.js.snap +122 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/integration.test.js +63 -0
- data/webpack/ForemanTasks/Components/TaskDetails/index.js +77 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.js +6 -1
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/__snapshots__/PausedTasksCard.test.js.snap +2 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.js +6 -1
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/__snapshots__/RunningTasksCard.test.js.snap +2 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.js +3 -6
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.scss +0 -3
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/__snapshots__/ScheduledTasksCard.test.js.snap +3 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js +2 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.scss +0 -4
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCardHelper.js +3 -3
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCard.test.js.snap +495 -54
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.js +1 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.scss +6 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.scss +0 -3
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.scss +1 -1
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboard.scss +2 -2
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/index.js +83 -0
- data/webpack/ForemanTasks/ForemanTasksReducers.js +2 -0
- data/webpack/__mocks__/foremanReact/common/I18n.js +2 -0
- data/webpack/__mocks__/foremanReact/components/Layout/LayoutActions.js +2 -0
- data/webpack/index.js +5 -0
- metadata +46 -9
- data/app/views/foreman_tasks/tasks/_details.html.erb +0 -195
- data/app/views/foreman_tasks/tasks/_errors.html.erb +0 -42
- data/app/views/foreman_tasks/tasks/_locks.html.erb +0 -19
- data/app/views/foreman_tasks/tasks/_raw.html.erb +0 -28
- data/app/views/foreman_tasks/tasks/_running_steps.html.erb +0 -40
@@ -0,0 +1,87 @@
|
|
1
|
+
import React, { Component } from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { Tab, Tabs } from 'patternfly-react';
|
4
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
5
|
+
import Task from './Components/Task';
|
6
|
+
import RunningSteps from './Components/RunningSteps';
|
7
|
+
import Errors from './Components/Errors';
|
8
|
+
import Locks from './Components/Locks';
|
9
|
+
import Raw from './Components/Raw';
|
10
|
+
import { getTaskID } from './TasksDetailsHelper';
|
11
|
+
|
12
|
+
import './TaskDetails.scss';
|
13
|
+
|
14
|
+
class TaskDetails extends Component {
|
15
|
+
componentDidMount() {
|
16
|
+
const { timeoutId, refetchTaskDetails, fetchTaskDetails } = this.props;
|
17
|
+
|
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;
|
39
|
+
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>
|
64
|
+
);
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
TaskDetails.propTypes = {
|
69
|
+
label: PropTypes.string,
|
70
|
+
fetchTaskDetails: PropTypes.func,
|
71
|
+
...Task.propTypes,
|
72
|
+
...RunningSteps.propTypes,
|
73
|
+
...Errors.propTypes,
|
74
|
+
...Locks.propTypes,
|
75
|
+
...Raw.propTypes,
|
76
|
+
};
|
77
|
+
TaskDetails.defaultProps = {
|
78
|
+
label: '',
|
79
|
+
fetchTaskDetails: () => null,
|
80
|
+
...Task.defaultProps,
|
81
|
+
...RunningSteps.defaultProps,
|
82
|
+
...Errors.defaultProps,
|
83
|
+
...Locks.defaultProps,
|
84
|
+
...Raw.defaultProps,
|
85
|
+
};
|
86
|
+
|
87
|
+
export default TaskDetails;
|
@@ -0,0 +1,63 @@
|
|
1
|
+
.task-details-react {
|
2
|
+
.progress-label-top-right {
|
3
|
+
font-size: 11px;
|
4
|
+
text-align: right;
|
5
|
+
}
|
6
|
+
a,
|
7
|
+
button {
|
8
|
+
margin-right: 3px;
|
9
|
+
}
|
10
|
+
.container {
|
11
|
+
margin: 0;
|
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
|
+
.spin {
|
28
|
+
-webkit-animation: spin 1s infinite linear;
|
29
|
+
-moz-animation: spin 1s infinite linear;
|
30
|
+
-o-animation: spin 1s infinite linear;
|
31
|
+
animation: spin 1s infinite linear;
|
32
|
+
-webkit-transform-origin: 50% 50%;
|
33
|
+
transform-origin: 50% 50%;
|
34
|
+
-ms-transform-origin: 50% 50%; /* IE 9 */
|
35
|
+
}
|
36
|
+
|
37
|
+
@-moz-keyframes spin {
|
38
|
+
from {
|
39
|
+
-moz-transform: rotate(0deg);
|
40
|
+
}
|
41
|
+
to {
|
42
|
+
-moz-transform: rotate(360deg);
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
@-webkit-keyframes spin {
|
47
|
+
from {
|
48
|
+
-webkit-transform: rotate(0deg);
|
49
|
+
}
|
50
|
+
to {
|
51
|
+
-webkit-transform: rotate(360deg);
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
@keyframes spin {
|
56
|
+
from {
|
57
|
+
transform: rotate(0deg);
|
58
|
+
}
|
59
|
+
to {
|
60
|
+
transform: rotate(360deg);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
@@ -0,0 +1,109 @@
|
|
1
|
+
import API from 'foremanReact/API';
|
2
|
+
import {
|
3
|
+
showLoading,
|
4
|
+
hideLoading,
|
5
|
+
} from 'foremanReact/components/Layout/LayoutActions';
|
6
|
+
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
|
+
FOREMAN_TASK_DETAILS_TOGGLE_UNLOCK_MODAL,
|
13
|
+
FOREMAN_TASK_DETAILS_TOGGLE_FORCE_UNLOCK_MODAL,
|
14
|
+
} from './TaskDetailsConstants';
|
15
|
+
|
16
|
+
export const taskReloadStop = timeoutId => {
|
17
|
+
if (timeoutId) {
|
18
|
+
clearTimeout(timeoutId);
|
19
|
+
}
|
20
|
+
return {
|
21
|
+
type: FOREMAN_TASK_DETAILS_STOP_POLLING,
|
22
|
+
payload: { timeoutId },
|
23
|
+
};
|
24
|
+
};
|
25
|
+
|
26
|
+
export const taskReloadStart = (
|
27
|
+
timeoutId,
|
28
|
+
refetchTaskDetails,
|
29
|
+
id,
|
30
|
+
loading = false
|
31
|
+
) => {
|
32
|
+
if (!timeoutId) {
|
33
|
+
timeoutId = setInterval(() => refetchTaskDetails(id, loading), 5000);
|
34
|
+
}
|
35
|
+
return {
|
36
|
+
type: FOREMAN_TASK_DETAILS_START_POLLING,
|
37
|
+
payload: { timeoutId },
|
38
|
+
};
|
39
|
+
};
|
40
|
+
|
41
|
+
export const refetchTaskDetails = (id, loading) => dispatch => {
|
42
|
+
if (!loading) {
|
43
|
+
showLoading();
|
44
|
+
dispatch(startRequest());
|
45
|
+
reloadTasksDetails(id, dispatch);
|
46
|
+
}
|
47
|
+
};
|
48
|
+
|
49
|
+
const reloadTasksDetails = async (id, dispatch) => {
|
50
|
+
try {
|
51
|
+
const { data } = await API.get(`/foreman_tasks/api/tasks/${id}/details`);
|
52
|
+
dispatch(requestSuccess(data));
|
53
|
+
} catch (error) {
|
54
|
+
dispatch(requestFailure(error));
|
55
|
+
document.location.reload();
|
56
|
+
} finally {
|
57
|
+
hideLoading();
|
58
|
+
}
|
59
|
+
};
|
60
|
+
|
61
|
+
export const fetchTaskDetails = (
|
62
|
+
id,
|
63
|
+
timeoutId,
|
64
|
+
refetchTaskDetailsAction
|
65
|
+
) => dispatch => {
|
66
|
+
showLoading();
|
67
|
+
dispatch(startRequest());
|
68
|
+
getTasksDetails(id, dispatch, timeoutId, refetchTaskDetailsAction);
|
69
|
+
};
|
70
|
+
|
71
|
+
const getTasksDetails = async (
|
72
|
+
id,
|
73
|
+
dispatch,
|
74
|
+
timeoutId,
|
75
|
+
refetchTaskDetailsAction
|
76
|
+
) => {
|
77
|
+
try {
|
78
|
+
const { data } = await API.get(`/foreman_tasks/api/tasks/${id}/details`);
|
79
|
+
dispatch(requestSuccess(data));
|
80
|
+
if (data.state !== 'stopped') {
|
81
|
+
dispatch(taskReloadStart(timeoutId, refetchTaskDetailsAction, id));
|
82
|
+
}
|
83
|
+
} catch (error) {
|
84
|
+
dispatch(requestFailure(error));
|
85
|
+
} finally {
|
86
|
+
hideLoading();
|
87
|
+
}
|
88
|
+
};
|
89
|
+
|
90
|
+
const startRequest = () => ({
|
91
|
+
type: FOREMAN_TASK_DETAILS_FETCH_TASK_REQUEST,
|
92
|
+
});
|
93
|
+
|
94
|
+
const requestSuccess = data => ({
|
95
|
+
type: FOREMAN_TASK_DETAILS_FETCH_TASK_SUCCESS,
|
96
|
+
payload: data,
|
97
|
+
});
|
98
|
+
|
99
|
+
const requestFailure = error => ({
|
100
|
+
type: FOREMAN_TASK_DETAILS_FETCH_TASK_FAILURE,
|
101
|
+
payload: error,
|
102
|
+
});
|
103
|
+
|
104
|
+
export const toggleUnlockModal = () => ({
|
105
|
+
type: FOREMAN_TASK_DETAILS_TOGGLE_UNLOCK_MODAL,
|
106
|
+
});
|
107
|
+
export const toggleForceUnlockModal = () => ({
|
108
|
+
type: FOREMAN_TASK_DETAILS_TOGGLE_FORCE_UNLOCK_MODAL,
|
109
|
+
});
|
@@ -0,0 +1,18 @@
|
|
1
|
+
export const FOREMAN_TASK_DETAILS_INIT = 'FOREMAN_TASK_DETAILS_INIT';
|
2
|
+
|
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';
|
14
|
+
|
15
|
+
export const FOREMAN_TASK_DETAILS_TOGGLE_UNLOCK_MODAL =
|
16
|
+
'FOREMAN_TASK_DETAILS_TOGGLE_UNLOCK_MODAL';
|
17
|
+
export const FOREMAN_TASK_DETAILS_TOGGLE_FORCE_UNLOCK_MODAL =
|
18
|
+
'FOREMAN_TASK_DETAILS_TOGGLE_FORCE_UNLOCK_MODAL';
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import Immutable from 'seamless-immutable';
|
2
|
+
import {
|
3
|
+
FOREMAN_TASK_DETAILS_FETCH_TASK_REQUEST,
|
4
|
+
FOREMAN_TASK_DETAILS_FETCH_TASK_SUCCESS,
|
5
|
+
FOREMAN_TASK_DETAILS_STOP_POLLING,
|
6
|
+
FOREMAN_TASK_DETAILS_START_POLLING,
|
7
|
+
FOREMAN_TASK_DETAILS_TOGGLE_UNLOCK_MODAL,
|
8
|
+
FOREMAN_TASK_DETAILS_TOGGLE_FORCE_UNLOCK_MODAL,
|
9
|
+
} from './TaskDetailsConstants';
|
10
|
+
|
11
|
+
const initialState = Immutable({});
|
12
|
+
|
13
|
+
export default (state = initialState, action) => {
|
14
|
+
const { type, payload } = action;
|
15
|
+
let { taskReload, timeoutId } = state;
|
16
|
+
|
17
|
+
switch (type) {
|
18
|
+
case FOREMAN_TASK_DETAILS_FETCH_TASK_REQUEST:
|
19
|
+
return state.set('loading', true);
|
20
|
+
case FOREMAN_TASK_DETAILS_FETCH_TASK_SUCCESS:
|
21
|
+
if (payload.state === 'stopped') {
|
22
|
+
clearTimeout(state.timeoutId);
|
23
|
+
taskReload = false;
|
24
|
+
timeoutId = null;
|
25
|
+
}
|
26
|
+
return state.merge({
|
27
|
+
loading: false,
|
28
|
+
...payload,
|
29
|
+
taskReload,
|
30
|
+
timeoutId,
|
31
|
+
});
|
32
|
+
case FOREMAN_TASK_DETAILS_STOP_POLLING:
|
33
|
+
return state.merge({ taskReload: false, timeoutId: null });
|
34
|
+
case FOREMAN_TASK_DETAILS_START_POLLING:
|
35
|
+
clearTimeout(state.timeoutId);
|
36
|
+
return state.merge({ taskReload: true, timeoutId: payload.timeoutId });
|
37
|
+
case FOREMAN_TASK_DETAILS_TOGGLE_UNLOCK_MODAL:
|
38
|
+
return state.set('showUnlockModal', !state.showUnlockModal);
|
39
|
+
case FOREMAN_TASK_DETAILS_TOGGLE_FORCE_UNLOCK_MODAL:
|
40
|
+
return state.set('showForceUnlockModal', !state.showForceUnlockModal);
|
41
|
+
default:
|
42
|
+
return state;
|
43
|
+
}
|
44
|
+
};
|
@@ -0,0 +1,83 @@
|
|
1
|
+
import { selectForemanTasks } from '../../ForemanTasksSelectors';
|
2
|
+
|
3
|
+
export const selectTaskDetails = state =>
|
4
|
+
selectForemanTasks(state).taskDetails || {};
|
5
|
+
|
6
|
+
export const selectStartAt = state => selectTaskDetails(state).start_at || null;
|
7
|
+
|
8
|
+
export const selectStartBefore = state =>
|
9
|
+
selectTaskDetails(state).start_before || null;
|
10
|
+
|
11
|
+
export const selectStartedAt = state =>
|
12
|
+
selectTaskDetails(state).started_at || null;
|
13
|
+
|
14
|
+
export const selectEndedAt = state => selectTaskDetails(state).ended_at || null;
|
15
|
+
|
16
|
+
export const selectInput = state => selectTaskDetails(state).input || [];
|
17
|
+
|
18
|
+
export const selectOutput = state => selectTaskDetails(state).output || {};
|
19
|
+
|
20
|
+
export const selectResumable = state =>
|
21
|
+
selectTaskDetails(state).resumable || false;
|
22
|
+
|
23
|
+
export const selectCancellable = state =>
|
24
|
+
selectTaskDetails(state).cancellable || false;
|
25
|
+
|
26
|
+
export const selectErrors = state => {
|
27
|
+
const { humanized } = selectTaskDetails(state);
|
28
|
+
return humanized ? humanized.errors : [];
|
29
|
+
};
|
30
|
+
|
31
|
+
export const selectProgress = state =>
|
32
|
+
selectTaskDetails(state).progress * 100 || 0;
|
33
|
+
|
34
|
+
export const selectUsername = state =>
|
35
|
+
selectTaskDetails(state).username || null;
|
36
|
+
|
37
|
+
export const selectLabel = state => selectTaskDetails(state).label || null;
|
38
|
+
|
39
|
+
export const selectExecutionPlan = state =>
|
40
|
+
selectTaskDetails(state).execution_plan || {};
|
41
|
+
|
42
|
+
export const selectFailedSteps = state =>
|
43
|
+
selectTaskDetails(state).failed_steps || [];
|
44
|
+
|
45
|
+
export const selectRunningSteps = state =>
|
46
|
+
selectTaskDetails(state).running_steps || [];
|
47
|
+
|
48
|
+
export const selectHelp = state => selectTaskDetails(state).help || null;
|
49
|
+
|
50
|
+
export const selectHasSubTasks = state =>
|
51
|
+
selectTaskDetails(state).has_sub_tasks || false;
|
52
|
+
|
53
|
+
export const selectAllowDangerousActions = state =>
|
54
|
+
selectTaskDetails(state).allowDangerousActions || false;
|
55
|
+
|
56
|
+
export const selectLocks = state => selectTaskDetails(state).locks || [];
|
57
|
+
|
58
|
+
export const selectUsernamePath = state =>
|
59
|
+
selectTaskDetails(state).username_path || null;
|
60
|
+
|
61
|
+
export const selectAction = state => selectTaskDetails(state).action || null;
|
62
|
+
|
63
|
+
export const selectState = state => selectTaskDetails(state).state || null;
|
64
|
+
|
65
|
+
export const selectResult = state => selectTaskDetails(state).result || null;
|
66
|
+
|
67
|
+
export const selectTimeoutId = state =>
|
68
|
+
selectTaskDetails(state).timeoutId || null;
|
69
|
+
|
70
|
+
export const selectTaskReload = state =>
|
71
|
+
selectTaskDetails(state).taskReload || false;
|
72
|
+
|
73
|
+
export const selectParentTask = state =>
|
74
|
+
selectTaskDetails(state).parent_task_id || '';
|
75
|
+
|
76
|
+
export const selectShowUnlockModal = state =>
|
77
|
+
selectTaskDetails(state).showUnlockModal || false;
|
78
|
+
|
79
|
+
export const selectShowForceUnlockModal = state =>
|
80
|
+
selectTaskDetails(state).showForceUnlockModal || false;
|
81
|
+
|
82
|
+
export const selectExternalId = state =>
|
83
|
+
selectTaskDetails(state).external_id || null;
|
@@ -0,0 +1 @@
|
|
1
|
+
export const getTaskID = () => window.location.pathname.split('/').slice(-1)[0];
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
|
2
|
+
|
3
|
+
import TaskDetails from '../TaskDetails';
|
4
|
+
|
5
|
+
const fixtures = {
|
6
|
+
'render without Props': {},
|
7
|
+
};
|
8
|
+
|
9
|
+
describe('TaskDetails', () => {
|
10
|
+
describe('rendering', () =>
|
11
|
+
testComponentSnapshotsWithFixtures(TaskDetails, fixtures));
|
12
|
+
});
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { testActionSnapshotWithFixtures } from 'react-redux-test-utils';
|
2
|
+
import API from 'foremanReact/API';
|
3
|
+
import {
|
4
|
+
taskReloadStop,
|
5
|
+
taskReloadStart,
|
6
|
+
fetchTaskDetails,
|
7
|
+
} from '../TaskDetailsActions';
|
8
|
+
|
9
|
+
jest.mock('foremanReact/API');
|
10
|
+
|
11
|
+
API.get.mockImplementation(async () => ({ data: 'some-data' }));
|
12
|
+
|
13
|
+
const fixtures = {
|
14
|
+
'should start reload': () => taskReloadStart(1),
|
15
|
+
'should stop reload': () => taskReloadStop(2),
|
16
|
+
'should fetch-task-details and success': () => fetchTaskDetails(),
|
17
|
+
};
|
18
|
+
|
19
|
+
describe('TaskDetails - Actions', () =>
|
20
|
+
testActionSnapshotWithFixtures(fixtures));
|