foreman-tasks 12.1.0 → 12.2.1

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/app/lib/actions/helpers/lock.rb +0 -6
  4. data/app/lib/actions/middleware/keep_current_user.rb +6 -12
  5. data/app/views/foreman_tasks/api/tasks/show.json.rabl +1 -1
  6. data/foreman-tasks.gemspec +1 -3
  7. data/lib/foreman_tasks/version.rb +1 -1
  8. data/test/controllers/api/tasks_controller_test.rb +2 -2
  9. data/webpack/ForemanTasks/Components/TaskDetails/Components/Errors.js +25 -5
  10. data/webpack/ForemanTasks/Components/TaskDetails/Components/RunningSteps.js +12 -4
  11. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +217 -201
  12. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskSkeleton.js +30 -34
  13. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Dependencies.test.js +30 -30
  14. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Errors.test.js +50 -27
  15. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Raw.test.js +44 -22
  16. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +56 -24
  17. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +42 -22
  18. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskInfo.test.js +45 -54
  19. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +65 -25
  20. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +37 -13
  21. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +53 -8
  22. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.test.js +53 -7
  23. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.test.js +53 -7
  24. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.js +5 -4
  25. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.test.js +44 -14
  26. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js +6 -5
  27. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.js +5 -4
  28. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.scss +3 -8
  29. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.test.js +75 -34
  30. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.test.js +57 -34
  31. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChartHelper.test.js +23 -9
  32. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.fixtures.js +14 -11
  33. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.js +19 -21
  34. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.test.js +63 -14
  35. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.js +9 -17
  36. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.test.js +49 -13
  37. metadata +2 -45
  38. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Errors.test.js.snap +0 -77
  39. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Raw.test.js.snap +0 -174
  40. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/RunningSteps.test.js.snap +0 -62
  41. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +0 -127
  42. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +0 -580
  43. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +0 -172
  44. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap +0 -52
  45. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/__snapshots__/PausedTasksCard.test.js.snap +0 -38
  46. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/__snapshots__/RunningTasksCard.test.js.snap +0 -38
  47. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/__snapshots__/ScheduledTasksCard.test.js.snap +0 -97
  48. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/__snapshots__/TasksDonutCard.test.js.snap +0 -183
  49. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/__snapshots__/TasksDonutChart.test.js.snap +0 -302
  50. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/__snapshots__/TasksDonutChartHelper.test.js.snap +0 -21
  51. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/__snapshots__/TasksCardsGrid.test.js.snap +0 -210
  52. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/__snapshots__/TimeDropDown.test.js.snap +0 -85
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: faba9c8433d1b6c6faa616d7f6d58bfade42692f3e0afa6de35d67a0f1740bf2
4
- data.tar.gz: 912a3a297fde3eddbbef8fca0e3da6e2bec6e6ca5882eb69a37eafe00a443ec9
3
+ metadata.gz: f3ab9dfe5221351a1c392ddc1ba3c9c8693ba9c7dd6ceea8659aabc30de78d56
4
+ data.tar.gz: d666650ff5f3073c9c66e3c37ec6d9c2d28ac08e3abd18f13157261cf0e511b6
5
5
  SHA512:
6
- metadata.gz: bb4842d2685129d098bb05d37a423ce7817294cf523d2dd7f4e867618d80584135564d9df7c24a460bdad68372ac663dde160189d60cdd580bce9b825d3d89f8
7
- data.tar.gz: e11dd77bbe8d94f347ed31d5b67dfec2924fba89207007fa370f7053ec5549c46a5d16e1fc34ea4e4f23ad1607abddb40db87aa74413d9b8d51f214aecab9485
6
+ metadata.gz: 99b91eb15001bc4d8d93605b1e7ffff2d39aab63ae044259d474f84827cf9888233d3e7b7b107e32ab63a7145ed419f5ac163a5c8d8a13857bfa6a2dc2fc935e
7
+ data.tar.gz: f95f6d9169b3b442fe9a4c8a20a3426984d997365fb9c7bf2708828e4f7e8ca634f78f70b8f07d02f9e22e92ed597b6f59d4140f36bb3661532f459adfd4baa3
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
+
5
+ gem 'theforeman-rubocop', '~> 0.1.2', require: false, groups: %i[development rubocop]
@@ -13,12 +13,6 @@ module Actions
13
13
  end
