foreman_rh_cloud 14.2.0 → 14.3.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.
- checksums.yaml +4 -4
- data/app/models/concerns/rh_cloud_host.rb +36 -1
- data/config/routes.rb +1 -0
- data/lib/foreman_inventory_upload/async/upload_report_direct_job.rb +2 -0
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/package.json +1 -1
- data/test/jobs/upload_report_direct_job_test.rb +29 -0
- data/test/unit/insights_facet_test.rb +5 -0
- data/test/unit/rh_cloud_host_test.rb +68 -0
- data/webpack/ForemanInventoryUpload/Components/AccountList/AccountList.js +5 -1
- data/webpack/ForemanInventoryUpload/Components/AccountList/AccountListConstants.js +5 -0
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyResults/EmptyResults.js +15 -6
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyResults/emptyResults.scss +1 -5
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyState/EmptyState.js +15 -7
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyState/__tests__/EmptyState.test.js +1 -3
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyState/emptyState.scss +1 -5
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ErrorState/ErrorState.js +2 -2
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/__tests__/ListItem.test.js +0 -1
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountList.test.js +2 -6
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/Components/ClearButton/ClearButton.js +13 -10
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/InventoryFilter.js +30 -11
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/integration.test.js +3 -1
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/inventoryFilter.scss +28 -22
- data/webpack/ForemanInventoryUpload/Components/InventorySettings/InventorySettings.js +4 -4
- data/webpack/ForemanInventoryUpload/Components/InventorySettings/InventorySettings.scss +16 -3
- data/webpack/ForemanInventoryUpload/Components/InventorySettings/MinimalInventoryDropdown.js +13 -14
- data/webpack/ForemanInventoryUpload/Components/PageHeader/PageHeader.js +7 -7
- data/webpack/ForemanInventoryUpload/Components/PageHeader/PageHeader.scss +3 -2
- data/webpack/ForemanInventoryUpload/Components/PageHeader/PageTitle.js +63 -46
- data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/PageHeader.test.js +4 -7
- data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/PageTitle.test.js +83 -12
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudPingModal/index.js +31 -38
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButton.test.js +3 -1
- data/webpack/ForemanInventoryUpload/Components/TaskConstants.js +6 -0
- data/webpack/ForemanInventoryUpload/Components/TaskHistory/TaskHistory.js +3 -2
- data/webpack/ForemanInventoryUpload/Components/TaskProgress/TaskProgress.js +4 -3
- data/webpack/ForemanInventoryUpload/ForemanInventoryHelpers.js +1 -1
- data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/InventoryAutoUpload.js +29 -22
- data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/__tests__/InventoryAutoUpload.test.js +6 -2
- data/webpack/ForemanInventoryUpload/__tests__/ForemanInventoryHelpers.test.js +9 -6
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +90 -23
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableActions.js +1 -2
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableConstants.js +24 -30
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableHelpers.js +5 -6
- data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/InsightsTable.test.js +193 -8
- data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/InsightsTableActions.test.js +4 -1
- data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationHelpers.js +8 -9
- data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +26 -13
- data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModalFooter.js +5 -2
- data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationTableConstants.js +16 -10
- data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +21 -9
- data/webpack/InsightsCloudSync/InsightsCloudSync.test.js +12 -19
- data/webpack/InsightsCloudSync/__tests__/InsightsCloudSyncActions.test.js +0 -1
- data/webpack/IopRecommendationDetails/IopRecommendationDetails.js +19 -0
- data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware.js +5 -1
- data/webpack/common/DropdownToggle.js +20 -6
- metadata +3 -45
- data/webpack/ForemanInventoryUpload/Components/FileDownload/FileDownload.fixtures.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/FileDownload/FileDownload.js +0 -25
- data/webpack/ForemanInventoryUpload/Components/FileDownload/FileDownloadHelper.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/FileDownload/__tests__/FileDownload.test.js +0 -17
- data/webpack/ForemanInventoryUpload/Components/FileDownload/fileDownload.scss +0 -5
- data/webpack/ForemanInventoryUpload/Components/FileDownload/index.js +0 -1
- data/webpack/ForemanInventoryUpload/Components/NavContainer/NavContainer.fixtures.js +0 -20
- data/webpack/ForemanInventoryUpload/Components/NavContainer/NavContainer.js +0 -66
- data/webpack/ForemanInventoryUpload/Components/NavContainer/NavContainerHelper.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/NavContainer/__tests__/NavContainer.test.js +0 -69
- data/webpack/ForemanInventoryUpload/Components/NavContainer/index.js +0 -1
- data/webpack/ForemanInventoryUpload/Components/NavContainer/navContainer.scss +0 -9
- data/webpack/ForemanInventoryUpload/Components/ScheduledRun/ScheduledRun.fixtures.js +0 -4
- data/webpack/ForemanInventoryUpload/Components/ScheduledRun/ScheduledRun.js +0 -29
- data/webpack/ForemanInventoryUpload/Components/ScheduledRun/ScheduledRunHelper.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/ScheduledRun/__tests__/ScheduledRun.test.js +0 -33
- data/webpack/ForemanInventoryUpload/Components/ScheduledRun/index.js +0 -12
- data/webpack/ForemanInventoryUpload/Components/ScheduledRun/scheduledRun.scss +0 -13
- data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.fixtures.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.js +0 -57
- data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChartHelper.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/StatusChart/__tests__/StatusChart.test.js +0 -30
- data/webpack/ForemanInventoryUpload/Components/StatusChart/index.js +0 -1
- data/webpack/ForemanInventoryUpload/Components/StatusChart/statusChart.scss +0 -10
- data/webpack/ForemanInventoryUpload/Components/TabContainer/TabContainer.fixtures.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/TabContainer/TabContainer.js +0 -24
- data/webpack/ForemanInventoryUpload/Components/TabContainer/TabContainerHelper.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/TabContainer/__tests__/TabContainer.test.js +0 -15
- data/webpack/ForemanInventoryUpload/Components/TabContainer/index.js +0 -1
- data/webpack/ForemanInventoryUpload/Components/TabContainer/tabContainer.scss +0 -10
- data/webpack/ForemanInventoryUpload/Components/TabFooter/TabFooter.fixtures.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/TabFooter/TabFooter.js +0 -19
- data/webpack/ForemanInventoryUpload/Components/TabFooter/TabFooterHelper.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/TabFooter/__tests__/TabFooter.test.js +0 -15
- data/webpack/ForemanInventoryUpload/Components/TabFooter/index.js +0 -1
- data/webpack/ForemanInventoryUpload/Components/TabFooter/tabFooter.scss +0 -0
- data/webpack/ForemanInventoryUpload/Components/TabHeader/TabHeader.fixtures.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/TabHeader/TabHeader.js +0 -85
- data/webpack/ForemanInventoryUpload/Components/TabHeader/TabHeaderHelper.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/TabHeader/__tests__/TabHeader.test.js +0 -114
- data/webpack/ForemanInventoryUpload/Components/TabHeader/index.js +0 -1
- data/webpack/ForemanInventoryUpload/Components/TabHeader/tabHeader.scss +0 -23
- data/webpack/common/Switcher/index.js +0 -80
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Grid } from 'patternfly-
|
|
2
|
+
import { Grid, GridItem } from '@patternfly/react-core';
|
|
3
3
|
import InventorySettings from '../InventorySettings';
|
|
4
4
|
import PageDescription from './components/PageDescription';
|
|
5
5
|
import InventoryFilter from '../InventoryFilter';
|
|
@@ -20,14 +20,14 @@ const PageHeader = () => {
|
|
|
20
20
|
<PageDescription />
|
|
21
21
|
</div>
|
|
22
22
|
)}
|
|
23
|
-
<Grid
|
|
24
|
-
<
|
|
23
|
+
<Grid hasGutter>
|
|
24
|
+
<GridItem span={4}>
|
|
25
25
|
<InventoryFilter />
|
|
26
|
-
</
|
|
27
|
-
<
|
|
26
|
+
</GridItem>
|
|
27
|
+
<GridItem span={8}>
|
|
28
28
|
<ToolbarButtons />
|
|
29
|
-
</
|
|
30
|
-
</Grid
|
|
29
|
+
</GridItem>
|
|
30
|
+
</Grid>
|
|
31
31
|
</div>
|
|
32
32
|
);
|
|
33
33
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.rh-cloud-inventory-page {
|
|
2
2
|
.inventory-upload-header {
|
|
3
|
-
padding: var(--pf-v5-global--spacer--md)
|
|
3
|
+
padding: var(--pf-v5-global--spacer--md) 0 var(--pf-v5-global--spacer--lg) var(--pf-v5-global--spacer--lg);
|
|
4
4
|
|
|
5
5
|
h1 {
|
|
6
6
|
font-family: 'RedHatDisplay';
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
.pf-v5-c-dropdown__toggle {
|
|
16
|
-
margin-right:
|
|
16
|
+
margin-right: 0;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
.settings-alert {
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
.title-dropdown {
|
|
40
40
|
float: right;
|
|
41
|
+
margin-right: -24px;
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { Grid, GridItem } from '@patternfly/react-core';
|
|
3
2
|
import {
|
|
3
|
+
Grid,
|
|
4
|
+
GridItem,
|
|
4
5
|
Dropdown,
|
|
5
6
|
DropdownItem,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from '@patternfly/react-core
|
|
7
|
+
DropdownList,
|
|
8
|
+
MenuToggle,
|
|
9
|
+
} from '@patternfly/react-core';
|
|
10
|
+
import { EllipsisVIcon } from '@patternfly/react-icons';
|
|
11
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
|
9
12
|
import Head from 'foremanReact/components/Head';
|
|
10
13
|
import {
|
|
11
14
|
INVENTORY_PAGE_TITLE,
|
|
@@ -25,37 +28,7 @@ const PageTitle = () => {
|
|
|
25
28
|
const isIop = useIopConfig();
|
|
26
29
|
const [showPingModal, setPingModal] = useState(false);
|
|
27
30
|
const togglePingModal = () => setPingModal(v => !v);
|
|
28
|
-
|
|
29
|
-
<DropdownItem
|
|
30
|
-
key="tasks-history-button"
|
|
31
|
-
ouiaId="tasks-history-button"
|
|
32
|
-
href={getActionsHistoryUrl()}
|
|
33
|
-
target="_blank"
|
|
34
|
-
rel="noopener noreferrer"
|
|
35
|
-
>
|
|
36
|
-
{ACTIONS_HISTORY_BUTTON_TEXT}
|
|
37
|
-
</DropdownItem>,
|
|
38
|
-
<DropdownItem
|
|
39
|
-
key="inventory-documentation-button"
|
|
40
|
-
ouiaId="inventory-documentation-button"
|
|
41
|
-
href={getInventoryDocsUrl()}
|
|
42
|
-
target="_blank"
|
|
43
|
-
rel="noopener noreferrer"
|
|
44
|
-
>
|
|
45
|
-
{DOCS_BUTTON_TEXT}
|
|
46
|
-
</DropdownItem>,
|
|
47
|
-
...(!isIop
|
|
48
|
-
? [
|
|
49
|
-
<DropdownItem
|
|
50
|
-
key="cloud-ping"
|
|
51
|
-
ouiaId="dropdownItem-cloud-ping"
|
|
52
|
-
onClick={togglePingModal}
|
|
53
|
-
>
|
|
54
|
-
{CLOUD_PING_TITLE}
|
|
55
|
-
</DropdownItem>,
|
|
56
|
-
]
|
|
57
|
-
: []),
|
|
58
|
-
];
|
|
31
|
+
|
|
59
32
|
return (
|
|
60
33
|
<Grid className="inventory-upload-header-title">
|
|
61
34
|
<GridItem span={6}>
|
|
@@ -64,21 +37,65 @@ const PageTitle = () => {
|
|
|
64
37
|
</Head>
|
|
65
38
|
<h1>{INVENTORY_PAGE_TITLE}</h1>
|
|
66
39
|
</GridItem>
|
|
67
|
-
<GridItem
|
|
40
|
+
<GridItem
|
|
41
|
+
span={6}
|
|
42
|
+
style={{
|
|
43
|
+
display: 'flex',
|
|
44
|
+
justifyContent: 'flex-end',
|
|
45
|
+
marginRight: '-16px',
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
68
48
|
<Dropdown
|
|
69
49
|
className="title-dropdown"
|
|
70
50
|
ouiaId="title-dropdown"
|
|
71
|
-
onSelect={() => setIsDropdownOpen(false)}
|
|
72
|
-
toggle={
|
|
73
|
-
<KebabToggle
|
|
74
|
-
onToggle={(_event, isOpen) => setIsDropdownOpen(isOpen)}
|
|
75
|
-
/>
|
|
76
|
-
}
|
|
77
51
|
isOpen={isDropdownOpen}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
52
|
+
onSelect={() => setIsDropdownOpen(false)}
|
|
53
|
+
onOpenChange={val => setIsDropdownOpen(val)}
|
|
54
|
+
popperProps={{ position: 'end' }}
|
|
55
|
+
toggle={toggleRef => (
|
|
56
|
+
<MenuToggle
|
|
57
|
+
ref={toggleRef}
|
|
58
|
+
aria-label={__('Actions')}
|
|
59
|
+
variant="plain"
|
|
60
|
+
onClick={() => setIsDropdownOpen(prev => !prev)}
|
|
61
|
+
isExpanded={isDropdownOpen}
|
|
62
|
+
>
|
|
63
|
+
<EllipsisVIcon />
|
|
64
|
+
</MenuToggle>
|
|
65
|
+
)}
|
|
66
|
+
>
|
|
67
|
+
<DropdownList>
|
|
68
|
+
<DropdownItem
|
|
69
|
+
key="tasks-history-button"
|
|
70
|
+
ouiaId="tasks-history-button"
|
|
71
|
+
to={getActionsHistoryUrl()}
|
|
72
|
+
component="a"
|
|
73
|
+
target="_blank"
|
|
74
|
+
rel="noopener noreferrer"
|
|
75
|
+
>
|
|
76
|
+
{ACTIONS_HISTORY_BUTTON_TEXT}
|
|
77
|
+
</DropdownItem>
|
|
78
|
+
<DropdownItem
|
|
79
|
+
key="inventory-documentation-button"
|
|
80
|
+
ouiaId="inventory-documentation-button"
|
|
81
|
+
to={getInventoryDocsUrl()}
|
|
82
|
+
component="a"
|
|
83
|
+
target="_blank"
|
|
84
|
+
rel="noopener noreferrer"
|
|
85
|
+
>
|
|
86
|
+
{DOCS_BUTTON_TEXT}
|
|
87
|
+
</DropdownItem>
|
|
88
|
+
{!isIop && (
|
|
89
|
+
<DropdownItem
|
|
90
|
+
key="cloud-ping"
|
|
91
|
+
ouiaId="dropdownItem-cloud-ping"
|
|
92
|
+
onClick={togglePingModal}
|
|
93
|
+
>
|
|
94
|
+
{CLOUD_PING_TITLE}
|
|
95
|
+
</DropdownItem>
|
|
96
|
+
)}
|
|
97
|
+
</DropdownList>
|
|
98
|
+
</Dropdown>
|
|
82
99
|
<CloudPingModal
|
|
83
100
|
isOpen={showPingModal}
|
|
84
101
|
toggle={togglePingModal}
|
|
@@ -121,14 +121,11 @@ describe('PageHeader', () => {
|
|
|
121
121
|
},
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
-
const
|
|
125
|
-
expect(
|
|
124
|
+
const grid = container.querySelector('.pf-v5-l-grid');
|
|
125
|
+
expect(grid).toBeTruthy();
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
expect(
|
|
129
|
-
|
|
130
|
-
const toolbarColumn = container.querySelector('.col-xs-7');
|
|
131
|
-
expect(toolbarColumn).toBeTruthy();
|
|
127
|
+
expect(screen.getByTestId('inventory-filter')).toBeTruthy();
|
|
128
|
+
expect(screen.getByTestId('toolbar-buttons')).toBeTruthy();
|
|
132
129
|
});
|
|
133
130
|
|
|
134
131
|
test('renders description section only when not in IoP mode', () => {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { act, fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
+
import '@testing-library/jest-dom';
|
|
3
5
|
import PageTitle from '../PageTitle';
|
|
4
6
|
|
|
5
7
|
let mockIopMode = false;
|
|
@@ -15,10 +17,30 @@ jest.mock('foremanReact/Root/Context/ForemanContext', () => ({
|
|
|
15
17
|
}),
|
|
16
18
|
}));
|
|
17
19
|
|
|
18
|
-
jest.mock('../components/CloudPingModal', () =>
|
|
19
|
-
|
|
20
|
-
)
|
|
21
|
-
|
|
20
|
+
jest.mock('../components/CloudPingModal', () => {
|
|
21
|
+
const React = require('react');
|
|
22
|
+
const PropTypes = require('prop-types');
|
|
23
|
+
|
|
24
|
+
const MockCloudPingModal = ({ isOpen, title }) =>
|
|
25
|
+
isOpen ? (
|
|
26
|
+
<div role="dialog" aria-label={title}>
|
|
27
|
+
Organization status
|
|
28
|
+
</div>
|
|
29
|
+
) : null;
|
|
30
|
+
|
|
31
|
+
MockCloudPingModal.propTypes = {
|
|
32
|
+
isOpen: PropTypes.bool.isRequired,
|
|
33
|
+
title: PropTypes.string.isRequired,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
__esModule: true,
|
|
38
|
+
default: MockCloudPingModal,
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
jest.mock('foremanReact/common/helpers', () => ({
|
|
42
|
+
getDocsURL: () => '/links/manual/test',
|
|
43
|
+
}));
|
|
22
44
|
|
|
23
45
|
describe('PageTitle', () => {
|
|
24
46
|
afterEach(() => {
|
|
@@ -31,21 +53,70 @@ describe('PageTitle', () => {
|
|
|
31
53
|
});
|
|
32
54
|
|
|
33
55
|
it('renders the kebab dropdown', () => {
|
|
34
|
-
|
|
35
|
-
expect(
|
|
56
|
+
render(<PageTitle />);
|
|
57
|
+
expect(screen.getByLabelText('Actions')).toBeTruthy();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('renders cloud-ping dropdown item when not in IoP mode', async () => {
|
|
61
|
+
mockIopMode = false;
|
|
62
|
+
render(<PageTitle />);
|
|
63
|
+
|
|
64
|
+
await act(async () => {
|
|
65
|
+
fireEvent.click(screen.getByLabelText('Actions'));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Verify all dropdown items are present
|
|
69
|
+
const connectivityItem = screen.getByText('Connectivity test');
|
|
70
|
+
expect(connectivityItem).toBeTruthy();
|
|
71
|
+
|
|
72
|
+
const tasksHistoryLink = screen.getByRole('menuitem', {
|
|
73
|
+
name: 'Actions history',
|
|
74
|
+
});
|
|
75
|
+
const inventoryDocsLink = screen.getByRole('menuitem', {
|
|
76
|
+
name: 'Documentation',
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
expect(tasksHistoryLink).toBeTruthy();
|
|
80
|
+
expect(inventoryDocsLink).toBeTruthy();
|
|
81
|
+
|
|
82
|
+
// Verify links open in a new tab
|
|
83
|
+
expect(tasksHistoryLink).toHaveAttribute('target', '_blank');
|
|
84
|
+
expect(inventoryDocsLink).toHaveAttribute('target', '_blank');
|
|
85
|
+
|
|
86
|
+
// Verify links have the expected URL patterns
|
|
87
|
+
expect(tasksHistoryLink.getAttribute('href')).toContain(
|
|
88
|
+
'/foreman_tasks/tasks'
|
|
89
|
+
);
|
|
90
|
+
expect(inventoryDocsLink.getAttribute('href')).toContain('/links/manual/');
|
|
36
91
|
});
|
|
37
92
|
|
|
38
|
-
it('
|
|
93
|
+
it('opens CloudPingModal when clicking Connectivity test', async () => {
|
|
39
94
|
mockIopMode = false;
|
|
40
95
|
render(<PageTitle />);
|
|
41
|
-
|
|
42
|
-
|
|
96
|
+
|
|
97
|
+
// Modal should not be visible initially
|
|
98
|
+
expect(screen.queryByRole('dialog')).toBeNull();
|
|
99
|
+
|
|
100
|
+
await act(async () => {
|
|
101
|
+
fireEvent.click(screen.getByLabelText('Actions'));
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await act(async () => {
|
|
105
|
+
fireEvent.click(screen.getByText('Connectivity test'));
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Modal should now be visible
|
|
109
|
+
const dialog = screen.getByRole('dialog');
|
|
110
|
+
expect(dialog).toBeTruthy();
|
|
111
|
+
expect(dialog).toHaveTextContent('Organization status');
|
|
43
112
|
});
|
|
44
113
|
|
|
45
|
-
it('does not render cloud-ping dropdown item when in IoP mode', () => {
|
|
114
|
+
it('does not render cloud-ping dropdown item when in IoP mode', async () => {
|
|
46
115
|
mockIopMode = true;
|
|
47
116
|
render(<PageTitle />);
|
|
48
|
-
|
|
117
|
+
await act(async () => {
|
|
118
|
+
fireEvent.click(screen.getByLabelText('Actions'));
|
|
119
|
+
});
|
|
49
120
|
expect(screen.queryByText('Connectivity test')).toBeNull();
|
|
50
121
|
mockIopMode = false;
|
|
51
122
|
});
|
data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudPingModal/index.js
CHANGED
|
@@ -2,11 +2,7 @@
|
|
|
2
2
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import { useDispatch, useSelector } from 'react-redux';
|
|
5
|
-
import {
|
|
6
|
-
Table,
|
|
7
|
-
TableBody,
|
|
8
|
-
TableHeader,
|
|
9
|
-
} from '@patternfly/react-table/deprecated';
|
|
5
|
+
import { Table, Tbody, Tr, Td } from '@patternfly/react-table';
|
|
10
6
|
import {
|
|
11
7
|
Card,
|
|
12
8
|
CardTitle,
|
|
@@ -21,6 +17,10 @@ import {
|
|
|
21
17
|
CheckCircleIcon,
|
|
22
18
|
ExclamationCircleIcon,
|
|
23
19
|
} from '@patternfly/react-icons';
|
|
20
|
+
import {
|
|
21
|
+
global_danger_color_200 as dangerColor,
|
|
22
|
+
global_success_color_100 as successColor,
|
|
23
|
+
} from '@patternfly/react-tokens';
|
|
24
24
|
import { get } from 'foremanReact/redux/API';
|
|
25
25
|
import { translate as __, sprintf } from 'foremanReact/common/I18n';
|
|
26
26
|
import { STATUS } from 'foremanReact/constants';
|
|
@@ -30,34 +30,20 @@ import { inventoryUrl } from '../../../../ForemanInventoryHelpers';
|
|
|
30
30
|
export const API_KEY = 'CLOUD_PING';
|
|
31
31
|
|
|
32
32
|
const CloudPingModal = ({ title, isOpen, toggle }) => {
|
|
33
|
-
const [
|
|
33
|
+
const [certAuths, setCertAuths] = useState([]);
|
|
34
34
|
const dispatch = useDispatch();
|
|
35
|
+
const status = useSelector(state => selectAPIStatus(state, API_KEY));
|
|
36
|
+
const isPending = status === STATUS.PENDING;
|
|
37
|
+
|
|
35
38
|
const handleSuccess = useCallback(
|
|
36
39
|
({
|
|
37
40
|
data: {
|
|
38
41
|
ping: { cert_auth = [] },
|
|
39
42
|
},
|
|
40
43
|
}) => {
|
|
41
|
-
cert_auth
|
|
42
|
-
setRows(
|
|
43
|
-
cert_auth.map(cert => ({
|
|
44
|
-
cells: [
|
|
45
|
-
{
|
|
46
|
-
title: (
|
|
47
|
-
<>
|
|
48
|
-
<StatusIcon
|
|
49
|
-
isPending={status === STATUS.PENDING}
|
|
50
|
-
authStatus={cert}
|
|
51
|
-
/>{' '}
|
|
52
|
-
{cert.org_name} {cert.error}
|
|
53
|
-
</>
|
|
54
|
-
),
|
|
55
|
-
},
|
|
56
|
-
],
|
|
57
|
-
}))
|
|
58
|
-
);
|
|
44
|
+
setCertAuths(cert_auth);
|
|
59
45
|
},
|
|
60
|
-
[
|
|
46
|
+
[]
|
|
61
47
|
);
|
|
62
48
|
|
|
63
49
|
useEffect(() => {
|
|
@@ -71,10 +57,6 @@ const CloudPingModal = ({ title, isOpen, toggle }) => {
|
|
|
71
57
|
);
|
|
72
58
|
}, [isOpen, dispatch, handleSuccess]);
|
|
73
59
|
|
|
74
|
-
const status = useSelector(state => selectAPIStatus(state, API_KEY));
|
|
75
|
-
const isPending = status === STATUS.PENDING;
|
|
76
|
-
// const error = useSelector(state => selectAPIErrorMessage(state, API_KEY));
|
|
77
|
-
|
|
78
60
|
return (
|
|
79
61
|
<>
|
|
80
62
|
<Modal
|
|
@@ -97,17 +79,28 @@ const CloudPingModal = ({ title, isOpen, toggle }) => {
|
|
|
97
79
|
) : (
|
|
98
80
|
<>
|
|
99
81
|
<Text className="pull-right" ouiaId="text-org-count">
|
|
100
|
-
{sprintf(__('%s organizations'),
|
|
82
|
+
{sprintf(__('%s organizations'), certAuths.length)}
|
|
101
83
|
</Text>
|
|
102
84
|
<Table
|
|
103
|
-
aria-label="
|
|
85
|
+
aria-label="Organization status"
|
|
104
86
|
ouiaId="simple-table"
|
|
105
|
-
|
|
106
|
-
|
|
87
|
+
variant="compact"
|
|
88
|
+
borders={false}
|
|
107
89
|
>
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
90
|
+
<Tbody>
|
|
91
|
+
{certAuths.map((cert, idx) => (
|
|
92
|
+
<Tr
|
|
93
|
+
key={cert.org_name || idx}
|
|
94
|
+
ouiaId={`org-status-row-${idx}`}
|
|
95
|
+
>
|
|
96
|
+
<Td dataLabel={__('Organization')}>
|
|
97
|
+
<StatusIcon isPending={isPending} authStatus={cert} />{' '}
|
|
98
|
+
{cert.org_name} {cert.error}
|
|
99
|
+
</Td>
|
|
100
|
+
</Tr>
|
|
101
|
+
))}
|
|
102
|
+
</Tbody>
|
|
103
|
+
</Table>
|
|
111
104
|
</>
|
|
112
105
|
)}
|
|
113
106
|
</CardBody>
|
|
@@ -121,13 +114,13 @@ const StatusIcon = ({ isPending, authStatus }) => {
|
|
|
121
114
|
if (isPending) return <Spinner size="sm" />;
|
|
122
115
|
if (authStatus.success)
|
|
123
116
|
return (
|
|
124
|
-
<Icon color=
|
|
117
|
+
<Icon color={successColor.value}>
|
|
125
118
|
<CheckCircleIcon />
|
|
126
119
|
</Icon>
|
|
127
120
|
);
|
|
128
121
|
if (authStatus.error)
|
|
129
122
|
return (
|
|
130
|
-
<Icon color=
|
|
123
|
+
<Icon color={dangerColor.value}>
|
|
131
124
|
<ExclamationCircleIcon />
|
|
132
125
|
</Icon>
|
|
133
126
|
);
|
|
@@ -5,7 +5,9 @@ import SyncButton from '../SyncButton';
|
|
|
5
5
|
describe('SyncButton', () => {
|
|
6
6
|
it('renders the sync button text', () => {
|
|
7
7
|
render(<SyncButton handleSync={jest.fn()} />);
|
|
8
|
-
expect(
|
|
8
|
+
expect(
|
|
9
|
+
screen.getByRole('button', { name: /Sync all inventory status/ })
|
|
10
|
+
).toBeTruthy();
|
|
9
11
|
});
|
|
10
12
|
|
|
11
13
|
it('calls handleSync on click', () => {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Task durations reported by the API are in seconds; used to derive
|
|
2
|
+
// minutes/seconds for display in TaskHistory and TaskProgress.
|
|
3
|
+
export const SECONDS_PER_MINUTE = 60;
|
|
4
|
+
|
|
5
|
+
// Progress percentage to show once a task has finished running.
|
|
6
|
+
export const PERCENT_COMPLETE = 100;
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from '@patternfly/react-icons';
|
|
19
19
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
20
20
|
import RelativeDateTime from 'foremanReact/components/common/dates/RelativeDateTime';
|
|
21
|
+
import { SECONDS_PER_MINUTE } from '../TaskConstants';
|
|
21
22
|
import './taskHistory.scss';
|
|
22
23
|
|
|
23
24
|
const TaskHistory = ({ tasks, title }) => {
|
|
@@ -52,8 +53,8 @@ const TaskHistory = ({ tasks, title }) => {
|
|
|
52
53
|
if (!Number.isFinite(seconds) || seconds < 0) {
|
|
53
54
|
return __('N/A');
|
|
54
55
|
}
|
|
55
|
-
const mins = Math.floor(seconds /
|
|
56
|
-
const secs = Math.floor(seconds %
|
|
56
|
+
const mins = Math.floor(seconds / SECONDS_PER_MINUTE);
|
|
57
|
+
const secs = Math.floor(seconds % SECONDS_PER_MINUTE);
|
|
57
58
|
if (mins > 0) {
|
|
58
59
|
return `${mins}m ${secs}s`;
|
|
59
60
|
}
|
|
@@ -29,6 +29,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
|
|
29
29
|
import { inventoryUrl } from '../../ForemanInventoryHelpers';
|
|
30
30
|
import { selectSubscriptionConnectionEnabled } from '../InventorySettings/InventorySettingsSelectors';
|
|
31
31
|
import { useIopConfig } from '../../../common/Hooks/ConfigHooks';
|
|
32
|
+
import { SECONDS_PER_MINUTE, PERCENT_COMPLETE } from '../TaskConstants';
|
|
32
33
|
import './taskProgress.scss';
|
|
33
34
|
|
|
34
35
|
const TaskProgress = ({
|
|
@@ -213,8 +214,8 @@ const TaskProgress = ({
|
|
|
213
214
|
) {
|
|
214
215
|
return '';
|
|
215
216
|
}
|
|
216
|
-
const mins = Math.floor(seconds /
|
|
217
|
-
const secs = Math.floor(seconds %
|
|
217
|
+
const mins = Math.floor(seconds / SECONDS_PER_MINUTE);
|
|
218
|
+
const secs = Math.floor(seconds % SECONDS_PER_MINUTE);
|
|
218
219
|
if (mins > 0) {
|
|
219
220
|
return `${mins}m ${secs}s`;
|
|
220
221
|
}
|
|
@@ -232,7 +233,7 @@ const TaskProgress = ({
|
|
|
232
233
|
if (isStartingNewTask) {
|
|
233
234
|
progressValue = 0;
|
|
234
235
|
} else if (task.state === 'stopped') {
|
|
235
|
-
progressValue =
|
|
236
|
+
progressValue = PERCENT_COMPLETE;
|
|
236
237
|
} else {
|
|
237
238
|
progressValue = task.progress || 0;
|
|
238
239
|
}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import React, { useEffect } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
Text,
|
|
5
|
+
TextVariants,
|
|
6
|
+
Popover,
|
|
7
|
+
Button,
|
|
8
|
+
FormGroup,
|
|
9
|
+
Grid,
|
|
10
|
+
GridItem,
|
|
11
|
+
} from '@patternfly/react-core';
|
|
4
12
|
import { InfoAltIcon, CaretRightIcon } from '@patternfly/react-icons';
|
|
5
|
-
import { FormGroup, Grid } from 'patternfly-react';
|
|
6
13
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
7
14
|
import { foremanUrl } from '../../../ForemanRhCloudHelpers';
|
|
8
|
-
import
|
|
15
|
+
import SwitcherPF4 from '../../../common/Switcher/SwitcherPF4';
|
|
9
16
|
import { settingsDict } from '../../Components/InventorySettings/AdvancedSetting/AdvancedSettingsConstants';
|
|
10
17
|
import InventorySettings from '../../Components/InventorySettings/InventorySettings';
|
|
11
18
|
|
|
@@ -27,19 +34,19 @@ const InventoryAutoUploadSwitcher = ({
|
|
|
27
34
|
<Grid>
|
|
28
35
|
<h3>{__('Red Hat Cloud Inventory')}</h3>
|
|
29
36
|
<hr />
|
|
30
|
-
<Grid
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<
|
|
37
|
+
<Grid hasGutter>
|
|
38
|
+
<GridItem span={7}>
|
|
39
|
+
<SwitcherPF4
|
|
40
|
+
id="auto-upload"
|
|
41
|
+
label={__('Inventory Auto Upload')}
|
|
42
|
+
tooltip={__(
|
|
43
|
+
'Enable automatic upload of your hosts inventory to the Red Hat cloud'
|
|
44
|
+
)}
|
|
45
|
+
isChecked={autoUploadEnabled}
|
|
46
|
+
onChange={handleToggle}
|
|
47
|
+
/>
|
|
48
|
+
</GridItem>
|
|
49
|
+
<GridItem span={5}>
|
|
43
50
|
<Popover
|
|
44
51
|
headerContent={
|
|
45
52
|
<strong>{__('Advanced Inventory Settings')}</strong>
|
|
@@ -55,11 +62,11 @@ const InventoryAutoUploadSwitcher = ({
|
|
|
55
62
|
{__('Show Advanced Settings')} <CaretRightIcon />
|
|
56
63
|
</Button>
|
|
57
64
|
</Popover>
|
|
58
|
-
</
|
|
59
|
-
</Grid
|
|
65
|
+
</GridItem>
|
|
66
|
+
</Grid>
|
|
60
67
|
<br />
|
|
61
|
-
<Grid
|
|
62
|
-
<
|
|
68
|
+
<Grid>
|
|
69
|
+
<GridItem span={12}>
|
|
63
70
|
<Text component={TextVariants.p} ouiaId="text-more-details">
|
|
64
71
|
<InfoAltIcon /> {__('More details can be found in')}{' '}
|
|
65
72
|
<Text
|
|
@@ -76,8 +83,8 @@ const InventoryAutoUploadSwitcher = ({
|
|
|
76
83
|
</strong>
|
|
77
84
|
</Text>
|
|
78
85
|
</Text>
|
|
79
|
-
</
|
|
80
|
-
</Grid
|
|
86
|
+
</GridItem>
|
|
87
|
+
</Grid>
|
|
81
88
|
</Grid>
|
|
82
89
|
</FormGroup>
|
|
83
90
|
);
|
|
@@ -22,12 +22,16 @@ describe('InventoryAutoUpload', () => {
|
|
|
22
22
|
|
|
23
23
|
it('renders the auto upload switcher', () => {
|
|
24
24
|
render(<InventoryAutoUpload {...buildProps()} />);
|
|
25
|
-
expect(
|
|
25
|
+
expect(
|
|
26
|
+
screen.getByRole('checkbox', { name: /Inventory Auto Upload/ })
|
|
27
|
+
).toBeTruthy();
|
|
26
28
|
});
|
|
27
29
|
|
|
28
30
|
it('renders the advanced settings button', () => {
|
|
29
31
|
render(<InventoryAutoUpload {...buildProps()} />);
|
|
30
|
-
expect(
|
|
32
|
+
expect(
|
|
33
|
+
screen.getByRole('button', { name: /Show Advanced Settings/ })
|
|
34
|
+
).toBeTruthy();
|
|
31
35
|
});
|
|
32
36
|
|
|
33
37
|
it('calls getSettings on mount', () => {
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
+
import { getDocsURL } from 'foremanReact/common/helpers';
|
|
2
|
+
import {
|
|
3
|
+
getInventoryDocsUrl,
|
|
4
|
+
isExitCodeLoading,
|
|
5
|
+
} from '../ForemanInventoryHelpers';
|
|
6
|
+
|
|
1
7
|
jest.mock('foremanReact/common/helpers', () => ({
|
|
2
8
|
getDocsURL: jest.fn(),
|
|
3
9
|
}));
|
|
4
10
|
|
|
5
|
-
import { getDocsURL } from 'foremanReact/common/helpers';
|
|
6
|
-
import { getInventoryDocsUrl, isExitCodeLoading } from '../ForemanInventoryHelpers';
|
|
7
|
-
|
|
8
11
|
describe('ForemanInventoryUpload helpers', () => {
|
|
9
12
|
describe('getInventoryDocsUrl', () => {
|
|
10
|
-
it('requests the
|
|
13
|
+
it('requests the admin guide cloud connection chapter', () => {
|
|
11
14
|
getInventoryDocsUrl();
|
|
12
15
|
expect(getDocsURL).toHaveBeenCalledWith(
|
|
13
|
-
'
|
|
14
|
-
'configuring-foreman-server-for-cloud-connection'
|
|
16
|
+
'Administering_Project',
|
|
17
|
+
'configuring-foreman-server-for-cloud-connection'
|
|
15
18
|
);
|
|
16
19
|
});
|
|
17
20
|
});
|