foreman_rh_cloud 3.0.21.1 → 3.0.22

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/insights_cloud/api/machine_telemetries_controller.rb +17 -7
  3. data/app/models/insights_client_report_status.rb +58 -0
  4. data/app/services/foreman_rh_cloud/cloud_auth.rb +12 -0
  5. data/app/services/foreman_rh_cloud/cloud_request.rb +14 -0
  6. data/app/services/foreman_rh_cloud/cloud_request_forwarder.rb +1 -6
  7. data/app/services/foreman_rh_cloud/remediations_retriever.rb +1 -4
  8. data/app/subscribers/foreman_rh_cloud/insights_subscriber.rb +9 -0
  9. data/lib/foreman_inventory_upload/generators/fact_helpers.rb +19 -0
  10. data/lib/foreman_inventory_upload/generators/slice.rb +6 -6
  11. data/lib/foreman_rh_cloud/engine.rb +4 -1
  12. data/lib/foreman_rh_cloud/version.rb +1 -1
  13. data/lib/insights_cloud/async/insights_full_sync.rb +4 -14
  14. data/lib/insights_cloud/async/insights_resolutions_sync.rb +1 -4
  15. data/lib/insights_cloud/async/insights_rules_sync.rb +2 -7
  16. data/lib/inventory_sync/async/inventory_full_sync.rb +2 -1
  17. data/lib/inventory_sync/async/inventory_scheduled_sync.rb +8 -0
  18. data/lib/inventory_sync/async/query_inventory_job.rb +1 -4
  19. data/lib/tasks/rh_cloud_inventory.rake +6 -0
  20. data/package.json +2 -2
  21. data/test/factories/inventory_upload_factories.rb +1 -1
  22. data/test/jobs/insights_full_sync_test.rb +3 -0
  23. data/test/jobs/insights_resolutions_sync_test.rb +3 -0
  24. data/test/jobs/insights_rules_sync_test.rb +3 -0
  25. data/test/jobs/inventory_full_sync_test.rb +3 -0
  26. data/test/models/insights_client_report_status_test.rb +77 -0
  27. data/test/unit/slice_generator_test.rb +66 -29
  28. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/FullScreenModal.js +1 -1
  29. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/__tests__/__snapshots__/FullScreenModal.test.js.snap +1 -1
  30. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/fullScreenModal.scss +14 -16
  31. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButtonActions.js +28 -63
  32. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/integrations.test.js.snap +2 -3
  33. data/webpack/ForemanInventoryUpload/Components/Terminal/Terminal.js +1 -1
  34. data/webpack/ForemanInventoryUpload/Components/Terminal/__tests__/Terminal.test.js +1 -1
  35. data/webpack/ForemanInventoryUpload/Components/Terminal/__tests__/__snapshots__/Terminal.test.js.snap +2 -2
  36. data/webpack/ForemanInventoryUpload/Components/Terminal/terminal.scss +25 -27
  37. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableActions.js +19 -19
  38. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTableActions.test.js.snap +14 -14
  39. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediateButton.js +1 -0
  40. data/webpack/InsightsCloudSync/InsightsCloudSync.js +4 -1
  41. data/webpack/InsightsCloudSync/InsightsCloudSyncActions.js +44 -20
  42. data/webpack/InsightsCloudSync/InsightsCloudSyncConstants.js +2 -0
  43. data/webpack/InsightsCloudSync/__tests__/__snapshots__/InsightsCloudSyncActions.test.js.snap +11 -7
  44. data/webpack/common/ForemanTasks/ForemanTasksActions.js +64 -0
  45. data/webpack/common/ForemanTasks/ForemanTasksHelpers.js +7 -0
  46. data/webpack/common/ForemanTasks/index.js +1 -0
  47. metadata +10 -2
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
- import { get, post } from 'foremanReact/redux/API';
3
- import { withInterval } from 'foremanReact/redux/middlewares/IntervalMiddleware';
2
+ import { post } from 'foremanReact/redux/API';
4
3
  import { addToast } from 'foremanReact/redux/actions/toasts';
5
4
  import { translate as __ } from 'foremanReact/common/I18n';