14
14
  end
15
15
 
16
- # @see Lock.lock!
17
- def lock!(resource, *_lock_names)
18
- Foreman::Deprecation.deprecation_warning('2.4', 'locking in foreman-tasks was reworked, please use a combination of exclusive_lock! and link! instead.')
19
- exclusive_lock!(resource)
20
- end
21
-
22
16
  # @see Lock.link!
23
17
  def link!(resource)
24
18
  phase! Dynflow::Action::Plan
@@ -12,26 +12,20 @@ module Actions
12
12
  end
13
13
 
14
14
  def run(*args)
15
- restore_curent_user { pass(*args) }
15
+ restore_current_user { pass(*args) }
16
16
  end
17
17
 
18
18
  def finalize
19
- current_id = User.current.try(:id)
20
- saved_id = action.input[:current_user_id]
21
- if User.current && saved_id && current_id != saved_id
22
- Foreman::Deprecation.deprecation_warning('2.5', 'relying on per-step setting of current user in finalize phase')
23
- end
24
-
25
- restore_curent_user { pass }
19
+ restore_current_user { pass }
26
20
  end
27
21
 
28
22
  def finalize_phase(execution_plan, *args)
29
- restore_curent_user(execution_plan.entry_action) { pass(execution_plan, *args) }
23
+ restore_current_user(execution_plan.entry_action) { pass(execution_plan, *args) }
30
24
  end
31
25
 
32
26
  # Run all execution plan lifecycle hooks as the original user
33
27
  def hook(*args)
34
- restore_curent_user { pass(*args) }
28
+ restore_current_user { pass(*args) }
35
29
  end
36
30
 
37
31
  private
@@ -40,7 +34,7 @@ module Actions
40
34
  if User.current || action.input[:current_user_id].nil?
41
35
  yield
42
36
  else
43
- restore_curent_user { yield }
37
+ restore_current_user { yield }
44
38
  end
45
39
  end
46
40
 
@@ -48,7 +42,7 @@ module Actions
48
42
  action.input[:current_user_id] = User.current.try(:id)
49
43
  end
50
44
 
51
- def restore_curent_user(action = self.action)
45
+ def restore_current_user(action = self.action)
52
46
  old_user = User.current
53
47
  User.current = User.unscoped.find(action.input[:current_user_id]) if action.input[:current_user_id].present?
54
48
  yield
@@ -6,6 +6,6 @@ attributes :id, :label, :pending, :action
6
6
  attributes :username, :started_at, :ended_at, :state, :result, :progress
7
7
 
8
8
  # A workaround for https://github.com/ruby/json/issues/957
9
- node(:duration) { |t| t.duration&.in_seconds&.to_s if t.respond_to?(:duration) }
9
+ node(:duration) { |t| t.duration&.to_f&.to_s if t.respond_to?(:duration) }
10
10
  attributes :input, :output, :humanized, :cli_example, :start_at
11
11
  node(:available_actions) { |t| { cancellable: t.execution_plan&.cancellable?, resumable: t.resumable? } }
@@ -33,7 +33,5 @@ same resource. It also optionally provides Dynflow infrastructure for using it f
33
33
  s.add_dependency "get_process_mem" # for memory polling
34
34
  s.add_dependency "sinatra" # for Dynflow web console
35
35
 
36
- s.add_development_dependency 'factory_bot_rails', '~> 4.8.0'
37
- s.add_development_dependency 'sqlite3'
38
- s.add_development_dependency 'theforeman-rubocop', '~> 0.1.0'
36
+ s.add_development_dependency "sqlite3"
39
37
  end
@@ -1,3 +1,3 @@
1
1
  module ForemanTasks
2
- VERSION = '12.1.0'.freeze
2
+ VERSION = '12.2.1'.freeze
3
3
  end
@@ -108,7 +108,7 @@ module ForemanTasks
108
108
  get :show, params: { id: task.id }, session: set_session_user
109
109
  assert_response :success
110
110
  data = JSON.parse(response.body)
111
- assert_equal task.duration.in_seconds.to_s, data['duration']
111
+ assert_equal task.duration.to_f.to_s, data['duration']
112
112
  end
