foreman_rh_cloud 2.0.10 → 2.0.11

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +27 -2
  3. data/app/controllers/insights_cloud/hits_controller.rb +17 -0
  4. data/app/models/concerns/rh_cloud_host.rb +12 -0
  5. data/app/views/hosts/_insights_tab.html.erb +15 -0
  6. data/config/routes.rb +1 -0
  7. data/lib/foreman_inventory_upload/async/generate_report_job.rb +1 -1
  8. data/lib/foreman_inventory_upload/async/shell_process.rb +15 -9
  9. data/lib/foreman_inventory_upload/async/upload_report_job.rb +19 -1
  10. data/lib/foreman_inventory_upload/generators/metadata.rb +3 -0
  11. data/lib/foreman_inventory_upload/generators/queries.rb +2 -4
  12. data/lib/foreman_rh_cloud/engine.rb +10 -0
  13. data/lib/foreman_rh_cloud/version.rb +1 -1
  14. data/lib/tasks/insights.rake +15 -0
  15. data/lib/tasks/{generator.rake → rh_cloud_inventory.rake} +7 -1
  16. data/package.json +3 -1
  17. data/test/jobs/upload_report_job_test.rb +34 -0
  18. data/test/unit/metadata_generator_test.rb +2 -0
  19. data/test/unit/slice_generator_test.rb +17 -0
  20. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/InventoryFilterReducer.js +13 -2
  21. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/InventoryFilterReducer.test.js +10 -1
  22. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilterReducer.test.js.snap +6 -0
  23. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/integration.test.js.snap +3 -0
  24. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/components/Toast.js +1 -1
  25. data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.js +1 -1
  26. data/webpack/ForemanInventoryUpload/Components/StatusChart/__tests__/__snapshots__/StatusChart.test.js.snap +1 -1
  27. data/webpack/ForemanInventoryUpload/Components/TabContainer/tabContainer.scss +1 -1
  28. data/webpack/ForemanRhCloudPages.js +2 -0
  29. data/webpack/ForemanRhCloudReducers.js +2 -0
  30. data/webpack/ForemanRhCloudSelectors.js +5 -0
  31. data/webpack/ForemanRhCloudTestHelpers.js +6 -1
  32. data/webpack/InsightsHostDetailsTab/InsightsTab.js +64 -0
  33. data/webpack/InsightsHostDetailsTab/InsightsTab.scss +86 -0
  34. data/webpack/InsightsHostDetailsTab/InsightsTabActions.js +30 -0
  35. data/webpack/InsightsHostDetailsTab/InsightsTabConstants.js +3 -0
  36. data/webpack/InsightsHostDetailsTab/InsightsTabReducer.js +26 -0
  37. data/webpack/InsightsHostDetailsTab/InsightsTabSelectors.js +3 -0
  38. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTab.fixtures.js +25 -0
  39. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTab.test.js +13 -0
  40. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabActions.test.js +13 -0
  41. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabIntegration.test.js +17 -0
  42. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabReducer.test.js +35 -0
  43. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabSelectors.test.js +13 -0
  44. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTab.test.js.snap +30 -0
  45. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabActions.test.js.snap +20 -0
  46. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabReducer.test.js.snap +41 -0
  47. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabSelectors.test.js.snap +20 -0
  48. data/webpack/InsightsHostDetailsTab/components/ListItem/ListItem.js +69 -0
  49. data/webpack/InsightsHostDetailsTab/components/ListItem/index.js +1 -0
  50. data/webpack/InsightsHostDetailsTab/index.js +20 -0
  51. data/webpack/__mocks__/foremanReact/components/Layout/LayoutConstants.js +1 -0
  52. data/webpack/__tests__/__snapshots__/ForemanRhCloudSelectors.test.js.snap +1 -0
  53. data/webpack/__tests__/__snapshots__/ForemanRhCloudTestHelpers.test.js.snap +3 -0
  54. metadata +38 -13
