foreman_rh_cloud 3.0.18.1 → 4.0.21.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -5
  3. data/app/controllers/foreman_inventory_upload/tasks_controller.rb +14 -3
  4. data/app/controllers/foreman_inventory_upload/uploads_settings_controller.rb +8 -0
  5. data/app/controllers/insights_cloud/api/machine_telemetries_controller.rb +17 -7
  6. data/app/controllers/insights_cloud/hits_controller.rb +37 -0
  7. data/app/controllers/insights_cloud/settings_controller.rb +1 -1
  8. data/app/controllers/insights_cloud/tasks_controller.rb +1 -2
  9. data/app/models/insights_client_report_status.rb +58 -0
  10. data/app/models/insights_resolution.rb +1 -1
  11. data/app/models/inventory_sync/inventory_status.rb +6 -0
  12. data/app/models/setting/rh_cloud.rb +5 -5
  13. data/app/services/foreman_rh_cloud/cloud_connector.rb +1 -1
  14. data/app/services/foreman_rh_cloud/remediations_retriever.rb +78 -0
  15. data/app/services/foreman_rh_cloud/template_renderer_helper.rb +22 -0
  16. data/app/subscribers/foreman_rh_cloud/insights_subscriber.rb +9 -0
  17. data/app/views/job_templates/rh_cloud_remediations.erb +14 -0
  18. data/config/routes.rb +2 -1
  19. data/db/migrate/20210404000001_change_resolutions.foreman_rh_cloud.rb +10 -0
  20. data/db/seeds.d/179_ui_notifications.rb +11 -0
  21. data/db/seeds.d/50_job_templates.rb +14 -0
  22. data/lib/foreman_inventory_upload.rb +9 -0
  23. data/lib/foreman_inventory_upload/async/generate_all_reports_job.rb +8 -2
  24. data/lib/foreman_inventory_upload/generators/queries.rb +3 -2
  25. data/lib/foreman_inventory_upload/generators/slice.rb +1 -1
  26. data/lib/foreman_inventory_upload/generators/tags.rb +8 -6
  27. data/lib/foreman_inventory_upload/scripts/uploader.sh.erb +5 -1
  28. data/lib/foreman_rh_cloud.rb +18 -0
  29. data/lib/foreman_rh_cloud/engine.rb +36 -2
  30. data/lib/foreman_rh_cloud/version.rb +1 -1
  31. data/lib/insights_cloud.rb +12 -0
  32. data/lib/insights_cloud/async/insights_full_sync.rb +39 -24
  33. data/lib/insights_cloud/async/insights_generate_notifications.rb +58 -0
  34. data/lib/insights_cloud/async/insights_resolutions_sync.rb +69 -0
  35. data/lib/insights_cloud/async/insights_rules_sync.rb +13 -17
  36. data/lib/insights_cloud/async/insights_scheduled_sync.rb +1 -1
  37. data/lib/inventory_sync/async/host_result.rb +11 -6
  38. data/lib/inventory_sync/async/inventory_full_sync.rb +24 -41
  39. data/lib/inventory_sync/async/inventory_hosts_sync.rb +34 -0
  40. data/lib/inventory_sync/async/inventory_scheduled_sync.rb +17 -0
  41. data/lib/inventory_sync/async/query_inventory_job.rb +54 -0
  42. data/lib/tasks/insights.rake +4 -12
  43. data/lib/tasks/rh_cloud_inventory.rake +12 -4
  44. data/package.json +1 -1
  45. data/test/factories/insights_factories.rb +22 -0
  46. data/test/jobs/insights_full_sync_test.rb +28 -15
  47. data/test/jobs/insights_resolutions_sync_test.rb +77 -0
  48. data/test/jobs/insights_rules_sync_test.rb +8 -3
  49. data/test/jobs/inventory_full_sync_test.rb +185 -12
  50. data/test/models/insights_client_report_status_test.rb +77 -0
  51. data/test/unit/rh_cloud_http_proxy_test.rb +4 -4
  52. data/test/unit/services/foreman_rh_cloud/remediations_retriever_test.rb +49 -0
  53. data/test/unit/services/foreman_rh_cloud/template_renderer_helper_test.rb +28 -0
  54. data/test/unit/slice_generator_test.rb +11 -2
  55. data/test/unit/tags_generator_test.rb +10 -0
  56. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/FullScreenModal.js +1 -1
  57. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/__tests__/__snapshots__/FullScreenModal.test.js.snap +1 -1
  58. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/fullScreenModal.scss +14 -16
  59. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/InventoryFilter.js +1 -1
  60. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/integration.test.js.snap +0 -1
  61. data/webpack/ForemanInventoryUpload/Components/InventorySettings/AdvancedSetting/AdvancedSettingsConstants.js +5 -3
  62. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/PageDescription.js +15 -2
  63. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/PageDescription/__tests__/__snapshots__/PageDescription.test.js.snap +13 -2
  64. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButtonActions.js +81 -46
  65. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButtonConstants.js +3 -3
  66. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButtonSelectors.js +6 -12
  67. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButtonFixtures.js +1 -9
  68. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButtonSelectors.test.js +18 -27
  69. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButtonSelectors.test.js.snap +1 -16
  70. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/integrations.test.js.snap +58 -0
  71. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/integrations.test.js +51 -0
  72. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/index.js +2 -5
  73. data/webpack/ForemanInventoryUpload/Components/Terminal/Terminal.js +1 -1
  74. data/webpack/ForemanInventoryUpload/Components/Terminal/__tests__/Terminal.test.js +1 -1
  75. data/webpack/ForemanInventoryUpload/Components/Terminal/__tests__/__snapshots__/Terminal.test.js.snap +2 -2
  76. data/webpack/ForemanInventoryUpload/Components/Terminal/terminal.scss +25 -27
  77. data/webpack/ForemanInventoryUpload/ForemanInventoryUploadReducers.js +0 -2
  78. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +1 -1
  79. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableSelectors.js +3 -0
  80. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTable.test.js.snap +2 -0
  81. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediateButton.js +59 -0
  82. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationActions.js +12 -0
  83. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationHelpers.js +43 -0
  84. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +101 -0
  85. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.scss +9 -0
  86. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModalFooter.js +43 -0
  87. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationTableConstants.js +38 -0
  88. data/webpack/InsightsCloudSync/Components/RemediationModal/Resolutions.js +55 -0
  89. data/webpack/InsightsCloudSync/Components/RemediationModal/index.js +34 -0
  90. data/webpack/InsightsCloudSync/InsightsCloudSync.js +8 -3
  91. data/webpack/InsightsCloudSync/InsightsCloudSync.scss +5 -0
  92. data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +9 -6
  93. data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware.js +4 -0
  94. data/webpack/{InsightsCloudSync/Components/InsightsTable/components → common/table}/EmptyState.js +0 -0
  95. data/webpack/common/table/helpers.js +7 -0
  96. metadata +56 -26
  97. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/SyncButtonReducer.js +0 -36
  98. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButtonActions.test.js +0 -31
  99. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButtonReducer.test.js +0 -26
  100. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButtonActions.test.js.snap +0 -98
  101. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButtonReducer.test.js.snap +0 -18