6
5
  import { inventoryUrl } from '../../../../ForemanInventoryHelpers';
@@ -9,7 +8,10 @@ import {
9
8
  INVENTORY_SYNC,
10
9
  INVENTORY_SYNC_TASK_UPDATE,
11
10
  } from './SyncButtonConstants';
12
- import { foremanUrl } from '../../../../../ForemanRhCloudHelpers';
11
+ import {
12
+ setupTaskPolling,
13
+ taskRelatedToast,
14
+ } from '../../../../../common/ForemanTasks';
13
15
 
14
16
  export const handleSync = () => dispatch => {
15
17
  dispatch(
@@ -21,9 +23,9 @@ export const handleSync = () => dispatch => {
21
23
  task: { id },
22
24
  },
23
25
  }) => {
24
- dispatch(getSyncTaskInterval(id));
26
+ dispatch(setupInventorySyncTaskPolling(id, dispatch));
25
27
  return dispatch(
26
- taskPageRefererToast(id, 'info', __('Inventory sync has started:'))
28
+ taskRelatedToast(id, 'info', __('Inventory sync has started:'))
27
29
  );
28
30
  },
29
31
  errorToast: inventorySyncErrorToast,
@@ -31,62 +33,25 @@ export const handleSync = () => dispatch => {
31
33
  );
32
34
  };
33
35
 
