foreman_rh_cloud 14.2.0 → 14.2.1

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/lib/foreman_rh_cloud/version.rb +1 -1
  3. data/package.json +1 -1
  4. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyResults/EmptyResults.js +15 -6
  5. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyResults/emptyResults.scss +1 -5
  6. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyState/EmptyState.js +15 -7
  7. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyState/__tests__/EmptyState.test.js +1 -3
  8. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyState/emptyState.scss +1 -5
  9. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ErrorState/ErrorState.js +2 -2
  10. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/__tests__/ListItem.test.js +0 -1
  11. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountList.test.js +2 -6
  12. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/Components/ClearButton/ClearButton.js +13 -10
  13. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/InventoryFilter.js +30 -11
  14. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/integration.test.js +3 -1
  15. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/inventoryFilter.scss +28 -22
  16. data/webpack/ForemanInventoryUpload/Components/InventorySettings/InventorySettings.js +4 -4
  17. data/webpack/ForemanInventoryUpload/Components/InventorySettings/InventorySettings.scss +16 -3
  18. data/webpack/ForemanInventoryUpload/Components/InventorySettings/MinimalInventoryDropdown.js +13 -14
  19. data/webpack/ForemanInventoryUpload/Components/PageHeader/PageHeader.js +7 -7
  20. data/webpack/ForemanInventoryUpload/Components/PageHeader/PageHeader.scss +3 -2
  21. data/webpack/ForemanInventoryUpload/Components/PageHeader/PageTitle.js +63 -46
  22. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/PageHeader.test.js +4 -7
  23. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/PageTitle.test.js +83 -12
  24. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudPingModal/index.js +31 -38
  25. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButton.test.js +3 -1
  26. data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/InventoryAutoUpload.js +29 -22
  27. data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/__tests__/InventoryAutoUpload.test.js +6 -2
  28. data/webpack/ForemanInventoryUpload/__tests__/ForemanInventoryHelpers.test.js +6 -3
  29. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +90 -23
  30. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableActions.js +1 -2
  31. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableConstants.js +24 -30
  32. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTableHelpers.js +5 -6
  33. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/InsightsTable.test.js +193 -8
  34. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/InsightsTableActions.test.js +4 -1
  35. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationHelpers.js +8 -9
  36. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +26 -13
  37. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationTableConstants.js +12 -10
  38. data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +21 -9
  39. data/webpack/InsightsCloudSync/InsightsCloudSync.test.js +12 -19
  40. data/webpack/InsightsCloudSync/__tests__/InsightsCloudSyncActions.test.js +0 -1
  41. data/webpack/common/DropdownToggle.js +20 -6
  42. metadata +1 -44
  43. data/webpack/ForemanInventoryUpload/Components/FileDownload/FileDownload.fixtures.js +0 -0
  44. data/webpack/ForemanInventoryUpload/Components/FileDownload/FileDownload.js +0 -25
  45. data/webpack/ForemanInventoryUpload/Components/FileDownload/FileDownloadHelper.js +0 -0
  46. data/webpack/ForemanInventoryUpload/Components/FileDownload/__tests__/FileDownload.test.js +0 -17
  47. data/webpack/ForemanInventoryUpload/Components/FileDownload/fileDownload.scss +0 -5
  48. data/webpack/ForemanInventoryUpload/Components/FileDownload/index.js +0 -1
  49. data/webpack/ForemanInventoryUpload/Components/NavContainer/NavContainer.fixtures.js +0 -20
  50. data/webpack/ForemanInventoryUpload/Components/NavContainer/NavContainer.js +0 -66
  51. data/webpack/ForemanInventoryUpload/Components/NavContainer/NavContainerHelper.js +0 -0
  52. data/webpack/ForemanInventoryUpload/Components/NavContainer/__tests__/NavContainer.test.js +0 -69
  53. data/webpack/ForemanInventoryUpload/Components/NavContainer/index.js +0 -1
  54. data/webpack/ForemanInventoryUpload/Components/NavContainer/navContainer.scss +0 -9
  55. data/webpack/ForemanInventoryUpload/Components/ScheduledRun/ScheduledRun.fixtures.js +0 -4
  56. data/webpack/ForemanInventoryUpload/Components/ScheduledRun/ScheduledRun.js +0 -29
  57. data/webpack/ForemanInventoryUpload/Components/ScheduledRun/ScheduledRunHelper.js +0 -0
  58. data/webpack/ForemanInventoryUpload/Components/ScheduledRun/__tests__/ScheduledRun.test.js +0 -33
  59. data/webpack/ForemanInventoryUpload/Components/ScheduledRun/index.js +0 -12
  60. data/webpack/ForemanInventoryUpload/Components/ScheduledRun/scheduledRun.scss +0 -13
  61. data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.fixtures.js +0 -0
  62. data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.js +0 -57
  63. data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChartHelper.js +0 -0
  64. data/webpack/ForemanInventoryUpload/Components/StatusChart/__tests__/StatusChart.test.js +0 -30
  65. data/webpack/ForemanInventoryUpload/Components/StatusChart/index.js +0 -1
  66. data/webpack/ForemanInventoryUpload/Components/StatusChart/statusChart.scss +0 -10
  67. data/webpack/ForemanInventoryUpload/Components/TabContainer/TabContainer.fixtures.js +0 -0
  68. data/webpack/ForemanInventoryUpload/Components/TabContainer/TabContainer.js +0 -24
  69. data/webpack/ForemanInventoryUpload/Components/TabContainer/TabContainerHelper.js +0 -0
  70. data/webpack/ForemanInventoryUpload/Components/TabContainer/__tests__/TabContainer.test.js +0 -15
  71. data/webpack/ForemanInventoryUpload/Components/TabContainer/index.js +0 -1
  72. data/webpack/ForemanInventoryUpload/Components/TabContainer/tabContainer.scss +0 -10
  73. data/webpack/ForemanInventoryUpload/Components/TabFooter/TabFooter.fixtures.js +0 -0
  74. data/webpack/ForemanInventoryUpload/Components/TabFooter/TabFooter.js +0 -19
  75. data/webpack/ForemanInventoryUpload/Components/TabFooter/TabFooterHelper.js +0 -0
  76. data/webpack/ForemanInventoryUpload/Components/TabFooter/__tests__/TabFooter.test.js +0 -15
  77. data/webpack/ForemanInventoryUpload/Components/TabFooter/index.js +0 -1
  78. data/webpack/ForemanInventoryUpload/Components/TabFooter/tabFooter.scss +0 -0
  79. data/webpack/ForemanInventoryUpload/Components/TabHeader/TabHeader.fixtures.js +0 -0
  80. data/webpack/ForemanInventoryUpload/Components/TabHeader/TabHeader.js +0 -85
  81. data/webpack/ForemanInventoryUpload/Components/TabHeader/TabHeaderHelper.js +0 -0
  82. data/webpack/ForemanInventoryUpload/Components/TabHeader/__tests__/TabHeader.test.js +0 -114
  83. data/webpack/ForemanInventoryUpload/Components/TabHeader/index.js +0 -1
  84. data/webpack/ForemanInventoryUpload/Components/TabHeader/tabHeader.scss +0 -23
  85. data/webpack/common/Switcher/index.js +0 -80
