foreman_remote_execution 14.0.0 → 14.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman_remote_execution/locale/de/foreman_remote_execution.js +77 -77
  3. data/app/assets/javascripts/foreman_remote_execution/locale/en/foreman_remote_execution.js +2 -1667
  4. data/app/assets/javascripts/foreman_remote_execution/locale/en_GB/foreman_remote_execution.js +7 -7
  5. data/app/assets/javascripts/foreman_remote_execution/locale/es/foreman_remote_execution.js +33 -33
  6. data/app/assets/javascripts/foreman_remote_execution/locale/fr/foreman_remote_execution.js +131 -131
  7. data/app/assets/javascripts/foreman_remote_execution/locale/ja/foreman_remote_execution.js +131 -131
  8. data/app/assets/javascripts/foreman_remote_execution/locale/ka/foreman_remote_execution.js +38 -38
  9. data/app/assets/javascripts/foreman_remote_execution/locale/ko/foreman_remote_execution.js +16 -16
  10. data/app/assets/javascripts/foreman_remote_execution/locale/pt_BR/foreman_remote_execution.js +33 -33
  11. data/app/assets/javascripts/foreman_remote_execution/locale/ru/foreman_remote_execution.js +7 -7
  12. data/app/assets/javascripts/foreman_remote_execution/locale/zh_CN/foreman_remote_execution.js +134 -134
  13. data/app/assets/javascripts/foreman_remote_execution/locale/zh_TW/foreman_remote_execution.js +6 -6
  14. data/app/controllers/api/v2/job_invocations_controller.rb +34 -17
  15. data/app/helpers/job_invocations_helper.rb +1 -1
  16. data/app/helpers/remote_execution_helper.rb +2 -2
  17. data/app/lib/actions/remote_execution/proxy_action.rb +10 -5
  18. data/app/lib/actions/remote_execution/run_host_job.rb +1 -1
  19. data/app/lib/actions/remote_execution/template_invocation_progress_logging.rb +2 -3
  20. data/app/models/concerns/foreman_remote_execution/errors_flattener.rb +2 -2
  21. data/app/views/api/v2/job_invocations/hosts.json.rabl +15 -0
  22. data/app/views/template_invocations/show.html.erb +1 -1
  23. data/app/views/templates/script/package_action.erb +1 -1
  24. data/config/routes.rb +1 -0
  25. data/db/migrate/20240312133027_extend_template_invocation_events.rb +19 -0
  26. data/db/migrate/20240522093413_migrate_smart_proxy_ids_to_template_invocations.rb +3 -0
  27. data/lib/foreman_remote_execution/engine.rb +0 -4
  28. data/lib/foreman_remote_execution/version.rb +1 -1
  29. data/locale/Makefile +12 -2
  30. data/locale/de/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  31. data/locale/de/foreman_remote_execution.po +81 -80
  32. data/locale/en/foreman_remote_execution.po +0 -1675
  33. data/locale/en_GB/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  34. data/locale/en_GB/foreman_remote_execution.po +7 -7
  35. data/locale/es/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  36. data/locale/es/foreman_remote_execution.po +33 -33
  37. data/locale/fr/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  38. data/locale/fr/foreman_remote_execution.po +132 -132
  39. data/locale/ja/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  40. data/locale/ja/foreman_remote_execution.po +131 -131
  41. data/locale/ka/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  42. data/locale/ka/foreman_remote_execution.po +38 -38
  43. data/locale/ko/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  44. data/locale/ko/foreman_remote_execution.po +16 -16
  45. data/locale/pt_BR/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  46. data/locale/pt_BR/foreman_remote_execution.po +33 -33
  47. data/locale/ru/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  48. data/locale/ru/foreman_remote_execution.po +7 -7
  49. data/locale/zh_CN/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  50. data/locale/zh_CN/foreman_remote_execution.po +136 -134
  51. data/locale/zh_TW/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  52. data/locale/zh_TW/foreman_remote_execution.po +6 -6
  53. data/webpack/JobInvocationDetail/JobInvocationActions.js +1 -1
  54. data/webpack/JobInvocationDetail/JobInvocationConstants.js +84 -0
  55. data/webpack/JobInvocationDetail/JobInvocationDetail.scss +0 -1
  56. data/webpack/JobInvocationDetail/JobInvocationHostTable.js +210 -0
  57. data/webpack/JobInvocationDetail/JobInvocationSelectors.js +2 -2
  58. data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +5 -1
  59. data/webpack/JobInvocationDetail/__tests__/fixtures.js +9 -0
  60. data/webpack/JobInvocationDetail/index.js +56 -34
  61. data/webpack/__mocks__/foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState.js +1 -2
  62. data/webpack/react_app/components/RecentJobsCard/JobStatusIcon.js +38 -7
  63. data/webpack/react_app/components/RecentJobsCard/constants.js +4 -0
  64. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostStatus.test.js.snap +1 -1
  65. data/webpack/react_app/components/TargetingHosts/components/HostStatus.js +6 -6
  66. metadata +6 -95
  67. data/.babelrc.js +0 -3
  68. data/.eslintignore +0 -3
  69. data/.eslintrc +0 -13
  70. data/.github/workflows/js_ci.yml +0 -32
  71. data/.github/workflows/release.yml +0 -16
  72. data/.github/workflows/ruby_ci.yml +0 -19
  73. data/.gitignore +0 -18
  74. data/.packit.yaml +0 -45
  75. data/.prettierrc +0 -4
  76. data/.rubocop.yml +0 -105
  77. data/.rubocop_todo.yml +0 -516
  78. data/.tx/config +0 -10
  79. data/Gemfile +0 -5
  80. data/app/mailers/.gitkeep +0 -0
  81. data/app/views/dashboard/.gitkeep +0 -0
  82. data/foreman_remote_execution.gemspec +0 -33
  83. data/jsconfig.json +0 -8
  84. data/locale/action_names.rb +0 -2
  85. data/test/benchmark/run_hosts_job_benchmark.rb +0 -70
  86. data/test/benchmark/targeting_benchmark.rb +0 -31
  87. data/test/factories/foreman_remote_execution_factories.rb +0 -147
  88. data/test/functional/api/v2/foreign_input_sets_controller_test.rb +0 -58
  89. data/test/functional/api/v2/job_invocations_controller_test.rb +0 -446
  90. data/test/functional/api/v2/job_templates_controller_test.rb +0 -110
  91. data/test/functional/api/v2/registration_controller_test.rb +0 -73
  92. data/test/functional/api/v2/remote_execution_features_controller_test.rb +0 -34
  93. data/test/functional/api/v2/template_invocations_controller_test.rb +0 -33
  94. data/test/functional/cockpit_controller_test.rb +0 -16
  95. data/test/functional/job_invocations_controller_test.rb +0 -132
  96. data/test/functional/job_templates_controller_test.rb +0 -31
  97. data/test/functional/ui_job_wizard_controller_test.rb +0 -16
  98. data/test/graphql/mutations/job_invocations/create_test.rb +0 -58
  99. data/test/graphql/queries/job_invocation_query_test.rb +0 -31
  100. data/test/graphql/queries/job_invocations_query_test.rb +0 -35
  101. data/test/helpers/remote_execution_helper_test.rb +0 -46
  102. data/test/support/remote_execution_helper.rb +0 -5
  103. data/test/test_plugin_helper.rb +0 -9
  104. data/test/unit/actions/run_host_job_test.rb +0 -115
  105. data/test/unit/actions/run_hosts_job_test.rb +0 -214
  106. data/test/unit/api_params_test.rb +0 -25
  107. data/test/unit/concerns/foreman_tasks_cleaner_extensions_test.rb +0 -29
  108. data/test/unit/concerns/host_extensions_test.rb +0 -219
  109. data/test/unit/concerns/nic_extensions_test.rb +0 -9
  110. data/test/unit/execution_task_status_mapper_test.rb +0 -92
  111. data/test/unit/input_template_renderer_test.rb +0 -503
  112. data/test/unit/job_invocation_composer_test.rb +0 -974
  113. data/test/unit/job_invocation_report_template_test.rb +0 -60
  114. data/test/unit/job_invocation_test.rb +0 -232
  115. data/test/unit/job_template_effective_user_test.rb +0 -37
  116. data/test/unit/job_template_test.rb +0 -316
  117. data/test/unit/remote_execution_feature_test.rb +0 -86
  118. data/test/unit/remote_execution_provider_test.rb +0 -298
  119. data/test/unit/renderer_scope_input_test.rb +0 -49
  120. data/test/unit/targeting_test.rb +0 -206
  121. data/test/unit/template_invocation_input_value_test.rb +0 -38