@@ -1,3 +1,3 @@
1
- export const INVENTORY_SYNC_REQUEST = 'INVENTORY_SYNC_REQUEST';
2
- export const INVENTORY_SYNC_SUCCESS = 'INVENTORY_SYNC_SUCCESS';
3
- export const INVENTORY_SYNC_ERROR = 'INVENTORY_SYNC_ERROR';
1
+ export const INVENTORY_SYNC = 'INVENTORY_SYNC';
2
+
3
+ export const INVENTORY_SYNC_TASK_UPDATE = 'INVENTORY_SYNC_TASK_UPDATE';
@@ -1,13 +1,7 @@
1
- import { selectForemanInventoryUpload } from '../../../../../ForemanRhCloudSelectors';
1
+ import { selectAPIResponse } from 'foremanReact/redux/API/APISelectors';
2
+ import { INVENTORY_SYNC_TASK_UPDATE } from './SyncButtonConstants';
2
3
 
3
- export const selectInventorySync = state =>
4
- selectForemanInventoryUpload(state).inventorySync;
5
-
6
- export const selectStatus = state => selectInventorySync(state).status;
7
-
8
- export const selectError = state => selectInventorySync(state).error;
9
-
10
- export const selectSyncHosts = state => selectInventorySync(state).syncHosts;
11
-
12
- export const selectDisconnectHosts = state =>
13
- selectInventorySync(state).disconnectHosts;
4
+ export const selectTaskStatus = state => {
5
+ const { result } = selectAPIResponse(state, INVENTORY_SYNC_TASK_UPDATE);
6
+ return typeof result === 'string' ? result.toUpperCase() : null;
7
+ };
@@ -1,9 +1 @@
1
- export const syncHosts = 1;
2
-
3
- export const disconnectHosts = 0;
4
-
5
- export const successResponse = { data: { syncHosts, disconnectHosts } };
6
-
7
- export const status = 'RESOLVED';
8
-
9
- export const error = 'some-error';
1
+ export const successResponse = { data: { task: { id: 1 } } };
@@ -1,35 +1,26 @@
1
1
  import { testSelectorsSnapshotWithFixtures } from '@theforeman/test';
