foreman_remote_execution 14.1.4 → 15.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman_remote_execution/locale/de/foreman_remote_execution.js +178 -13
  3. data/app/assets/javascripts/foreman_remote_execution/locale/en/foreman_remote_execution.js +1832 -2
  4. data/app/assets/javascripts/foreman_remote_execution/locale/en_GB/foreman_remote_execution.js +176 -11
  5. data/app/assets/javascripts/foreman_remote_execution/locale/es/foreman_remote_execution.js +178 -13
  6. data/app/assets/javascripts/foreman_remote_execution/locale/fr/foreman_remote_execution.js +179 -14
  7. data/app/assets/javascripts/foreman_remote_execution/locale/ja/foreman_remote_execution.js +179 -14
  8. data/app/assets/javascripts/foreman_remote_execution/locale/ka/foreman_remote_execution.js +178 -13
  9. data/app/assets/javascripts/foreman_remote_execution/locale/ko/foreman_remote_execution.js +449 -285
  10. data/app/assets/javascripts/foreman_remote_execution/locale/pt_BR/foreman_remote_execution.js +178 -13
  11. data/app/assets/javascripts/foreman_remote_execution/locale/ru/foreman_remote_execution.js +177 -12
  12. data/app/assets/javascripts/foreman_remote_execution/locale/zh_CN/foreman_remote_execution.js +179 -14
  13. data/app/assets/javascripts/foreman_remote_execution/locale/zh_TW/foreman_remote_execution.js +177 -12
  14. data/app/controllers/api/v2/job_invocations_controller.rb +8 -0
  15. data/app/controllers/job_invocations_controller.rb +1 -1
  16. data/app/controllers/template_invocations_controller.rb +57 -0
  17. data/app/controllers/ui_job_wizard_controller.rb +6 -3
  18. data/app/helpers/remote_execution_helper.rb +5 -6
  19. data/app/views/api/v2/job_invocations/base.json.rabl +1 -1
  20. data/app/views/api/v2/job_invocations/hosts.json.rabl +1 -1
  21. data/app/views/api/v2/job_invocations/main.json.rabl +1 -1
  22. data/app/views/api/v2/job_invocations/show.json.rabl +18 -0
  23. data/app/views/templates/script/convert2rhel_analyze.erb +4 -4
  24. data/config/routes.rb +2 -0
  25. data/lib/foreman_remote_execution/engine.rb +3 -3
  26. data/lib/foreman_remote_execution/version.rb +1 -1
  27. data/locale/de/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  28. data/locale/de/foreman_remote_execution.po +178 -13
  29. data/locale/en/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  30. data/locale/en/foreman_remote_execution.po +1840 -0
  31. data/locale/en_GB/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  32. data/locale/en_GB/foreman_remote_execution.po +176 -11
  33. data/locale/es/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  34. data/locale/es/foreman_remote_execution.po +178 -13
  35. data/locale/foreman_remote_execution.pot +470 -184
  36. data/locale/fr/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  37. data/locale/fr/foreman_remote_execution.po +179 -14
  38. data/locale/ja/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  39. data/locale/ja/foreman_remote_execution.po +179 -14
  40. data/locale/ka/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  41. data/locale/ka/foreman_remote_execution.po +178 -13
  42. data/locale/ko/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  43. data/locale/ko/foreman_remote_execution.po +449 -285
  44. data/locale/pt_BR/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  45. data/locale/pt_BR/foreman_remote_execution.po +178 -13
  46. data/locale/ru/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  47. data/locale/ru/foreman_remote_execution.po +177 -12
  48. data/locale/zh_CN/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  49. data/locale/zh_CN/foreman_remote_execution.po +179 -14
  50. data/locale/zh_TW/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  51. data/locale/zh_TW/foreman_remote_execution.po +177 -12
  52. data/webpack/JobInvocationDetail/JobAdditionInfo.js +214 -0
  53. data/webpack/JobInvocationDetail/JobInvocationConstants.js +40 -2
  54. data/webpack/JobInvocationDetail/JobInvocationDetail.scss +70 -0
  55. data/webpack/JobInvocationDetail/JobInvocationHostTable.js +177 -80
  56. data/webpack/JobInvocationDetail/JobInvocationHostTableToolbar.js +63 -0
  57. data/webpack/JobInvocationDetail/JobInvocationSelectors.js +8 -1
  58. data/webpack/JobInvocationDetail/JobInvocationSystemStatusChart.js +61 -10
  59. data/webpack/JobInvocationDetail/OpenAlInvocations.js +111 -0
  60. data/webpack/JobInvocationDetail/TemplateInvocation.js +202 -0
  61. data/webpack/JobInvocationDetail/TemplateInvocationComponents/OutputCodeBlock.js +124 -0
  62. data/webpack/JobInvocationDetail/TemplateInvocationComponents/OutputToggleGroup.js +156 -0
  63. data/webpack/JobInvocationDetail/TemplateInvocationComponents/PreviewTemplate.js +50 -0
  64. data/webpack/JobInvocationDetail/TemplateInvocationComponents/TemplateActionButtons.js +224 -0
  65. data/webpack/JobInvocationDetail/TemplateInvocationPage.js +53 -0
  66. data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +1 -1
  67. data/webpack/JobInvocationDetail/__tests__/OpenAlInvocations.test.js +110 -0
  68. data/webpack/JobInvocationDetail/__tests__/OutputCodeBlock.test.js +69 -0
  69. data/webpack/JobInvocationDetail/__tests__/TemplateInvocation.test.js +131 -0
  70. data/webpack/JobInvocationDetail/__tests__/fixtures.js +130 -0
  71. data/webpack/JobInvocationDetail/index.js +18 -3
  72. data/webpack/JobWizard/JobWizard.js +38 -16
  73. data/webpack/JobWizard/{StartsBeforeErrorAlert.js → StartsErrorAlert.js} +16 -1
  74. data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +1 -1
  75. data/webpack/JobWizard/steps/Schedule/ScheduleFuture.js +1 -1
  76. data/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js +5 -3
  77. data/webpack/JobWizard/steps/Schedule/ScheduleType.js +1 -1
  78. data/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js +3 -3
  79. data/webpack/JobWizard/steps/form/DateTimePicker.js +13 -0
  80. data/webpack/JobWizard/steps/form/Formatter.js +1 -0
  81. data/webpack/JobWizard/steps/form/ResourceSelect.js +34 -9
  82. data/webpack/Routes/routes.js +6 -0
  83. data/webpack/__mocks__/foremanReact/Root/Context/ForemanContext/index.js +1 -0
  84. data/webpack/react_app/components/RegistrationExtension/RexPull.js +27 -2
  85. data/webpack/react_app/components/TargetingHosts/components/HostStatus.js +1 -1
  86. metadata +16 -7