@@ -5,11 +5,11 @@
5
5
  # Translators:
6
6
  msgid ""
7
7
  msgstr ""
8
- "Project-Id-Version: foreman_remote_execution 9.0.1\n"
8
+ "Project-Id-Version: foreman_remote_execution 14.0.0\n"
9
9
  "Report-Msgid-Bugs-To: \n"
10
10
  "PO-Revision-Date: 2016-02-15 13:54+0000\n"
11
11
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12
- "Language-Team: Chinese (Taiwan) (http://www.transifex.com/foreman/foreman/lang"
12
+ "Language-Team: Chinese (Taiwan) (http://app.transifex.com/foreman/foreman/lang"
13
13
  "uage/zh_TW/)\n"
14
14
  "MIME-Version: 1.0\n"
15
15
  "Content-Type: text/plain; charset=UTF-8\n"
@@ -86,7 +86,7 @@ msgid "Abort Job"
86
86
  msgstr ""
87
87
 
88
88
  msgid "Access denied"
89
- msgstr ""
89
+ msgstr "拒絕存取"
90
90
 
91
91
  msgid "Actions"
92
92
  msgstr "動作"
@@ -137,7 +137,7 @@ msgid "Awaiting start"
137
137
  msgstr ""
138
138
 
139
139
  msgid "Back"