34
- export const getSyncTaskInterval = id => dispatch => {
35
- dispatch(
36
- withInterval(
37
- get({
38
- key: INVENTORY_SYNC_TASK_UPDATE,
39
- url: inventoryUrl(`tasks/${id}`),
40
- handleSuccess: ({ data: { result, output } }, stopTaskInterval) => {
41
- if (result === 'success') {
42
- const {
43
- host_statuses: { sync, disconnect },
44
- } = output;
45
- dispatch(
46
- addToast({
47
- sticky: true,
48
- type: 'success',
49
- message: (
50
- <Toast syncHosts={sync} disconnectHosts={disconnect} />
51
- ),
52
- })
53
- );
54
- }
55
- if (result === 'error') {
56
- dispatch(
57
- taskPageRefererToast(
58
- id,
59
- 'error',
60
- __('Inventory sync has failed:'),
61
- true
62
- )
63
- );
64
- }
65
- stopTaskInterval();
66
- },
67
- errorToast: inventorySyncErrorToast,
68
- })
69
- )
70
- );
71
- };
72
-
73
- const inventorySyncErrorToast = ({ message, response }) =>
74
- `${__('Inventory sync has failed: ')} ${response.data?.message || message}`;
75
-
76
- const taskPageRefererToast = (taskID, toastType, prefix, sticky = false) =>
77
- addToast({
78
- sticky,
79
- type: toastType,
80
- message: (
81
- <span>
82
- {prefix}{' '}
83
- <a
84
- target="_blank"
85
- rel="noopener noreferrer"
86
- href={foremanUrl(`/foreman_tasks/tasks/${taskID}`)}
87
- >
88
- {__('view the task page for more details')}
89
- </a>
90
- </span>
91
- ),
36
+ export const setupInventorySyncTaskPolling = (id, dispatch) =>
37
+ setupTaskPolling({
38
+ taskId: id,
39
+ key: INVENTORY_SYNC_TASK_UPDATE,
40
+ onTaskSuccess: ({
41
+ output: {
42
+ host_statuses: { sync, disconnect },
43
+ },
44
+ }) =>
45
+ dispatch(
46
+ addToast({
47
+ sticky: true,
48
+ type: 'success',
49
+ message: <Toast syncHosts={sync} disconnectHosts={disconnect} />,
50
+ })
51
+ ),
52
+ dispatch,
92
53
  });
54
+
55
+ const inventorySyncErrorToast = message =>
56
+ `${__('Inventory sync has failed: ')} ${message.response?.data?.message ||
57
+ message}`;
@@ -22,7 +22,7 @@ Array [
22
22
  "errorToast": [Function],
23
23
  "interval": 3000,
24
24
  "type": "API_GET",
25
- "url": "/foreman_inventory_upload/tasks/1",
25
+ "url": "/foreman_tasks/api/tasks/1/details?include_permissions",
26
26
  },
27
27
  ],
28
28
  Array [
@@ -31,7 +31,7 @@ Array [
31
31
  "message": Object {
32
32
  "message": <span>
33
33
  Inventory sync has started:
34
-
34
+ <br />
35
35
  <a
36
36
  href="/foreman_tasks/tasks/1"
37
37
  rel="noopener noreferrer"
@@ -40,7 +40,6 @@ Array [
40
40
  view the task page for more details
41
41
  </a>
42
42
  </span>,
43
- "sticky": false,
44
43
  "type": "info",
45
44
  },
46
45
  },
@@ -72,7 +72,7 @@ class Terminal extends React.Component {
72
72
  return (
73
73
  <Grid.Col sm={12}>
74
74
  <div
75
- className="terminal"
75
+ className="rh-cloud-inventory-terminal"
76
76
  ref={this.terminal}
77
77
  onScroll={this.handleScroll}
78
78
  >
@@ -29,6 +29,6 @@ describe('Terminal', () => {
29
29
  const text = 'some-string-log';
30
30
  const modifiedProps = { ...props, logs: text };
31
31
  const wrapper = mount(<Terminal {...modifiedProps} />);
32
- expect(wrapper.find('.terminal p').text()).toEqual(text);
32
+ expect(wrapper.find('.rh-cloud-inventory-terminal p').text()).toEqual(text);
33
33
  });
34
34
  });
@@ -7,7 +7,7 @@ exports[`Terminal rendering render with props 1`] = `
7
7
  sm={12}
8
8
  >
9
9
  <div
10
- className="terminal"
10
+ className="rh-cloud-inventory-terminal"
11
11
  onScroll={[Function]}
12
12
  >
13
13
  <Grid
@@ -65,7 +65,7 @@ exports[`Terminal rendering render without Props 1`] = `
65
65
  sm={12}
66
66
  >
67
67
  <div
68
- className="terminal"
68
+ className="rh-cloud-inventory-terminal"
69
69
  onScroll={[Function]}
70
70
  >
71
71
  <Grid
@@ -1,34 +1,32 @@
1
- .rh-cloud-inventory-page {
2
- .terminal {
3
- height: 200px;
4
- background-color: #222;
5
- padding: 10px 0;
6
- margin-bottom: 20px;
7
- overflow-y: scroll;
8
- overflow-x: hidden;
1
+ .rh-cloud-inventory-terminal {
2
+ height: 200px;
3
+ background-color: #222;
4
+ padding: 10px 0;
5
+ margin-bottom: 20px;
6
+ overflow-y: scroll;
7
+ overflow-x: hidden;
9
8
 
10
- p {
11
- font-family: monospace;
12
- font-size: 16px;
13
- color: #22da26;
14
- overflow-wrap: anywhere;
9
+ p {
10
+ font-family: monospace;
11
+ font-size: 16px;
12
+ color: #22da26;
13
+ overflow-wrap: anywhere;
15
14
 
16
- &.terminal_error {
17
- color: #f00;
18
- }
15
+ &.terminal_error {
16
+ color: #f00;
19
17
  }
18
+ }
20
19
 
21
- &::-webkit-scrollbar {
22
- width: 12px;
23
- height: 12px;
24
- background: #aaa;
25
- }
20
+ &::-webkit-scrollbar {
21
+ width: 12px;
22
+ height: 12px;
23
+ background: #aaa;
24
+ }
26
25
 
27
- &::-webkit-scrollbar-thumb {
28
- background: #222;
29
- border-radius: 6px;
30
- border: 3px solid transparent;
31
- background-clip: content-box;
32
- }
26
+ &::-webkit-scrollbar-thumb {
27
+ background: #222;
28
+ border-radius: 6px;
29
+ border: 3px solid transparent;
30
+ background-clip: content-box;
33
31
  }
34
32
  }
@@ -19,25 +19,6 @@ export const fetchInsights = (queryParams = {}) => (dispatch, getState) => {
19
19
  ...queryParams,
20
20
  };
21
21
 
22
- dispatch(
23
- get({
24
- key: INSIGHTS_HITS_API_KEY,
25
- url: INSIGHTS_HITS_PATH,
26
- params: {
27
- page,
28
- per_page: perPage,
29
- search: query,
30
- order: `${sortBy} ${sortOrder}`,
31
- },
32
- handleSuccess: response => {
33
- if (isSelectAll) {
34
- selectAllIds(dispatch, response.data.hits || []);
35
- dispatch(selectAll());
36
- }
37
- },
38
- })
39
- );
40
-
41
22
  const uri = new URI();
42
23
  uri.search({
43
24
  page,
@@ -58,6 +39,25 @@ export const fetchInsights = (queryParams = {}) => (dispatch, getState) => {
58
39
  if (!isSelectAll) {
59
40
  dispatch(setSelectAllAlert(false));
60
41
  }
42
+
43
+ return dispatch(
44
+ get({
45
+ key: INSIGHTS_HITS_API_KEY,
46
+ url: INSIGHTS_HITS_PATH,
47
+ params: {
48
+ page,
49
+ per_page: perPage,
50
+ search: query,
51
+ order: `${sortBy} ${sortOrder}`,
52
+ },
53
+ handleSuccess: response => {
54
+ if (isSelectAll) {
55
+ selectAllIds(dispatch, response.data.hits || []);
56
+ dispatch(selectAll());
57
+ }
58
+ },
59
+ })
60
+ );
61
61
  };
62
62
 
63
63
  const selectAllIds = (dispatch, results, prevSelectedIds = {}) => {
@@ -26,6 +26,20 @@ Array [
26
26
 
27
27
  exports[`insights table actions should fetchInsights 1`] = `
28
28
  Array [
29
+ Array [
30
+ Object {
31
+ "payload": Object {
32
+ "args": Array [
33
+ Object {
34
+ "pathname": "/foreman_rh_cloud/insights_cloud",
35
+ "search": "?page=2&per_page=7&search=&sort_by=&sort_order=&select_all=true",
36
+ },
37
+ ],
38
+ "method": "push",
39
+ },
40
+ "type": "@@router/CALL_HISTORY_METHOD",
41
+ },
42
+ ],
29
43
  Array [
30
44
  Object {
31
45
  "payload": Object {
@@ -61,20 +75,6 @@ Array [
61
75
  "url": "/insights_cloud/hits",
62
76
  },
63
77
  ],
64
- Array [
65
- Object {
66
- "payload": Object {
67
- "args": Array [
68
- Object {
69
- "pathname": "/foreman_rh_cloud/insights_cloud",
70
- "search": "?page=2&per_page=7&search=&sort_by=&sort_order=&select_all=true",
71
- },
72
- ],
73
- "method": "push",
74
- },
75
- "type": "@@router/CALL_HISTORY_METHOD",
76
- },
77
- ],
78
78
  ]
79
79
  `;
80
80
 
@@ -34,6 +34,7 @@ const RemediateButton = ({ isExperimentalMode, selectedIds, toggleModal }) => {
34
34
  button = (
35
35
  <Popover
36
36
  isVisible={isVisible}
37
+ aria-label={__('Please enable lab features to use this button')}
37
38
  bodyContent={
38
39
  <div dangerouslySetInnerHTML={{ __html: popoverContent }} />
39
40
  }
@@ -36,7 +36,10 @@ const InsightsCloudSync = ({
36
36
  toolbarButtons={
37
37
  <>
38
38
  <RemediationModal />
39
- <Button variant="secondary" onClick={syncInsights}>
39
+ <Button
40
+ variant="secondary"
41
+ onClick={() => syncInsights(fetchInsights, query)}
42
+ >
40
43
  {__('Start recommendations sync')}
41
44
  </Button>
42
45
  </>
@@ -1,25 +1,49 @@
1
- import React from 'react';
2
1
  import { post } from 'foremanReact/redux/API';
3
2
  import { translate as __ } from 'foremanReact/common/I18n';
4
3
  import { insightsCloudUrl } from './InsightsCloudSyncHelpers';
5
- import { INSIGHTS_CLOUD_SYNC } from './InsightsCloudSyncConstants';
6
- import { foremanUrl } from '../ForemanRhCloudHelpers';
4
+ import {
5
+ INSIGHTS_CLOUD_SYNC,
6
+ INSIGHTS_CLOUD_SYNC_TASK,
7
+ } from './InsightsCloudSyncConstants';
8
+ import { setupTaskPolling, taskRelatedToast } from '../common/ForemanTasks';
7
9
 
8
- export const syncInsights = () =>
9
- post({
10
- key: INSIGHTS_CLOUD_SYNC,
11
- url: insightsCloudUrl('tasks'),
12
- successToast: response => (
13
- <span>
14
- {__('Recommendation sync has started: ')}
15
- <a
16
- target="_blank"
17
- rel="noopener noreferrer"
18
- href={foremanUrl(`/foreman_tasks/tasks/${response.data?.task?.id}`)}
19
- >
20
- {__('view the task in progress')}
21
- </a>
22
- </span>
23
- ),
24
- errorToast: error => `${__('Recommendation sync has failed: ')} ${error}`,
10
+ export const syncInsights = (fetchInsights, query) => dispatch =>
11
+ dispatch(
12
+ post({
13
+ key: INSIGHTS_CLOUD_SYNC,
14
+ url: insightsCloudUrl('tasks'),
15
+ handleSuccess: ({
16
+ data: {
17
+ task: { id },
18
+ },
19
+ }) => {
20
+ dispatch(syncInsightsStartedToast(id));
21
+ dispatch(setupInsightsTaskPolling(id, fetchInsights, query, dispatch));
22
+ },
23
+ errorToast: error => syncInsightsError(error),
24
+ })
25
+ );
26
+
27
+ const syncInsightsError = error =>
28
+ `${__('Recommendation sync has failed: ')} ${error}`;
29
+
30
+ const syncInsightsStartedToast = taskId =>
31
+ taskRelatedToast(taskId, 'info', __('Recommendation sync has started: '));
32
+
33
+ const setupInsightsTaskPolling = (taskId, fetchInsights, query, dispatch) =>
34
+ setupTaskPolling({
35
+ taskId,
36
+ key: INSIGHTS_CLOUD_SYNC_TASK,
37
+ onTaskSuccess: () => {
38
+ fetchInsights({ query, page: 1 });
39
+ dispatch(
40
+ taskRelatedToast(
41
+ taskId,
42
+ 'success',
43
+ __('Recommendations synced successfully')
44
+ )
45
+ );
46
+ },
47
+ taskErrorMessage: data => syncInsightsError(data.humanized.errors),
48
+ dispatch,
25
49
  });
@@ -4,6 +4,8 @@ import { foremanUrl } from '../ForemanRhCloudHelpers';
4
4
 
5
5
  export const INSIGHTS_CLOUD_SYNC = 'INSIGHTS_CLOUD_SYNC';
6
6
 
7
+ export const INSIGHTS_CLOUD_SYNC_TASK = 'INSIGHTS_CLOUD_SYNC_TASK';
8
+
7
9
  export const INSIGHTS_SYNC_PAGE_TITLE = __('Red Hat Insights');
8
10
 
9
11
  export const INSIGHTS_PATH = foremanUrl('/foreman_rh_cloud/insights_cloud');
@@ -1,11 +1,15 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`Insights cloud sync actions should syncInsights 1`] = `
4
- Object {
5
- "errorToast": [Function],
6
- "key": "INSIGHTS_CLOUD_SYNC",
7
- "successToast": [Function],
8
- "type": "post-some-type",
9
- "url": "/insights_cloud/tasks",
10
- }
4
+ Array [
5
+ Array [
6
+ Object {
7
+ "errorToast": [Function],
8
+ "handleSuccess": [Function],
9
+ "key": "INSIGHTS_CLOUD_SYNC",
10
+ "type": "post-some-type",
11
+ "url": "/insights_cloud/tasks",
12
+ },
13
+ ],
14
+ ]
11
15
  `;