113
113
  end
114
114
 
@@ -118,7 +118,7 @@ module ForemanTasks
118
118
  get :index, session: set_session_user
119
119
  assert_response :success
120
120
  data = JSON.parse(response.body)
121
- assert_equal task.duration.in_seconds.to_s, data['results'][0]['duration']
121
+ assert_equal task.duration.to_f.to_s, data['results'][0]['duration']
122
122
  end
123
123
  end
124
124
 
@@ -1,20 +1,40 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Alert } from 'patternfly-react';
3
+ import { Alert } from '@patternfly/react-core';
4
4
  import { translate as __ } from 'foremanReact/common/I18n';
5
5
 
6
6
  const Errors = ({ ...props }) => {
7
7
  const { failedSteps, executionPlan } = props;
8
8
  if (!executionPlan)
9
9
  return (
10
- <Alert type="error">{__('Execution plan data not available ')}</Alert>
10
+ <Alert
11
+ variant="danger"
12
+ isInline
13
+ ouiaId="task-errors-plan-missing"
14
+ title={__('Execution plan unavailable')}
15
+ >
16
+ {__('Execution plan data not available ')}
17
+ </Alert>
11
18
  );
12
19
  if (!failedSteps.length)
13
- return <Alert type="success">{__('No errors')}</Alert>;
20
+ return (
21
+ <Alert
22
+ variant="success"
23
+ isInline
24
+ ouiaId="task-errors-none"
25
+ title={__('No errors')}
26
+ />
27
+ );
14
28
  return (
15
29
  <div>
16
30
  {failedSteps.map((step, i) => (
17
- <Alert type="error" key={i}>
31
+ <Alert
32
+ variant="danger"
33
+ isInline
34
+ key={i}
35
+ ouiaId={`task-error-${i}`}
36
+ title={__('Step error')}
37
+ >
18
38
  <span>{__('Action')}:</span>
19
39
  <span>
20
40
  <pre>{step.action_class}</pre>
@@ -37,7 +57,7 @@ const Errors = ({ ...props }) => {
37
57
  </span>
38
58
  <span>{__('Backtrace')}:</span>
39
59
  <span>
40
- <pre>{step.error.backtrace.join('\n')}</pre>
60
+ <pre>{(step.error.backtrace || []).join('\n')}</pre>
41
61
  </span>
42
62
  </React.Fragment>
43
63
  )}
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Alert, Button } from 'patternfly-react';
4
- import { translate as __ } from 'foremanReact/common/I18n';
3
+ import { Alert, AlertVariant, Button } from '@patternfly/react-core';
4
+ import { translate as __, sprintf } from 'foremanReact/common/I18n';
5
5
 
6
6
  const RunningSteps = ({
7
7
  runningSteps,
@@ -14,11 +14,19 @@ const RunningSteps = ({
14
14
  return (
15
15
  <div>
16
16
  {runningSteps.map((step, i) => (
17
- <Alert type="warning" key={i}>
17
+ <Alert
18
+ variant={AlertVariant.warning}
19
+ isInline
20
+ key={step.id || i}
21
+ ouiaId={`running-step-${i}`}
22
+ title={sprintf(__('Running step %s'), i + 1)}
23
+ >
18
24
  {step.cancellable && (
19
25
  <p>
20
26
  <Button
21
- bsSize="small"
27
+ variant="danger"
28
+ size="sm"
29
+ ouiaId={`running-step-cancel-button-${i}`}
22
30
  onClick={() => {
23
31
  if (!taskReload) {
24
32
  taskReloadStart(id);
@@ -1,208 +1,227 @@
1
- import React, { Component } from 'react';
1
+ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Grid, Row, Col, ProgressBar } from 'patternfly-react';
3
+ import {
4
+ Grid,
5
+ GridItem,
6
+ Progress,
7
+ ProgressVariant,
8
+ Icon,
9
+ } from '@patternfly/react-core';
10
+ import {
11
+ CheckCircleIcon,
12
+ ExclamationCircleIcon,
13
+ ExclamationTriangleIcon,
14
+ QuestionCircleIcon,
15
+ } from '@patternfly/react-icons';
4
16
  import { translate as __ } from 'foremanReact/common/I18n';
5
17
  import RelativeDateTime from 'foremanReact/components/common/dates/RelativeDateTime';
6
18
 
7
- class TaskInfo extends Component {
8
- isDelayed = () => {
9
- const startAt = new Date(this.props.startAt);
10
- const startedAt = new Date(this.props.startedAt);
11
- startAt.setMilliseconds(0);
12
- startedAt.setMilliseconds(0);
13
- return startAt.getTime() !== startedAt.getTime();
14
- };
15
- resultIcon = () => {
16
- if (this.props.state !== 'stopped') return 'task-status pficon-help';
17
- const { result } = this.props;
18
- let icon;
19
- switch (result) {
20
- case 'success':
21
- icon = 'pficon-ok';
22
- break;
23
- case 'error':
24
- icon = 'pficon-error-circle-o';
25
- break;
26
- case 'warning':
27
- icon = 'pficon-ok status-warn';
28
- break;
29
- default:
30
- icon = 'pficon-help';
31
- break;
32
- }
33
- return `task-status ${icon}`;
34
- };
35
-
36
- progressBarType = () => {
37
- const { result } = this.props;
38
- switch (result) {
39
- case 'error':
40
- return 'danger';
41
- case 'success':
42
- return 'success';
43
- case 'warning':
44
- return 'warning';
45
- default:
46
- return null;
47
- }
48
- };
49
-
50
- render() {
51
- const {
52
- action,
53
- endedAt,
54
- result,
55
- startAt,
56
- startBefore,
57
- startedAt,
58
- state,
59
- help,
60
- output,
61
- errors,
62
- progress,
63
- username,
64
- usernamePath,
65
- } = this.props;
19
+ const isDelayed = ({ startAt, startedAt }) => {
20
+ if (
21
+ startAt == null ||
22
+ startedAt == null ||
23
+ startAt === '' ||
24
+ startedAt === ''
25
+ ) {
26
+ return false;
27
+ }
28
+ const a = new Date(startAt);
29
+ const b = new Date(startedAt);
30
+ if (Number.isNaN(a.getTime()) || Number.isNaN(b.getTime())) {
31
+ return false;
32
+ }
33
+ a.setMilliseconds(0);
34
+ b.setMilliseconds(0);
35
+ return a.getTime() !== b.getTime();
36
+ };
66
37
 
67
- const details = [
68
- [
69
- {
70
- title: 'Name',
71
- value: action || __('N/A'),
72
- className: 'details-name',
73
- },
74
- {
75
- title: 'Start at',
76
- value: <RelativeDateTime defaultValue={__('N/A')} date={startAt} />,
77
- },
78
- ],
79
- [
80
- {
81
- title: 'Result',
82
- value: (
83
- <React.Fragment>
84
- <i className={this.resultIcon()} />
85
- <span> {result}</span>
86
- </React.Fragment>
87
- ),
88
- },
89
- {
90
- title: 'Started at',
91
- value: <RelativeDateTime defaultValue={__('N/A')} date={startedAt} />,
92
- },
93
- ],
94
- [
95
- {
96
- title: 'Triggered by',
97
- value: (usernamePath || '').includes('href') ? (
98
- <a href={usernamePath.split('"')[1]}>{username}</a>
99
- ) : (
100
- username || ''
101
- ),
102
- },
103
- {
104
- title: 'Ended at',
105
- value: <RelativeDateTime defaultValue={__('N/A')} date={endedAt} />,
106
- },
107
- ],
108
- [
109
- {
110
- title: 'Execution type',
111
- value: __(this.isDelayed() ? 'Delayed' : 'Immediate'),
112
- },
113
- {
114
- title: 'Start before',
115
- value: startBefore ? (
116
- <RelativeDateTime defaultValue={__('N/A')} date={startBefore} />
117
- ) : (
118
- '-'
119
- ),
120
- },
121
- ],
122
- ];
38
+ const resultIconEl = (state, result) => {
39
+ if (state !== 'stopped')
123
40
  return (
124
- <Grid>
125
- <br />
126
- {details.map((items, key) => (
127
- <Row key={key}>
128
- <Col md={2} sm={6}>
129
- <span className="list-group-item-heading">
130
- {__(items[0].title)}:
131
- </span>
132
- </Col>
133
- <Col md={5} sm={6} className={items[0].className}>
134
- <span>{items[0].value}</span>
135
- </Col>
136
- <Col md={2} sm={6}>
137
- <span className="list-group-item-heading">
138
- {__(items[1].title)}:
139
- </span>
140
- </Col>
141
- <Col md={3} sm={6} className={items[1].className}>
142
- {items[1].value}
143
- </Col>
144
- </Row>
145
- ))}
146
- <br />
147
- <Row>
148
- <Col xs={6}>
149
- <div className="progress-description">
150
- <span className="list-group-item-heading">{__('State')}: </span>
151
- {state}
152
- </div>
153
- </Col>
154
- <Col xs={3} xsOffset={3} className="progress-label-top-right">
155
- <span>{`${progress}% ${__('Complete')}`}</span>
156
- </Col>
157
- <Col xs={12}>
158
- <ProgressBar
159
- now={progress}
160
- bsStyle={this.progressBarType()}
161
- striped
162
- />
163
- </Col>
164
- </Row>
165
- <br />
166
- {help && (
167
- <Row>
168
- <Col xs={12}>
169
- <p>
170
- <span>
171
- <b>{__('Troubleshooting')}</b>
172
- </span>
173
- </p>
174
- <p dangerouslySetInnerHTML={{ __html: help }} />
175
- </Col>
176
- </Row>
177
- )}
178
- {output && output.length > 0 && (
179
- <Row>
180
- <Col xs={12}>
181
- <p>
182
- <span>
183
- <b>{__('Output:')}</b>
184
- </span>
185
- </p>
186
- <pre>{output}</pre>
187
- </Col>
188
- </Row>
189
- )}
190
- {errors && errors.length > 0 && (
191
- <Row>
192
- <Col xs={12}>
193
- <div>
194
- <span>
195
- <b>{__('Errors:')}</b>
196
- </span>
197
- </div>
198
- <pre>{errors}</pre>
199
- </Col>
200
- </Row>
201
- )}
202
- </Grid>
41
+ <Icon>
42
+ <QuestionCircleIcon />
43
+ </Icon>
203
44
  );
45
+ switch (result) {
46
+ case 'success':
47
+ return (
48
+ <Icon status="success">
49
+ <CheckCircleIcon />
50
+ </Icon>
51
+ );
52
+ case 'error':
53
+ return (
54
+ <Icon status="danger">
55
+ <ExclamationCircleIcon />
56
+ </Icon>
57
+ );
58
+ case 'warning':
59
+ return (
60
+ <Icon status="warning">
61
+ <ExclamationTriangleIcon />
62
+ </Icon>
63
+ );
64
+ default:
65
+ return (
66
+ <Icon>
67
+ <QuestionCircleIcon />
68
+ </Icon>
69
+ );
70
+ }
71
+ };
72
+
73
+ const progressVariantForResult = result => {
74
+ switch (result) {
75
+ case 'error':
76
+ return ProgressVariant.danger;
77
+ case 'success':
78
+ return ProgressVariant.success;
79
+ case 'warning':
80
+ return ProgressVariant.warning;
81
+ default:
82
+ return undefined;
204
83
  }
205
- }
84
+ };
85
+
86
+ const TaskInfo = props => {
87
+ const {
88
+ action,
89
+ endedAt,
90
+ result,
91
+ startAt,
92
+ startBefore,
93
+ startedAt,
94
+ state,
95
+ help,
96
+ output,
97
+ errors,
98
+ progress,
99
+ username,
100
+ usernamePath,
101
+ } = props;
102
+
103
+ const details = [
104
+ [
105
+ {
106
+ title: 'Name',
107
+ value: action || __('N/A'),
108
+ className: 'details-name',
109
+ },
110
+ {
111
+ title: 'Start at',
112
+ value: <RelativeDateTime defaultValue={__('N/A')} date={startAt} />,
113
+ },
114
+ ],
115
+ [
116
+ {
117
+ title: 'Result',
118
+ value: (
119
+ <span>
120
+ {resultIconEl(state, result)} {result}
121
+ </span>
122
+ ),
123
+ },
124
+ {
125
+ title: 'Started at',
126
+ value: <RelativeDateTime defaultValue={__('N/A')} date={startedAt} />,
127
+ },
128
+ ],
129
+ [
130
+ {
131
+ title: 'Triggered by',
132
+ value: (usernamePath || '').includes('href') ? (
133
+ <a href={usernamePath.split('"')[1]}>{username}</a>
134
+ ) : (
135
+ username || ''
136
+ ),
137
+ },
138
+ {
139
+ title: 'Ended at',
140
+ value: <RelativeDateTime defaultValue={__('N/A')} date={endedAt} />,
141
+ },
142
+ ],
143
+ [
144
+ {
145
+ title: 'Execution type',
146
+ value: __(isDelayed(props) ? 'Delayed' : 'Immediate'),
147
+ },
148
+ {
149
+ title: 'Start before',
150
+ value: startBefore ? (
151
+ <RelativeDateTime defaultValue={__('N/A')} date={startBefore} />
152
+ ) : (
153
+ '-'
154
+ ),
155
+ },
156
+ ],
157
+ ];
158
+
159
+ const progVariant = progressVariantForResult(result);
160
+
161
+ return (
162
+ <Grid>
163
+ <GridItem span={12} className="pf-v5-u-pb-lg" />
164
+ {details.map((items, key) => (
165
+ <React.Fragment key={key}>
166
+ <GridItem md={2} sm={6}>
167
+ <span className="list-group-item-heading">
168
+ {__(items[0].title)}:
169
+ </span>
170
+ </GridItem>
171
+ <GridItem md={5} sm={6} className={items[0].className}>
172
+ <span>{items[0].value}</span>
173
+ </GridItem>
174
+ <GridItem md={2} sm={6}>
175
+ <span className="list-group-item-heading">
176
+ {__(items[1].title)}:
177
+ </span>
178
+ </GridItem>
179
+ <GridItem md={3} sm={6} className={items[1].className}>
180
+ {items[1].value}
181
+ </GridItem>
182
+ </React.Fragment>
183
+ ))}
184
+ <GridItem span={12} className="pf-v5-u-pb-lg" />
185
+ <GridItem span={6}>
186
+ <div className="progress-description">
187
+ <span className="list-group-item-heading">{__('State')}: </span>
188
+ {state}
189
+ </div>
190
+ </GridItem>
191
+ <GridItem span={6} className="progress-label-top-right">
192
+ <span>{`${progress}% ${__('Complete')}`}</span>
193
+ </GridItem>
194
+ <GridItem span={12}>
195
+ <Progress
196
+ value={progress}
197
+ max={100}
198
+ aria-label={`${progress}% ${__('Complete')}`}
199
+ measureLocation="outside"
200
+ {...(progVariant ? { variant: progVariant } : {})}
201
+ />
202
+ </GridItem>
203
+ <GridItem span={12} className="pf-v5-u-pb-lg" />
204
+ {help && (
205
+ <GridItem span={12}>
206
+ <b>{__('Troubleshooting')}</b>
207
+ <p dangerouslySetInnerHTML={{ __html: help }} />
208
+ </GridItem>
209
+ )}
210
+ {output && output.length > 0 && (
211
+ <GridItem span={12}>
212
+ <b>{__('Output:')}</b>
213
+ <pre>{output}</pre>
214
+ </GridItem>
215
+ )}
216
+ {errors && errors.length > 0 && (
217
+ <GridItem span={12}>
218
+ <b>{__('Errors:')}</b>
219
+ <pre>{errors}</pre>
220
+ </GridItem>
221
+ )}
222
+ </Grid>
223
+ );
224
+ };
206
225
 
207
226
  TaskInfo.propTypes = {
208
227
  action: PropTypes.string,
@@ -217,10 +236,7 @@ TaskInfo.propTypes = {
217
236
  progress: PropTypes.number,
218
237
  username: PropTypes.string,
219
238
  usernamePath: PropTypes.string,
220
- output: PropTypes.PropTypes.oneOfType([
221
- PropTypes.string,
222
- PropTypes.shape({}),
223
- ]),
239
+ output: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({})]),
224
240
  };
225
241
 
226
242
  TaskInfo.defaultProps = {