foreman_leapp 3.2.1 → 3.3.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.
- checksums.yaml +4 -4
- data/lib/foreman_leapp/version.rb +1 -1
- data/webpack/components/PreupgradeReportsTable/PreupgradeReportsTable.scss +5 -0
- data/webpack/components/PreupgradeReportsTable/ReportDetails.js +134 -0
- data/webpack/components/PreupgradeReportsTable/__tests__/PreupgradeReportsTable.test.js +87 -18
- data/webpack/components/PreupgradeReportsTable/index.js +81 -24
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8841245ebb39f45ba92ea5b955a3398434dc103a860c50f2930019c0ee102a4e
|
|
4
|
+
data.tar.gz: 9a13e0df52eb412eecff7dfa1adff514670ada9dec259a9e349eef1b5ec9e092
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 37b092dbdd94f413763b9301c29c552a55cc44a0a0881462fe228d0f1b3510f750145b20eb55b459bc6acf09212b40381657749eaf0590a49024dbd79c9b097a
|
|
7
|
+
data.tar.gz: f93aca5a49a5c5f76fc36759310c0372f7e56b418ee2bad597461700ba9055544c9bdcb0b5ffab9561eddf7121dc0ad80af0061ee5557944f2d71b2af2927be2
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import {
|
|
4
|
+
DescriptionList,
|
|
5
|
+
DescriptionListGroup,
|
|
6
|
+
DescriptionListTerm,
|
|
7
|
+
DescriptionListDescription,
|
|
8
|
+
Label,
|
|
9
|
+
LabelGroup,
|
|
10
|
+
} from '@patternfly/react-core';
|
|
11
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
|
12
|
+
import './PreupgradeReportsTable.scss';
|
|
13
|
+
|
|
14
|
+
export const renderSeverityLabel = severity => {
|
|
15
|
+
switch (severity) {
|
|
16
|
+
case 'high':
|
|
17
|
+
return <Label color="red">{__('High')}</Label>;
|
|
18
|
+
case 'medium':
|
|
19
|
+
return <Label color="orange">{__('Medium')}</Label>;
|
|
20
|
+
case 'low':
|
|
21
|
+
return <Label color="blue">{__('Low')}</Label>;
|
|
22
|
+
case 'info':
|
|
23
|
+
return <Label color="grey">{__('Info')}</Label>;
|
|
24
|
+
default:
|
|
25
|
+
return <Label color="grey">{severity || __('Info')}</Label>;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const ReportDetails = ({ entry }) => (
|
|
30
|
+
<DescriptionList isHorizontal isCompact className="leapp-report-details">
|
|
31
|
+
{entry.title && (
|
|
32
|
+
<DescriptionListGroup>
|
|
33
|
+
<DescriptionListTerm>{__('Title')}</DescriptionListTerm>
|
|
34
|
+
<DescriptionListDescription>{entry.title}</DescriptionListDescription>
|
|
35
|
+
</DescriptionListGroup>
|
|
36
|
+
)}
|
|
37
|
+
|
|
38
|
+
{entry.severity && (
|
|
39
|
+
<DescriptionListGroup>
|
|
40
|
+
<DescriptionListTerm>{__('Risk Factor')}</DescriptionListTerm>
|
|
41
|
+
<DescriptionListDescription>
|
|
42
|
+
{renderSeverityLabel(entry.severity)}
|
|
43
|
+
</DescriptionListDescription>
|
|
44
|
+
</DescriptionListGroup>
|
|
45
|
+
)}
|
|
46
|
+
|
|
47
|
+
{entry.summary && (
|
|
48
|
+
<DescriptionListGroup>
|
|
49
|
+
<DescriptionListTerm>{__('Summary')}</DescriptionListTerm>
|
|
50
|
+
<DescriptionListDescription>{entry.summary}</DescriptionListDescription>
|
|
51
|
+
</DescriptionListGroup>
|
|
52
|
+
)}
|
|
53
|
+
|
|
54
|
+
{entry.tags && entry.tags.length > 0 && (
|
|
55
|
+
<DescriptionListGroup>
|
|
56
|
+
<DescriptionListTerm>{__('Tags')}</DescriptionListTerm>
|
|
57
|
+
<DescriptionListDescription>
|
|
58
|
+
<LabelGroup>
|
|
59
|
+
{entry.tags.map(tag => (
|
|
60
|
+
<Label key={tag} color="blue">
|
|
61
|
+
{tag}
|
|
62
|
+
</Label>
|
|
63
|
+
))}
|
|
64
|
+
</LabelGroup>
|
|
65
|
+
</DescriptionListDescription>
|
|
66
|
+
</DescriptionListGroup>
|
|
67
|
+
)}
|
|
68
|
+
|
|
69
|
+
{entry.detail?.external?.filter(link => link.url).length > 0 && (
|
|
70
|
+
<DescriptionListGroup>
|
|
71
|
+
<DescriptionListTerm>{__('Links')}</DescriptionListTerm>
|
|
72
|
+
<DescriptionListDescription>
|
|
73
|
+
{entry.detail.external
|
|
74
|
+
.filter(link => link.url)
|
|
75
|
+
.map((item, i) => (
|
|
76
|
+
<div key={item.url || i}>
|
|
77
|
+
<a href={item.url} target="_blank" rel="noopener noreferrer">
|
|
78
|
+
{item.title || item.url}
|
|
79
|
+
</a>
|
|
80
|
+
</div>
|
|
81
|
+
))}
|
|
82
|
+
</DescriptionListDescription>
|
|
83
|
+
</DescriptionListGroup>
|
|
84
|
+
)}
|
|
85
|
+
|
|
86
|
+
{entry.detail?.remediations?.length > 0 &&
|
|
87
|
+
entry.detail.remediations.map((item, i) => (
|
|
88
|
+
<DescriptionListGroup key={`remediations-${i}`}>
|
|
89
|
+
<DescriptionListTerm>
|
|
90
|
+
{item.type === 'command' ? __('Command') : __('Hint')}
|
|
91
|
+
</DescriptionListTerm>
|
|
92
|
+
<DescriptionListDescription>
|
|
93
|
+
{item.type === 'command' ? (
|
|
94
|
+
<code>
|
|
95
|
+
{Array.isArray(item.context)
|
|
96
|
+
? item.context.join(' ')
|
|
97
|
+
: item.context}
|
|
98
|
+
</code>
|
|
99
|
+
) : (
|
|
100
|
+
item.context
|
|
101
|
+
)}
|
|
102
|
+
</DescriptionListDescription>
|
|
103
|
+
</DescriptionListGroup>
|
|
104
|
+
))}
|
|
105
|
+
</DescriptionList>
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
ReportDetails.propTypes = {
|
|
109
|
+
entry: PropTypes.shape({
|
|
110
|
+
title: PropTypes.string,
|
|
111
|
+
severity: PropTypes.string,
|
|
112
|
+
summary: PropTypes.string,
|
|
113
|
+
tags: PropTypes.arrayOf(PropTypes.string),
|
|
114
|
+
detail: PropTypes.shape({
|
|
115
|
+
external: PropTypes.arrayOf(
|
|
116
|
+
PropTypes.shape({
|
|
117
|
+
url: PropTypes.string,
|
|
118
|
+
title: PropTypes.string,
|
|
119
|
+
})
|
|
120
|
+
),
|
|
121
|
+
remediations: PropTypes.arrayOf(
|
|
122
|
+
PropTypes.shape({
|
|
123
|
+
type: PropTypes.string,
|
|
124
|
+
context: PropTypes.oneOfType([
|
|
125
|
+
PropTypes.string,
|
|
126
|
+
PropTypes.arrayOf(PropTypes.string),
|
|
127
|
+
]),
|
|
128
|
+
})
|
|
129
|
+
),
|
|
130
|
+
}),
|
|
131
|
+
}).isRequired,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export default ReportDetails;
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
render,
|
|
4
|
+
screen,
|
|
5
|
+
waitFor,
|
|
6
|
+
fireEvent,
|
|
7
|
+
within,
|
|
8
|
+
} from '@testing-library/react';
|
|
3
9
|
import '@testing-library/jest-dom/extend-expect';
|
|
4
10
|
import { Provider } from 'react-redux';
|
|
5
11
|
import configureMockStore from 'redux-mock-store';
|
|
@@ -23,8 +29,15 @@ const mockEntries = Array.from({ length: 12 }, (_, i) => ({
|
|
|
23
29
|
title: `Report Entry ${i + 1}`,
|
|
24
30
|
hostname: 'example.com',
|
|
25
31
|
severity: i === 0 ? 'high' : 'low',
|
|
32
|
+
summary: `Summary for report entry ${i + 1}`,
|
|
33
|
+
tags: i === 0 ? ['security', 'network'] : [],
|
|
26
34
|
flags: i === 0 ? ['inhibitor'] : [],
|
|
27
|
-
detail: {
|
|
35
|
+
detail: {
|
|
36
|
+
remediations:
|
|
37
|
+
i === 0 ? [{ type: 'command', context: ['echo', 'fix_command'] }] : [],
|
|
38
|
+
external:
|
|
39
|
+
i === 0 ? [{ url: 'http://example.com', title: 'External Link' }] : [],
|
|
40
|
+
},
|
|
28
41
|
}));
|
|
29
42
|
|
|
30
43
|
describe('PreupgradeReportsTable', () => {
|
|
@@ -48,10 +61,10 @@ describe('PreupgradeReportsTable', () => {
|
|
|
48
61
|
});
|
|
49
62
|
});
|
|
50
63
|
|
|
51
|
-
const renderComponent = () =>
|
|
64
|
+
const renderComponent = (data = mockJobData) =>
|
|
52
65
|
render(
|
|
53
66
|
<Provider store={store}>
|
|
54
|
-
<PreupgradeReportsTable data={
|
|
67
|
+
<PreupgradeReportsTable data={data} />
|
|
55
68
|
</Provider>
|
|
56
69
|
);
|
|
57
70
|
|
|
@@ -62,37 +75,67 @@ describe('PreupgradeReportsTable', () => {
|
|
|
62
75
|
it('renders data', async () => {
|
|
63
76
|
renderComponent();
|
|
64
77
|
expandSection();
|
|
78
|
+
await waitFor(() => screen.getByText('Report Entry 1', { selector: 'td' }));
|
|
79
|
+
expect(
|
|
80
|
+
screen.getByText('Report Entry 1', { selector: 'td' })
|
|
81
|
+
).toBeInTheDocument();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('expands a row and shows details', async () => {
|
|
85
|
+
renderComponent();
|
|
86
|
+
expandSection();
|
|
87
|
+
await waitFor(() => screen.getByText('Report Entry 1', { selector: 'td' }));
|
|
88
|
+
|
|
89
|
+
const rowExpandButtons = screen.getAllByLabelText('Details');
|
|
90
|
+
fireEvent.click(rowExpandButtons[0]);
|
|
91
|
+
|
|
92
|
+
expect(await screen.findByText('Summary')).toBeInTheDocument();
|
|
93
|
+
expect(
|
|
94
|
+
await screen.findByText('Summary for report entry 1')
|
|
95
|
+
).toBeInTheDocument();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('expands all rows', async () => {
|
|
99
|
+
renderComponent();
|
|
100
|
+
expandSection();
|
|
101
|
+
await waitFor(() => screen.getByText('Report Entry 1', { selector: 'td' }));
|
|
65
102
|
|
|
66
|
-
|
|
103
|
+
const expandAllButton = screen.getByLabelText('Expand all rows');
|
|
104
|
+
fireEvent.click(expandAllButton);
|
|
67
105
|
|
|
68
|
-
expect(
|
|
69
|
-
|
|
70
|
-
|
|
106
|
+
expect(
|
|
107
|
+
await screen.findByText('Summary for report entry 1')
|
|
108
|
+
).toBeInTheDocument();
|
|
109
|
+
expect(
|
|
110
|
+
await screen.findByText('Summary for report entry 5')
|
|
111
|
+
).toBeInTheDocument();
|
|
71
112
|
});
|
|
72
113
|
|
|
73
114
|
it('paginates to the next page', async () => {
|
|
74
115
|
renderComponent();
|
|
75
116
|
expandSection();
|
|
76
|
-
await waitFor(() => screen.getByText('Report Entry 1'));
|
|
117
|
+
await waitFor(() => screen.getByText('Report Entry 1', { selector: 'td' }));
|
|
77
118
|
|
|
78
119
|
fireEvent.click(screen.getAllByLabelText('Go to next page')[0]);
|
|
120
|
+
await waitFor(() => screen.getByText('Report Entry 6', { selector: 'td' }));
|
|
79
121
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
122
|
+
expect(
|
|
123
|
+
screen.getByText('Report Entry 10', { selector: 'td' })
|
|
124
|
+
).toBeInTheDocument();
|
|
83
125
|
});
|
|
84
126
|
|
|
85
127
|
it('changes perPage limit to 10', async () => {
|
|
86
128
|
renderComponent();
|
|
87
129
|
expandSection();
|
|
88
|
-
await waitFor(() => screen.getByText('Report Entry 1'));
|
|
130
|
+
await waitFor(() => screen.getByText('Report Entry 1', { selector: 'td' }));
|
|
89
131
|
|
|
90
132
|
fireEvent.click(screen.getAllByLabelText('Items per page')[0]);
|
|
91
133
|
fireEvent.click(screen.getAllByText('10 per page')[0]);
|
|
92
134
|
|
|
93
135
|
await waitFor(() => {
|
|
94
|
-
expect(
|
|
95
|
-
|
|
136
|
+
expect(
|
|
137
|
+
screen.getByText('Report Entry 10', { selector: 'td' })
|
|
138
|
+
).toBeInTheDocument();
|
|
96
139
|
});
|
|
97
140
|
});
|
|
98
141
|
|
|
@@ -106,12 +149,38 @@ describe('PreupgradeReportsTable', () => {
|
|
|
106
149
|
return { type: 'EMPTY' };
|
|
107
150
|
};
|
|
108
151
|
});
|
|
109
|
-
|
|
110
152
|
renderComponent();
|
|
111
153
|
expandSection();
|
|
112
|
-
|
|
113
154
|
await waitFor(() => {
|
|
114
|
-
expect(
|
|
155
|
+
expect(
|
|
156
|
+
screen.getByText('The preupgrade report shows no issues.')
|
|
157
|
+
).toBeInTheDocument();
|
|
115
158
|
});
|
|
116
159
|
});
|
|
160
|
+
|
|
161
|
+
it('does not render anything for non-Leapp jobs', () => {
|
|
162
|
+
const nonLeappData = { id: 55, template_name: 'Standard RHEL Update' };
|
|
163
|
+
renderComponent(nonLeappData);
|
|
164
|
+
expect(
|
|
165
|
+
screen.queryByText('Leapp preupgrade report')
|
|
166
|
+
).not.toBeInTheDocument();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('displays correct inhibitor status based on flags', async () => {
|
|
170
|
+
renderComponent();
|
|
171
|
+
expandSection();
|
|
172
|
+
await waitFor(() => screen.getByText('Report Entry 1', { selector: 'td' }));
|
|
173
|
+
|
|
174
|
+
const row1 = screen
|
|
175
|
+
.getByText('Report Entry 1', { selector: 'td' })
|
|
176
|
+
.closest('tr');
|
|
177
|
+
const inhibitorCell1 = row1.querySelector('td[data-label="Inhibitor?"]');
|
|
178
|
+
expect(within(inhibitorCell1).getByText('Yes')).toBeInTheDocument();
|
|
179
|
+
|
|
180
|
+
const row2 = screen
|
|
181
|
+
.getByText('Report Entry 2', { selector: 'td' })
|
|
182
|
+
.closest('tr');
|
|
183
|
+
const inhibitorCell2 = row2.querySelector('td[data-label="Inhibitor?"]');
|
|
184
|
+
expect(within(inhibitorCell2).getByText('No')).toBeInTheDocument();
|
|
185
|
+
});
|
|
117
186
|
});
|
|
@@ -1,35 +1,25 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
2
|
import React, { useEffect, useState } from 'react';
|
|
3
3
|
import { useDispatch } from 'react-redux';
|
|
4
|
-
import { ExpandableSection,
|
|
4
|
+
import { ExpandableSection, Tooltip } from '@patternfly/react-core';
|
|
5
|
+
import { ExpandableRowContent, Tbody, Td, Tr } from '@patternfly/react-table';
|
|
5
6
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
6
7
|
import { Table } from 'foremanReact/components/PF4/TableIndexPage/Table/Table';
|
|
8
|
+
import { getColumnHelpers } from 'foremanReact/components/PF4/TableIndexPage/Table/helpers';
|
|
7
9
|
import { APIActions } from 'foremanReact/redux/API';
|
|
8
10
|
import { STATUS } from 'foremanReact/constants';
|
|
9
|
-
|
|
10
11
|
import { entriesPage } from '../PreupgradeReports/PreupgradeReportsHelpers';
|
|
11
|
-
|
|
12
|
-
const renderSeverityLabel = severity => {
|
|
13
|
-
switch (severity) {
|
|
14
|
-
case 'high':
|
|
15
|
-
return <Label color="red">{__('High')}</Label>;
|
|
16
|
-
case 'medium':
|
|
17
|
-
return <Label color="orange">{__('Medium')}</Label>;
|
|
18
|
-
case 'low':
|
|
19
|
-
return <Label color="blue">{__('Low')}</Label>;
|
|
20
|
-
case 'info':
|
|
21
|
-
return <Label color="grey">{__('Info')}</Label>;
|
|
22
|
-
default:
|
|
23
|
-
return <Label color="grey">{severity || __('Info')}</Label>;
|
|
24
|
-
}
|
|
25
|
-
};
|
|
12
|
+
import ReportDetails, { renderSeverityLabel } from './ReportDetails';
|
|
26
13
|
|
|
27
14
|
const PreupgradeReportsTable = ({ data = {} }) => {
|
|
28
15
|
const [error, setError] = useState(null);
|
|
29
|
-
|
|
16
|
+
|
|
17
|
+
const [isReportExpanded, setIsReportExpanded] = useState(false); // Outer expansion state (Leapp Report Section)
|
|
30
18
|
const [pagination, setPagination] = useState({ page: 1, perPage: 5 });
|
|
31
19
|
const [reportData, setReportData] = useState(null);
|
|
32
20
|
const [status, setStatus] = useState(STATUS.RESOLVED);
|
|
21
|
+
const [expandedRowIds, setExpandedRowIds] = useState(new Set()); // Inner table expansion state (Rows)
|
|
22
|
+
|
|
33
23
|
const dispatch = useDispatch();
|
|
34
24
|
// eslint-disable-next-line camelcase
|
|
35
25
|
const isLeappJob = data?.template_name?.includes('Run preupgrade via Leapp');
|
|
@@ -67,7 +57,7 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
67
57
|
|
|
68
58
|
useEffect(() => {
|
|
69
59
|
let isMounted = true;
|
|
70
|
-
if (!isLeappJob || !
|
|
60
|
+
if (!isLeappJob || !isReportExpanded || reportData) {
|
|
71
61
|
return undefined;
|
|
72
62
|
}
|
|
73
63
|
setStatus(STATUS.PENDING);
|
|
@@ -117,7 +107,7 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
117
107
|
return () => {
|
|
118
108
|
isMounted = false;
|
|
119
109
|
};
|
|
120
|
-
}, [
|
|
110
|
+
}, [isReportExpanded, data.id, isLeappJob, reportData, dispatch]);
|
|
121
111
|
|
|
122
112
|
// eslint-disable-next-line camelcase
|
|
123
113
|
const entries = reportData?.preupgrade_report_entries || [];
|
|
@@ -129,15 +119,43 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
129
119
|
page: newParams.page || prev.page,
|
|
130
120
|
perPage: newParams.per_page || prev.perPage,
|
|
131
121
|
}));
|
|
122
|
+
setExpandedRowIds(new Set());
|
|
132
123
|
};
|
|
133
124
|
|
|
125
|
+
const toggleRowExpansion = (id, isExpanding) => {
|
|
126
|
+
setExpandedRowIds(prev => {
|
|
127
|
+
const newSet = new Set(prev);
|
|
128
|
+
if (isExpanding) {
|
|
129
|
+
newSet.add(id);
|
|
130
|
+
} else {
|
|
131
|
+
newSet.delete(id);
|
|
132
|
+
}
|
|
133
|
+
return newSet;
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const areAllRowsExpanded =
|
|
138
|
+
pagedEntries.length > 0 &&
|
|
139
|
+
pagedEntries.every(entry => expandedRowIds.has(entry.id));
|
|
140
|
+
|
|
141
|
+
const onExpandAll = () => {
|
|
142
|
+
setExpandedRowIds(() => {
|
|
143
|
+
if (areAllRowsExpanded) {
|
|
144
|
+
return new Set();
|
|
145
|
+
}
|
|
146
|
+
return new Set(pagedEntries.map(e => e.id));
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const [columnKeys, keysToColumnNames] = getColumnHelpers(columns);
|
|
151
|
+
|
|
134
152
|
if (!isLeappJob) return null;
|
|
135
153
|
|
|
136
154
|
return (
|
|
137
155
|
<ExpandableSection
|
|
138
156
|
className="leapp-report-section"
|
|
139
|
-
isExpanded={
|
|
140
|
-
onToggle={(_event, val) =>
|
|
157
|
+
isExpanded={isReportExpanded}
|
|
158
|
+
onToggle={(_event, val) => setIsReportExpanded(val)}
|
|
141
159
|
toggleText={__('Leapp preupgrade report')}
|
|
142
160
|
>
|
|
143
161
|
<Table
|
|
@@ -161,14 +179,53 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
161
179
|
isDeleteable={false}
|
|
162
180
|
emptyMessage={__('The preupgrade report shows no issues.')}
|
|
163
181
|
setParams={handleParamsChange}
|
|
164
|
-
|
|
182
|
+
childrenOutsideTbody
|
|
183
|
+
onExpandAll={onExpandAll}
|
|
184
|
+
// Inverted per PatternFly implementation to ensure correct toggle icon state
|
|
185
|
+
areAllRowsExpanded={!areAllRowsExpanded}
|
|
186
|
+
>
|
|
187
|
+
{pagedEntries.map((entry, rowIndex) => {
|
|
188
|
+
const isRowExpanded = expandedRowIds.has(entry.id);
|
|
189
|
+
return (
|
|
190
|
+
<Tbody key={entry.id} isExpanded={isRowExpanded}>
|
|
191
|
+
<Tr ouiaId={`table-row-${rowIndex}`}>
|
|
192
|
+
<Td
|
|
193
|
+
expand={{
|
|
194
|
+
rowIndex,
|
|
195
|
+
isExpanded: isRowExpanded,
|
|
196
|
+
onToggle: (_event, _rowIndex, isOpen) =>
|
|
197
|
+
toggleRowExpansion(entry.id, isOpen),
|
|
198
|
+
}}
|
|
199
|
+
/>
|
|
200
|
+
{columnKeys.map(key => (
|
|
201
|
+
<Td key={key} dataLabel={keysToColumnNames[key]}>
|
|
202
|
+
{columns[key].wrapper
|
|
203
|
+
? columns[key].wrapper(entry)
|
|
204
|
+
: entry[key]}
|
|
205
|
+
</Td>
|
|
206
|
+
))}
|
|
207
|
+
</Tr>
|
|
208
|
+
<Tr
|
|
209
|
+
isExpanded={isRowExpanded}
|
|
210
|
+
ouiaId={`table-row-details-${rowIndex}`}
|
|
211
|
+
>
|
|
212
|
+
<Td colSpan={columnKeys.length + 1}>
|
|
213
|
+
<ExpandableRowContent>
|
|
214
|
+
{isRowExpanded && <ReportDetails entry={entry} />}
|
|
215
|
+
</ExpandableRowContent>
|
|
216
|
+
</Td>
|
|
217
|
+
</Tr>
|
|
218
|
+
</Tbody>
|
|
219
|
+
);
|
|
220
|
+
})}
|
|
221
|
+
</Table>
|
|
165
222
|
</ExpandableSection>
|
|
166
223
|
);
|
|
167
224
|
};
|
|
168
225
|
|
|
169
226
|
PreupgradeReportsTable.propTypes = {
|
|
170
227
|
data: PropTypes.shape({
|
|
171
|
-
id: PropTypes.
|
|
228
|
+
id: PropTypes.number,
|
|
172
229
|
template_name: PropTypes.string,
|
|
173
230
|
}),
|
|
174
231
|
};
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foreman_leapp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Foreman Leapp team
|
|
@@ -186,6 +186,8 @@ files:
|
|
|
186
186
|
- webpack/components/PreupgradeReportsList/components/images/i_severity-low.svg
|
|
187
187
|
- webpack/components/PreupgradeReportsList/components/images/i_severity-med.svg
|
|
188
188
|
- webpack/components/PreupgradeReportsList/index.js
|
|
189
|
+
- webpack/components/PreupgradeReportsTable/PreupgradeReportsTable.scss
|
|
190
|
+
- webpack/components/PreupgradeReportsTable/ReportDetails.js
|
|
189
191
|
- webpack/components/PreupgradeReportsTable/__tests__/PreupgradeReportsTable.test.js
|
|
190
192
|
- webpack/components/PreupgradeReportsTable/index.js
|
|
191
193
|
- webpack/consts.js
|