foreman_remote_execution 13.1.0 → 13.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman_remote_execution/locale/de/foreman_remote_execution.js +1000 -973
  3. data/app/assets/javascripts/foreman_remote_execution/locale/en/foreman_remote_execution.js +553 -526
  4. data/app/assets/javascripts/foreman_remote_execution/locale/en_GB/foreman_remote_execution.js +584 -557
  5. data/app/assets/javascripts/foreman_remote_execution/locale/es/foreman_remote_execution.js +1043 -1016
  6. data/app/assets/javascripts/foreman_remote_execution/locale/fr/foreman_remote_execution.js +1047 -1020
  7. data/app/assets/javascripts/foreman_remote_execution/locale/ja/foreman_remote_execution.js +1041 -1014
  8. data/app/assets/javascripts/foreman_remote_execution/locale/ka/foreman_remote_execution.js +1015 -988
  9. data/app/assets/javascripts/foreman_remote_execution/locale/ko/foreman_remote_execution.js +886 -859
  10. data/app/assets/javascripts/foreman_remote_execution/locale/pt_BR/foreman_remote_execution.js +1047 -1020
  11. data/app/assets/javascripts/foreman_remote_execution/locale/ru/foreman_remote_execution.js +901 -874
  12. data/app/assets/javascripts/foreman_remote_execution/locale/zh_CN/foreman_remote_execution.js +1041 -1014
  13. data/app/assets/javascripts/foreman_remote_execution/locale/zh_TW/foreman_remote_execution.js +886 -859
  14. data/app/controllers/api/v2/job_invocations_controller.rb +1 -0
  15. data/app/models/job_invocation.rb +23 -0
  16. data/app/models/job_invocation_composer.rb +2 -0
  17. data/app/views/api/v2/job_invocations/base.json.rabl +3 -2
  18. data/app/views/templates/script/package_action.erb +5 -2
  19. data/lib/foreman_remote_execution/version.rb +1 -1
  20. data/locale/de/foreman_remote_execution.po +27 -0
  21. data/locale/en/foreman_remote_execution.po +27 -0
  22. data/locale/en_GB/foreman_remote_execution.po +27 -0
  23. data/locale/es/foreman_remote_execution.po +27 -0
  24. data/locale/foreman_remote_execution.pot +177 -141
  25. data/locale/fr/foreman_remote_execution.po +27 -0
  26. data/locale/ja/foreman_remote_execution.po +27 -0
  27. data/locale/ka/foreman_remote_execution.po +27 -0
  28. data/locale/ko/foreman_remote_execution.po +27 -0
  29. data/locale/pt_BR/foreman_remote_execution.po +27 -0
  30. data/locale/ru/foreman_remote_execution.po +27 -0
  31. data/locale/zh_CN/foreman_remote_execution.po +27 -0
  32. data/locale/zh_TW/foreman_remote_execution.po +27 -0
  33. data/package.json +2 -1
  34. data/webpack/JobInvocationDetail/JobInvocationActions.js +134 -3
  35. data/webpack/JobInvocationDetail/JobInvocationConstants.js +14 -0
  36. data/webpack/JobInvocationDetail/JobInvocationDetail.scss +5 -2
  37. data/webpack/JobInvocationDetail/JobInvocationSelectors.js +5 -0
  38. data/webpack/JobInvocationDetail/JobInvocationSystemStatusChart.js +13 -9
  39. data/webpack/JobInvocationDetail/JobInvocationToolbarButtons.js +268 -0
  40. data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +259 -0
  41. data/webpack/JobInvocationDetail/__tests__/fixtures.js +117 -0
  42. data/webpack/JobInvocationDetail/index.js +58 -38
  43. data/webpack/JobWizard/JobWizardPageRerun.js +16 -11
  44. data/webpack/JobWizard/steps/HostsAndInputs/HostPreviewModal.js +8 -6
  45. data/webpack/__mocks__/foremanReact/Root/Context/ForemanContext/index.js +2 -0
  46. data/webpack/__mocks__/foremanReact/components/BreadcrumbBar/index.js +4 -0
  47. data/webpack/__mocks__/foremanReact/components/Head/index.js +10 -0
  48. data/webpack/__mocks__/foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState.js +8 -0
  49. data/webpack/__mocks__/foremanReact/components/ToastsList/index.js +3 -0
  50. data/webpack/__mocks__/foremanReact/redux/API/APIActions.js +21 -0
  51. data/webpack/__mocks__/foremanReact/redux/API/APIConstants.js +7 -0
  52. data/webpack/__mocks__/foremanReact/redux/API/index.js +14 -0
  53. data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware/index.js +9 -0
  54. metadata +12 -2