@@ -18,6 +18,12 @@ Object {
18
18
  }
19
19
  `;
20
20
 
21
+ exports[`AccountList reducer should handle LAYOUT_INITIALIZE 1`] = `
22
+ Object {
23
+ "filterTerm": "some_org",
24
+ }
25
+ `;
26
+
21
27
  exports[`AccountList reducer should return the initial state 1`] = `
22
28
  Object {
23
29
  "filterTerm": "",
@@ -19,6 +19,9 @@ Object {
19
19
  "insightsSyncEnabled": false,
20
20
  },
21
21
  },
22
+ "hostInsights": Object {
23
+ "hits": Array [],
24
+ },
22
25
  "inventoryUpload": Object {
23
26
  "accountsList": Object {
24
27
  "accounts": Object {},
@@ -8,7 +8,7 @@ const Toast = ({ syncHosts, disconnectHosts }) => {
8
8
  return (
9
9
  <span>
10
10
  <p>
11
- {__("Total org's hosts with subscriprion: ")}
11
+ {__('Hosts with subscription in organization: ')}
12
12
  <strong>{totalHosts}</strong>
13
13
  </p>
14
14
  <p>
@@ -27,7 +27,7 @@ const StatusChart = ({ completed }) => {
27
27
  <Grid.Col sm={4}>
28
28
  <div className="status-chart">
29
29
  <DonutChart
30
- id="donunt-chart-1"
30
+ id="donut-chart-1"
31
31
  size={{
32
32
  width: 210,
33
33
  height: 210,
@@ -43,7 +43,7 @@ exports[`StatusChart rendering render without Props 1`] = `
43
43
  "width": 11,
44
44
  }
45
45
  }
46
- id="donunt-chart-1"
46
+ id="donut-chart-1"
47
47
  legend={
48
48
  Object {
49
49
  "show": false,
@@ -1,4 +1,4 @@
1
- .tab-content {
1
+ .dashboard .tab-content {
2
2
  padding: 20px;
3
3
  min-height: 0;
4
4
 
@@ -1,7 +1,9 @@
1
1
  import ForemanInventoryUpload from './ForemanInventoryUpload';
2
2
  import InsightsCloudSync from './InsightsCloudSync';
3
+ import InsightsHostDetailsTab from './InsightsHostDetailsTab';
3
4
 
4
5
  export default [
5
6
  { name: 'ForemanInventoryUpload', type: ForemanInventoryUpload },
6
7
  { name: 'InsightsCloudSync', type: InsightsCloudSync },
8
+ { name: 'InsightsHostDetailsTab', type: InsightsHostDetailsTab },
7
9
  ];
@@ -1,10 +1,12 @@
1
1
  import { combineReducers } from 'redux';
2
2
  import inventoryUploadReducers from './ForemanInventoryUpload/ForemanInventoryUploadReducers';
3
3
  import insightsReducers from './InsightsCloudSync/InsightsCloudSyncReducers';
4
+ import { hostInsightsReducers } from './InsightsHostDetailsTab';
4
5
 
5
6
  export default {
6
7
  ForemanRhCloud: combineReducers({
7
8
  ...inventoryUploadReducers,
8
9
  ...insightsReducers,
10
+ ...hostInsightsReducers,
9
11
  }),
10
12
  };
@@ -1,5 +1,10 @@
1
1
  export const selectForemanRhCloud = state => state.ForemanRhCloud;
2
+
2
3
  export const selectForemanInventoryUpload = state =>
3
4
  selectForemanRhCloud(state).inventoryUpload;
5
+
4
6
  export const selectInsightsCloudSync = state =>
5
7
  selectForemanRhCloud(state).InsightsCloudSync;
8
+
9
+ export const selectHostInsights = state =>
10
+ selectForemanRhCloud(state).hostInsights;
@@ -1,10 +1,12 @@
1
1
  export const rhCloudStateWrapper = (
2
2
  inventoryState = {},
3
- insightsState = {}
3
+ insightsState = {},
4
+ hostInsightsState = {}
4
5
  ) => ({
5
6
  ForemanRhCloud: {
6
7
  inventoryUpload: { ...inventoryState },
7
8
  InsightsCloudSync: { ...insightsState },
9
+ hostInsights: { ...hostInsightsState },
8
10
  },
9
11
  });
10
12
 
@@ -13,3 +15,6 @@ export const inventoryStateWrapper = innerState =>
13
15
 
14
16
  export const insightsStateWrapper = innerState =>
15
17
  rhCloudStateWrapper({}, innerState);
18
+
19
+ export const hostInsightsStateWrapper = innerState =>
20
+ rhCloudStateWrapper({}, {}, innerState);
@@ -0,0 +1,64 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { orderBy } from 'lodash';
4
+ import { Grid, ListView, noop } from 'patternfly-react';
5
+ import ListItem from './components/ListItem';
6
+ import './InsightsTab.scss';
7
+
8
+ class InsightsHostDetailsTab extends React.Component {
9
+ componentDidMount() {
10
+ const { fetchHits, hostID } = this.props;
11
+ fetchHits(hostID);
12
+ }
13
+
14
+ render() {
15
+ const { hits } = this.props;
16
+
17
+ if (!hits.length) {
18
+ return <h2>No recommendations were found for this host!</h2>;
19
+ }
20
+ const hitsSorted = orderBy(hits, ['insights_hit.total_risk'], ['desc']);
21
+ const items = hitsSorted.map(
22
+ (
23
+ {
24
+ insights_hit: {
25
+ title,
26
+ total_risk: totalRisk,
27
+ results_url: resultsUrl,
28
+ solution_url: solutionUrl,
29
+ },
30
+ },
31
+ index
32
+ ) => (
33
+ <ListItem
34
+ key={index}
35
+ title={title}
36
+ totalRisk={totalRisk}
37
+ resultsUrl={resultsUrl}
38
+ solutionUrl={solutionUrl}
39
+ />
40
+ )
41
+ );
42
+ return (
43
+ <Grid.Row>
44
+ <Grid.Col xs={12}>
45
+ <h2>Recommendations</h2>
46
+ <ListView id="hits_list">{items}</ListView>
47
+ </Grid.Col>
48
+ </Grid.Row>
49
+ );
50
+ }
51
+ }
52
+
53
+ InsightsHostDetailsTab.propTypes = {
54
+ hostID: PropTypes.number.isRequired,
55
+ fetchHits: PropTypes.func,
56
+ hits: PropTypes.array,
57
+ };
58
+
59
+ InsightsHostDetailsTab.defaultProps = {
60
+ fetchHits: noop,
61
+ hits: [],
62
+ };
63
+
64
+ export default InsightsHostDetailsTab;
@@ -0,0 +1,86 @@
1
+ #host_details_insights_react_container {
2
+ #btn_toolbar {
3
+ float: right;
4
+ }
5
+
6
+ #btn_fullscreen {
7
+ margin-left: 5px;
8
+
9
+ .fa-arrows-alt {
10
+ margin-left: 5px;
11
+ }
12
+ }
13
+
14
+ h2 {
15
+ margin-top: 5px;
16
+ }
17
+
18
+ #hits_list {
19
+ max-height: 650px;
20
+ overflow-y: scroll;
21
+ overflow-x: hidden;
22
+ margin-top: 15px;
23
+
24
+ .list-view-pf-expand {
25
+ padding: 0;
26
+ }
27
+
28
+ .list-group-item-header {
29
+ .list-view-pf-expand .fa-angle-right {
30
+ margin-top: 6px;
31
+ }
32
+
33
+ .list-view-pf-main-info .list-view-pf-description {
34
+ width: 83%;
35
+
36
+ .list-group-item-heading {
37
+ width: 375px;
38
+ }
39
+
40
+ p {
41
+ margin: 0;
42
+ font-size: 14px;
43
+ }
44
+ }
45
+
46
+ .list-view-pf-additional-info {
47
+ .risk-label {
48
+ padding: 5px 8px;
49
+ border-radius: 12px;
50
+
51
+ &.Low {
52
+ background-color: #e7f1fa;
53
+ }
54
+
55
+ &.Moderate {
56
+ background-color: #fdf7e7;
57
+ }
58
+
59
+ &.Important {
60
+ background-color: #f9dddd;
61
+ }
62
+
63
+ &.Critical {
64
+ background-color: #ffecec;
65
+ }
66
+
67
+ p {
68
+ margin: 0;
69
+ }
70
+ }
71
+ }
72
+ }
73
+
74
+ &::-webkit-scrollbar {
75
+ width: 12px;
76
+ height: 12px;
77
+ }
78
+
79
+ &::-webkit-scrollbar-thumb {
80
+ background: #0e0e0e6e;
81
+ border-radius: 6px;
82
+ border: 3px solid transparent;
83
+ background-clip: content-box;
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,30 @@
1
+ import API from 'foremanReact/API';
2
+ import { insightsCloudUrl } from '../InsightsCloudSync/InsightsCloudSyncHelpers';
3
+ import {
4
+ INSIGHTS_HITS_REQUEST,
5
+ INSIGHTS_HITS_SUCCESS,
6
+ INSIGHTS_HITS_FAILURE,
7
+ } from './InsightsTabConstants';
8
+
9
+ export const fetchHits = hostID => async dispatch => {
10
+ try {
11
+ dispatch({
12
+ type: INSIGHTS_HITS_REQUEST,
13
+ payload: {},
14
+ });
15
+ const {
16
+ data: { hits },
17
+ } = await API.get(insightsCloudUrl(`hits/${hostID}`));
18
+ dispatch({
19
+ type: INSIGHTS_HITS_SUCCESS,
20
+ payload: { hits },
21
+ });
22
+ } catch (error) {
23
+ dispatch({
24
+ type: INSIGHTS_HITS_FAILURE,
25
+ payload: {
26
+ error: error.message,
27
+ },
28
+ });
29
+ }
30
+ };
@@ -0,0 +1,3 @@
1
+ export const INSIGHTS_HITS_REQUEST = 'INSIGHTS_HITS_REQUEST';
2
+ export const INSIGHTS_HITS_SUCCESS = 'INSIGHTS_HITS_SUCCESS';
3
+ export const INSIGHTS_HITS_FAILURE = 'INSIGHTS_HITS_FAILURE';
@@ -0,0 +1,26 @@
1
+ import Immutable from 'seamless-immutable';
2
+ import {
3
+ INSIGHTS_HITS_SUCCESS,
4
+ INSIGHTS_HITS_FAILURE,
5
+ } from './InsightsTabConstants';
6
+
7
+ const initialState = Immutable({
8
+ hits: [],
9
+ });
10
+
11
+ export default (state = initialState, action) => {
12
+ const { payload: { hits, error } = {} } = action;
13
+
14
+ switch (action.type) {
15
+ case INSIGHTS_HITS_SUCCESS:
16
+ return state.merge({
17
+ hits,
18
+ });
19
+ case INSIGHTS_HITS_FAILURE:
20
+ return state.merge({
21
+ error,
22
+ });
23
+ default:
24
+ return state;
25
+ }
26
+ };
@@ -0,0 +1,3 @@
1
+ import { selectHostInsights } from '../ForemanRhCloudSelectors';
2
+
3
+ export const selectHits = state => selectHostInsights(state).hits;
@@ -0,0 +1,25 @@
1
+ export const hostID = 1234;
2
+
3
+ export const hits = [
4
+ {
5
+ insights_hit: {
6
+ hostname: 'my-host.example.com',
7
+ rhel_version: '7.8',
8
+ uuid: '4739b323-a343-4e89-b71b-81991b8dc656',
9
+ last_seen: '2020-08-19T04:43:09.068706Z',
10
+ title:
11
+ 'New Ansible Engine packages are inaccessible when dedicated Ansible repo is not enabled',
12
+ solution_url: 'https://access.redhat.com/node/3359651',
13
+ total_risk: 2,
14
+ likelihood: 2,
15
+ publish_date: '2018-04-16T10:03:16Z',
16
+ results_url:
17
+ 'https://cloud.redhat.com/insights/advisor/recommendations/ansible_deprecated_repo%7CANSIBLE_DEPRECATED_REPO/4739b323-a343-4e89-b71b-81991b8dc656/',
18
+ },
19
+ },
20
+ ];
21
+
22
+ export const props = {
23
+ hostID,
24
+ hits,
25
+ };
@@ -0,0 +1,13 @@
1
+ import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
+
3
+ import InsightsTab from '../InsightsTab';
4
+ import { props } from './InsightsTab.fixtures';
5
+
6
+ const fixtures = {
7
+ 'render with props': props,
8
+ };
9
+
10
+ describe('InsightsTab', () => {
11
+ describe('rendering', () =>
12
+ testComponentSnapshotsWithFixtures(InsightsTab, fixtures));
13
+ });
@@ -0,0 +1,13 @@
1
+ import { testActionSnapshotWithFixtures } from '@theforeman/test';
2
+ import API from 'foremanReact/API';
3
+ import { fetchHits } from '../InsightsTabActions';
4
+ import { hostID, hits } from './InsightsTab.fixtures';
5
+
6
+ jest.mock('foremanReact/API');
7
+ API.get.mockImplementation(async () => hits);
8
+
9
+ const fixtures = {
10
+ 'should fetchHits': () => fetchHits(hostID),
11
+ };
12
+
13
+ describe('InsightsTab actions', () => testActionSnapshotWithFixtures(fixtures));
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { IntegrationTestHelper } from '@theforeman/test';
3
+
4
+ import InsightsTab from '../index';
5
+ import reducers from '../../ForemanRhCloudReducers';
6
+ import { hostID } from './InsightsTab.fixtures';
7
+
8
+ describe('InsightsTab integration test', () => {
9
+ it('should flow', async () => {
10
+ const integrationTestHelper = new IntegrationTestHelper(reducers);
11
+ const component = integrationTestHelper.mount(
12
+ <InsightsTab hostID={hostID} />
13
+ );
14
+ component.update();
15
+ /** Create a Flow test */
16
+ });
17
+ });
@@ -0,0 +1,35 @@
1
+ import { testReducerSnapshotWithFixtures } from '@theforeman/test';
2
+ import reducer from '../InsightsTabReducer';
3
+ import { hits } from './InsightsTab.fixtures';
4
+ import {
5
+ INSIGHTS_HITS_REQUEST,
6
+ INSIGHTS_HITS_SUCCESS,
7
+ INSIGHTS_HITS_FAILURE,
8
+ } from '../InsightsTabConstants';
9
+
10
+ const fixtures = {
11
+ 'should return the initial state': {},
12
+ 'should handle INSIGHTS_HITS_REQUEST': {
13
+ action: {
14
+ type: INSIGHTS_HITS_REQUEST,
15
+ payload: {},
16
+ },
17
+ },
18
+ 'should handle INSIGHTS_HITS_SUCCESS': {
19
+ action: {
20
+ type: INSIGHTS_HITS_SUCCESS,
21
+ payload: { hits },
22
+ },
23
+ },
24
+ 'should handle INSIGHTS_HITS_FAILURE': {
25
+ action: {
26
+ type: INSIGHTS_HITS_FAILURE,
27
+ payload: {
28
+ error: 'some-error',
29
+ },
30
+ },
31
+ },
32
+ };
33
+
34
+ describe('AccountList reducer', () =>
35
+ testReducerSnapshotWithFixtures(reducer, fixtures));