@@ -0,0 +1,214 @@
1
+ /* eslint-disable max-lines */
2
+ /* eslint-disable camelcase */
3
+ import React, { useState } from 'react';
4
+ import PropTypes from 'prop-types';
5
+ import {
6
+ ExpandableSection,
7
+ DataList,
8
+ DataListCell,
9
+ DataListItemCells,
10
+ DataListItem,
11
+ DataListItemRow,
12
+ } from '@patternfly/react-core';
13
+ import { translate as __ } from 'foremanReact/common/I18n';
14
+ import { TARGETING_TYPES } from './JobInvocationConstants';
15
+
16
+ const ItemsParser = ({ items }) => (
17
+ <>
18
+ {items.map(
19
+ ({ title, value, wrappedValue }, index) =>
20
+ value && (
21
+ <DataListItem key={index}>
22
+ <DataListItemRow>
23
+ <DataListItemCells
24
+ dataListCells={[
25
+ <DataListCell width={1} key={0}>
26
+ {title}
27
+ </DataListCell>,
28
+ <DataListCell width={4} key={1}>
29
+ {wrappedValue || value}
30
+ </DataListCell>,
31
+ ]}
32
+ />
33
+ </DataListItemRow>
34
+ </DataListItem>
35
+ )
36
+ )}
37
+ </>
38
+ );
39
+ const Schedule = ({ data }) => {
40
+ const [isExpanded, setIsExpanded] = useState(false);
41
+ const {
42
+ concurrency_level,
43
+ scheduling,
44
+ time_to_pickup,
45
+ execution_timeout_interval,
46
+ } = data;
47
+ if (
48
+ !concurrency_level &&
49
+ !scheduling &&
50
+ !time_to_pickup &&
51
+ !execution_timeout_interval
52
+ )
53
+ return null;
54
+ const items = [
55
+ { title: __('Concurrency level limited to'), value: concurrency_level },
56
+ { title: __('Scheduled to start before'), value: scheduling?.start_before },
57
+ { title: __('Scheduled to start at'), value: scheduling?.start_at },
58
+ {
59
+ title: __('Timeout to kill after'),
60
+ value: execution_timeout_interval,
61
+ wrappedValue: `${execution_timeout_interval} ${__('seconds')}`,
62
+ },
63
+ {
64
+ title: __('Time to pickup'),
65
+ value: time_to_pickup,
66
+ wrappedValue: `${time_to_pickup} ${__('seconds')}`,
67
+ },
68
+ ];
69
+ return (
70
+ <ExpandableSection
71
+ toggleText={__('Schedule')}
72
+ onToggle={setIsExpanded}
73
+ isExpanded={isExpanded}
74
+ >
75
+ <DataList isCompact>
76
+ <ItemsParser items={items} />
77
+ </DataList>
78
+ </ExpandableSection>
79
+ );
80
+ };
81
+ const Recurring = ({ data }) => {
82
+ const [isExpanded, setIsExpanded] = useState(false);
83
+ const { recurrence } = data;
84
+
85
+ if (!recurrence) return null;
86
+ const items = [
87
+ {
88
+ title: __('ID'),
89
+ value: recurrence.id,
90
+ wrappedValue: (
91
+ <a href={`/foreman_tasks/recurring_logics/${recurrence.id}`}>
92
+ {recurrence.id}
93
+ </a>
94
+ ),
95
+ },
96
+ { title: __('Cron line'), value: recurrence.cron_line },
97
+ // TODO { title:__('Action') , value: {format_task_input(recurring_logic.tasks.last)} },
98
+ { title: __('Last occurrence'), value: recurrence.last_occurrence },
99
+ { title: __('Next occurrence'), value: recurrence.next_occurrence },
100
+ { title: __('Current iteration'), value: recurrence.iteration },
101
+ { title: __('Iteration limit'), value: recurrence.max_iteration },
102
+ { title: __('Repeat until'), value: recurrence.end_time },
103
+ // TODO { title:__('State') , value: {recurring_logic_state(recurring_logic)} },
104
+ { title: __('Purpose'), value: recurrence.purpose },
105
+ { title: __('Task count'), value: recurrence.task_count },
106
+ ];
107
+ return (
108
+ <ExpandableSection
109
+ toggleText={__('Recurring logic')}
110
+ onToggle={setIsExpanded}
111
+ isExpanded={isExpanded}
112
+ >
113
+ <DataList isCompact>
114
+ <ItemsParser items={items} />
115
+ </DataList>
116
+ </ExpandableSection>
117
+ );
118
+ };
119
+ const TargetHosts = ({ data }) => {
120
+ const [isExpanded, setIsExpanded] = useState(false);
121
+ const {
122
+ targeting,
123
+ job_location: location,
124
+ job_organization: organization,
125
+ } = data;
126
+
127
+ const targetingSelectioning = targeting.bookmark_name
128
+ ? `${__('Bookmark')} ${targeting.bookmark_name}`
129
+ : __('Manual selection');
130
+ const items = [
131
+ {
132
+ title: __('Organization'),
133
+ value: true,
134
+ wrappedValue: organization || __('Any organization'),
135
+ },
136
+ {
137
+ title: __('Location'),
138
+ value: true,
139
+ wrappedValue: location || __('Any location'),
140
+ },
141
+ {
142
+ title: __('Execution order'),
143
+ value: true,
144
+ wrappedValue: targeting.randomized_ordering
145
+ ? __('Randomized')
146
+ : __('Alphabetical'),
147
+ },
148
+ ];
149
+ return (
150
+ <ExpandableSection
151
+ toggleText={__('Target Hosts')}
152
+ onToggle={setIsExpanded}
153
+ isExpanded={isExpanded}
154
+ >
155
+ <span>{targetingSelectioning}</span>{' '}
156
+ <span>
157
+ {__('using ')}
158
+ <b>{TARGETING_TYPES[targeting.targeting_type].toLowerCase()}</b>
159
+ </span>
160
+ <pre>{targeting.search_query}</pre>
161
+ <DataList isCompact>
162
+ <ItemsParser items={items} />
163
+ </DataList>
164
+ </ExpandableSection>
165
+ );
166
+ };
167
+ const Inputs = ({ data }) => {
168
+ const [isExpanded, setIsExpanded] = useState(false);
169
+ const inputs =
170
+ data?.pattern_template_invocations?.[0]?.template_invocation_input_values;
171
+
172
+ if (!inputs) return null;
173
+ return (
174
+ <ExpandableSection
175
+ toggleText={__('User Inputs')}
176
+ onToggle={setIsExpanded}
177
+ isExpanded={isExpanded}
178
+ >
179
+ <DataList isCompact>
180
+ <ItemsParser
181
+ items={inputs.map(({ template_input_name: title, value }) => ({
182
+ title,
183
+ value: true,
184
+ wrappedValue: value,
185
+ }))}
186
+ />
187
+ </DataList>
188
+ </ExpandableSection>
189
+ );
190
+ };
191
+ export const JobAdditionInfo = ({ data }) => (
192
+ <>
193
+ <Recurring data={data} />
194
+ <TargetHosts data={data} />
195
+ <Inputs data={data} />
196
+ <Schedule data={data} />
197
+ </>
198
+ );
199
+
200
+ JobAdditionInfo.propTypes = {
201
+ data: PropTypes.shape({
202
+ recurrence: PropTypes.object,
203
+ targeting: PropTypes.object,
204
+ }).isRequired,
205
+ };
206
+
207
+ Recurring.propTypes = JobAdditionInfo.propTypes;
208
+ TargetHosts.propTypes = JobAdditionInfo.propTypes;
209
+ Inputs.propTypes = JobAdditionInfo.propTypes;
210
+ Schedule.propTypes = JobAdditionInfo.propTypes;
211
+
212
+ ItemsParser.propTypes = {
213
+ items: PropTypes.array.isRequired,
214
+ };
@@ -19,6 +19,15 @@ export const JOB_INVOCATION_HOSTS = 'JOB_INVOCATION_HOSTS';
19
19
  export const currentPermissionsUrl = foremanUrl(
20
20
  '/api/v2/permissions/current_permissions'
21
21
  );
