foreman_rh_cloud 12.1.4 → 12.2.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/insights_cloud/api/machine_telemetries_controller.rb +1 -2
  3. data/app/controllers/insights_cloud/ui_requests_controller.rb +99 -0
  4. data/app/services/foreman_rh_cloud/cloud_request_forwarder.rb +7 -13
  5. data/app/services/foreman_rh_cloud/gateway_request.rb +26 -0
  6. data/app/services/foreman_rh_cloud/insights_api_forwarder.rb +116 -0
  7. data/app/services/foreman_rh_cloud/tags_auth.rb +55 -0
  8. data/config/routes.rb +7 -0
  9. data/lib/foreman_rh_cloud/engine.rb +7 -1
  10. data/lib/foreman_rh_cloud/version.rb +1 -1
  11. data/lib/insights_cloud.rb +8 -0
  12. data/package.json +5 -1
  13. data/test/controllers/insights_cloud/ui_requests_controller_test.rb +169 -0
  14. data/test/unit/services/foreman_rh_cloud/cloud_request_forwarder_test.rb +3 -3
  15. data/test/unit/services/foreman_rh_cloud/insights_api_forwarder_test.rb +176 -0
  16. data/test/unit/services/foreman_rh_cloud/tags_auth_test.rb +29 -0
  17. data/webpack/CVEsHostDetailsTab/CVEsHostDetailsTab.js +30 -10
  18. data/webpack/CVEsHostDetailsTab/__tests__/CVEsHostDetailsTab.test.js +18 -11
  19. data/webpack/CVEsHostDetailsTab/index.js +2 -2
  20. data/webpack/CveDetailsPage/CveDetailsPage.js +20 -0
  21. data/webpack/CveDetailsPage/CveDetailsPage.test.js +31 -0
  22. data/webpack/CveDetailsPage/index.js +1 -0
  23. data/webpack/ForemanColumnExtensions/index.js +49 -14
  24. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/InventoryFilter.js +1 -0
  25. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilter.test.js.snap +1 -0
  26. data/webpack/ForemanInventoryUpload/Components/InventorySettings/MinimalInventoryDropdown.js +2 -0
  27. data/webpack/ForemanInventoryUpload/Components/PageHeader/PageTitle.js +8 -1
  28. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +4 -0
  29. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/CloudConnectorButton.js +3 -3
  30. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/__snapshots__/CloudConnectorButton.test.js.snap +3 -0
  31. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudPingModal/index.js +10 -4
  32. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/PageDescription.js +6 -6
  33. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SettingsWarning/SettingsWarning.js +2 -0
  34. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SettingsWarning/__snapshots__/SettingsWarning.test.js.snap +2 -0
  35. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButton.js +1 -0
  36. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButton.test.js.snap +1 -0
  37. data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/InventoryAutoUpload.js +3 -1
  38. data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/__tests__/__snapshots__/InventoryAutoUpload.test.js.snap +3 -0
  39. data/webpack/ForemanRhCloudFills.js +6 -3
  40. data/webpack/ForemanRhCloudPages.js +21 -3
  41. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +1 -0
  42. data/webpack/InsightsCloudSync/Components/InsightsTable/SelectAllAlert.js +2 -0
  43. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTable.test.js.snap +1 -0
  44. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +3 -0
  45. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModalFooter.js +12 -2
  46. data/webpack/InsightsCloudSync/Components/RemediationModal/Resolutions.js +1 -0
  47. data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +6 -1
  48. data/webpack/InsightsCloudSync/InsightsCloudSync.js +39 -1
  49. data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +6 -50
  50. data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +51 -1
  51. data/webpack/InsightsVulnerability/InsightsVulnerabilityListPage.js +21 -0
  52. data/webpack/InsightsVulnerability/InsightsVulnerabilityListPage.test.js +20 -0
  53. data/webpack/InsightsVulnerabilityHostIndexExtensions/CVECountCell.js +45 -0
  54. data/webpack/InsightsVulnerabilityHostIndexExtensions/__tests__/CVECountCell.test.js +28 -0
  55. data/webpack/IopRecommendationDetails/IopRecommendationDetails.js +44 -0
  56. data/webpack/common/DropdownToggle.js +1 -0
  57. data/webpack/common/ScalprumModule/ScalprumContext.js +73 -0
  58. data/webpack/common/Switcher/SwitcherPF4.js +1 -0
  59. data/webpack/common/Switcher/__tests__/__snapshots__/SwitcherPF4.test.js.snap +1 -0
  60. data/webpack/common/Switcher/index.js +1 -0
  61. metadata +21 -4
  62. data/webpack/InsightsVulnerability/InsightsVulnerability.js +0 -13
  63. data/webpack/InsightsVulnerability/InsightsVulnerability.test.js +0 -18