2
- import { inventoryStateWrapper } from '../../../../../../ForemanRhCloudTestHelpers';
3
- import {
4
- status,
5
- error,
6
- syncHosts,
7
- disconnectHosts,
8
- } from './SyncButtonFixtures';
9
- import {
10
- selectInventorySync,
11
- selectStatus,
12
- selectError,
13
- selectSyncHosts,
14
- selectDisconnectHosts,
15
- } from '../SyncButtonSelectors';
2
+ import { selectTaskStatus } from '../SyncButtonSelectors';
16
3
 
17
- const state = inventoryStateWrapper({
18
- inventorySync: {
19
- status,
20
- error,
21
- syncHosts,
22
- disconnectHosts,
4
+ const state = {
5
+ API: {
6
+ INVENTORY_SYNC_TASK_UPDATE: {
7
+ response: {
8
+ endedAt: '2021-03-08T14:27:30.718+02:00',
9
+ output: {
10
+ host_statuses: {
11
+ sync: 0,
12
+ disconnect: 2,
13
+ },
14
+ },
15
+ result: 'pending',
16
+ },
17
+ status: 'RESOLVED',
18
+ },
23
19
  },
24
- });
20
+ };
25
21
 
26
22
  const fixtures = {
27
- 'should return InventorySync': () => selectInventorySync(state),
28
- 'should return InventorySync status': () => selectStatus(state),
29
- 'should return InventorySync error': () => selectError(state),
30
- 'should return InventorySync SyncHosts': () => selectSyncHosts(state),
31
- 'should return InventorySync disconnectHosts': () =>
32
- selectDisconnectHosts(state),
23
+ 'should return InventorySync status': () => selectTaskStatus(state),
33
24
  };
34
25
 
35
26
  describe('SyncButton selectors', () =>
@@ -1,18 +1,3 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`SyncButton selectors should return InventorySync 1`] = `
4
- Object {
5
- "disconnectHosts": 0,
6
- "error": "some-error",
7
- "status": "RESOLVED",
8
- "syncHosts": 1,
9
- }
10
- `;
11
-
12
- exports[`SyncButton selectors should return InventorySync SyncHosts 1`] = `1`;
13
-
14
- exports[`SyncButton selectors should return InventorySync disconnectHosts 1`] = `0`;
15
-
16
- exports[`SyncButton selectors should return InventorySync error 1`] = `"some-error"`;
17
-
18
- exports[`SyncButton selectors should return InventorySync status 1`] = `"RESOLVED"`;
3
+ exports[`SyncButton selectors should return InventorySync status 1`] = `"PENDING"`;
@@ -0,0 +1,58 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`SyncButton integration test Successful task was triggered on the server resulting in an info toast and polling on the task: handleSync was called 1`] = `
4
+ Array [
5
+ Array [
6
+ Object {
7
+ "payload": Object {
8
+ "message": Object {
9
+ "message": <Toast
10
+ disconnectHosts={2}
11
+ syncHosts={0}
12
+ />,
13
+ "sticky": true,
14
+ "type": "success",
15
+ },
16
+ },
17
+ "type": "TOASTS_ADD",
18
+ },
19
+ ],
20
+ Array [
21
+ Object {
22
+ "errorToast": [Function],
23
+ "interval": 3000,
24
+ "type": "API_GET",
25
+ "url": "/foreman_inventory_upload/tasks/1",
26
+ },
27
+ ],
28
+ Array [
29
+ Object {
30
+ "payload": Object {
31
+ "message": Object {
32
+ "message": <span>
33
+ Inventory sync has started:
34
+
35
+ <a
36
+ href="/foreman_tasks/tasks/1"
37
+ rel="noopener noreferrer"
38
+ target="_blank"
39
+ >
40
+ view the task page for more details
41
+ </a>
42
+ </span>,
43
+ "sticky": false,
44
+ "type": "info",
45
+ },
46
+ },
47
+ "type": "TOASTS_ADD",
48
+ },
49
+ ],
50
+ Array [
51
+ Object {
52
+ "errorToast": [Function],
53
+ "type": "API_POST",
54
+ "url": "/foreman_inventory_upload/tasks",
55
+ },
56
+ ],
57
+ ]
58
+ `;
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ import { IntegrationTestHelper } from '@theforeman/test';
3
+ import * as API from 'foremanReact/redux/API';
4
+ import { noop } from 'foremanReact/common/helpers';
5
+ import SyncButton from '../index';
6
+ import { successResponse } from './SyncButtonFixtures';
7
+ import {
8
+ INVENTORY_SYNC,
9
+ INVENTORY_SYNC_TASK_UPDATE,
10
+ } from '../SyncButtonConstants';
11
+
12
+ jest.spyOn(API, 'post');
13
+ jest.spyOn(API, 'get');
14
+
15
+ describe('SyncButton integration test', () => {
16
+ it('Successful task was triggered on the server resulting in an info toast and polling on the task', async () => {
17
+ API.post.mockImplementation(({ handleSuccess = noop, key, ...action }) => {
18
+ if (key === INVENTORY_SYNC) {
19
+ handleSuccess(successResponse);
20
+ }
21
+ return { type: 'API_POST', ...action };
22
+ });
23
+ API.get.mockImplementation(({ handleSuccess = noop, key, ...action }) => {
24
+ if (key === INVENTORY_SYNC_TASK_UPDATE) {
25
+ handleSuccess(
26
+ {
27
+ data: {
28
+ endedAt: '2021-03-22T15:59:02.468+02:00',
29
+ output: {
30
+ host_statuses: {
31
+ sync: 0,
32
+ disconnect: 2,
33
+ },
34
+ },
35
+ result: 'success',
36
+ },
37
+ },
38
+ jest.fn
39
+ );
40
+ }
41
+ return { type: 'API_GET', ...action };
42
+ });
43
+
44
+ const integrationTestHelper = new IntegrationTestHelper();
45
+ const wrapper = integrationTestHelper.mount(<SyncButton />);
46
+ const instance = wrapper.find('SyncButton').instance();
47
+ instance.props.handleSync();
48
+ await IntegrationTestHelper.flushAllPromises();
49
+ integrationTestHelper.takeActionsSnapshot('handleSync was called');
50
+ });
51
+ });
@@ -2,21 +2,18 @@ import { bindActionCreators } from 'redux';
2
2
  import { connect } from 'react-redux';
