foreman-tasks 13.0.0 → 13.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/services/foreman_tasks/troubleshooting_help_generator.rb +1 -1
- data/lib/foreman_tasks/version.rb +1 -1
- data/webpack/ForemanTasks/Components/Chart/Chart.js +3 -1
- data/webpack/ForemanTasks/Components/TaskActions/TaskActionHelpers.js +8 -1
- data/webpack/ForemanTasks/Components/TaskActions/TaskActionsConstants.js +1 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +8 -70
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskButtons.js +115 -104
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskButtons.scss +45 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskHelper.js +58 -1
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +236 -131
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +27 -33
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskButtons.test.js +83 -67
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskHelper.test.js +118 -1
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskInfo.test.js +190 -20
- data/webpack/ForemanTasks/Components/TaskDetails/ExecutionDetails.js +71 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +48 -51
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.scss +1 -39
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +6 -2
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsConstants.js +2 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +2 -7
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/ExecutionDetails.test.js +241 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.fixtures.js +99 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +129 -8
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.scss +0 -1
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.scss +1 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.scss +1 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardHelper.js +9 -4
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableHelpers.js +2 -1
- data/webpack/ForemanTasks/Components/common/taskResultIcon.js +39 -29
- data/webpack/ForemanTasks/Routes/ShowTaskDetails/TaskDetailsHeader.js +174 -0
- data/webpack/ForemanTasks/Routes/ShowTaskDetails/TaskDetailsHeader.scss +5 -0
- data/webpack/ForemanTasks/Routes/ShowTaskDetails/TaskDetailsPage.js +10 -33
- data/webpack/ForemanTasks/Routes/ShowTaskDetails/__tests__/TaskDetailsHeader.test.js +142 -0
- data/webpack/ForemanTasks/Routes/ShowTaskDetails/__tests__/TaskDetailsPage.test.js +100 -88
- data/webpack/ForemanTasks/{Components/TaskDetails → Routes/ShowTaskDetails}/index.js +7 -8
- data/webpack/Routes/routes.js +1 -1
- data/webpack/Routes/routes.test.js +1 -1
- data/webpack/index.js +0 -5
- metadata +9 -3
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import RunningSteps from './Components/RunningSteps';
|
|
4
|
+
import Errors from './Components/Errors';
|
|
5
|
+
|
|
6
|
+
const ExecutionDetails = ({
|
|
7
|
+
state,
|
|
8
|
+
runningSteps,
|
|
9
|
+
cancelStep,
|
|
10
|
+
id,
|
|
11
|
+
taskReload,
|
|
12
|
+
taskReloadStart,
|
|
13
|
+
executionPlan,
|
|
14
|
+
failedSteps,
|
|
15
|
+
result,
|
|
16
|
+
}) => {
|
|
17
|
+
const hasFailedSteps = failedSteps.length > 0;
|
|
18
|
+
const hasRunningSteps = runningSteps.length > 0;
|
|
19
|
+
const isActiveExecutionState =
|
|
20
|
+
state === 'running' || state === 'pending' || state === 'paused';
|
|
21
|
+
|
|
22
|
+
// Prefer Errors when failed steps exist (e.g. paused-after-error). Only fall
|
|
23
|
+
// back to the RunningSteps empty state for active tasks with no failures.
|
|
24
|
+
const showRunningSteps =
|
|
25
|
+
hasRunningSteps || (isActiveExecutionState && !hasFailedSteps);
|
|
26
|
+
const showErrors = hasFailedSteps || !showRunningSteps;
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div
|
|
30
|
+
id="execution-details-panel"
|
|
31
|
+
data-ouia-component-id="execution-details-panel"
|
|
32
|
+
>
|
|
33
|
+
{showRunningSteps && (
|
|
34
|
+
<RunningSteps
|
|
35
|
+
executionPlan={executionPlan}
|
|
36
|
+
result={result}
|
|
37
|
+
runningSteps={runningSteps}
|
|
38
|
+
id={id}
|
|
39
|
+
cancelStep={cancelStep}
|
|
40
|
+
taskReload={taskReload}
|
|
41
|
+
taskReloadStart={taskReloadStart}
|
|
42
|
+
/>
|
|
43
|
+
)}
|
|
44
|
+
{showErrors && (
|
|
45
|
+
<Errors executionPlan={executionPlan} failedSteps={failedSteps} />
|
|
46
|
+
)}
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
ExecutionDetails.propTypes = {
|
|
52
|
+
state: PropTypes.string,
|
|
53
|
+
result: PropTypes.string,
|
|
54
|
+
runningSteps: PropTypes.array,
|
|
55
|
+
cancelStep: PropTypes.func.isRequired,
|
|
56
|
+
id: PropTypes.string.isRequired,
|
|
57
|
+
taskReload: PropTypes.bool.isRequired,
|
|
58
|
+
taskReloadStart: PropTypes.func.isRequired,
|
|
59
|
+
executionPlan: PropTypes.shape({}),
|
|
60
|
+
failedSteps: PropTypes.array,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
ExecutionDetails.defaultProps = {
|
|
64
|
+
state: '',
|
|
65
|
+
result: undefined,
|
|
66
|
+
runningSteps: [],
|
|
67
|
+
executionPlan: {},
|
|
68
|
+
failedSteps: [],
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export default ExecutionDetails;
|
|
@@ -6,17 +6,22 @@ import { STATUS } from 'foremanReact/constants';
|
|
|
6
6
|
import { usePermissions } from 'foremanReact/common/hooks/Permissions/permissionHooks';
|
|
7
7
|
import { ResourceLoadFailedEmptyState } from 'foremanReact/components/common/EmptyState';
|
|
8
8
|
import Task from './Components/Task';
|
|
9
|
-
import RunningSteps from './Components/RunningSteps';
|
|
10
|
-
import Errors from './Components/Errors';
|
|
11
9
|
import Locks from './Components/Locks';
|
|
12
10
|
import Raw from './Components/Raw';
|
|
11
|
+
import ExecutionDetails from './ExecutionDetails';
|
|
13
12
|
import Dependencies from './Components/Dependencies';
|
|
14
13
|
import { TASKS_PATH, VIEW_FOREMAN_TASKS } from './TaskDetailsConstants';
|
|
15
|
-
import { getTaskID } from './TasksDetailsHelper';
|
|
16
14
|
import { TaskSkeleton } from './Components/TaskSkeleton';
|
|
17
15
|
|
|
18
16
|
import './TaskDetails.scss';
|
|
19
17
|
|
|
18
|
+
export const TASK_DETAILS_TAB_KEYS = Object.freeze({
|
|
19
|
+
EXECUTION: 'execution',
|
|
20
|
+
DEPENDENCIES: 'dependencies',
|
|
21
|
+
LOCKS: 'locks',
|
|
22
|
+
RAW: 'raw',
|
|
23
|
+
});
|
|
24
|
+
|
|
20
25
|
const TaskDetails = ({
|
|
21
26
|
executionPlan,
|
|
22
27
|
failedSteps,
|
|
@@ -31,11 +36,11 @@ const TaskDetails = ({
|
|
|
31
36
|
apiStatus,
|
|
32
37
|
apiErrorMessage,
|
|
33
38
|
apiErrorCode,
|
|
39
|
+
id,
|
|
34
40
|
...props
|
|
35
41
|
}) => {
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const [activeTabKey, setActiveTabKey] = useState(1);
|
|
42
|
+
const { taskReload, isLoading } = props;
|
|
43
|
+
const [activeTab, setActiveTab] = useState(TASK_DETAILS_TAB_KEYS.EXECUTION);
|
|
39
44
|
const hasViewPermission = usePermissions([VIEW_FOREMAN_TASKS]);
|
|
40
45
|
|
|
41
46
|
useEffect(() => {
|
|
@@ -76,7 +81,7 @@ const TaskDetails = ({
|
|
|
76
81
|
const cancellable = executionPlan ? executionPlan.cancellable : false;
|
|
77
82
|
const lockRecords = locks.concat(links);
|
|
78
83
|
|
|
79
|
-
const
|
|
84
|
+
const taskProps = {
|
|
80
85
|
...props,
|
|
81
86
|
cancellable,
|
|
82
87
|
resumable,
|
|
@@ -87,49 +92,49 @@ const TaskDetails = ({
|
|
|
87
92
|
|
|
88
93
|
return (
|
|
89
94
|
<div className="task-details-react">
|
|
95
|
+
<section className="task-details-overview-section">
|
|
96
|
+
{isLoading ? <TaskSkeleton /> : <Task {...taskProps} />}
|
|
97
|
+
</section>
|
|
90
98
|
<Tabs
|
|
99
|
+
aria-label={__('Task details')}
|
|
91
100
|
id="task-details-tabs"
|
|
92
101
|
ouiaId="task-details-tabs"
|
|
93
|
-
activeKey={
|
|
94
|
-
onSelect={(_event, tabKey) => setActiveTabKey(tabKey)}
|
|
102
|
+
activeKey={activeTab}
|
|
95
103
|
mountOnEnter
|
|
104
|
+
onSelect={(_e, tabKey) => setActiveTab(tabKey)}
|
|
96
105
|
>
|
|
97
106
|
<Tab
|
|
98
|
-
eventKey={1}
|
|
99
|
-
title={<TabTitleText>{__('Task')}</TabTitleText>}
|
|
100
|
-
aria-label={__('Task')}
|
|
101
|
-
ouiaId="task-details-tab-task"
|
|
102
|
-
>
|
|
103
|
-
{isLoading ? <TaskSkeleton /> : <Task {...taskComponentProps} />}
|
|
104
|
-
</Tab>
|
|
105
|
-
<Tab
|
|
106
|
-
eventKey={2}
|
|
107
|
-
title={<TabTitleText>{__('Running Steps')}</TabTitleText>}
|
|
108
107
|
isDisabled={isLoading}
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
eventKey={TASK_DETAILS_TAB_KEYS.EXECUTION}
|
|
109
|
+
title={<TabTitleText>{__('Execution details')}</TabTitleText>}
|
|
110
|
+
aria-label={__('Execution details')}
|
|
111
|
+
ouiaId="task-details-tab-execution-details"
|
|
111
112
|
>
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
{!isLoading && (
|
|
114
|
+
<ExecutionDetails
|
|
115
|
+
state={props.state}
|
|
116
|
+
result={props.result}
|
|
117
|
+
runningSteps={runningSteps}
|
|
118
|
+
cancelStep={cancelStep}
|
|
119
|
+
id={id}
|
|
120
|
+
taskReload={taskReload}
|
|
121
|
+
taskReloadStart={taskReloadStart}
|
|
122
|
+
executionPlan={executionPlan}
|
|
123
|
+
failedSteps={failedSteps}
|
|
124
|
+
/>
|
|
125
|
+
)}
|
|
121
126
|
</Tab>
|
|
122
127
|
<Tab
|
|
123
|
-
eventKey={
|
|
124
|
-
title={<TabTitleText>{__('Errors')}</TabTitleText>}
|
|
128
|
+
eventKey={TASK_DETAILS_TAB_KEYS.DEPENDENCIES}
|
|
125
129
|
isDisabled={isLoading}
|
|
126
|
-
|
|
127
|
-
|
|
130
|
+
title={<TabTitleText>{__('Dependencies')}</TabTitleText>}
|
|
131
|
+
aria-label={__('Dependencies')}
|
|
132
|
+
ouiaId="task-details-tab-dependencies"
|
|
128
133
|
>
|
|
129
|
-
<
|
|
134
|
+
<Dependencies dependsOn={dependsOn} blocks={blocks} />
|
|
130
135
|
</Tab>
|
|
131
136
|
<Tab
|
|
132
|
-
eventKey={
|
|
137
|
+
eventKey={TASK_DETAILS_TAB_KEYS.LOCKS}
|
|
133
138
|
title={<TabTitleText>{__('Locks')}</TabTitleText>}
|
|
134
139
|
isDisabled={isLoading}
|
|
135
140
|
aria-label={__('Locks')}
|
|
@@ -138,16 +143,7 @@ const TaskDetails = ({
|
|
|
138
143
|
<Locks locks={lockRecords} />
|
|
139
144
|
</Tab>
|
|
140
145
|
<Tab
|
|
141
|
-
eventKey={
|
|
142
|
-
title={<TabTitleText>{__('Dependencies')}</TabTitleText>}
|
|
143
|
-
isDisabled={isLoading}
|
|
144
|
-
aria-label={__('Dependencies')}
|
|
145
|
-
ouiaId="task-details-tab-dependencies"
|
|
146
|
-
>
|
|
147
|
-
<Dependencies dependsOn={dependsOn} blocks={blocks} />
|
|
148
|
-
</Tab>
|
|
149
|
-
<Tab
|
|
150
|
-
eventKey={6}
|
|
146
|
+
eventKey={TASK_DETAILS_TAB_KEYS.RAW}
|
|
151
147
|
title={<TabTitleText>{__('Raw')}</TabTitleText>}
|
|
152
148
|
isDisabled={isLoading}
|
|
153
149
|
aria-label={__('Raw')}
|
|
@@ -169,7 +165,9 @@ const TaskDetails = ({
|
|
|
169
165
|
};
|
|
170
166
|
|
|
171
167
|
TaskDetails.propTypes = {
|
|
168
|
+
id: PropTypes.string.isRequired,
|
|
172
169
|
label: PropTypes.string,
|
|
170
|
+
result: PropTypes.string,
|
|
173
171
|
runningSteps: PropTypes.array,
|
|
174
172
|
cancelStep: PropTypes.func.isRequired,
|
|
175
173
|
taskReload: PropTypes.bool.isRequired,
|
|
@@ -181,10 +179,10 @@ TaskDetails.propTypes = {
|
|
|
181
179
|
links: PropTypes.array,
|
|
182
180
|
dependsOn: PropTypes.array,
|
|
183
181
|
blocks: PropTypes.array,
|
|
182
|
+
executionPlan: PropTypes.shape({}),
|
|
183
|
+
failedSteps: PropTypes.array,
|
|
184
184
|
...Task.propTypes,
|
|
185
|
-
...Errors.propTypes,
|
|
186
185
|
...Locks.propTypes,
|
|
187
|
-
...Dependencies.propTypes,
|
|
188
186
|
...Raw.propTypes,
|
|
189
187
|
};
|
|
190
188
|
TaskDetails.defaultProps = {
|
|
@@ -194,11 +192,10 @@ TaskDetails.defaultProps = {
|
|
|
194
192
|
links: [],
|
|
195
193
|
dependsOn: [],
|
|
196
194
|
blocks: [],
|
|
195
|
+
failedSteps: [],
|
|
196
|
+
executionPlan: {},
|
|
197
197
|
...Task.defaultProps,
|
|
198
|
-
...RunningSteps.defaultProps,
|
|
199
|
-
...Errors.defaultProps,
|
|
200
198
|
...Locks.defaultProps,
|
|
201
|
-
...Dependencies.defaultProps,
|
|
202
199
|
...Raw.defaultProps,
|
|
203
200
|
};
|
|
204
201
|
|
|
@@ -3,48 +3,10 @@
|
|
|
3
3
|
#pf-tab-section-1-task-details-tabs > button {
|
|
4
4
|
margin-right: 3px;
|
|
5
5
|
}
|
|
6
|
+
|
|
6
7
|
.container {
|
|
7
8
|
margin: 0;
|
|
8
9
|
}
|
|
9
|
-
.spin {
|
|
10
|
-
-webkit-animation: spin 1s infinite linear;
|
|
11
|
-
-moz-animation: spin 1s infinite linear;
|
|
12
|
-
-o-animation: spin 1s infinite linear;
|
|
13
|
-
animation: spin 1s infinite linear;
|
|
14
|
-
-webkit-transform-origin: 50% 50%;
|
|
15
|
-
transform-origin: 50% 50%;
|
|
16
|
-
-ms-transform-origin: 50% 50%; /* IE 9 */
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
@-moz-keyframes spin {
|
|
20
|
-
from {
|
|
21
|
-
-moz-transform: rotate(0deg);
|
|
22
|
-
}
|
|
23
|
-
to {
|
|
24
|
-
-moz-transform: rotate(360deg);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@-webkit-keyframes spin {
|
|
29
|
-
from {
|
|
30
|
-
-webkit-transform: rotate(0deg);
|
|
31
|
-
}
|
|
32
|
-
to {
|
|
33
|
-
-webkit-transform: rotate(360deg);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
@keyframes spin {
|
|
38
|
-
from {
|
|
39
|
-
transform: rotate(0deg);
|
|
40
|
-
}
|
|
41
|
-
to {
|
|
42
|
-
transform: rotate(360deg);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
.dynflow-button > span {
|
|
46
|
-
pointer-events: auto;
|
|
47
|
-
}
|
|
48
10
|
|
|
49
11
|
pre {
|
|
50
12
|
white-space: pre-wrap;
|
|
@@ -6,7 +6,11 @@ import {
|
|
|
6
6
|
stopInterval,
|
|
7
7
|
} from 'foremanReact/redux/middlewares/IntervalMiddleware';
|
|
8
8
|
import { foremanTasksApiPath, foremanTasksPath } from '../common/urlHelpers';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
TASK_STEP_CANCEL,
|
|
11
|
+
FOREMAN_TASK_DETAILS,
|
|
12
|
+
TASK_RELOAD_INTERVAL_MS,
|
|
13
|
+
} from './TaskDetailsConstants';
|
|
10
14
|
import {
|
|
11
15
|
errorToastData,
|
|
12
16
|
infoToastData,
|
|
@@ -30,7 +34,7 @@ export const taskReloadStart = id => dispatch => {
|
|
|
30
34
|
dispatch(stopInterval(FOREMAN_TASK_DETAILS));
|
|
31
35
|
},
|
|
32
36
|
}),
|
|
33
|
-
|
|
37
|
+
TASK_RELOAD_INTERVAL_MS
|
|
34
38
|
)
|
|
35
39
|
);
|
|
36
40
|
};
|
|
@@ -3,3 +3,5 @@ export const FOREMAN_TASK_DETAILS_SUCCESS = 'FOREMAN_TASK_DETAILS_SUCCESS';
|
|
|
3
3
|
export const TASKS_PATH = '/foreman_tasks/tasks';
|
|
4
4
|
export const TASK_STEP_CANCEL = 'TASK_STEP_CANCEL';
|
|
5
5
|
export const VIEW_FOREMAN_TASKS = 'view_foreman_tasks';
|
|
6
|
+
|
|
7
|
+
export const TASK_RELOAD_INTERVAL_MS = 5000;
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
selectAPIError as selectAPIErrorByKey,
|
|
6
6
|
} from 'foremanReact/redux/API/APISelectors';
|
|
7
7
|
import { selectDoesIntervalExist } from 'foremanReact/redux/middlewares/IntervalMiddleware/IntervalSelectors';
|
|
8
|
-
import { STATUS } from 'foremanReact/constants';
|
|
8
|
+
import { STATUS, PERCENT_MULTIPLIER } from 'foremanReact/constants';
|
|
9
9
|
import { selectForemanTasks } from '../../ForemanTasksSelectors';
|
|
10
10
|
import { FOREMAN_TASK_DETAILS } from './TaskDetailsConstants';
|
|
11
11
|
|
|
@@ -39,14 +39,9 @@ export const selectResumable = state =>
|
|
|
39
39
|
export const selectCancellable = state =>
|
|
40
40
|
selectTaskDetailsResponse(state).cancellable || false;
|
|
41
41
|
|
|
42
|
-
export const selectErrors = state => {
|
|
43
|
-
const { humanized } = selectTaskDetailsResponse(state);
|
|
44
|
-
return humanized ? humanized.errors : [];
|
|
45
|
-
};
|
|
46
|
-
|
|
47
42
|
export const selectProgress = state =>
|
|
48
43
|
selectTaskDetailsResponse(state).progress
|
|
49
|
-
? Math.trunc(selectTaskDetailsResponse(state).progress *
|
|
44
|
+
? Math.trunc(selectTaskDetailsResponse(state).progress * PERCENT_MULTIPLIER)
|
|
50
45
|
: 0;
|
|
51
46
|
|
|
52
47
|
export const selectUsername = state =>
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
|
|
5
|
+
import ExecutionDetails from '../ExecutionDetails';
|
|
6
|
+
import {
|
|
7
|
+
fixtureFailedExecutionDetail,
|
|
8
|
+
fixtureRunningExecutionDetail,
|
|
9
|
+
} from './TaskDetails.fixtures';
|
|
10
|
+
|
|
11
|
+
const rtlBaseProps = {
|
|
12
|
+
cancelStep: jest.fn(),
|
|
13
|
+
taskReloadStart: jest.fn(),
|
|
14
|
+
id: 'a15dd820-32f1-4ced-9ab7-c0fab8234c47',
|
|
15
|
+
taskReload: false,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
describe('ExecutionDetails', () => {
|
|
19
|
+
it('renders execution details panel with OUIA id', () => {
|
|
20
|
+
render(
|
|
21
|
+
<ExecutionDetails
|
|
22
|
+
{...rtlBaseProps}
|
|
23
|
+
state="stopped"
|
|
24
|
+
runningSteps={[]}
|
|
25
|
+
executionPlan={{ state: 'stopped', cancellable: false }}
|
|
26
|
+
failedSteps={[]}
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
expect(
|
|
31
|
+
document.querySelector(
|
|
32
|
+
'[data-ouia-component-id="execution-details-panel"]'
|
|
33
|
+
)
|
|
34
|
+
).toBeInTheDocument();
|
|
35
|
+
expect(
|
|
36
|
+
document.getElementById('execution-details-panel')
|
|
37
|
+
).toBeInTheDocument();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('shows Errors pane when stopped with no running steps', () => {
|
|
41
|
+
render(
|
|
42
|
+
<ExecutionDetails
|
|
43
|
+
{...rtlBaseProps}
|
|
44
|
+
state="stopped"
|
|
45
|
+
runningSteps={[]}
|
|
46
|
+
executionPlan={{ state: 'stopped', cancellable: false }}
|
|
47
|
+
failedSteps={[]}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
expect(
|
|
52
|
+
screen.getByRole('heading', { name: /^no errors found$/i })
|
|
53
|
+
).toBeInTheDocument();
|
|
54
|
+
expect(
|
|
55
|
+
screen.getByText(/the task finished with no errors or warnings/i)
|
|
56
|
+
).toBeInTheDocument();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('shows RunningSteps when stopped but runningSteps list is non-empty', () => {
|
|
60
|
+
render(
|
|
61
|
+
<ExecutionDetails
|
|
62
|
+
{...rtlBaseProps}
|
|
63
|
+
state="stopped"
|
|
64
|
+
runningSteps={[
|
|
65
|
+
{
|
|
66
|
+
cancellable: false,
|
|
67
|
+
id: 1,
|
|
68
|
+
action_class: 'Actions::Stale',
|
|
69
|
+
state: 'paused',
|
|
70
|
+
input: '{}',
|
|
71
|
+
output: '{}',
|
|
72
|
+
},
|
|
73
|
+
]}
|
|
74
|
+
executionPlan={{ state: 'stopped', cancellable: false }}
|
|
75
|
+
failedSteps={[]}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
expect(
|
|
80
|
+
screen.getByRole('heading', { name: 'Warning alert: Running step 1' })
|
|
81
|
+
).toBeInTheDocument();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('forwards executionPlan and result to RunningSteps when state is pending without steps', () => {
|
|
85
|
+
render(
|
|
86
|
+
<ExecutionDetails
|
|
87
|
+
{...rtlBaseProps}
|
|
88
|
+
state="pending"
|
|
89
|
+
runningSteps={[]}
|
|
90
|
+
executionPlan={{ state: 'planned', cancellable: false }}
|
|
91
|
+
result="pending"
|
|
92
|
+
failedSteps={[]}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(
|
|
97
|
+
screen.getByRole('heading', { level: 2, name: /planned task/i })
|
|
98
|
+
).toBeInTheDocument();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('shows temporarily suspended messaging when pending, plan running, result pending', () => {
|
|
102
|
+
render(
|
|
103
|
+
<ExecutionDetails
|
|
104
|
+
{...rtlBaseProps}
|
|
105
|
+
state="pending"
|
|
106
|
+
runningSteps={[]}
|
|
107
|
+
executionPlan={{ state: 'running', cancellable: false }}
|
|
108
|
+
result="pending"
|
|
109
|
+
failedSteps={[]}
|
|
110
|
+
/>
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
expect(
|
|
114
|
+
screen.getByRole('heading', {
|
|
115
|
+
level: 4,
|
|
116
|
+
name: /temporarily suspended step/i,
|
|
117
|
+
})
|
|
118
|
+
).toBeInTheDocument();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('routes failed steps through Errors pane when stopped', () => {
|
|
122
|
+
render(
|
|
123
|
+
<ExecutionDetails
|
|
124
|
+
{...rtlBaseProps}
|
|
125
|
+
{...fixtureFailedExecutionDetail}
|
|
126
|
+
executionPlan={fixtureFailedExecutionDetail.executionPlan}
|
|
127
|
+
failedSteps={fixtureFailedExecutionDetail.failedSteps}
|
|
128
|
+
/>
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
expect(
|
|
132
|
+
screen.getByRole('tab', {
|
|
133
|
+
name: /action actions::katello::eventqueue::monitor is already active/i,
|
|
134
|
+
})
|
|
135
|
+
).toBeInTheDocument();
|
|
136
|
+
expect(screen.getByLabelText(/failed task errors/i)).toBeInTheDocument();
|
|
137
|
+
expect(screen.getByText('Exception:')).toBeInTheDocument();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('renders RunningSteps with cancel when task is running', () => {
|
|
141
|
+
const cancelStep = jest.fn();
|
|
142
|
+
|
|
143
|
+
render(
|
|
144
|
+
<ExecutionDetails
|
|
145
|
+
{...rtlBaseProps}
|
|
146
|
+
cancelStep={cancelStep}
|
|
147
|
+
{...fixtureRunningExecutionDetail}
|
|
148
|
+
runningSteps={[
|
|
149
|
+
{
|
|
150
|
+
...fixtureRunningExecutionDetail.runningSteps[0],
|
|
151
|
+
cancellable: true,
|
|
152
|
+
},
|
|
153
|
+
]}
|
|
154
|
+
/>
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('shows RunningSteps when state is paused without running steps', () => {
|
|
161
|
+
render(
|
|
162
|
+
<ExecutionDetails
|
|
163
|
+
{...rtlBaseProps}
|
|
164
|
+
state="paused"
|
|
165
|
+
runningSteps={[]}
|
|
166
|
+
executionPlan={{ state: 'paused', cancellable: false }}
|
|
167
|
+
failedSteps={[]}
|
|
168
|
+
/>
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
expect(screen.getByText(/no running steps/i)).toBeInTheDocument();
|
|
172
|
+
expect(
|
|
173
|
+
screen.queryByRole('heading', { name: /^no errors found$/i })
|
|
174
|
+
).not.toBeInTheDocument();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('shows RunningSteps when state is paused with running steps', () => {
|
|
178
|
+
render(
|
|
179
|
+
<ExecutionDetails
|
|
180
|
+
{...rtlBaseProps}
|
|
181
|
+
state="paused"
|
|
182
|
+
runningSteps={[
|
|
183
|
+
{
|
|
184
|
+
...fixtureRunningExecutionDetail.runningSteps[0],
|
|
185
|
+
state: 'paused',
|
|
186
|
+
},
|
|
187
|
+
]}
|
|
188
|
+
executionPlan={{ state: 'paused', cancellable: false }}
|
|
189
|
+
failedSteps={[]}
|
|
190
|
+
/>
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
expect(
|
|
194
|
+
screen.getByRole('heading', { name: 'Warning alert: Running step 1' })
|
|
195
|
+
).toBeInTheDocument();
|
|
196
|
+
expect(screen.getByText('paused')).toBeInTheDocument();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('shows Errors when state is paused with failed steps', () => {
|
|
200
|
+
render(
|
|
201
|
+
<ExecutionDetails
|
|
202
|
+
{...rtlBaseProps}
|
|
203
|
+
{...fixtureFailedExecutionDetail}
|
|
204
|
+
state="paused"
|
|
205
|
+
executionPlan={{ state: 'paused', cancellable: false }}
|
|
206
|
+
runningSteps={[]}
|
|
207
|
+
/>
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
expect(
|
|
211
|
+
screen.getByRole('tab', {
|
|
212
|
+
name: /action actions::katello::eventqueue::monitor is already active/i,
|
|
213
|
+
})
|
|
214
|
+
).toBeInTheDocument();
|
|
215
|
+
expect(screen.getByLabelText(/failed task errors/i)).toBeInTheDocument();
|
|
216
|
+
expect(screen.getByText('Exception:')).toBeInTheDocument();
|
|
217
|
+
expect(screen.queryByText(/no running steps/i)).not.toBeInTheDocument();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('shows Errors and RunningSteps when paused with both failed and running steps', () => {
|
|
221
|
+
render(
|
|
222
|
+
<ExecutionDetails
|
|
223
|
+
{...rtlBaseProps}
|
|
224
|
+
{...fixtureFailedExecutionDetail}
|
|
225
|
+
state="paused"
|
|
226
|
+
executionPlan={{ state: 'paused', cancellable: false }}
|
|
227
|
+
runningSteps={[
|
|
228
|
+
{
|
|
229
|
+
...fixtureRunningExecutionDetail.runningSteps[0],
|
|
230
|
+
state: 'suspended',
|
|
231
|
+
},
|
|
232
|
+
]}
|
|
233
|
+
/>
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
expect(
|
|
237
|
+
screen.getByRole('heading', { name: 'Warning alert: Running step 1' })
|
|
238
|
+
).toBeInTheDocument();
|
|
239
|
+
expect(screen.getByLabelText(/failed task errors/i)).toBeInTheDocument();
|
|
240
|
+
});
|
|
241
|
+
});
|