@@ -1,5 +1,7 @@
1
1
  import React from 'react';
2
- import { render, screen } from '@testing-library/react';
2
+ import Immutable from 'seamless-immutable';
3
+ import { fireEvent, render, screen } from '@testing-library/react';
4
+ import { SortByDirection } from '@patternfly/react-table';
3
5
  import InsightsTable from '../InsightsTable';
4
6
  import { tableProps } from './fixtures';
5
7
 
@@ -17,6 +19,36 @@ const buildProps = (overrides = {}) => ({
17
19
  ...overrides,
18
20
  });
19
21
 
22
+ const selectableHits = Immutable([
23
+ {
24
+ id: 16,
25
+ hostname: 'foo.example.com',
26
+ title: 'Decreased security: Yum GPG verification disabled',
27
+ total_risk: 1,
28
+ has_playbook: true,
29
+ results_url: 'https://cloud.redhat.com/foo',
30
+ solution_url: '',
31
+ },
32
+ {
33
+ id: 17,
34
+ hostname: 'bar.example.com',
35
+ title: 'Installation of packages across major releases is not supported',
36
+ total_risk: 2,
37
+ has_playbook: false,
38
+ results_url: 'https://cloud.redhat.com/bar',
39
+ solution_url: 'https://access.redhat.com/node/54483',
40
+ },
41
+ {
42
+ id: 18,
43
+ hostname: 'baz.example.com',
44
+ title: 'Kernel package is old',
45
+ total_risk: 3,
46
+ has_playbook: true,
47
+ results_url: 'https://cloud.redhat.com/baz',
48
+ solution_url: '',
49
+ },
50
+ ]);
51
+
20
52
  describe('InsightsTable', () => {
21
53
  afterEach(() => {
22
54
  jest.clearAllMocks();
@@ -36,9 +68,7 @@ describe('InsightsTable', () => {
36
68
  const props = buildProps();
37
69
  render(<InsightsTable {...props} />);
38
70
 
39
- expect(
40
- screen.getByRole('grid', { name: /Recommendations Table/ })
41
- ).toBeTruthy();
71
+ expect(screen.getByLabelText(/Recommendations Table/)).toBeTruthy();
42
72
  });
43
73
 
44
74
  it('re-fetches when hostname changes', () => {
@@ -46,9 +76,7 @@ describe('InsightsTable', () => {
46
76
  const { rerender } = render(<InsightsTable {...props} />);
47
77
 
48
78
  props.fetchInsights.mockClear();
49
- rerender(
50
- <InsightsTable {...props} hostname="host2.example.com" />
51
- );
79
+ rerender(<InsightsTable {...props} hostname="host2.example.com" />);
52
80
 
53
81
  expect(props.fetchInsights).toHaveBeenCalledTimes(1);
54
82
  });
@@ -57,6 +85,163 @@ describe('InsightsTable', () => {
57
85
  const props = buildProps({ hits: [], status: 'RESOLVED' });
58
86
  const { container } = render(<InsightsTable {...props} />);
59
87
 
60
- expect(container.querySelector('.rh-cloud-recommendations-table')).toBeTruthy();
88
+ expect(
89
+ container.querySelector('.rh-cloud-recommendations-table')
90
+ ).toBeTruthy();
91
+ });
92
+
93
+ it('selects all enabled rows via header checkbox', () => {
94
+ const props = buildProps({ hits: selectableHits, selectedIds: {} });
95
+ render(<InsightsTable {...props} />);
96
+
97
+ const headerCheckbox = screen.getByLabelText(/Select all rows/i);
98
+ fireEvent.click(headerCheckbox);
99
+
100
+ expect(props.onTableSelect).toHaveBeenCalledTimes(1);
101
+ const [
102
+ isSelected,
103
+ rowId,
104
+ rowsArg,
105
+ selectedIdsArg,
106
+ ] = props.onTableSelect.mock.calls[0];
107
+
108
+ expect(isSelected).toBe(true);
109
+ expect(rowId).toBe(-1);
110
+ expect(selectedIdsArg).toEqual({});
111
+ expect(rowsArg).toHaveLength(selectableHits.length);
112
+ expect(rowsArg.map(row => row.id)).toEqual(
113
+ selectableHits.map(hit => hit.id)
114
+ );
115
+
116
+ const disabledRows = rowsArg.filter(row => row.disableCheckbox);
117
+ expect(disabledRows).toHaveLength(1);
118
+ expect(disabledRows[0].id).toBe(17);
119
+ expect(disabledRows[0].selected).toBe(false);
120
+
121
+ const enabledRows = rowsArg.filter(row => !row.disableCheckbox);
122
+ expect(enabledRows).toHaveLength(2);
123
+ enabledRows.forEach(row => {
124
+ expect(row.selected).toBe(false);
125
+ });
126
+ });
127
+
128
+ it('selects an individual row via row checkbox', () => {
129
+ const props = buildProps({ hits: selectableHits, selectedIds: {} });
130
+ render(<InsightsTable {...props} />);
131
+
132
+ const rowCheckboxes = screen.getAllByRole('checkbox').slice(1);
133
+ const firstSelectableCheckbox = rowCheckboxes.find(
134
+ checkbox => !checkbox.disabled
135
+ );
136
+ expect(firstSelectableCheckbox).toBeTruthy();
137
+ fireEvent.click(firstSelectableCheckbox);
138
+
139
+ expect(props.onTableSelect).toHaveBeenCalledTimes(1);
140
+ expect(props.onTableSelect).toHaveBeenCalledWith(
141
+ true,
142
+ 0,
143
+ expect.any(Array),
144
+ {}
145
+ );
146
+ });
147
+
148
+ it('renders disabled checkbox rows as disabled', () => {
149
+ const props = buildProps({ hits: selectableHits, selectedIds: {} });
150
+ render(<InsightsTable {...props} />);
151
+
152
+ const checkboxes = screen.getAllByRole('checkbox');
153
+ const rowCheckboxes = checkboxes.slice(1);
154
+ const disabledRowCheckboxes = rowCheckboxes.filter(
155
+ checkbox => checkbox.disabled
156
+ );
157
+ const enabledRowCheckboxes = rowCheckboxes.filter(
158
+ checkbox => !checkbox.disabled
159
+ );
160
+
161
+ expect(disabledRowCheckboxes).toHaveLength(1);
162
+ expect(enabledRowCheckboxes).toHaveLength(2);
163
+ });
164
+
165
+ it('reflects partial/all header checkbox state from selected ids', () => {
166
+ const props = buildProps({
167
+ hits: selectableHits,
168
+ selectedIds: { 16: true },
169
+ });
170
+ const { rerender } = render(<InsightsTable {...props} />);
171
+
172
+ let [headerCheckbox] = screen.getAllByRole('checkbox');
173
+ expect(headerCheckbox.checked).toBe(false);
174
+
175
+ rerender(<InsightsTable {...props} selectedIds={{ 16: true, 18: true }} />);
176
+ [headerCheckbox] = screen.getAllByRole('checkbox');
177
+ expect(headerCheckbox.checked).toBe(true);
178
+ });
179
+
180
+ it('passes normalized sort index when selection column is present', () => {
181
+ const props = buildProps({
182
+ hits: selectableHits,
183
+ sortBy: '',
184
+ sortOrder: SortByDirection.asc,
185
+ });
186
+ render(<InsightsTable {...props} />);
187
+
188
+ fireEvent.click(screen.getByRole('button', { name: /Recommendation/i }));
189
+
190
+ expect(props.onTableSort).toHaveBeenCalledTimes(1);
191
+ expect(props.onTableSort).toHaveBeenCalledWith(
192
+ expect.any(Array),
193
+ 1,
194
+ expect.stringMatching(/asc|desc/)
195
+ );
196
+ });
197
+
198
+ it('passes base sort index when selection column is absent', () => {
199
+ const props = buildProps({
200
+ hits: Immutable([
201
+ {
202
+ id: 16,
203
+ hostname: 'foo.example.com',
204
+ title: 'Decreased security: Yum GPG verification disabled',
205
+ total_risk: 1,
206
+ has_playbook: false,
207
+ results_url: 'https://cloud.redhat.com/foo',
208
+ solution_url: '',
209
+ },
210
+ ]),
211
+ sortBy: '',
212
+ sortOrder: SortByDirection.asc,
213
+ });
214
+ render(<InsightsTable {...props} />);
215
+
216
+ fireEvent.click(screen.getByRole('button', { name: /Hostname/i }));
217
+
218
+ expect(props.onTableSort).toHaveBeenCalledTimes(1);
219
+ expect(props.onTableSort).toHaveBeenCalledWith(
220
+ expect.any(Array),
221
+ 0,
222
+ expect.stringMatching(/asc|desc/)
223
+ );
224
+ });
225
+
226
+ it('does not trigger sort for non-sortable Actions column', () => {
227
+ const props = buildProps({ hits: selectableHits });
228
+ render(<InsightsTable {...props} />);
229
+
230
+ const actionsHeader = screen.getByText(/Actions/i).closest('th');
231
+ expect(actionsHeader).toBeTruthy();
232
+ fireEvent.click(actionsHeader);
233
+
234
+ expect(props.onTableSort).not.toHaveBeenCalled();
235
+ });
236
+
237
+ it('does not apply sort aria state for invalid sortOrder', () => {
238
+ const props = buildProps({
239
+ hits: selectableHits,
240
+ sortBy: 'total_risk',
241
+ sortOrder: 'INVALID_DIRECTION',
242
+ });
243
+ const { container } = render(<InsightsTable {...props} />);
244
+
245
+ expect(container.querySelector('[aria-sort]')).toBeNull();
61
246
  });
62
247
  });
@@ -16,7 +16,10 @@ import {
16
16
  } from '../InsightsTableConstants';
17
17
 
18
18
  jest.mock('connected-react-router', () => ({
19
- push: jest.fn(args => ({ type: '@@router/CALL_HISTORY_METHOD', payload: args })),
19
+ push: jest.fn(args => ({
20
+ type: '@@router/CALL_HISTORY_METHOD',
21
+ payload: args,
22
+ })),
20
23
  }));
21
24
 
22
25
  const buildGetState = (queryOverrides = {}) => () => ({
@@ -29,8 +29,7 @@ export const modifyRows = (
29
29
  // For IoP:
30
30
  // All of the values will be plain strings
31
31
  // {
32
- // eslint-disable-next-line spellcheck/spell-checker
33
- // hit_id: "c7c6727e-2966-4f7c-87f1-20ef14db7a2d", <-- this refers to a host by insights ID
32
+ // hit_id: "sample-insights-host-id", <-- this refers to a host by insights ID
34
33
  // rule_id: "hardening_ssh_client_alive|OPENSSH_HARDENING_CLIENT_ALIVE",
35
34
  // resolution_type: "less_secure",
36
35
  // resolution_id:"hardening_ssh_client_alive|OPENSSH_HARDENING_CLIENT_ALIVE_less_secure", <-- joined rule id and resolution type
@@ -48,9 +47,10 @@ export const modifyRows = (
48
47
  resolution_id: getResolutionId(selectedResolution, id, isIop),
49
48
  });
50
49
  return {
51
- cells: [
52
- hostname,
53
- title,
50
+ id,
51
+ hostname,
52
+ recommendation: title,
53
+ resolution: (
54
54
  <div>
55
55
  <Resolutions
56
56
  hit_id={isIop ? host_id : id}
@@ -59,10 +59,9 @@ export const modifyRows = (
59
59
  selectedResolution={selectedResolution}
60
60
  isIop={isIop}
61
61
  />
62
- </div>,
63
- reboot,
64
- ],
65
- id,
62
+ </div>
63
+ ),
64
+ reboot,
66
65
  };
67
66
  });
68
67
 
@@ -2,11 +2,7 @@
2
2
  import React, { useEffect } from 'react';
3
3
  import Immutable from 'seamless-immutable';
4
4
  import PropTypes from 'prop-types';
5
- import {
6
- Table,
7
- TableHeader,
8
- TableBody,
9
- } from '@patternfly/react-table/deprecated';
5
+ import { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
10
6
  import { Modal, ModalVariant, Button } from '@patternfly/react-core';
11
7
  import { isEmpty, noop } from 'lodash';
12
8
  import { STATUS } from 'foremanReact/constants';
@@ -21,8 +17,7 @@ import { useIopConfig } from '../../../common/Hooks/ConfigHooks';
21
17
  // Sample iopData:
22
18
  // const iopTestData = Immutable([
23
19
  // {
24
- // eslint-disable-next-line spellcheck/spell-checker
25
- // hostid: 'c7c6727e-2966-4f7c-87f1-20ef14db7a2d',
20
+ // hostid: 'sample-insights-host-id',
26
21
  // host_name: 'advisor-test.local',
27
22
  // rulename: 'hardening_cryptopol_krb5|NO_CPOL_KRB5',
28
23
  // resolutions: [
@@ -37,8 +32,7 @@ import { useIopConfig } from '../../../common/Hooks/ConfigHooks';
37
32
  // description: 'Decreased security: krb5 crypto-policies overridden',
38
33
  // },
39
34
  // {
40
- // eslint-disable-next-line spellcheck/spell-checker
41
- // hostid: 'c7c6727e-2966-4f7c-87f1-20ef14db7a2d',
35
+ // hostid: 'sample-insights-host-id',
42
36
  // host_name: 'advisor-test.local',
43
37
  // rulename: 'hardening_logging_auditd|HARDENING_LOGGING_5_AUDITD',
44
38
  // resolutions: [
@@ -133,11 +127,30 @@ const RemediationModal = ({
133
127
  className="remediations-table"
134
128
  ouiaId="remediations-table"
135
129
  aria-label="remediations Table"
136
- cells={columns}
137
- rows={rows}
138
130
  >
139
- <TableHeader />
140
- <TableBody />
131
+ <Thead>
132
+ <Tr ouiaId="remediations-table-head-row">
133
+ {columns.map(column => (
134
+ <Th key={column.id} width={column.width}>
135
+ {column.title}
136
+ </Th>
137
+ ))}
138
+ </Tr>
139
+ </Thead>
140
+ <Tbody>
141
+ {rows.map(row => (
142
+ <Tr key={row.id} ouiaId={`remediations-row-${row.id}`}>
143
+ {columns.map(column => {
144
+ const value = row[column.id];
145
+ return (
146
+ <Td key={`${row.id}-${column.id}`}>
147
+ {column.formatter ? column.formatter(value) : value}
148
+ </Td>
149
+ );
150
+ })}
151
+ </Tr>
152
+ ))}
153
+ </Tbody>
141
154
  </Table>
142
155
  <TableEmptyState
143
156
  status={status}
@@ -1,38 +1,40 @@
1
1
  import React from 'react';
2
- import { cellWidth } from '@patternfly/react-table';
3
2
  import { Icon } from '@patternfly/react-core';
4
3
  import { CheckCircleIcon } from '@patternfly/react-icons';
5
4
  import { translate as __ } from 'foremanReact/common/I18n';
6
5
  import { foremanUrl } from '../../../ForemanRhCloudHelpers';
7
6
 
8
- export const rebootFormatter = ({ title: reboot }) => ({
9
- children: reboot ? (
7
+ export const rebootFormatter = reboot =>
8
+ reboot ? (
10
9
  <Icon color="green">
11
10
  <CheckCircleIcon />
12
11
  </Icon>
13
12
  ) : (
14
13
  __('No')
15
- ),
16
- });
14
+ );
17
15
 
18
16
  export const columns = [
19
17
  {
18
+ id: 'hostname',
20
19
  sortKey: 'hostname',
21
20
  title: __('Hostname'),
22
- transforms: [cellWidth(20)],
21
+ width: 20,
23
22
  },
24
23
  {
24
+ id: 'recommendation',
25
25
  title: __('Recommendation'),
26
- transforms: [cellWidth(35)],
26
+ width: 35,
27
27
  },
28
28
  {
29
+ id: 'resolution',
29
30
  title: __('Resolution'),
30
- transforms: [cellWidth(30)],
31
+ width: 30,
31
32
  },
32
33
  {
34
+ id: 'reboot',
33
35
  title: __('Reboot Required'),
34
- transforms: [cellWidth(15)],
35
- cellTransforms: [rebootFormatter],
36
+ width: 15,
37
+ formatter: rebootFormatter,
36
38
  },
37
39
  ];
38
40
 
@@ -4,9 +4,10 @@ import { translate as __ } from 'foremanReact/common/I18n';
4
4
  import {
5
5
  Dropdown,
6
6
  DropdownItem,
7
- KebabToggle,
8
- } from '@patternfly/react-core/deprecated';
9
- import { ExternalLinkAltIcon } from '@patternfly/react-icons';
7
+ DropdownList,
8
+ MenuToggle,
9
+ } from '@patternfly/react-core';
10
+ import { EllipsisVIcon, ExternalLinkAltIcon } from '@patternfly/react-icons';
10
11
  import { redHatAdvisorSystems } from '../InsightsCloudSyncHelpers';
11
12
  import { useIopConfig } from '../../common/Hooks/ConfigHooks';
12
13
 
@@ -44,13 +45,24 @@ const ToolbarDropdown = ({ onRecommendationSync }) => {
44
45
  className="title-dropdown"
45
46
  ouiaId="title-dropdown"
46
47
  onSelect={() => setIsDropdownOpen(false)}
47
- toggle={
48
- <KebabToggle onToggle={(_event, isOpen) => setIsDropdownOpen(isOpen)} />
49
- }
48
+ onOpenChange={setIsDropdownOpen}
49
+ toggle={toggleRef => (
50
+ <MenuToggle
51
+ ref={toggleRef}
52
+ variant="plain"
53
+ aria-label={__('Recommendations actions')}
54
+ onClick={() => setIsDropdownOpen(prev => !prev)}
55
+ isExpanded={isDropdownOpen}
56
+ >
57
+ <EllipsisVIcon />
58
+ </MenuToggle>
59
+ )}
50
60
  isOpen={isDropdownOpen}
51
- isPlain
52
- dropdownItems={dropdownItems}
53
- />
61
+ shouldFocusToggleOnSelect
62
+ popperProps={{ position: 'right' }}
63
+ >
64
+ <DropdownList>{dropdownItems}</DropdownList>
65
+ </Dropdown>
54
66
  );
55
67
  };
56
68
 
@@ -15,16 +15,15 @@ jest.mock('./Components/InsightsTable', () => () => null);
15
15
  jest.mock('./Components/RemediationModal', () => () => null);
16
16
  jest.mock('./Components/InsightsTable/Pagination', () => () => null);
17
17
  jest.mock('./Components/InsightsSettings', () => () => null);
18
- jest.mock('foremanReact/routes/common/PageLayout/PageLayout', () => ({
19
- children,
20
- header,
21
- toolbarButtons,
22
- }) => (
23
- <div data-testid="page-layout" data-header={header}>
24
- {toolbarButtons}
25
- {children}
26
- </div>
27
- ));
18
+ jest.mock(
19
+ 'foremanReact/routes/common/PageLayout/PageLayout',
20
+ () => ({ children, header, toolbarButtons }) => (
21
+ <div data-testid="page-layout" data-header={header}>
22
+ {toolbarButtons}
23
+ {children}
24
+ </div>
25
+ )
26
+ );
28
27
  jest.mock('@scalprum/react-core', () => ({
29
28
  ScalprumComponent: () => <div data-testid="scalprum-component" />,
30
29
  ScalprumProvider: ({ children }) => <div>{children}</div>,
@@ -47,9 +46,7 @@ describe('RecommendationsPage', () => {
47
46
 
48
47
  describe('non-IOP mode', () => {
49
48
  it('renders with rh-cloud-insights class and correct header', () => {
50
- const { container } = render(
51
- <RecommendationsPage {...defaultProps} />
52
- );
49
+ const { container } = render(<RecommendationsPage {...defaultProps} />);
53
50
 
54
51
  expect(container.querySelector('.rh-cloud-insights')).toBeTruthy();
55
52
  expect(
@@ -58,9 +55,7 @@ describe('RecommendationsPage', () => {
58
55
  });
59
56
 
60
57
  it('does not render IOP advisor view', () => {
61
- const { container } = render(
62
- <RecommendationsPage {...defaultProps} />
63
- );
58
+ const { container } = render(<RecommendationsPage {...defaultProps} />);
64
59
 
65
60
  expect(container.querySelector('.advisor')).toBeNull();
66
61
  });
@@ -72,9 +67,7 @@ describe('RecommendationsPage', () => {
72
67
  });
73
68
 
74
69
  it('renders advisor view instead of insights page', () => {
75
- const { container } = render(
76
- <RecommendationsPage {...defaultProps} />
77
- );
70
+ const { container } = render(<RecommendationsPage {...defaultProps} />);
78
71
 
79
72
  expect(container.querySelector('.advisor')).toBeTruthy();
80
73
  expect(container.querySelector('.rh-cloud-insights')).toBeNull();
@@ -1,7 +1,6 @@
1
1
  import { syncInsights } from '../InsightsCloudSyncActions';
2
2
  import { INSIGHTS_CLOUD_SYNC } from '../InsightsCloudSyncConstants';
3
3
 
4
-
5
4
  jest.mock('../../common/ForemanTasks');
6
5
 
7
6
  describe('InsightsCloudSync actions', () => {
@@ -1,6 +1,8 @@
1
1
  import React, { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Dropdown, KebabToggle } from '@patternfly/react-core/deprecated';
3
+ import { Dropdown, DropdownList, MenuToggle } from '@patternfly/react-core';
4
+ import { EllipsisVIcon } from '@patternfly/react-icons';
5
+ import { translate as __ } from 'foremanReact/common/I18n';
4
6
 
5
7
  const DropdownToggle = ({ items, ...props }) => {
6
8
  const [isOpen, setOpen] = useState(false);
@@ -8,13 +10,25 @@ const DropdownToggle = ({ items, ...props }) => {
8
10
  <Dropdown
9
11
  ouiaId="toggle-dropdown"
10
12
  onSelect={() => setOpen(false)}
11
- toggle={<KebabToggle onToggle={(_event, value) => setOpen(value)} />}
13
+ onOpenChange={setOpen}
14
+ toggle={toggleRef => (
15
+ <MenuToggle
16
+ ref={toggleRef}
17
+ variant="plain"
18
+ aria-label={__('Table actions')}
19
+ onClick={() => setOpen(prev => !prev)}
20
+ isExpanded={isOpen}
21
+ >
22
+ <EllipsisVIcon />
23
+ </MenuToggle>
24
+ )}
12
25
  isOpen={isOpen}
13
- isPlain
14
- dropdownItems={items}
15
- position="right"
26
+ shouldFocusToggleOnSelect
27
+ popperProps={{ position: 'right' }}
16
28
  {...props}
17
- />
29
+ >
30
+ <DropdownList>{items}</DropdownList>
31
+ </Dropdown>
18
32
  );
19
33
  };
20
34
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_rh_cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 14.2.0
4
+ version: 14.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Foreman Red Hat Cloud team
@@ -334,12 +334,6 @@ files:
334
334
  - webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/Dashboard.test.js
335
335
  - webpack/ForemanInventoryUpload/Components/Dashboard/dashboard.scss
336
336
  - webpack/ForemanInventoryUpload/Components/Dashboard/index.js
337
- - webpack/ForemanInventoryUpload/Components/FileDownload/FileDownload.fixtures.js
338
- - webpack/ForemanInventoryUpload/Components/FileDownload/FileDownload.js
339
- - webpack/ForemanInventoryUpload/Components/FileDownload/FileDownloadHelper.js
340
- - webpack/ForemanInventoryUpload/Components/FileDownload/__tests__/FileDownload.test.js
341
- - webpack/ForemanInventoryUpload/Components/FileDownload/fileDownload.scss
342
- - webpack/ForemanInventoryUpload/Components/FileDownload/index.js
343
337
  - webpack/ForemanInventoryUpload/Components/InventoryFilter/Components/ClearButton/ClearButton.js
344
338
  - webpack/ForemanInventoryUpload/Components/InventoryFilter/Components/ClearButton/index.js
345
339
  - webpack/ForemanInventoryUpload/Components/InventoryFilter/InventoryFilter.fixtures.js
@@ -362,12 +356,6 @@ files:
362
356
  - webpack/ForemanInventoryUpload/Components/InventorySettings/InventorySettingsSelectors.js
363
357
  - webpack/ForemanInventoryUpload/Components/InventorySettings/MinimalInventoryDropdown.js
364
358
  - webpack/ForemanInventoryUpload/Components/InventorySettings/index.js
365
- - webpack/ForemanInventoryUpload/Components/NavContainer/NavContainer.fixtures.js
366
- - webpack/ForemanInventoryUpload/Components/NavContainer/NavContainer.js
367
- - webpack/ForemanInventoryUpload/Components/NavContainer/NavContainerHelper.js
368
- - webpack/ForemanInventoryUpload/Components/NavContainer/__tests__/NavContainer.test.js
369
- - webpack/ForemanInventoryUpload/Components/NavContainer/index.js
370
- - webpack/ForemanInventoryUpload/Components/NavContainer/navContainer.scss
371
359
  - webpack/ForemanInventoryUpload/Components/PageHeader/PageHeader.js
372
360
  - webpack/ForemanInventoryUpload/Components/PageHeader/PageHeader.scss
373
361
  - webpack/ForemanInventoryUpload/Components/PageHeader/PageTitle.js
@@ -393,36 +381,6 @@ files:
393
381
  - webpack/ForemanInventoryUpload/Components/PageHeader/components/ToolbarButtons/index.js
394
382
  - webpack/ForemanInventoryUpload/Components/PageHeader/components/ToolbarButtons/toolbarButtons.scss
395
383
  - webpack/ForemanInventoryUpload/Components/PageHeader/index.js
396
- - webpack/ForemanInventoryUpload/Components/ScheduledRun/ScheduledRun.fixtures.js
397
- - webpack/ForemanInventoryUpload/Components/ScheduledRun/ScheduledRun.js
398
- - webpack/ForemanInventoryUpload/Components/ScheduledRun/ScheduledRunHelper.js
399
- - webpack/ForemanInventoryUpload/Components/ScheduledRun/__tests__/ScheduledRun.test.js
400
- - webpack/ForemanInventoryUpload/Components/ScheduledRun/index.js
401
- - webpack/ForemanInventoryUpload/Components/ScheduledRun/scheduledRun.scss
402
- - webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.fixtures.js
403
- - webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.js
404
- - webpack/ForemanInventoryUpload/Components/StatusChart/StatusChartHelper.js
405
- - webpack/ForemanInventoryUpload/Components/StatusChart/__tests__/StatusChart.test.js
406
- - webpack/ForemanInventoryUpload/Components/StatusChart/index.js
407
- - webpack/ForemanInventoryUpload/Components/StatusChart/statusChart.scss
408
- - webpack/ForemanInventoryUpload/Components/TabContainer/TabContainer.fixtures.js
409
- - webpack/ForemanInventoryUpload/Components/TabContainer/TabContainer.js
410
- - webpack/ForemanInventoryUpload/Components/TabContainer/TabContainerHelper.js
411
- - webpack/ForemanInventoryUpload/Components/TabContainer/__tests__/TabContainer.test.js
412
- - webpack/ForemanInventoryUpload/Components/TabContainer/index.js
413
- - webpack/ForemanInventoryUpload/Components/TabContainer/tabContainer.scss
414
- - webpack/ForemanInventoryUpload/Components/TabFooter/TabFooter.fixtures.js
415
- - webpack/ForemanInventoryUpload/Components/TabFooter/TabFooter.js
416
- - webpack/ForemanInventoryUpload/Components/TabFooter/TabFooterHelper.js
417
- - webpack/ForemanInventoryUpload/Components/TabFooter/__tests__/TabFooter.test.js
418
- - webpack/ForemanInventoryUpload/Components/TabFooter/index.js
419
- - webpack/ForemanInventoryUpload/Components/TabFooter/tabFooter.scss
420
- - webpack/ForemanInventoryUpload/Components/TabHeader/TabHeader.fixtures.js
421
- - webpack/ForemanInventoryUpload/Components/TabHeader/TabHeader.js
422
- - webpack/ForemanInventoryUpload/Components/TabHeader/TabHeaderHelper.js
423
- - webpack/ForemanInventoryUpload/Components/TabHeader/__tests__/TabHeader.test.js
424
- - webpack/ForemanInventoryUpload/Components/TabHeader/index.js
425
- - webpack/ForemanInventoryUpload/Components/TabHeader/tabHeader.scss
426
384
  - webpack/ForemanInventoryUpload/Components/TaskHistory/TaskHistory.js
427
385
  - webpack/ForemanInventoryUpload/Components/TaskHistory/index.js
428
386
  - webpack/ForemanInventoryUpload/Components/TaskHistory/taskHistory.scss
@@ -548,7 +506,6 @@ files:
548
506
  - webpack/common/Switcher/SwitcherPF4.scss
549
507
  - webpack/common/Switcher/__tests__/HelpLabel.test.js
550
508
  - webpack/common/Switcher/__tests__/SwitcherPF4.test.js
551
- - webpack/common/Switcher/index.js
552
509
  - webpack/common/styles.scss
553
510
  - webpack/common/table/EmptyState.js
554
511
  - webpack/common/table/helpers.js
@@ -1,25 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import { Grid, Button, Icon } from 'patternfly-react';
4
- import { noop } from 'foremanReact/common/helpers';
5
- import { translate as __ } from 'foremanReact/common/I18n';
6
-
7
- import './fileDownload.scss';
8
-
9
- const FileDownload = ({ onClick }) => (
10
- <Grid.Col sm={12}>
11
- <Button onClick={onClick} className="download-button">
12
- {__('Download Report')} <Icon name="download" />
13
- </Button>
14
- </Grid.Col>
15
- );
16
-
17
- FileDownload.propTypes = {
18
- onClick: PropTypes.func,
19
- };
20
-
21
- FileDownload.defaultProps = {
22
- onClick: noop,
23
- };
24
-
25
- export default FileDownload;