3
3
 
4
4
  import * as actions from './SyncButtonActions';
5
- import reducer from './SyncButtonReducer';
6
5
  import SyncButton from './SyncButton';
7
6
  import { selectCloudToken } from '../../../InventorySettings/InventorySettingsSelectors';
8
- import { selectStatus } from './SyncButtonSelectors';
7
+ import { selectTaskStatus } from './SyncButtonSelectors';
9
8
 
10
9
  // map state to props
11
10
  const mapStateToProps = state => ({
12
11
  cloudToken: selectCloudToken(state),
13
- status: selectStatus(state),
12
+ status: selectTaskStatus(state),
14
13
  });
15
14
 
16
15
  // map action dispatchers to props
17
16
  const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);
18
17
 
19
- export const reducers = { inventorySync: reducer };
20
-
21
18
  // export connected component
22
19
  export default connect(mapStateToProps, mapDispatchToProps)(SyncButton);
@@ -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
  }
@@ -2,13 +2,11 @@ import { combineReducers } from 'redux';
2
2
  import { reducers as accountListReducers } from './Components/AccountList';
3
3
  import { reducers as dashboardReducers } from './Components/Dashboard';
4
4
  import { reducers as filterReducers } from './Components/InventoryFilter';
5
- import { reducers as inventorySyncReducers } from './Components/PageHeader/components/SyncButton';
6
5
 