@@ -13,18 +13,18 @@ export const PageDescription = () => {
13
13
 
14
14
  return (
15
15
  <div id="inventory_page_description">
16
- <Text>
16
+ <Text ouiaId="text-cloud-console">
17
17
  {__(
18
18
  'The Red Hat Hybrid Cloud Console provides a set of cloud services, including Red Hat Insights and Subscriptions, that provide predictive analysis, remediation of issues, and unified subscription reporting for this Foreman instance.'
19
19
  )}
20
20
  </Text>
21
- <Text>
21
+ <Text ouiaId="text-inventory-upload">
22
22
  {__(
23
23
  'The Foreman inventory upload plugin automatically uploads Foreman host inventory data to the Inventory service of Insights, where it can also be used by the Subscriptions service for subscription reporting. If you use the Subscriptions service, enabling inventory uploads is required.'
24
24
  )}
25
25
  </Text>
26
26
  {subscriptionConnectionEnabled && (
27
- <Text>
27
+ <Text ouiaId="text-enable-report">
28
28
  <FormattedMessage
29
29
  id="enable-upload-hint"
30
30
  defaultMessage={__(
@@ -39,7 +39,7 @@ export const PageDescription = () => {
39
39
  </Text>
40
40
  )}
41
41
  {subscriptionConnectionEnabled && (
42
- <Text>
42
+ <Text ouiaId="text-restart-button">
43
43
  <FormattedMessage
44
44
  id="restart-button-hint"
45
45
  defaultMessage={__(
@@ -53,7 +53,7 @@ export const PageDescription = () => {
53
53
  />
54
54
  </Text>
55
55
  )}
56
- <Text>
56
+ <Text ouiaId="text-more-info-subscription">
57
57
  {__('For more information about the Subscriptions service, see:')}
58
58
  &nbsp;
59
59
  <a
@@ -64,7 +64,7 @@ export const PageDescription = () => {
64
64
  {__('About subscription watch')}
65
65
  </a>
66
66
  </Text>
67
- <Text>
67
+ <Text ouiaId="text-more-info-insights">
68
68
  {__('For more information about Insights and Cloud Connector, see:')}
69
69
  &nbsp;
70
70
  <a
@@ -22,6 +22,7 @@ export const SettingsWarning = ({
22
22
  alerts.push(
23
23
  <Alert
24
24
  key="auto-upload"
25
+ ouiaId="auto-upload"
25
26
  variant="warning"
26
27
  title={__(
27
28
  "Cloud Connector has been configured however the inventory auto-upload is disabled, it's recommended to enable it"
@@ -36,6 +37,7 @@ export const SettingsWarning = ({
36
37
  alerts.push(
37
38
  <Alert
38
39
  key="obfuscating-host"
40
+ ouiaId="obfuscating-host"
39
41
  variant="warning"
40
42
  title={__(
41
43
  "Cloud Connector has been configured however obfuscating host names setting is enabled, it's recommended to disable it"
@@ -11,6 +11,7 @@ exports[`SettingsWarning with 2 alerts 1`] = `
11
11
  />
12
12
  }
13
13
  key="auto-upload"
14
+ ouiaId="auto-upload"
14
15
  title="Cloud Connector has been configured however the inventory auto-upload is disabled, it's recommended to enable it"
15
16
  variant="warning"
16
17
  />
@@ -21,6 +22,7 @@ exports[`SettingsWarning with 2 alerts 1`] = `
21
22
  />
22
23
  }
23
24
  key="obfuscating-host"
25
+ ouiaId="obfuscating-host"
24
26
  title="Cloud Connector has been configured however obfuscating host names setting is enabled, it's recommended to disable it"
25
27
  variant="warning"
26
28
  />
@@ -21,6 +21,7 @@ class SyncButton extends React.Component {
21
21
  <React.Fragment>
22
22
  <Button
23
23
  className="sync_button"
24
+ ouiaId="sync-button"
24
25
  onClick={handleClick}
25
26
  isDisabled={status === STATUS.PENDING}
26
27
  variant="secondary"
@@ -6,6 +6,7 @@ exports[`SyncButton rendering render with Props 1`] = `
6
6
  className="sync_button"
7
7
  isDisabled={false}
8
8
  onClick={[Function]}
9
+ ouiaId="sync-button"
9
10
  variant="secondary"
10
11
  >
11
12
  Sync all inventory status
@@ -48,6 +48,7 @@ const InventoryAutoUploadSwitcher = ({
48
48
  position="right"
49
49
  >
50
50
  <Button
51
+ ouiaId="button-advanced-settings"
51
52
  variant="secondary"
52
53
  style={{ fontSize: 'small', marginTop: '-4px' }}
53
54
  >
@@ -59,9 +60,10 @@ const InventoryAutoUploadSwitcher = ({
59
60
  <br />
60
61
  <Grid.Row>
61
62
  <Grid.Col sm={12}>
62
- <Text component={TextVariants.p}>
63
+ <Text component={TextVariants.p} ouiaId="text-more-details">
63
64
  <InfoAltIcon /> {__('More details can be found in')}{' '}
64
65
  <Text
66
+ ouiaId="text-details-link"
65
67
  component={TextVariants.a}
66
68
  href={foremanUrl('/foreman_rh_cloud/inventory_upload')}
67
69
  target="_blank"
@@ -41,6 +41,7 @@ exports[`InventoryAutoUpload rendering render with props 1`] = `
41
41
  position="right"
42
42
  >
43
43
  <Button
44
+ ouiaId="button-advanced-settings"
44
45
  style={
45
46
  Object {
46
47
  "fontSize": "small",
@@ -68,6 +69,7 @@ exports[`InventoryAutoUpload rendering render with props 1`] = `
68
69
  >
69
70
  <Text
70
71
  component="p"
72
+ ouiaId="text-more-details"
71
73
  >
72
74
  <InfoAltIcon />
73
75
 
@@ -76,6 +78,7 @@ exports[`InventoryAutoUpload rendering render with props 1`] = `
76
78
  <Text
77
79
  component="a"
78
80
  href="/foreman_rh_cloud/inventory_upload"
81
+ ouiaId="text-details-link"
79
82
  rel="noopener noreferrer"
80
83
  target="_blank"
81
84
  >
@@ -1,10 +1,11 @@
1
1
  import React from 'react';
2
2
  import { addGlobalFill } from 'foremanReact/components/common/Fill/GlobalFill';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
3
4
  import InventoryAutoUploadSwitcher from './ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload';
4
5
  import NewHostDetailsTab from './InsightsHostDetailsTab/NewHostDetailsTab';
5
6
  import { InsightsTotalRiskChartWrapper } from './InsightsHostDetailsTab/InsightsTotalRiskChartWrapper';
6
7
  import { isNotRhelHost, vulnerabilityDisabled } from './ForemanRhCloudHelpers';
7
- import CVEsHostDetailsTab from './CVEsHostDetailsTab/CVEsHostDetailsTab';
8
+ import CVEsHostDetailsTabWrapper from './CVEsHostDetailsTab/CVEsHostDetailsTab';
8
9
 
9
10
  const fills = [
10
11
  {
@@ -20,6 +21,7 @@ const fills = [
20
21
  weight: 400,
21
22
  metadata: {
22
23
  hideTab: isNotRhelHost,
24
+ title: __('Insights'),
23
25
  },
24
26
  },
25
27
  {
@@ -30,11 +32,12 @@ const fills = [
30
32
  },
31
33
  {
32
34
  slot: 'host-details-page-tabs',
33
- name: 'CVEs',
34
- component: props => <CVEsHostDetailsTab {...props} />,
35
+ name: 'Vulnerabilities',
36
+ component: props => <CVEsHostDetailsTabWrapper {...props} />,
35
37
  weight: 300,
36
38
  metadata: {
37
39
  hideTab: vulnerabilityDisabled,
40
+ title: __('Vulnerabilities'),
38
41
  },
39
42
  },
40
43
  ];
@@ -1,16 +1,24 @@
1
+ /* eslint-disable spellcheck/spell-checker */
1
2
  import React from 'react';
2
3
  import componentRegistry from 'foremanReact/components/componentRegistry';
3
4
  import { registerRoutes as foremanRegisterRoutes } from 'foremanReact/routes/RoutingService';
4
5
  import ForemanInventoryUpload from './ForemanInventoryUpload';
5
- import InsightsVulnerability from './InsightsVulnerability/InsightsVulnerability';
6
+ import InsightsVulnerabilityListPage from './InsightsVulnerability/InsightsVulnerabilityListPage';
6
7
  import InsightsCloudSync from './InsightsCloudSync';
8
+ import IopRecommendationDetails from './IopRecommendationDetails/IopRecommendationDetails';
7
9
  import InsightsHostDetailsTab from './InsightsHostDetailsTab';
10
+ import CveDetailsPage from './CveDetailsPage';
8
11
 
9
12
  const pages = [
10
13
  { name: 'ForemanInventoryUpload', type: ForemanInventoryUpload },
11
14
  { name: 'InsightsCloudSync', type: InsightsCloudSync },
15
+ { name: 'IopRecommendationDetails', type: IopRecommendationDetails },
12
16
  { name: 'InsightsHostDetailsTab', type: InsightsHostDetailsTab },
13
- { name: 'InsightsVulnerability', type: InsightsVulnerability },
17
+ {
18
+ name: 'InsightsVulnerabilityListPage',
19
+ type: InsightsVulnerabilityListPage,
20
+ },
21
+ { name: 'CveDetailsPage', type: CveDetailsPage },
14
22
  ];
15
23
 
16
24
  export const registerPages = () => {
@@ -23,6 +31,11 @@ export const routes = [
23
31
  exact: true,
24
32
  render: props => <InsightsCloudSync {...props} />,
25
33
  },
34
+ {
35
+ path: '/foreman_rh_cloud/recommendations',
36
+ exact: false,
37
+ render: props => <IopRecommendationDetails {...props} />,
38
+ },
26
39
  {
27
40
  path: '/foreman_rh_cloud/inventory_upload',
28
41
  exact: true,
@@ -31,7 +44,12 @@ export const routes = [
31
44
  {
32
45
  path: '/foreman_rh_cloud/insights_vulnerability',
33
46
  exact: true,
34
- render: props => <InsightsVulnerability {...props} />,
47
+ render: props => <InsightsVulnerabilityListPage {...props} />,
48
+ },
49
+ {
50
+ path: '/foreman_rh_cloud/insights_vulnerability/:cveId',
51
+ exact: true,
52
+ render: props => <CveDetailsPage {...props} />,
35
53
  },
36
54
  ];
37
55
 
@@ -75,6 +75,7 @@ const InsightsTable = ({
75
75
  />
76
76
  <Table
77
77
  className="rh-cloud-recommendations-table"
78
+ ouiaId="rh-cloud-recommendations-table"
78
79
  aria-label="Recommendations Table"
79
80
  onSelect={(_event, isSelected, rowId) =>
80
81
  onTableSelect(isSelected, rowId, rows, selectedIds)
@@ -18,6 +18,7 @@ const SelectAllAlert = ({
18
18
  <Alert
19
19
  isInline
20
20
  variant="info"
21
+ ouiaId="alert-recommendations-selected"
21
22
  title={sprintf(__('Recommendations selected: %s.'), selectedCount)}
22
23
  actionLinks={
23
24
  <AlertActionLink onClick={selectAll}>
@@ -32,6 +33,7 @@ const SelectAllAlert = ({
32
33
  <Alert
33
34
  isInline
34
35
  variant="info"
36
+ ouiaId="alert-all-selected"
35
37
  title={__('All recommendations are now selected.')}
36
38
  actionLinks={
37
39
  <AlertActionLink onClick={clearAllSelection}>
@@ -83,6 +83,7 @@ exports[`InsightsTable rendering render with Props 1`] = `
83
83
  isTreeTable={false}
84
84
  onSelect={[Function]}
85
85
  onSort={[Function]}
86
+ ouiaId="rh-cloud-recommendations-table"
86
87
  ouiaSafe={true}
87
88
  role="grid"
88
89
  rowLabeledBy="simple-node"
@@ -46,6 +46,7 @@ const RemediationModal = ({
46
46
  return (
47
47
  <React.Fragment>
48
48
  <Button
49
+ ouiaId="button-remediate"
49
50
  variant="primary"
50
51
  isDisabled={isEmpty(selectedIds)}
51
52
  onClick={() => {
@@ -56,6 +57,7 @@ const RemediationModal = ({
56
57
  </Button>{' '}
57
58
  <Modal
58
59
  id="remediation-modal"
60
+ ouiaId="remediation-modal"
59
61
  appendTo={document.body}
60
62
  variant={ModalVariant.large}
61
63
  title={__('Remediation summary')}
@@ -71,6 +73,7 @@ const RemediationModal = ({
71
73
  >
72
74
  <Table
73
75
  className="remediations-table"
76
+ ouiaId="remediations-table"
74
77
  aria-label="remediations Table"
75
78
  cells={columns}
76
79
  rows={rows}
@@ -9,10 +9,20 @@ const ModalFooter = ({ toggleModal, resolutions, hostsIds }) => {
9
9
  token = token?.content || '';
10
10
  return (
11
11
  <form action={JOB_INVOCATION_PATH} method="post">
12
- <Button type="submit" key="confirm" variant="primary">
12
+ <Button
13
+ type="submit"
14
+ ouiaId="button-confirm"
15
+ key="confirm"
16
+ variant="primary"
17
+ >
13
18
  {__('Remediate')}
14
19
  </Button>
15
- <Button key="cancel" variant="link" onClick={toggleModal}>
20
+ <Button
21
+ key="cancel"
22
+ ouiaId="button-cancel"
23
+ variant="link"
24
+ onClick={toggleModal}
25
+ >
16
26
  {__('Cancel')}
17
27
  </Button>
18
28
  <input type="hidden" name="feature" value="rh_cloud_remediate_hosts" />
@@ -18,6 +18,7 @@ const Resolutions = ({
18
18
  {resolutions.map(({ id: resolution_id, description }) => (
19
19
  <Radio
20
20
  key={resolution_id}
21
+ ouiaId={`resolution-radio-${resolution_id}`}
21
22
  className="resolution-radio"
22
23
  id={resolution_id}
23
24
  isChecked={resolution_id === checkedID}
@@ -19,11 +19,15 @@ const ToolbarDropdown = ({ onRecommendationSync }) => {
19
19
  const dropdownItems = [
20
20
  <DropdownItem
21
21
  key="recommendation-manual-sync"
22
+ ouiaId="recommendation-manual-sync"
22
23
  onClick={onRecommendationSync}
23
24
  >
24
25
  {__('Sync recommendations')}
25
26
  </DropdownItem>,
26
- <DropdownItem key="cloud-advisor-systems-link">
27
+ <DropdownItem
28
+ key="cloud-advisor-systems-link"
29
+ ouiaId="cloud-advisor-systems-link"
30
+ >
27
31
  <a
28
32
  href={redHatAdvisorSystems()}
29
33
  target="_blank"
@@ -38,6 +42,7 @@ const ToolbarDropdown = ({ onRecommendationSync }) => {
38
42
  return (
39
43
  <Dropdown
40
44
  className="title-dropdown"
45
+ ouiaId="title-dropdown"
41
46
  onSelect={() => setIsDropdownOpen(false)}
42
47
  toggle={
43
48
  <KebabToggle onToggle={(_event, isOpen) => setIsDropdownOpen(isOpen)} />
@@ -1,7 +1,10 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import PageLayout from 'foremanReact/routes/common/PageLayout/PageLayout';
4
+ import { ScalprumComponent, ScalprumProvider } from '@scalprum/react-core';
4
5
  import InsightsTable from './Components/InsightsTable';
6
+ import { useAdvisorEngineConfig } from '../common/Hooks/ConfigHooks';
7
+ import { foremanUrl } from '../ForemanRhCloudHelpers';
5
8
  import RemediationModal from './Components/RemediationModal';
6
9
  import {
7
10
  INSIGHTS_SYNC_PAGE_TITLE,
@@ -11,7 +14,9 @@ import './InsightsCloudSync.scss';
11
14
  import Pagination from './Components/InsightsTable/Pagination';
12
15
  import ToolbarDropdown from './Components/ToolbarDropdown';
13
16
  import InsightsSettings from './Components/InsightsSettings';
17
+ import { providerOptions } from '../common/ScalprumModule/ScalprumContext';
14
18
 
19
+ // Hosted Insights advisor
15
20
  const InsightsCloudSync = ({ syncInsights, query, fetchInsights }) => {
16
21
  const onRecommendationSync = () => syncInsights(fetchInsights, query);
17
22
  const toolbarButtons = (
@@ -54,4 +59,37 @@ InsightsCloudSync.defaultProps = {
54
59
  query: '',
55
60
  };
56
61
 
57
- export default InsightsCloudSync;
62
+ // Local Insights advisor
63
+ const scope = 'advisor';
64
+ const module = './ListWrapped';
65
+
66
+ export const generateRuleUrl = ruleId =>
67
+ foremanUrl(`/foreman_rh_cloud/recommendations/${ruleId}`);
68
+
69
+ const IopRecommendationsPage = props => (
70
+ <ScalprumComponent
71
+ scope={scope}
72
+ module={module}
73
+ IopRemediationModal={RemediationModal}
74
+ generateRuleUrl={generateRuleUrl}
75
+ {...props}
76
+ />
77
+ );
78
+
79
+ const IopRecommendationsPageWrapped = props => (
80
+ <ScalprumProvider {...providerOptions}>
81
+ <IopRecommendationsPage {...props} />
82
+ </ScalprumProvider>
83
+ );
84
+
85
+ const RecommendationsPage = props => {
86
+ const isLocalAdvisorEngine = useAdvisorEngineConfig();
87
+
88
+ return isLocalAdvisorEngine ? (
89
+ <IopRecommendationsPageWrapped {...props} />
90
+ ) : (
91
+ <InsightsCloudSync {...props} />
92
+ );
93
+ };
94
+
95
+ export default RecommendationsPage;
@@ -1,54 +1,10 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`InsightsCloudSync render 1`] = `
4
- <div
5
- className="rh-cloud-insights"
6
- >
7
- <Connect(InsightsSettings) />
8
- <PageLayout
9
- beforeToolbarComponent={null}
10
- header="Red Hat Insights"
11
- onSearch={[Function]}
12
- searchProps={
13
- Object {
14
- "autocomplete": Object {
15
- "id": "searchBar",
16
- "searchQuery": "",
17
- "url": "/insights_cloud/hits/auto_complete_search",
18
- "useKeyShortcuts": true,
19
- },
20
- "bookmarks": Object {
21
- "canCreateBookmarks": true,
22
- "documentationUrl": "4.1.5Searching",
23
- "url": "/api/bookmarks",
24
- },
25
- "controller": "insights_hits",
26
- }
27
- }
28
- searchQuery=""
29
- searchable={true}
30
- toolbarButtons={
31
- <React.Fragment>
32
- <span
33
- className="insights-toolbar-buttons"
34
- >
35
- <Memo(Connect(RemediationModal)) />
36
- <ToolbarDropdown
37
- onRecommendationSync={[Function]}
38
- />
39
- </span>
40
- <span
41
- className="pull-right"
42
- >
43
- <Pagination
44
- isCompact={true}
45
- variant="top"
46
- />
47
- </span>
48
- </React.Fragment>
49
- }
50
- >
51
- <Connect(InsightsTable) />
52
- </PageLayout>
53
- </div>
4
+ <InsightsCloudSync
5
+ fetchInsights={[Function]}
6
+ query=""
7
+ status="RESOLVED"
8
+ syncInsights={[Function]}
9
+ />
54
10
  `;
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import { useDispatch, useSelector } from 'react-redux';
4
4
  import SearchBar from 'foremanReact/components/SearchBar';
5
5
  import { translate as __ } from 'foremanReact/common/I18n';
6
+ import { ScalprumComponent, ScalprumProvider } from '@scalprum/react-core';
6
7
  import { Grid, GridItem } from '@patternfly/react-core';
7
8
  import {
8
9
  Dropdown,
@@ -21,7 +22,10 @@ import {
21
22
  } from '../InsightsCloudSync/Components/InsightsTable/InsightsTableSelectors';
22
23
  import { redHatAdvisorSystems } from '../InsightsCloudSync/InsightsCloudSyncHelpers';
23
24
  import { useAdvisorEngineConfig } from '../common/Hooks/ConfigHooks';
25
+ import { generateRuleUrl } from '../InsightsCloudSync/InsightsCloudSync';
26
+ import { providerOptions } from '../common/ScalprumModule/ScalprumContext';
24
27
 
28
+ // Hosted Insights advisor
25
29
  const NewHostDetailsTab = ({ hostName, router }) => {
26
30
  const dispatch = useDispatch();
27
31
  const query = useSelector(selectSearch);
@@ -104,4 +108,50 @@ NewHostDetailsTab.defaultProps = {
104
108
  router: {},
105
109
  };
106
110
 
107
- export default NewHostDetailsTab;
111
+ // Local Insights advisor
112
+ const scope = 'advisor';
113
+ // eslint-disable-next-line spellcheck/spell-checker
114
+ const module = './HostDetailsLightspeedTabWrapped';
115
+
116
+ const IopInsightsTab = props => (
117
+ <ScalprumComponent
118
+ scope={scope}
119
+ module={module}
120
+ IopRemediationModal={RemediationModal}
121
+ generateRuleUrl={generateRuleUrl}
122
+ {...props}
123
+ />
124
+ );
125
+
126
+ const IopInsightsTabWrapped = props => (
127
+ <ScalprumProvider {...providerOptions}>
128
+ <IopInsightsTab {...props} />
129
+ </ScalprumProvider>
130
+ );
131
+
132
+ const LightspeedTab = props => {
133
+ const { response } = props;
134
+ const isLocalAdvisorEngine =
135
+ // eslint-disable-next-line camelcase
136
+ response?.insights_attributes?.use_local_advisor_engine;
137
+
138
+ return isLocalAdvisorEngine ? (
139
+ <IopInsightsTabWrapped {...props} />
140
+ ) : (
141
+ <NewHostDetailsTab {...props} />
142
+ );
143
+ };
144
+
145
+ LightspeedTab.propTypes = {
146
+ response: PropTypes.shape({
147
+ insights_attributes: {
148
+ use_local_advisor_engine: PropTypes.bool,
149
+ },
150
+ }),
151
+ };
152
+
153
+ LightspeedTab.defaultProps = {
154
+ response: {},
155
+ };
156
+
157
+ export default LightspeedTab;
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { ScalprumComponent, ScalprumProvider } from '@scalprum/react-core';
3
+ import { providerOptions } from '../common/ScalprumModule/ScalprumContext';
4
+
5
+ const InsightsVulnerabilityListPage = () => {
6
+ const scope = 'vulnerability';
7
+ const module = './CveListPage';
8
+ return (
9
+ <div className="rh-cloud-insights-vulnerability-page">
10
+ <ScalprumComponent scope={scope} module={module} />
11
+ </div>
12
+ );
13
+ };
14
+
15
+ const InsightsVulnerabilityListPageWrap = () => (
16
+ <ScalprumProvider {...providerOptions}>
17
+ <InsightsVulnerabilityListPage />
18
+ </ScalprumProvider>
19
+ );
20
+
21
+ export default InsightsVulnerabilityListPageWrap;
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+ import InsightsVulnerabilityListPage from './InsightsVulnerabilityListPage';
5
+
6
+ jest.mock('@scalprum/react-core', () => ({
7
+ ScalprumComponent: jest.fn(props => (
8
+ <div data-testid="mock-scalprum-component">{JSON.stringify(props)}</div>
9
+ )),
10
+ ScalprumProvider: jest.fn(({ children }) => <div>{children}</div>),
11
+ }));
12
+
13
+ describe('InsightsVulnerabilityListPage component', () => {
14
+ it('renders the container with correct class', () => {
15
+ const { container } = render(<InsightsVulnerabilityListPage />);
16
+ expect(
17
+ container.querySelector('.rh-cloud-insights-vulnerability-page')
18
+ ).toBeTruthy();
19
+ });
20
+ });
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { UnknownIcon } from '@patternfly/react-icons';
4
+ import { Link } from 'react-router-dom';
5
+ import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
6
+
7
+ import { insightsCloudUrl } from '../InsightsCloudSync/InsightsCloudSyncHelpers';
8
+
9
+ const vulnerabilityApiPath = path =>
10
+ insightsCloudUrl(`api/vulnerability/v1/${path}`);
11
+
12
+ export const CVECountCell = ({ hostDetails }) => {
13
+ // eslint-disable-next-line camelcase
14
+ const uuid = hostDetails?.subscription_facet_attributes?.uuid;
15
+
16
+ const key = `HOST_CVE_COUNT_${uuid}`;
17
+ const response = useAPI(
18
+ uuid ? 'get' : null,
19
+ vulnerabilityApiPath(`systems?uuid=${uuid}`),
20
+ {
21
+ key,
22
+ }
23
+ );
24
+
25
+ if (uuid === undefined) {
26
+ return <UnknownIcon />;
27
+ }
28
+
29
+ // eslint-disable-next-line camelcase
30
+ const { cve_count } = (response.response?.data || [])[0]?.attributes || {};
31
+
32
+ const cveLink = (
33
+ // eslint-disable-next-line camelcase
34
+ <Link to={`hosts/${hostDetails.name}#/Vulnerabilities`}>{cve_count}</Link>
35
+ );
36
+
37
+ // eslint-disable-next-line camelcase
38
+ return cve_count === undefined ? <UnknownIcon /> : cveLink;
39
+ };
40
+
41
+ CVECountCell.propTypes = {
42
+ hostDetails: PropTypes.object.isRequired,
43
+ };
44
+
45
+ export default CVECountCell;
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { API } from 'foremanReact/redux/API';
4
+ import { CVECountCell } from '../CVECountCell';
5
+
6
+ jest.mock('foremanReact/redux/API');
7
+ API.get.mockImplementation(async () => ({
8
+ data: [
9
+ {
10
+ attributes: {
11
+ cve_count: 1,
12
+ },
13
+ },
14
+ ],
15
+ }));
16
+
17
+ describe('CVECountCell', () => {
18
+ it('renders an empty cves count column', () => {
19
+ const hostDetailsMock = {
20
+ name: 'test-host.example.com',
21
+ subscription_facet_attributes: {
22
+ uuid: null, // no subscription
23
+ },
24
+ };
25
+ render(<CVECountCell hostDetails={hostDetailsMock} />);
26
+ expect(screen.getByRole('img', { hidden: true })).toBeTruthy();
27
+ });
28
+ });