22
+ export const GET_TEMPLATE_INVOCATION = 'GET_TEMPLATE_INVOCATION';
23
+ export const showTemplateInvocationUrl = (hostID, jobID) =>
24
+ `/show_template_invocation_by_host/${hostID}/job_invocation/${jobID}`;
25
+
26
+ export const templateInvocationPageUrl = (hostID, jobID) =>
27
+ `/job_invocations_detail/${jobID}/host_invocation/${hostID}`;
28
+
29
+ export const jobInvocationDetailsUrl = id =>
30
+ `/experimental/job_invocations_detail/${id}`;
22
31
 
23
32
  export const STATUS = {
24
33
  PENDING: 'pending',
@@ -33,6 +42,14 @@ export const STATUS_UPPERCASE = {
33
42
  PENDING: 'PENDING',
34
43
  };
35
44
 
45
+ export const STATUS_TITLES = {
46
+ ALL_STATUSES: { id: 'all_statuses', title: __('All statuses') },
47
+ SUCCESS: { id: 'success', title: __('Succeeded') },
48
+ FAILED: { id: 'failed', title: __('Failed') },
49
+ PENDING: { id: 'pending', title: __('In Progress') },
50
+ CANCELLED: { id: 'cancelled', title: __('Cancelled') },
51
+ };
52
+
36
53
  export const DATE_OPTIONS = {
37
54
  day: 'numeric',
38
55
  month: 'short',
@@ -52,7 +69,7 @@ const Columns = () => {
52
69
  return { title: __('Failed'), status: 1 };
53
70
  case 'planned':
54
71
  return { title: __('Scheduled'), status: 2 };
55
- case 'running':
72
+ case 'running' || 'pending':
56
73
  return { title: __('Pending'), status: 3 };
57
74
  case 'cancelled':
58
75
  return { title: __('Cancelled'), status: 4 };
@@ -65,18 +82,25 @@ const Columns = () => {
65
82
  const hostDetailsPageUrl = useForemanHostDetailsPageUrl();
66
83
 
67
84
  return {
85
+ expand: {
86
+ title: '',
87
+ weight: 0,
88
+ wrapper: () => null,
89
+ },
68
90
  name: {
69
91
  title: __('Name'),
70
92
  wrapper: ({ name }) => (
71
93
  <a href={`${hostDetailsPageUrl}${name}`}>{name}</a>
72
94
  ),
95
+ isSorted: true,
73
96
  weight: 1,
74
97
  },
75
- groups: {
98
+ hostgroup: {
76
99
  title: __('Host group'),
77
100
  wrapper: ({ hostgroup_id, hostgroup_name }) => (
78
101
  <a href={`/hostgroups/${hostgroup_id}/edit`}>{hostgroup_name}</a>
79
102
  ),
103
+ isSorted: true,
80
104
  weight: 2,
81
105
  },
82
106
  os: {
@@ -86,6 +110,7 @@ const Columns = () => {
86
110
  {operatingsystem_name}
87
111
  </a>
88
112
  ),
113
+ isSorted: true,
89
114
  weight: 3,
90
115
  },
91
116
  smart_proxy: {
@@ -93,6 +118,7 @@ const Columns = () => {
93
118
  wrapper: ({ smart_proxy_name, smart_proxy_id }) => (
94
119
  <a href={`/smart_proxies/${smart_proxy_id}`}>{smart_proxy_name}</a>
95
120
  ),
121
+ isSorted: true,
96
122
  weight: 4,
97
123
  },
98
124
  status: {
@@ -109,7 +135,19 @@ const Columns = () => {
109
135
  },
110
136
  weight: 5,
111
137
  },
138
+ actions: {
139
+ title: '',
140
+ weight: 6,
141
+ wrapper: () => null,
142
+ },
112
143
  };
113
144
  };
114
145
 
115
146
  export default Columns;
147
+
148
+ const STATIC_TYPE = 'static_query';
149
+ const DYNAMIC_TYPE = 'dynamic_query';
150
+ export const TARGETING_TYPES = {
151
+ [STATIC_TYPE]: __('Static Query'),
152
+ [DYNAMIC_TYPE]: __('Dynamic Query'),
153
+ };
@@ -38,3 +38,73 @@
38
38
  height: $chart_size;
39
39
  }
40
40
  }
41
+ .job-additional-info {
42
+ padding: 0;
43
+ margin-bottom: -10px;
44
+ }
45
+ .job-details-table-section {
46
+ section:nth-child(1) {
47
+ padding: 0;
48
+ }
49
+ }
50
+
51
+ .template-invocation {
52
+ &.output-in-table-view {
53
+ div.invocation-output {
54
+ overflow: auto;
55
+ max-height: 25em;
56
+ }
57
+ }
58
+ div.invocation-output {
59
+ display: block;
60
+ padding: 9.5px;
61
+ margin: 0 0 10px;
62
+ font-size: 12px;
63
+ word-break: break-all;
64
+ word-wrap: break-word;
65
+ color: rgba(255, 255, 255, 1);
66
+ background-color: rgba(47, 47, 47, 1);
67
+ border: 1px solid #000000;
68
+ border-radius: 0px;
69
+ font-family: Menlo, Monaco, Consolas, monospace;
70
+
71
+ div.printable {
72
+ min-height: 50px;
73
+ }
74
+
75
+ div.line.stderr,
76
+ div.line.error,
77
+ div.line.debug {
78
+ color: red;
79
+ }
80
+
81
+ div.line span.counter {
82
+ float: left;
83
+ clear: left;
84
+ }
85
+
86
+ div.line div.content {
87
+ position: relative;
88
+ margin-left: 50px;
89
+ white-space: pre-wrap;
90
+ }
91
+
92
+ a {
93
+ color: #ffffff;
94
+ }
95
+
96
+ a.scroll-link{
97
+ position: relative;
98
+ bottom: 10px;
99
+ float: right;
100
+ }
101
+ }
102
+
103
+ .template-invocation-preview {
104
+ margin-top: 10px;
105
+ }
106
+
107
+ .pf-c-toggle-group {
108
+ margin-bottom: 10px;
109
+ }
110
+ }