7
6
  export default {
8
7
  inventoryUpload: combineReducers({
9
8
  ...accountListReducers,
10
9
  ...dashboardReducers,
11
10
  ...filterReducers,
12
- ...inventorySyncReducers,
13
11
  }),
14
12
  };
@@ -6,7 +6,7 @@ import { Table, TableHeader, TableBody } from '@patternfly/react-table';
6
6
  import { useForemanSettings } from 'foremanReact/Root/Context/ForemanContext';
7
7
  import SelectAllAlert from './SelectAllAlert';
8
8
  import { columns } from './InsightsTableConstants';
9
- import TableEmptyState from './components/EmptyState';
9
+ import TableEmptyState from '../../../common/table/EmptyState';
10
10
  import {
11
11
  modifySelectedRows,
12
12
  getSortColumnIndex,
@@ -76,3 +76,6 @@ export const selectItemCount = state =>
76
76
 
77
77
  export const selectHasToken = state =>
78
78
  selectAPIResponse(state, INSIGHTS_HITS_API_KEY).hasToken;
79
+
80
+ export const selectExperimental = state =>
81
+ selectAPIResponse(state, INSIGHTS_HITS_API_KEY).isExperimentalMode;
@@ -61,6 +61,7 @@ exports[`InsightsTable rendering render with Props 1`] = `
61
61
  expandId="expandable-toggle"
62
62
  gridBreakPoint="grid-md"
63
63
  isStickyHeader={false}
64
+ isTreeTable={false}
64
65
  onSelect={[Function]}
65
66
  onSort={[Function]}
66
67
  ouiaSafe={true}
@@ -137,6 +138,7 @@ exports[`InsightsTable rendering render with Props 1`] = `
137
138
  "currPage": "Current page",
138
139
  "items": "",
139
140
  "itemsPerPage": "Items per page",
141
+ "ofWord": "of",
140
142
  "optionsToggle": "Items per page",
141
143
  "page": "",
142
144
  "paginationTitle": "Pagination",
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { isEmpty } from 'lodash';
4
+ import { Button, Popover } from '@patternfly/react-core';
5
+ import { translate as __ } from 'foremanReact/common/I18n';
6
+ import { foremanUrl } from '../../../ForemanRhCloudHelpers';
7
+
8
+ const RemediateButton = ({ isExperimentalMode, selectedIds, toggleModal }) => {
9
+ const [isVisible, setVisible] = React.useState(true);
10
+
11
+ const popoverContent = __(
12
+ `To use this feature, please enable <a href=${foremanUrl(
13
+ '/settings?search=name+%3D+lab_features'
14
+ )}>Show Experimental Labs</a> in settings.`
15
+ );
16
+
17
+ let button = (
18
+ <Button
19
+ variant="primary"
20
+ isDisabled={isEmpty(selectedIds)}
21
+ onClick={() => {
22
+ if (!isExperimentalMode) {
23
+ setVisible(value => !value);
24
+ } else {
25
+ toggleModal();
26
+ }
27
+ }}
28
+ >
29
+ {__('Remediate')}
30
+ </Button>
31
+ );
32
+
33
+ if (!isExperimentalMode) {
34
+ button = (
35
+ <Popover
36
+ isVisible={isVisible}
37
+ bodyContent={
38
+ <div dangerouslySetInnerHTML={{ __html: popoverContent }} />
39
+ }
40
+ >
41
+ {button}
42
+ </Popover>
43
+ );
44
+ }
45
+ return button;
46
+ };
47
+
48
+ RemediateButton.propTypes = {
49
+ selectedIds: PropTypes.object,
50
+ isExperimentalMode: PropTypes.bool,
51
+ toggleModal: PropTypes.func.isRequired,
52
+ };
53
+
54
+ RemediateButton.defaultProps = {
55
+ selectedIds: {},
56
+ isExperimentalMode: false,
57
+ };
58
+
59
+ export default RemediateButton;