foreman_remote_execution 16.6.6 → 16.7.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.
@@ -2,6 +2,7 @@ import '@testing-library/jest-dom/extend-expect';
2
2
  import { fireEvent, render, screen, waitFor } from '@testing-library/react';
3
3
  import axios from 'axios';
4
4
  import { foremanUrl } from 'foremanReact/common/helpers';
5
+ import { usePermissions } from 'foremanReact/common/hooks/Permissions/permissionHooks';
5
6
  import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
6
7
  import React from 'react';
7
8
  import { Provider } from 'react-redux';
@@ -13,6 +14,7 @@ import { PopupAlert } from '../OpenAllInvocationsModal';
13
14
 
14
15
  jest.mock('axios');
15
16
  jest.mock('foremanReact/common/hooks/API/APIHooks');
17
+ jest.mock('foremanReact/common/hooks/Permissions/permissionHooks');
16
18
  jest.mock('../JobInvocationSelectors');
17
19
 
18
20
  jest.mock('../JobInvocationConstants', () => ({
@@ -26,8 +28,8 @@ jest.mock('../JobInvocationConstants', () => ({
26
28
  selectors.selectItems.mockImplementation(() => ({
27
29
  targeting: { search_query: 'name~*' },
28
30
  }));
29
- selectors.selectHasPermission.mockImplementation(() => () => true);
30
31
  selectors.selectTaskCancelable.mockImplementation(() => true);
32
+ usePermissions.mockReturnValue(true);
31
33
 
32
34
  const mockStore = configureStore([]);
33
35
  const store = mockStore({});
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { getForemanContext } from 'foremanReact/Root/Context/ForemanContext';
4
+
5
+ export const createForemanContextWrapper = (
6
+ permissions = ['view_job_invocations', 'create_job_invocations']
7
+ ) => {
8
+ const foremanContextValue = {
9
+ context: {
10
+ metadata: {
11
+ permissions: new Set(permissions),
12
+ UISettings: { perPage: 20 },
13
+ },
14
+ },
15
+ setContext: jest.fn(),
16
+ };
17
+ const ForemanContext = getForemanContext(foremanContextValue);
18
+
19
+ const ForemanContextWrapper = ({ children }) => (
20
+ <ForemanContext.Provider value={foremanContextValue}>
21
+ {children}
22
+ </ForemanContext.Provider>
23
+ );
24
+
25
+ ForemanContextWrapper.propTypes = {
26
+ children: PropTypes.node.isRequired,
27
+ };
28
+
29
+ return ForemanContextWrapper;
30
+ };
@@ -5,29 +5,33 @@ import {
5
5
  PageSectionVariants,
6
6
  Skeleton,
7
7
  } from '@patternfly/react-core';
8
- import React, { useEffect, useState } from 'react';
8
+ import React, { useEffect, useMemo, useState } from 'react';
9
9
  import { translate as __, documentLocale } from 'foremanReact/common/I18n';
10
10
  import { useDispatch, useSelector } from 'react-redux';
11
11
  import PageLayout from 'foremanReact/routes/common/PageLayout/PageLayout';
12
12
  import PropTypes from 'prop-types';
13
13
  import SkeletonLoader from 'foremanReact/components/common/SkeletonLoader';
14
14
  import { stopInterval } from 'foremanReact/redux/middlewares/IntervalMiddleware';
15
- import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
15
+ import { STATUS as API_STATUS } from 'foremanReact/constants';
16
+ import {
17
+ selectAPIErrorMessage,
18
+ selectAPIHttpStatus,
19
+ selectAPIStatus,
20
+ } from 'foremanReact/redux/API/APISelectors';
16
21
 
17
22
  import { JobAdditionInfo } from './JobAdditionInfo';
18
23
  import JobInvocationHostTable from './JobInvocationHostTable';
19
24
  import JobInvocationOverview from './JobInvocationOverview';
20
25
  import JobInvocationSystemStatusChart from './JobInvocationSystemStatusChart';
26
+ import JobInvocationEmptyState from './JobInvocationEmptyState';
21
27
  import JobInvocationToolbarButtons from './JobInvocationToolbarButtons';
22
28
  import { getJobInvocation, getTask } from './JobInvocationActions';
23
29
  import './JobInvocationDetail.scss';
24
30
  import {
25
- CURRENT_PERMISSIONS,
26
31
  DATE_OPTIONS,
27
32
  JOB_INVOCATION_KEY,
28
33
  STATUS,
29
34
  STATUS_UPPERCASE,
30
- currentPermissionsUrl,
31
35
  } from './JobInvocationConstants';
32
36
  import { selectItems } from './JobInvocationSelectors';
33
37
 
@@ -51,9 +55,15 @@ const JobInvocationDetailPage = ({
51
55
  statusLabel === STATUS.SUCCEEDED ||
52
56
  statusLabel === STATUS.CANCELLED;
53
57
  const autoRefresh = task?.state === STATUS.PENDING || false;
54
- useAPI('get', currentPermissionsUrl, {
55
- key: CURRENT_PERMISSIONS,
56
- });
58
+ const jobInvocationApiStatus = useSelector(state =>
59
+ selectAPIStatus(state, JOB_INVOCATION_KEY)
60
+ );
61
+ const jobInvocationErrorMessage = useSelector(state =>
62
+ selectAPIErrorMessage(state, JOB_INVOCATION_KEY)
63
+ );
64
+ const jobInvocationHttpStatus = useSelector(state =>
65
+ selectAPIHttpStatus(state, JOB_INVOCATION_KEY)
66
+ );
57
67
  const [selectedFilter, setSelectedFilter] = useState('');
58
68
 
59
69
  const handleFilterChange = newFilter => {
@@ -72,7 +82,7 @@ const JobInvocationDetailPage = ({
72
82
  }
73
83
 
74
84
  useEffect(() => {
75
- dispatch(getJobInvocation(`/api/job_invocations/${id}?host_status=true`));
85
+ dispatch(getJobInvocation(`/api/job_invocations/${id}`));
76
86
  if (finished && !autoRefresh) {
77
87
  dispatch(stopInterval(JOB_INVOCATION_KEY));
78
88
  }
@@ -88,6 +98,25 @@ const JobInvocationDetailPage = ({
88
98
  }
89
99
  }, [dispatch, taskId]);
90
100
 
101
+ const apiFailed = jobInvocationApiStatus === API_STATUS.ERROR;
102
+
103
+ const backendErrorMessage = useMemo(() => {
104
+ if (jobInvocationApiStatus === API_STATUS.ERROR) {
105
+ return jobInvocationErrorMessage || null;
106
+ }
107
+ return null;
108
+ }, [jobInvocationApiStatus, jobInvocationErrorMessage]);
109
+
110
+ if (apiFailed) {
111
+ return (
112
+ <JobInvocationEmptyState
113
+ jobInvocationId={id}
114
+ httpStatus={jobInvocationHttpStatus}
115
+ errorMessage={backendErrorMessage}
116
+ />
117
+ );
118
+ }
119
+
91
120
  const pageStatus =
92
121
  items.id === undefined
93
122
  ? STATUS_UPPERCASE.PENDING
@@ -123,7 +152,11 @@ const JobInvocationDetailPage = ({
123
152
  <PageLayout
124
153
  header={description}
125
154
  breadcrumbOptions={breadcrumbOptions}
126
- toolbarButtons={<JobInvocationToolbarButtons jobId={id} data={items} />}
155
+ toolbarButtons={
156
+ items.id !== undefined && (
157
+ <JobInvocationToolbarButtons jobId={id} data={items} />
158
+ )
159
+ }
127
160
  searchable={false}
128
161
  >
129
162
  <Flex className="job-invocation-detail-flex">
@@ -1,6 +1,21 @@
1
+ import React from 'react';
2
+
3
+ const getForemanContext = contextData => {
4
+ window.tfm_forced_singletons = window.tfm_forced_singletons || {};
5
+
6
+ if (!window.tfm_forced_singletons.Context) {
7
+ window.tfm_forced_singletons.Context = React.createContext(contextData);
8
+ }
9
+
10
+ return window.tfm_forced_singletons.Context;
11
+ };
12
+
13
+ export { getForemanContext };
1
14
  export const useForemanOrganization = () => ({ id: 1 });
2
15
  export const useForemanLocation = () => ({ id: 2 });
3
16
  export const useForemanVersion = () => '3.7';
4
17
  export const useForemanHostsPageUrl = () => '/hosts';
5
18
  export const useForemanHostDetailsPageUrl = () => '/hosts/';
6
19
  export const useForemanSettings = () => ({ perPage: 20 });
20
+ export const useForemanPermissions = () =>
21
+ new Set(['view_job_invocations', 'create_job_invocations']);
@@ -0,0 +1 @@
1
+ export const usePermissions = jest.fn(() => true);
@@ -19,3 +19,8 @@ export const selectAPIErrorMessage = (state, key) => {
19
19
  const error = selectAPIError(state, key);
20
20
  return error && error.message;
21
21
  };
22
+
23
+ export const selectAPIHttpStatus = (state, key) => {
24
+ const error = selectAPIError(state, key);
25
+ return error?.response?.status;
26
+ };
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_remote_execution
3
3
  version: !ruby/object:Gem::Version
4
- version: 16.6.6
4
+ version: 16.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Foreman Remote Execution team
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-10-02 00:00:00.000000000 Z
10
+ date: 2026-07-13 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: deface
@@ -30,9 +30,6 @@ dependencies:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: 8.3.0
33
- - - "<"
34
- - !ruby/object:Gem::Version
35
- version: '13'
36
33
  type: :runtime
37
34
  prerelease: false
38
35
  version_requirements: !ruby/object:Gem::Requirement
@@ -40,9 +37,6 @@ dependencies:
40
37
  - - ">="
41
38
  - !ruby/object:Gem::Version
42
39
  version: 8.3.0
43
- - - "<"
44
- - !ruby/object:Gem::Version
45
- version: '13'
46
40
  description: A plugin bringing remote execution to the Foreman, completing the config
47
41
  management functionality with remote management functionality.
48
42
  email:
@@ -388,6 +382,7 @@ files:
388
382
  - webpack/JobInvocationDetail/JobInvocationActions.js
389
383
  - webpack/JobInvocationDetail/JobInvocationConstants.js
390
384
  - webpack/JobInvocationDetail/JobInvocationDetail.scss
385
+ - webpack/JobInvocationDetail/JobInvocationEmptyState.js
391
386
  - webpack/JobInvocationDetail/JobInvocationHostTable.js
392
387
  - webpack/JobInvocationDetail/JobInvocationOverview.js
393
388
  - webpack/JobInvocationDetail/JobInvocationSelectors.js
@@ -401,11 +396,13 @@ files:
401
396
  - webpack/JobInvocationDetail/TemplateInvocationComponents/TemplateActionButtons.js
402
397
  - webpack/JobInvocationDetail/TemplateInvocationComponents/index.scss
403
398
  - webpack/JobInvocationDetail/TemplateInvocationPage.js
399
+ - webpack/JobInvocationDetail/__tests__/JobInvocationDetailEmptyState.test.js
404
400
  - webpack/JobInvocationDetail/__tests__/MainInformation.test.js
405
401
  - webpack/JobInvocationDetail/__tests__/OutputCodeBlock.test.js
406
402
  - webpack/JobInvocationDetail/__tests__/TableToolbarActions.test.js
407
403
  - webpack/JobInvocationDetail/__tests__/TemplateInvocation.test.js
408
404
  - webpack/JobInvocationDetail/__tests__/fixtures.js
405
+ - webpack/JobInvocationDetail/__tests__/foremanTestHelpers.js
409
406
  - webpack/JobInvocationDetail/index.js
410
407
  - webpack/JobWizard/Footer.js
411
408
  - webpack/JobWizard/JobWizard.js
@@ -475,6 +472,7 @@ files:
475
472
  - webpack/__mocks__/foremanReact/common/globalIdHelpers.js
476
473
  - webpack/__mocks__/foremanReact/common/helpers.js
477
474
  - webpack/__mocks__/foremanReact/common/hooks/API/APIHooks.js
475
+ - webpack/__mocks__/foremanReact/common/hooks/Permissions/permissionHooks.js
478
476
  - webpack/__mocks__/foremanReact/components/AutoComplete/AutoCompleteActions.js
479
477
  - webpack/__mocks__/foremanReact/components/AutoComplete/AutoCompleteConstants.js
480
478
  - webpack/__mocks__/foremanReact/components/BreadcrumbBar/index.js
@@ -566,7 +564,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
566
564
  - !ruby/object:Gem::Version
567
565
  version: '0'
568
566
  requirements: []
569
- rubygems_version: 4.0.20
567
+ rubygems_version: 4.0.10
570
568
  specification_version: 4
571
569
  summary: A plugin bringing remote execution to the Foreman, completing the config
572
570
  management functionality with remote management functionality.