@@ -1,9 +1,19 @@
1
- import { get } from 'foremanReact/redux/API';
1
+ import { translate as __, sprintf } from 'foremanReact/common/I18n';
2
+ import { foremanUrl } from 'foremanReact/common/helpers';
3
+ import { addToast } from 'foremanReact/components/ToastsList';
4
+ import { APIActions, get } from 'foremanReact/redux/API';
2
5
  import {
3
- withInterval,
4
6
  stopInterval,
7
+ withInterval,
5
8
  } from 'foremanReact/redux/middlewares/IntervalMiddleware';
6
- import { JOB_INVOCATION_KEY } from './JobInvocationConstants';
9
+ import {
10
+ CANCEL_JOB,
11
+ CANCEL_RECURRING_LOGIC,
12
+ CHANGE_ENABLED_RECURRING_LOGIC,
13
+ GET_TASK,
14
+ JOB_INVOCATION_KEY,
15
+ UPDATE_JOB,
16
+ } from './JobInvocationConstants';
7
17
 
8
18
  export const getData = url => dispatch => {
9
19
  const fetchData = withInterval(
@@ -20,3 +30,124 @@ export const getData = url => dispatch => {
20
30
 
21
31
  dispatch(fetchData);
22
32
  };
33
+
34
+ export const updateJob = jobId => dispatch => {
35
+ const url = foremanUrl(`/api/job_invocations/${jobId}`);
36
+ dispatch(
37
+ APIActions.get({
38
+ url,
39
+ key: UPDATE_JOB,
40
+ })
41
+ );
42
+ };
43
+
44
+ export const cancelJob = (jobId, force) => dispatch => {
45
+ const infoToast = () =>
46
+ force
47
+ ? sprintf(__('Trying to abort the job %s.'), jobId)
48
+ : sprintf(__('Trying to cancel the job %s.'), jobId);
49
+ const errorToast = response =>
50
+ force
51
+ ? sprintf(__(`Could not abort the job %s: ${response}`), jobId)
52
+ : sprintf(__(`Could not cancel the job %s: ${response}`), jobId);
53
+ const url = force
54
+ ? `/job_invocations/${jobId}/cancel?force=true`
55
+ : `/job_invocations/${jobId}/cancel`;
56
+
57
+ dispatch(
58
+ APIActions.post({
59
+ url,
60
+ key: CANCEL_JOB,
61
+ errorToast: ({ response }) =>
62
+ errorToast(
63
+ // eslint-disable-next-line camelcase
64
+ response?.data?.error?.full_messages ||
65
+ response?.data?.error?.message ||
66
+ 'Unknown error.'
67
+ ),
68
+ handleSuccess: () => {
69
+ dispatch(
70
+ addToast({
71
+ key: `cancel-job-error`,
72
+ type: 'info',
73
+ message: infoToast(),
74
+ })
75
+ );
76
+ dispatch(updateJob(jobId));
77
+ },
78
+ })
79
+ );
80
+ };
81
+
82
+ export const getTask = taskId => dispatch => {
83
+ dispatch(
84
+ get({
85
+ key: GET_TASK,
86
+ url: `/foreman_tasks/api/tasks/${taskId}`,
87
+ })
88
+ );
89
+ };
90
+
91
+ export const enableRecurringLogic = (
92
+ recurrenceId,
93
+ enabled,
94
+ jobId
95
+ ) => dispatch => {
96
+ const successToast = () =>
97
+ enabled
98
+ ? sprintf(__('Recurring logic %s disabled successfully.'), recurrenceId)
99
+ : sprintf(__('Recurring logic %s enabled successfully.'), recurrenceId);
100
+ const errorToast = response =>
101
+ enabled
102
+ ? sprintf(
103
+ __(`Could not disable recurring logic %s: ${response}`),
104
+ recurrenceId
105
+ )
106
+ : sprintf(
107
+ __(`Could not enable recurring logic %s: ${response}`),
108
+ recurrenceId
109
+ );
110
+ const url = `/foreman_tasks/api/recurring_logics/${recurrenceId}`;
111
+ dispatch(
112
+ APIActions.put({
113
+ url,
114
+ key: CHANGE_ENABLED_RECURRING_LOGIC,
115
+ params: { recurring_logic: { enabled: !enabled } },
116
+ successToast,
117
+ errorToast: ({ response }) =>
118
+ errorToast(
119
+ // eslint-disable-next-line camelcase
120
+ response?.data?.error?.full_messages ||
121
+ response?.data?.error?.message ||
122
+ 'Unknown error.'
123
+ ),
124
+ handleSuccess: () => dispatch(updateJob(jobId)),
125
+ })
126
+ );
127
+ };
128
+
129
+ export const cancelRecurringLogic = (recurrenceId, jobId) => dispatch => {
130
+ const successToast = () =>
131
+ sprintf(__('Recurring logic %s cancelled successfully.'), recurrenceId);
132
+ const errorToast = response =>
133
+ sprintf(
134
+ __(`Could not cancel recurring logic %s: ${response}`),
135
+ recurrenceId
136
+ );
137
+ const url = `/foreman_tasks/recurring_logics/${recurrenceId}/cancel`;
138
+ dispatch(
139
+ APIActions.post({
140
+ url,
141
+ key: CANCEL_RECURRING_LOGIC,
142
+ successToast,
143
+ errorToast: ({ response }) =>
144
+ errorToast(
145
+ // eslint-disable-next-line camelcase
146
+ response?.data?.error?.full_messages ||
147
+ response?.data?.error?.message ||
148
+ 'Unknown error.'
149
+ ),
150
+ handleSuccess: () => dispatch(updateJob(jobId)),
151
+ })
152
+ );
153
+ };
@@ -1,9 +1,23 @@
1
+ import { foremanUrl } from 'foremanReact/common/helpers';
2
+
1
3
  export const JOB_INVOCATION_KEY = 'JOB_INVOCATION_KEY';
4
+ export const CURRENT_PERMISSIONS = 'CURRENT_PERMISSIONS';
5
+ export const UPDATE_JOB = 'UPDATE_JOB';
6
+ export const CANCEL_JOB = 'CANCEL_JOB';
7
+ export const GET_TASK = 'GET_TASK';
8
+ export const CHANGE_ENABLED_RECURRING_LOGIC = 'CHANGE_ENABLED_RECURRING_LOGIC';
9
+ export const CANCEL_RECURRING_LOGIC = 'CANCEL_RECURRING_LOGIC';
10
+ export const GET_REPORT_TEMPLATES = 'GET_REPORT_TEMPLATES';
11
+ export const GET_REPORT_TEMPLATE_INPUTS = 'GET_REPORT_TEMPLATE_INPUTS';
12
+ export const currentPermissionsUrl = foremanUrl(
13
+ '/api/v2/permissions/current_permissions'
14
+ );
2
15
 
3
16
  export const STATUS = {
4
17
  PENDING: 'pending',
5
18
  SUCCEEDED: 'succeeded',
6
19
  FAILED: 'failed',
20
+ CANCELLED: 'cancelled',
7
21
  };
8
22
 
9
23
  export const DATE_OPTIONS = {
@@ -1,6 +1,8 @@
1
- .job-invocation-detail-page-section {
1
+ .job-invocation-detail-flex {
2
2
  $chart_size: 105px;
3
-
3
+ padding-top: 0px;
4
+ padding-left: 10px;
5
+
4
6
  .chart-donut {
5
7
  height: $chart_size;
6
8
  width: $chart_size;
@@ -36,3 +38,4 @@
36
38
  height: $chart_size;
37
39
  }
38
40
  }
41
+
@@ -3,3 +3,8 @@ import { JOB_INVOCATION_KEY } from './JobInvocationConstants';
3
3
 
4
4
  export const selectItems = state =>
5
5
  selectAPIResponse(state, JOB_INVOCATION_KEY);
6
+
7
+ export const selectTask = state => selectAPIResponse(state, 'GET_TASK');
8
+
9
+ export const selectTaskCancelable = state =>
10
+ selectTask(state).available_actions?.cancellable || false;
@@ -1,6 +1,7 @@
1
- import React, { useEffect, useState } from 'react';
2
1
  import PropTypes from 'prop-types';
2
+ import React, { useEffect, useState } from 'react';
3
3
  import { translate as __, sprintf } from 'foremanReact/common/I18n';
4
+ import DefaultLoaderEmptyState from 'foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState';
4
5
  import {
5
6
  ChartDonut,
6
7
  ChartLabel,
@@ -9,20 +10,19 @@ import {
9
10
  } from '@patternfly/react-charts';
10
11
  import {
11
12
  DescriptionList,
12
- DescriptionListTerm,
13
- DescriptionListGroup,
14
13
  DescriptionListDescription,
14
+ DescriptionListGroup,
15
+ DescriptionListTerm,
15
16
  FlexItem,
16
17
  Text,
17
18
  } from '@patternfly/react-core';
18
19
  import {
19
- global_palette_green_500 as successedColor,
20
- global_palette_red_100 as failedColor,
21
- global_palette_blue_300 as inProgressColor,
22
20
  global_palette_black_600 as canceledColor,
23
21
  global_palette_black_500 as emptyChartDonut,
22
+ global_palette_red_100 as failedColor,
23
+ global_palette_blue_300 as inProgressColor,
24
+ global_palette_green_500 as successedColor,
24
25
  } from '@patternfly/react-tokens';
25
- import DefaultLoaderEmptyState from 'foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState';
26
26
  import './JobInvocationDetail.scss';
27
27
 
28
28
  const JobInvocationSystemStatusChart = ({
@@ -35,9 +35,9 @@ const JobInvocationSystemStatusChart = ({
35
35
  failed,
36
36
  pending,
37
37
  cancelled,
38
- total,
39
38
  total_hosts: totalHosts, // includes scheduled
40
39
  } = data;
40
+ const total = succeeded + failed + pending + cancelled;
41
41
  const chartData = [
42
42
  { title: __('Succeeded:'), count: succeeded, color: successedColor.value },
43
43
  { title: __('Failed:'), count: failed, color: failedColor.value },
@@ -82,7 +82,11 @@ const JobInvocationSystemStatusChart = ({
82
82
  total > 0 ? chartData.map(d => d.color) : [emptyChartDonut.value]
83
83
  }
84
84
  labelComponent={
85
- <ChartTooltip pointerLength={0} constrainToVisibleArea />
85
+ <ChartTooltip
86
+ pointerLength={0}
87
+ constrainToVisibleArea
88
+ renderInPortal={false}
89
+ />
86
90
  }
87
91
  title={chartDonutTitle}
88
92
  titleComponent={
@@ -0,0 +1,268 @@
1
+ import PropTypes from 'prop-types';
2
+ import React, { useEffect, useState } from 'react';
3
+ import { useDispatch, useSelector } from 'react-redux';
4
+ import {
5
+ Button,
6
+ Dropdown,
7
+ DropdownItem,
8
+ DropdownPosition,
9
+ DropdownSeparator,
10
+ DropdownToggle,
11
+ Split,
12
+ SplitItem,
13
+ } from '@patternfly/react-core';
14
+ import { translate as __ } from 'foremanReact/common/I18n';
15
+ import { foremanUrl } from 'foremanReact/common/helpers';
16
+ import { STATUS as APIStatus } from 'foremanReact/constants';
17
+ import { get } from 'foremanReact/redux/API';
18
+ import {
19
+ cancelJob,
20
+ cancelRecurringLogic,
21
+ enableRecurringLogic,
22
+ } from './JobInvocationActions';
23
+ import {
24
+ STATUS,
25
+ GET_REPORT_TEMPLATES,
26
+ GET_REPORT_TEMPLATE_INPUTS,
27
+ } from './JobInvocationConstants';
28
+ import { selectTaskCancelable } from './JobInvocationSelectors';
29
+
30
+ const JobInvocationToolbarButtons = ({
31
+ jobId,
32
+ data,
33
+ currentPermissions,
34
+ permissionsStatus,
35
+ }) => {
36
+ const { succeeded, failed, task, recurrence, permissions } = data;
37
+ const recurringEnabled = recurrence?.state === 'active';
38
+ const canViewForemanTasks = permissions
39
+ ? permissions.view_foreman_tasks
40
+ : false;
41
+ const canEditRecurringLogic = permissions
42
+ ? permissions.edit_recurring_logics
43
+ : false;
44
+ const isTaskCancelable = useSelector(selectTaskCancelable);
45
+ const [isActionOpen, setIsActionOpen] = useState(false);
46
+ const [reportTemplateJobId, setReportTemplateJobId] = useState(undefined);
47
+ const [templateInputId, setTemplateInputId] = useState(undefined);
48
+ const queryParams = new URLSearchParams({
49
+ [`report_template_report[input_values][${templateInputId}][value]`]: jobId,
50
+ });
51
+ const dispatch = useDispatch();
52
+
53
+ const onActionFocus = () => {
54
+ const element = document.getElementById(
55
+ `toggle-split-button-action-primary-${jobId}`
56
+ );
57
+ element.focus();
58
+ };
59
+ const onActionSelect = () => {
60
+ setIsActionOpen(false);
61
+ onActionFocus();
62
+ };
63
+ const hasPermission = permissionRequired =>
64
+ permissionsStatus === APIStatus.RESOLVED
65
+ ? currentPermissions?.some(
66
+ permission => permission.name === permissionRequired
67
+ )
68
+ : false;
69
+
70
+ useEffect(() => {
71
+ dispatch(
72
+ get({
73
+ key: GET_REPORT_TEMPLATES,
74
+ url: '/api/report_templates',
75
+ handleSuccess: ({ data: { results } }) => {
76
+ setReportTemplateJobId(
77
+ results.find(result => result.name === 'Job - Invocation Report')
78
+ ?.id
79
+ );
80
+ },
81
+ handleError: () => {
82
+ setReportTemplateJobId(undefined);
83
+ },
84
+ })
85
+ );
86
+ }, [dispatch]);
87
+ useEffect(() => {
88
+ if (reportTemplateJobId !== undefined) {
89
+ dispatch(
90
+ get({
91
+ key: GET_REPORT_TEMPLATE_INPUTS,
92
+ url: `/api/templates/${reportTemplateJobId}/template_inputs`,
93
+ handleSuccess: ({ data: { results } }) => {
94
+ setTemplateInputId(
95
+ results.find(result => result.name === 'job_id')?.id
96
+ );
97
+ },
98
+ handleError: () => {
99
+ setTemplateInputId(undefined);
100
+ },
101
+ })
102
+ );
103
+ }
104
+ }, [dispatch, reportTemplateJobId]);
105
+
106
+ const recurrenceDropdownItems = recurrence
107
+ ? [
108
+ <DropdownSeparator ouiaId="dropdown-separator-1" key="separator-1" />,
109
+ <DropdownItem
110
+ ouiaId="change-enabled-recurring-dropdown-item"
111
+ onClick={() =>
112
+ dispatch(
113
+ enableRecurringLogic(recurrence?.id, recurringEnabled, jobId)
114
+ )
115
+ }
116
+ key="change-enabled-recurring"
117
+ component="button"
118
+ isDisabled={
119
+ recurrence?.id === undefined ||
120
+ recurrence?.state === 'cancelled' ||
121
+ !canEditRecurringLogic
122
+ }
123
+ >
124
+ {recurringEnabled ? __('Disable recurring') : __('Enable recurring')}
125
+ </DropdownItem>,
126
+ <DropdownItem
127
+ ouiaId="cancel-recurring-dropdown-item"
128
+ onClick={() => dispatch(cancelRecurringLogic(recurrence?.id, jobId))}
129
+ key="cancel-recurring"
130
+ component="button"
131
+ isDisabled={
132
+ recurrence?.id === undefined ||
133
+ recurrence?.state === 'cancelled' ||
134
+ !canEditRecurringLogic
135
+ }
136
+ >
137
+ {__('Cancel recurring')}
138
+ </DropdownItem>,
139
+ ]
140
+ : [];
141
+
142
+ const dropdownItems = [
143
+ <DropdownItem
144
+ ouiaId="rerun-succeeded-dropdown-item"
145
+ href={foremanUrl(`/job_invocations/${jobId}/rerun?succeeded_only=1`)}
146
+ key="rerun-succeeded"
147
+ isDisabled={!(succeeded > 0) || !hasPermission('create_job_invocations')}
148
+ description="Rerun job on successful hosts"
149
+ >
150
+ {__('Rerun successful')}
151
+ </DropdownItem>,
152
+ <DropdownItem
153
+ ouiaId="rerun-failed-dropdown-item"
154
+ href={foremanUrl(`/job_invocations/${jobId}/rerun?failed_only=1`)}
155
+ key="rerun-failed"
156
+ isDisabled={!(failed > 0) || !hasPermission('create_job_invocations')}
157
+ description="Rerun job on failed hosts"
158
+ >
159
+ {__('Rerun failed')}
160
+ </DropdownItem>,
161
+ <DropdownItem
162
+ ouiaId="view-task-dropdown-item"
163
+ href={foremanUrl(`/foreman_tasks/tasks/${task?.id}`)}
164
+ key="view-task"
165
+ isDisabled={!canViewForemanTasks || task === undefined}
166
+ description="See details of latest task"
167
+ >
168
+ {__('View task')}
169
+ </DropdownItem>,
170
+ <DropdownSeparator ouiaId="dropdown-separator-0" key="separator-0" />,
171
+ <DropdownItem
172
+ ouiaId="cancel-dropdown-item"
173
+ onClick={() => dispatch(cancelJob(jobId, false))}
174
+ key="cancel"
175
+ component="button"
176
+ isDisabled={!isTaskCancelable || !hasPermission('cancel_job_invocations')}
177
+ description="Cancel job gracefully"
178
+ >
179
+ {__('Cancel')}
180
+ </DropdownItem>,
181
+ <DropdownItem
182
+ ouiaId="abort-dropdown-item"
183
+ onClick={() => dispatch(cancelJob(jobId, true))}
184
+ key="abort"
185
+ component="button"
186
+ isDisabled={!isTaskCancelable || !hasPermission('cancel_job_invocations')}
187
+ description="Cancel job immediately"
188
+ >
189
+ {__('Abort')}
190
+ </DropdownItem>,
191
+ ...recurrenceDropdownItems,
192
+ <DropdownSeparator ouiaId="dropdown-separator-2" key="separator-2" />,
193
+ <DropdownItem
194
+ ouiaId="legacy-ui-dropdown-item"
195
+ href={`/job_invocations/${jobId}`}
196
+ key="legacy-ui"
197
+ >
198
+ {__('Legacy UI')}
199
+ </DropdownItem>,
200
+ ];
201
+
202
+ return (
203
+ <>
204
+ <Split hasGutter>
205
+ <SplitItem>
206
+ <Button
207
+ component="a"
208
+ ouiaId="button-create-report"
209
+ className="button-create-report"
210
+ href={foremanUrl(
211
+ `/templates/report_templates/${reportTemplateJobId}/generate?${queryParams.toString()}`
212
+ )}
213
+ variant="secondary"
214
+ isDisabled={
215
+ task?.state === STATUS.PENDING ||
216
+ templateInputId === undefined ||
217
+ !hasPermission('generate_report_templates')
218
+ }
219
+ >
220
+ {__(`Create report`)}
221
+ </Button>
222
+ </SplitItem>
223
+ <SplitItem>
224
+ <Dropdown
225
+ ouiaId="job-invocation-global-actions-dropdown"
226
+ onSelect={onActionSelect}
227
+ position={DropdownPosition.right}
228
+ toggle={
229
+ <DropdownToggle
230
+ ouiaId="toggle-button-action-primary"
231
+ id={`toggle-split-button-action-primary-${jobId}`}
232
+ splitButtonItems={[
233
+ <Button
234
+ component="a"
235
+ ouiaId="button-rerun-all"
236
+ key="rerun"
237
+ href={foremanUrl(`/job_invocations/${jobId}/rerun`)}
238
+ variant="control"
239
+ isDisabled={!hasPermission('create_job_invocations')}
240
+ >
241
+ {__(`Rerun all`)}
242
+ </Button>,
243
+ ]}
244
+ splitButtonVariant="action"
245
+ onToggle={setIsActionOpen}
246
+ />
247
+ }
248
+ isOpen={isActionOpen}
249
+ dropdownItems={dropdownItems}
250
+ />
251
+ </SplitItem>
252
+ </Split>
253
+ </>
254
+ );
255
+ };
256
+
257
+ JobInvocationToolbarButtons.propTypes = {
258
+ jobId: PropTypes.string.isRequired,
259
+ data: PropTypes.object.isRequired,
260
+ currentPermissions: PropTypes.array,
261
+ permissionsStatus: PropTypes.string,
262
+ };
263
+ JobInvocationToolbarButtons.defaultProps = {
264
+ currentPermissions: undefined,
265
+ permissionsStatus: undefined,
266
+ };
267
+
268
+ export default JobInvocationToolbarButtons;