140
- msgstr ""
140
+ msgstr "上一步"
141
141
 
142
142
  msgid "Back to Job"
143
143
  msgstr "回到工作"
@@ -776,7 +776,7 @@ msgid "New UI"
776
776
  msgstr ""
777
777
 
778
778
  msgid "Next"
779
- msgstr ""
779
+ msgstr "下一步"
780
780
 
781
781
  msgid "No (override)"
782
782
  msgstr ""
@@ -1555,7 +1555,7 @@ msgid "You are not allowed to see the currently assigned template. Saving the fo
1555
1555
  msgstr "您不能看到目前指定的範本。現在儲存表單會取消指定範本。"
1556
1556
 
1557
1557
  msgid "You are not authorized to perform this action."
1558
- msgstr ""
1558
+ msgstr "您未經許可執行這項動作。"
1559
1559
 
1560
1560
  msgid "You have %s results to display. Showing first %s results"
1561
1561
  msgstr ""
@@ -15,7 +15,7 @@ import {
15
15
  UPDATE_JOB,
16
16
  } from './JobInvocationConstants';
17
17
 
18
- export const getData = url => dispatch => {
18
+ export const getJobInvocation = url => dispatch => {
19
19
  const fetchData = withInterval(
20
20
  get({
21
21
  key: JOB_INVOCATION_KEY,
@@ -1,14 +1,21 @@
1
+ /* eslint-disable camelcase */
2
+ import React from 'react';
1
3
  import { foremanUrl } from 'foremanReact/common/helpers';
4
+ import { translate as __ } from 'foremanReact/common/I18n';
5
+ import { useForemanHostDetailsPageUrl } from 'foremanReact/Root/Context/ForemanContext';
6
+ import JobStatusIcon from '../react_app/components/RecentJobsCard/JobStatusIcon';
2
7
 
3
8
  export const JOB_INVOCATION_KEY = 'JOB_INVOCATION_KEY';
4
9
  export const CURRENT_PERMISSIONS = 'CURRENT_PERMISSIONS';
5
10
  export const UPDATE_JOB = 'UPDATE_JOB';
6
11
  export const CANCEL_JOB = 'CANCEL_JOB';
7
12
  export const GET_TASK = 'GET_TASK';
13
+ export const GET_TEMPLATE_INVOCATIONS = 'GET_TEMPLATE_INVOCATIONS';
8
14
  export const CHANGE_ENABLED_RECURRING_LOGIC = 'CHANGE_ENABLED_RECURRING_LOGIC';
9
15
  export const CANCEL_RECURRING_LOGIC = 'CANCEL_RECURRING_LOGIC';
10
16
  export const GET_REPORT_TEMPLATES = 'GET_REPORT_TEMPLATES';
11
17
  export const GET_REPORT_TEMPLATE_INPUTS = 'GET_REPORT_TEMPLATE_INPUTS';
18
+ export const JOB_INVOCATION_HOSTS = 'JOB_INVOCATION_HOSTS';
12
19
  export const currentPermissionsUrl = foremanUrl(
13
20
  '/api/v2/permissions/current_permissions'
14
21
  );
@@ -20,6 +27,12 @@ export const STATUS = {
20
27
  CANCELLED: 'cancelled',
21
28
  };
22
29
 
30
+ export const STATUS_UPPERCASE = {
31
+ RESOLVED: 'RESOLVED',
32
+ ERROR: 'ERROR',
33
+ PENDING: 'PENDING',
34
+ };
35
+
23
36
  export const DATE_OPTIONS = {
24
37
  day: 'numeric',
25
38
  month: 'short',
@@ -29,3 +42,74 @@ export const DATE_OPTIONS = {
29
42
  hour12: false,
30
43
  timeZoneName: 'short',
31
44
  };
45
+
46
+ const Columns = () => {
47
+ const getColumnsStatus = ({ hostJobStatus }) => {
48
+ switch (hostJobStatus) {
49
+ case 'success':
50
+ return { title: __('Succeeded'), status: 0 };
51
+ case 'error':
52
+ return { title: __('Failed'), status: 1 };
53
+ case 'planned':
54
+ return { title: __('Scheduled'), status: 2 };
55
+ case 'running':
56
+ return { title: __('Pending'), status: 3 };
57
+ case 'cancelled':
58
+ return { title: __('Cancelled'), status: 4 };
59
+ case 'N/A':
60
+ return { title: __('Awaiting start'), status: 5 };
61
+ default:
62
+ return { title: hostJobStatus, status: 6 };
63
+ }
64
+ };
65
+ const hostDetailsPageUrl = useForemanHostDetailsPageUrl();
66
+
67
+ return {
68
+ name: {
69
+ title: __('Name'),
70
+ wrapper: ({ name }) => (
71
+ <a href={`${hostDetailsPageUrl}${name}`}>{name}</a>
72
+ ),
73
+ weight: 1,
74
+ },
75
+ groups: {
76
+ title: __('Host group'),
77
+ wrapper: ({ hostgroup_id, hostgroup_name }) => (
78
+ <a href={`/hostgroups/${hostgroup_id}/edit`}>{hostgroup_name}</a>
79
+ ),
80
+ weight: 2,
81
+ },
82
+ os: {
83
+ title: __('OS'),
84
+ wrapper: ({ operatingsystem_id, operatingsystem_name }) => (
85
+ <a href={`/operatingsystems/${operatingsystem_id}/edit`}>
86
+ {operatingsystem_name}
87
+ </a>
88
+ ),
89
+ weight: 3,
90
+ },
91
+ smart_proxy: {
92
+ title: __('Smart proxy'),
93
+ wrapper: ({ smart_proxy_name, smart_proxy_id }) => (
94
+ <a href={`/smart_proxies/${smart_proxy_id}`}>{smart_proxy_name}</a>
95
+ ),
96
+ weight: 4,
97
+ },
98
+ status: {
99
+ title: __('Status'),
100
+ wrapper: ({ job_status }) => {
101
+ const { title, status } = getColumnsStatus({
102
+ hostJobStatus: job_status,
103
+ });
104
+ return (
105
+ <JobStatusIcon status={status}>
106
+ {title || __('Unknown')}
107
+ </JobStatusIcon>
108
+ );
109
+ },
110
+ weight: 5,
111
+ },
112
+ };
113
+ };
114
+
115
+ export default Columns;
@@ -38,4 +38,3 @@
38
38
  height: $chart_size;
39
39
  }
40
40
  }
41
-
@@ -0,0 +1,210 @@
1
+ /* eslint-disable camelcase */
2
+ import PropTypes from 'prop-types';
3
+ import React, { useMemo, useEffect } from 'react';
4
+ import { Icon } from 'patternfly-react';
5
+ import { translate as __ } from 'foremanReact/common/I18n';
6
+ import { FormattedMessage } from 'react-intl';
7
+ import { Tr, Td } from '@patternfly/react-table';
8
+ import {
9
+ Title,
10
+ EmptyState,
11
+ EmptyStateVariant,
12
+ EmptyStateBody,
13
+ } from '@patternfly/react-core';
14
+ import { foremanUrl } from 'foremanReact/common/helpers';
15
+ import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
16
+ import { Table } from 'foremanReact/components/PF4/TableIndexPage/Table/Table';
17
+ import TableIndexPage from 'foremanReact/components/PF4/TableIndexPage/TableIndexPage';
18
+ import { useSetParamsAndApiAndSearch } from 'foremanReact/components/PF4/TableIndexPage/Table/TableIndexHooks';
19
+ import {
20
+ useBulkSelect,
21
+ useUrlParams,
22
+ } from 'foremanReact/components/PF4/TableIndexPage/Table/TableHooks';
23
+ import Pagination from 'foremanReact/components/Pagination';
24
+ import { getControllerSearchProps } from 'foremanReact/constants';
25
+ import Columns, {
26
+ JOB_INVOCATION_HOSTS,
27
+ STATUS_UPPERCASE,
28
+ } from './JobInvocationConstants';
29
+
30
+ const JobInvocationHostTable = ({ id, targeting, finished, autoRefresh }) => {
31
+ const columns = Columns();
32
+ const columnNamesKeys = Object.keys(columns);
33
+ const apiOptions = { key: JOB_INVOCATION_HOSTS };
34
+ const {
35
+ searchParam: urlSearchQuery = '',
36
+ page: urlPage,
37
+ per_page: urlPerPage,
38
+ } = useUrlParams();
39
+ const defaultParams = { search: urlSearchQuery };
40
+ if (urlPage) defaultParams.page = Number(urlPage);
41
+ if (urlPerPage) defaultParams.per_page = Number(urlPerPage);
42
+ const { response, status, setAPIOptions } = useAPI(
43
+ 'get',
44
+ `/api/job_invocations/${id}/hosts`,
45
+ {
46
+ params: { ...defaultParams, key: JOB_INVOCATION_HOSTS },
47
+ }
48
+ );
49
+
50
+ const combinedResponse = {
51
+ response: {
52
+ search: urlSearchQuery,
53
+ can_create: false,
54
+ results: response?.results || [],
55
+ total: response?.total || 0,
56
+ per_page: response?.perPage,
57
+ page: response?.page,
58
+ subtotal: response?.subtotal || 0,
59
+ message: response?.message || 'error',
60
+ },
61
+ status,
62
+ setAPIOptions,
63
+ };
64
+
65
+ const { setParamsAndAPI, params } = useSetParamsAndApiAndSearch({
66
+ defaultParams,
67
+ apiOptions,
68
+ setAPIOptions: combinedResponse.setAPIOptions,
69
+ });
70
+
71
+ const { updateSearchQuery } = useBulkSelect({
72
+ initialSearchQuery: urlSearchQuery,
73
+ });
74
+
75
+ const controller = 'hosts';
76
+ const memoDefaultSearchProps = useMemo(
77
+ () => getControllerSearchProps(controller),
78
+ [controller]
79
+ );
80
+ memoDefaultSearchProps.autocomplete.url = foremanUrl(
81
+ `/${controller}/auto_complete_search`
82
+ );
83
+
84
+ useEffect(() => {
85
+ const intervalId = setInterval(() => {
86
+ if (!finished || autoRefresh) {
87
+ setAPIOptions(prevOptions => ({
88
+ ...prevOptions,
89
+ params: {
90
+ ...prevOptions.params,
91
+ },
92
+ }));
93
+ }
94
+ }, 5000);
95
+
96
+ return () => {
97
+ clearInterval(intervalId);
98
+ };
99
+ }, [finished, autoRefresh, setAPIOptions]);
100
+
101
+ const onPagination = newPagination => {
102
+ setParamsAndAPI({
103
+ ...params,
104
+ ...newPagination,
105
+ search: urlSearchQuery,
106
+ });
107
+ };
108
+
109
+ const bottomPagination = (
110
+ <Pagination
111
+ ouiaId="table-hosts-bottom-pagination"
112
+ key="table-bottom-pagination"
113
+ page={params.page}
114
+ perPage={params.perPage}
115
+ itemCount={response?.subtotal}
116
+ onChange={onPagination}
117
+ />
118
+ );
119
+
120
+ const customEmptyState = (
121
+ <Tr ouiaId="table-empty">
122
+ <Td colSpan={100}>
123
+ <EmptyState variant={EmptyStateVariant.xl}>
124
+ <span className="empty-state-icon">
125
+ <Icon name="add-circle-o" type="pf" size="2x" />
126
+ </span>
127
+ <Title ouiaId="empty-state-header" headingLevel="h5" size="4xl">
128
+ {__('No Results')}
129
+ </Title>
130
+ <EmptyStateBody>
131
+ <div className="empty-state-description">
132
+ {targeting?.targeting_type === 'dynamic_query' ? (
133
+ <FormattedMessage
134
+ id="view-dynamic-hosts"
135
+ defaultMessage={__(
136
+ 'The dynamic query is still being processed. You can {viewTheHosts} targeted by the query.'
137
+ )}
138
+ values={{
139
+ viewTheHosts: (
140
+ <a href={`/new/hosts?search=${targeting?.search_query}`}>
141
+ {__('view the hosts')}
142
+ </a>
143
+ ),
144
+ }}
145
+ />
146
+ ) : (
147
+ __('No hosts found')
148
+ )}
149
+ </div>
150
+ </EmptyStateBody>
151
+ </EmptyState>
152
+ </Td>
153
+ </Tr>
154
+ );
155
+
156
+ return (
157
+ <TableIndexPage
158
+ apiUrl=""
159
+ apiOptions={apiOptions}
160
+ customSearchProps={memoDefaultSearchProps}
161
+ controller="hosts"
162
+ creatable={false}
163
+ replacementResponse={combinedResponse}
164
+ updateSearchQuery={updateSearchQuery}
165
+ >
166
+ <Table
167
+ ouiaId="job-invocation-hosts-table"
168
+ columns={columns}
169
+ customEmptyState={
170
+ status === STATUS_UPPERCASE.RESOLVED && !response?.results?.length
171
+ ? customEmptyState
172
+ : null
173
+ }
174
+ params={params}
175
+ setParams={setParamsAndAPI}
176
+ itemCount={response?.subtotal}
177
+ results={response?.results}
178
+ url=""
179
+ refreshData={() => {}}
180
+ errorMessage={
181
+ status === STATUS_UPPERCASE.ERROR && response?.message
182
+ ? response.message
183
+ : null
184
+ }
185
+ isPending={status === STATUS_UPPERCASE.PENDING}
186
+ isDeleteable={false}
187
+ bottomPagination={bottomPagination}
188
+ >
189
+ {response?.results?.map((result, rowIndex) => (
190
+ <Tr key={rowIndex} ouiaId={`table-row-${rowIndex}`}>
191
+ {columnNamesKeys.map(k => (
192
+ <Td key={k}>{columns[k].wrapper(result)}</Td>
193
+ ))}
194
+ </Tr>
195
+ ))}
196
+ </Table>
197
+ </TableIndexPage>
198
+ );
199
+ };
200
+
201
+ JobInvocationHostTable.propTypes = {
202
+ id: PropTypes.string.isRequired,
203
+ targeting: PropTypes.object.isRequired,
204
+ finished: PropTypes.bool.isRequired,
205
+ autoRefresh: PropTypes.bool.isRequired,
206
+ };
207
+
208
+ JobInvocationHostTable.defaultProps = {};
209
+
210
+ export default JobInvocationHostTable;
@@ -1,10 +1,10 @@
1
1
  import { selectAPIResponse } from 'foremanReact/redux/API/APISelectors';
2
- import { JOB_INVOCATION_KEY } from './JobInvocationConstants';
2
+ import { JOB_INVOCATION_KEY, GET_TASK } from './JobInvocationConstants';
3
3
 
4
4
  export const selectItems = state =>
5
5
  selectAPIResponse(state, JOB_INVOCATION_KEY);
6
6
 
7
- export const selectTask = state => selectAPIResponse(state, 'GET_TASK');
7
+ export const selectTask = state => selectAPIResponse(state, GET_TASK);
8
8
 
9
9
  export const selectTaskCancelable = state =>
10
10
  selectTask(state).available_actions?.cancellable || false;
@@ -76,6 +76,10 @@ api.get.mockImplementation(({ handleSuccess, ...action }) => {
76
76
  return { type: 'get', ...action };
77
77
  });
78
78
 
79
+ jest.mock('../JobInvocationHostTable.js', () => () => (
80
+ <div data-testid="mock-table">Mock Table</div>
81
+ ));
82
+
79
83
  const reportTemplateJobId = mockReportTemplatesResponse.results[0].id;
80
84
 
81
85
  const mockStore = configureMockStore([thunk]);
@@ -207,7 +211,7 @@ describe('JobInvocationDetailPage', () => {
207
211
  { key: GET_REPORT_TEMPLATES, url: '/api/report_templates' },
208
212
  {
209
213
  key: JOB_INVOCATION_KEY,
210
- url: `/api/job_invocations/${jobId}`,
214
+ url: `/api/job_invocations/${jobId}?host_status=true`,
211
215
  },
212
216
  {
213
217
  key: GET_REPORT_TEMPLATE_INPUTS,
@@ -1,4 +1,7 @@
1
1
  export const jobInvocationData = {
2
+ search: '',
3
+ per_page: 20,
4
+ page: 1,
2
5
  id: 123,
3
6
  description: 'Description',
4
7
  job_category: 'Commands',
@@ -40,6 +43,9 @@ export const jobInvocationData = {
40
43
  };
41
44
 
42
45
  export const jobInvocationDataScheduled = {
46
+ search: '',
47
+ per_page: 20,
48
+ page: 1,
43
49
  id: 456,
44
50
  description: 'Description',
45
51
  job_category: 'Commands',
@@ -62,6 +68,9 @@ export const jobInvocationDataScheduled = {
62
68
  };
63
69
 
64
70
  export const jobInvocationDataRecurring = {
71
+ search: '',
72
+ per_page: 20,
73
+ page: 1,
65
74
  id: 789,
66
75
  description: 'Description',
67
76
  job_category: 'Commands',
@@ -1,12 +1,17 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React, { useEffect } from 'react';
3
3
  import { useDispatch, useSelector } from 'react-redux';
4
- import { Divider, Flex } from '@patternfly/react-core';
4
+ import {
5
+ Divider,
6
+ Flex,
7
+ PageSection,
8
+ PageSectionVariants,
9
+ } from '@patternfly/react-core';
5
10
  import { translate as __, documentLocale } from 'foremanReact/common/I18n';
6
11
  import PageLayout from 'foremanReact/routes/common/PageLayout/PageLayout';
7
12
  import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
8
13
  import { stopInterval } from 'foremanReact/redux/middlewares/IntervalMiddleware';
9
- import { getData, getTask } from './JobInvocationActions';
14
+ import { getJobInvocation, getTask } from './JobInvocationActions';
10
15
  import {
11
16
  CURRENT_PERMISSIONS,
12
17
  DATE_OPTIONS,
@@ -19,6 +24,7 @@ import JobInvocationOverview from './JobInvocationOverview';
19
24
  import { selectItems } from './JobInvocationSelectors';
20
25
  import JobInvocationSystemStatusChart from './JobInvocationSystemStatusChart';
21
26
  import JobInvocationToolbarButtons from './JobInvocationToolbarButtons';
27
+ import JobInvocationHostTable from './JobInvocationHostTable';
22
28
 
23
29
  const JobInvocationDetailPage = ({
24
30
  match: {
@@ -32,6 +38,7 @@ const JobInvocationDetailPage = ({
32
38
  status_label: statusLabel,
33
39
  task,
34
40
  start_at: startAt,
41
+ targeting,
35
42
  } = items;
36
43
  const finished =
37
44
  statusLabel === STATUS.FAILED ||
@@ -57,7 +64,7 @@ const JobInvocationDetailPage = ({
57
64
  }
58
65
 
59
66
  useEffect(() => {
60
- dispatch(getData(`/api/job_invocations/${id}`));
67
+ dispatch(getJobInvocation(`/api/job_invocations/${id}?host_status=true`));
61
68
  if (finished && !autoRefresh) {
62
69
  dispatch(stopInterval(JOB_INVOCATION_KEY));
63
70
  }
@@ -82,45 +89,60 @@ const JobInvocationDetailPage = ({
82
89
  };
83
90
 
84
91
  return (
85
- <PageLayout
86
- header={description}
87
- breadcrumbOptions={breadcrumbOptions}
88
- toolbarButtons={
89
- <JobInvocationToolbarButtons
90
- jobId={id}
91
- data={items}
92
- currentPermissions={response.results}
93
- permissionsStatus={status}
94
- />
95
- }
96
- searchable={false}
97
- >
98
- <Flex
99
- className="job-invocation-detail-flex"
100
- alignItems={{ default: 'alignItemsFlexStart' }}
92
+ <>
93
+ <PageLayout
94
+ header={description}
95
+ breadcrumbOptions={breadcrumbOptions}
96
+ toolbarButtons={
97
+ <JobInvocationToolbarButtons
98
+ jobId={id}
99
+ data={items}
100
+ currentPermissions={response.results}
101
+ permissionsStatus={status}
102
+ />
103
+ }
104
+ searchable={false}
101
105
  >
102
- <JobInvocationSystemStatusChart
103
- data={items}
104
- isAlreadyStarted={isAlreadyStarted}
105
- formattedStartDate={formattedStartDate}
106
- />
107
- <Divider
108
- orientation={{
109
- default: 'vertical',
110
- }}
111
- />
112
106
  <Flex
113
- className="job-overview"
114
- alignItems={{ default: 'alignItemsCenter' }}
107
+ className="job-invocation-detail-flex"
108
+ alignItems={{ default: 'alignItemsFlexStart' }}
115
109
  >
116
- <JobInvocationOverview
110
+ <JobInvocationSystemStatusChart
117
111
  data={items}
118
112
  isAlreadyStarted={isAlreadyStarted}
119
113
  formattedStartDate={formattedStartDate}
120
114
  />
115
+ <Divider
116
+ orientation={{
117
+ default: 'vertical',
118
+ }}
119
+ />
120
+ <Flex
121
+ className="job-overview"
122
+ alignItems={{ default: 'alignItemsCenter' }}
123
+ >
124
+ <JobInvocationOverview
125
+ data={items}
126
+ isAlreadyStarted={isAlreadyStarted}
127
+ formattedStartDate={formattedStartDate}
128
+ />
129
+ </Flex>
121
130
  </Flex>
122
- </Flex>
123
- </PageLayout>
131
+ </PageLayout>
132
+ <PageSection
133
+ variant={PageSectionVariants.light}
134
+ className="table-section"
135
+ >
136
+ {items.id !== undefined && (
137
+ <JobInvocationHostTable
138
+ id={id}
139
+ targeting={targeting}
140
+ finished={finished}
141
+ autoRefresh={autoRefresh}
142
+ />
143
+ )}
144
+ </PageSection>
145
+ </>
124
146
  );
125
147
  };
126
148
 
@@ -1,8 +1,7 @@
1
1
  import React from 'react';
2
- import { translate as __ } from '../../../common/I18n';
3
2
 
4
3
  const DefaultLoaderEmptyState = () => (
5
- <span className="disabled-text">{__('Not available')}</span>
4
+ <span className="disabled-text">Not available</span>
6
5
  );
7
6
 
8
7
  export default DefaultLoaderEmptyState;
@@ -3,29 +3,60 @@ import PropTypes from 'prop-types';
3
3
  import {
4
4
  CheckCircleIcon,
5
5
  ExclamationCircleIcon,
6
+ BuildIcon,
7
+ RunningIcon,
8
+ ExclamationTriangleIcon,
6
9
  QuestionCircleIcon,
7
10
  } from '@patternfly/react-icons';
8
- import { JOB_SUCCESS_STATUS, JOB_ERROR_STATUS } from './constants';
11
+ import {
12
+ JOB_SUCCESS_STATUS,
13
+ JOB_ERROR_STATUS,
14
+ JOB_PLANNED_STATUS,
15
+ JOB_RUNNING_STATUS,
16
+ JOB_CANCELLED_STATUS,
17
+ JOB_AWAITING_STATUS,
18
+ } from './constants';
9
19
  import './styles.scss';
10
20
 
11
21
  const JobStatusIcon = ({ status, children, ...props }) => {
12
22
  switch (status) {
13
23
  case JOB_SUCCESS_STATUS:
14
24
  return (
15
- <span className="job-success">
16
- <CheckCircleIcon {...props} /> {children}
25
+ <span>
26
+ <CheckCircleIcon className="job-success" {...props} /> {children}
17
27
  </span>
18
28
  );
19
29
  case JOB_ERROR_STATUS:
20
30
  return (
21
- <span className="job-error">
22
- <ExclamationCircleIcon {...props} /> {children}
31
+ <span>
32
+ <ExclamationCircleIcon className="job-error" {...props} /> {children}
33
+ </span>
34
+ );
35
+ case JOB_PLANNED_STATUS:
36
+ return (
37
+ <span>
38
+ <BuildIcon className="job-planned" {...props} /> {children}
39
+ </span>
40
+ );
41
+ case JOB_RUNNING_STATUS:
42
+ return (
43
+ <span>
44
+ <RunningIcon className="job-running" {...props} /> {children}
45
+ </span>
46
+ );
47
+ case JOB_CANCELLED_STATUS:
48
+ return (
49
+ <span>
50
+ <ExclamationTriangleIcon className="job-cancelled" {...props} />{' '}
51
+ {children}
23
52
  </span>
24
53
  );
54
+ case JOB_AWAITING_STATUS:
55
+ return <span className="job-awaiting_start">{children}</span>;
25
56
  default:
26
57
  return (
27
- <span className="job-info">
28
- <QuestionCircleIcon {...props} /> {children}
58
+ <span>
59
+ <QuestionCircleIcon className="job-unknown" {...props} /> {children}
29
60
  </span>
30
61
  );
31
62
  }
@@ -5,6 +5,10 @@ export const SCHEDULED_TAB = 2;
5
5
 
6
6
  export const JOB_SUCCESS_STATUS = 0;
7
7
  export const JOB_ERROR_STATUS = 1;
8
+ export const JOB_PLANNED_STATUS = 2;
9
+ export const JOB_RUNNING_STATUS = 3;
10
+ export const JOB_CANCELLED_STATUS = 4;
11
+ export const JOB_AWAITING_STATUS = 5;
8
12
 
9
13
  export const JOB_BASE_URL = '/job_invocations?search=targeted_host_id+%3D+';
10
14
  export const JOB_API_URL =
@@ -7,6 +7,6 @@ exports[`HostStatus renders 1`] = `
7
7
  type="pf"
8
8
  />
9
9
 
10
- success
10
+ Succeeded
11
11
  </div>
12
12
  `;