foreman_remote_execution 16.6.5 → 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.5
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-06-23 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
@@ -382,6 +382,7 @@ files:
382
382
  - webpack/JobInvocationDetail/JobInvocationActions.js
383
383
  - webpack/JobInvocationDetail/JobInvocationConstants.js
384
384
  - webpack/JobInvocationDetail/JobInvocationDetail.scss
385
+ - webpack/JobInvocationDetail/JobInvocationEmptyState.js
385
386
  - webpack/JobInvocationDetail/JobInvocationHostTable.js
386
387
  - webpack/JobInvocationDetail/JobInvocationOverview.js
387
388
  - webpack/JobInvocationDetail/JobInvocationSelectors.js
@@ -395,11 +396,13 @@ files:
395
396
  - webpack/JobInvocationDetail/TemplateInvocationComponents/TemplateActionButtons.js
396
397
  - webpack/JobInvocationDetail/TemplateInvocationComponents/index.scss
397
398
  - webpack/JobInvocationDetail/TemplateInvocationPage.js
399
+ - webpack/JobInvocationDetail/__tests__/JobInvocationDetailEmptyState.test.js
398
400
  - webpack/JobInvocationDetail/__tests__/MainInformation.test.js
399
401
  - webpack/JobInvocationDetail/__tests__/OutputCodeBlock.test.js
400
402
  - webpack/JobInvocationDetail/__tests__/TableToolbarActions.test.js
401
403
  - webpack/JobInvocationDetail/__tests__/TemplateInvocation.test.js
402
404
  - webpack/JobInvocationDetail/__tests__/fixtures.js
405
+ - webpack/JobInvocationDetail/__tests__/foremanTestHelpers.js
403
406
  - webpack/JobInvocationDetail/index.js
404
407
  - webpack/JobWizard/Footer.js
405
408
  - webpack/JobWizard/JobWizard.js
@@ -469,6 +472,7 @@ files:
469
472
  - webpack/__mocks__/foremanReact/common/globalIdHelpers.js
470
473
  - webpack/__mocks__/foremanReact/common/helpers.js
471
474
  - webpack/__mocks__/foremanReact/common/hooks/API/APIHooks.js
475
+ - webpack/__mocks__/foremanReact/common/hooks/Permissions/permissionHooks.js
472
476
  - webpack/__mocks__/foremanReact/components/AutoComplete/AutoCompleteActions.js
473
477
  - webpack/__mocks__/foremanReact/components/AutoComplete/AutoCompleteConstants.js
474
478
  - webpack/__mocks__/foremanReact/components/BreadcrumbBar/index.js