foreman_leapp 4.1.2 → 4.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/app/assets/javascripts/foreman_leapp/locale/de/foreman_leapp.js +37 -4
- data/app/assets/javascripts/foreman_leapp/locale/en/foreman_leapp.js +36 -3
- data/app/assets/javascripts/foreman_leapp/locale/fr/foreman_leapp.js +37 -4
- data/app/assets/javascripts/foreman_leapp/locale/ja/foreman_leapp.js +37 -4
- data/app/assets/javascripts/foreman_leapp/locale/ka/foreman_leapp.js +40 -7
- data/app/assets/javascripts/foreman_leapp/locale/ko/foreman_leapp.js +37 -4
- data/app/assets/javascripts/foreman_leapp/locale/zh_CN/foreman_leapp.js +37 -4
- data/app/controllers/api/v2/preupgrade_report_entries_controller.rb +17 -29
- data/app/controllers/concerns/foreman_leapp/preupgrade_report_entry_bulk_remediate.rb +69 -0
- data/app/lib/actions/foreman_leapp/preupgrade_job.rb +1 -2
- data/app/lib/helpers/job_helper.rb +8 -0
- data/app/views/api/v2/job_invocations/leapp_preupgrade_report.json.rabl +3 -0
- data/config/routes.rb +1 -2
- data/lib/foreman_leapp/engine.rb +3 -12
- data/lib/foreman_leapp/version.rb +1 -1
- data/locale/de/LC_MESSAGES/foreman_leapp.mo +0 -0
- data/locale/de/foreman_leapp.po +38 -5
- data/locale/en/LC_MESSAGES/foreman_leapp.mo +0 -0
- data/locale/en/foreman_leapp.po +36 -3
- data/locale/foreman_leapp.pot +66 -18
- data/locale/fr/LC_MESSAGES/foreman_leapp.mo +0 -0
- data/locale/fr/foreman_leapp.po +38 -5
- data/locale/ja/LC_MESSAGES/foreman_leapp.mo +0 -0
- data/locale/ja/foreman_leapp.po +38 -5
- data/locale/ka/LC_MESSAGES/foreman_leapp.mo +0 -0
- data/locale/ka/foreman_leapp.po +41 -8
- data/locale/ko/LC_MESSAGES/foreman_leapp.mo +0 -0
- data/locale/ko/foreman_leapp.po +38 -5
- data/locale/zh_CN/LC_MESSAGES/foreman_leapp.mo +0 -0
- data/locale/zh_CN/foreman_leapp.po +38 -5
- data/package.json +0 -1
- data/test/functional/api/v2/job_invocations_controller_test.rb +39 -0
- data/test/functional/api/v2/preupgrade_report_entries_controller_test.rb +64 -0
- data/test/unit/helpers/job_helper_test.rb +20 -0
- data/webpack/components/PreupgradeReportsTable/PreupgradeReportsTableHelpers.js +44 -17
- data/webpack/components/PreupgradeReportsTable/__tests__/PreupgradeReportsTable.test.js +131 -10
- data/webpack/components/PreupgradeReportsTable/index.js +67 -74
- data/webpack/index.js +0 -13
- metadata +7 -67
- data/app/controllers/preupgrade_reports_controller.rb +0 -17
- data/app/views/job_invocations/_leapp_preupgrade_report.html.erb +0 -11
- data/app/views/preupgrade_report_entries/base.json.rabl +0 -4
- data/app/views/preupgrade_reports/index.json.rabl +0 -3
- data/app/views/preupgrade_reports/show.json.rabl +0 -7
- data/test/functional/preupgrade_reports_controller_test.rb +0 -39
- data/webpack/components/PreupgradeReports/PreupgradeReports.js +0 -154
- data/webpack/components/PreupgradeReports/PreupgradeReportsActions.js +0 -31
- data/webpack/components/PreupgradeReports/PreupgradeReportsHelpers.js +0 -152
- data/webpack/components/PreupgradeReports/PreupgradeReportsReducer.js +0 -37
- data/webpack/components/PreupgradeReports/PreupgradeReportsSelectors.js +0 -18
- data/webpack/components/PreupgradeReports/__tests__/PreupgradeReports.fixtures.js +0 -129
- data/webpack/components/PreupgradeReports/__tests__/PreupgradeReports.test.js +0 -159
- data/webpack/components/PreupgradeReports/__tests__/PreupgradeReportsHelpers.test.js +0 -78
- data/webpack/components/PreupgradeReports/__tests__/PreupgradeReportsReducer.test.js +0 -44
- data/webpack/components/PreupgradeReports/__tests__/PreupgradeReportsSelectors.test.js +0 -28
- data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReportsHelpers.test.js.snap +0 -489
- data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReportsReducer.test.js.snap +0 -102
- data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReportsSelectors.test.js.snap +0 -76
- data/webpack/components/PreupgradeReports/components/EntriesFilter.js +0 -121
- data/webpack/components/PreupgradeReports/components/EntriesFilter.scss +0 -3
- data/webpack/components/PreupgradeReports/components/EntriesFilter.test.js +0 -30
- data/webpack/components/PreupgradeReports/components/FixSelectedButton.js +0 -35
- data/webpack/components/PreupgradeReports/components/FixSelectedButton.test.js +0 -15
- data/webpack/components/PreupgradeReports/components/NoReports.js +0 -35
- data/webpack/components/PreupgradeReports/components/NoReports.test.js +0 -29
- data/webpack/components/PreupgradeReports/components/UpgradeAllButton.js +0 -28
- data/webpack/components/PreupgradeReports/components/UpgradeAllButton.test.js +0 -17
- data/webpack/components/PreupgradeReports/components/__snapshots__/EntriesFilter.test.js.snap +0 -330
- data/webpack/components/PreupgradeReports/components/__snapshots__/FixSelectedButton.test.js.snap +0 -40
- data/webpack/components/PreupgradeReports/components/__snapshots__/UpgradeAllButton.test.js.snap +0 -41
- data/webpack/components/PreupgradeReports/index.js +0 -57
- data/webpack/components/PreupgradeReportsList/PreupgradeReportList.scss +0 -37
- data/webpack/components/PreupgradeReportsList/__tests__/PreupgradeReportsList.test.js +0 -124
- data/webpack/components/PreupgradeReportsList/components/EmptyInfoItem.js +0 -16
- data/webpack/components/PreupgradeReportsList/components/InfoItem.js +0 -34
- data/webpack/components/PreupgradeReportsList/components/InhibitorInfoItem.js +0 -33
- data/webpack/components/PreupgradeReportsList/components/PreupgradeReportEntry.js +0 -64
- data/webpack/components/PreupgradeReportsList/components/PreupgradeReportsListHeader.js +0 -56
- data/webpack/components/PreupgradeReportsList/components/SortableHeaderItem.js +0 -50
- data/webpack/components/PreupgradeReportsList/components/__tests__/EmptyInfoItem.test.js +0 -13
- data/webpack/components/PreupgradeReportsList/components/__tests__/InhibitorInfoItem.test.js +0 -27
- data/webpack/components/PreupgradeReportsList/components/__tests__/PreupgradeReportEntry.fixtures.js +0 -38
- data/webpack/components/PreupgradeReportsList/components/__tests__/PreupgradeReportEntry.test.js +0 -14
- data/webpack/components/PreupgradeReportsList/components/__tests__/PreupgradeReportsListHeader.test.js +0 -14
- data/webpack/components/PreupgradeReportsList/components/__tests__/SortableHeaderItem.test.js +0 -29
- data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/EmptyInfoItem.test.js.snap +0 -8
- data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/InhibitorInfoItem.test.js.snap +0 -32
- data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/PreupgradeReportEntry.test.js.snap +0 -134
- data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/PreupgradeReportsListHeader.test.js.snap +0 -113
- data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/SortableHeaderItem.test.js.snap +0 -36
- data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/helpers.test.js.snap +0 -197
- data/webpack/components/PreupgradeReportsList/components/__tests__/helpers.test.js +0 -28
- data/webpack/components/PreupgradeReportsList/components/foreman_leapp.scss +0 -15
- data/webpack/components/PreupgradeReportsList/components/helpers.js +0 -186
- data/webpack/components/PreupgradeReportsList/components/images/i_severity-critical.svg +0 -61
- data/webpack/components/PreupgradeReportsList/components/images/i_severity-high.svg +0 -61
- data/webpack/components/PreupgradeReportsList/components/images/i_severity-low.svg +0 -62
- data/webpack/components/PreupgradeReportsList/components/images/i_severity-med.svg +0 -62
- data/webpack/components/PreupgradeReportsList/index.js +0 -61
- data/webpack/consts.js +0 -3
- data/webpack/csrf.js +0 -4
- data/webpack/reducer.js +0 -5
|
@@ -17,6 +17,26 @@ module Helpers
|
|
|
17
17
|
FactoryBot.create(:template_invocation, template: job_template, job_invocation: job_invocation)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
describe 'with_leapp_report' do
|
|
21
|
+
test 'returns true for leapp preupgrade feature on template' do
|
|
22
|
+
RemoteExecutionFeature.find_by(label: feature_label).update(job_template: job_template)
|
|
23
|
+
job_invocation.task.stubs(:input).returns({})
|
|
24
|
+
assert helper.with_leapp_report(job_invocation)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
test 'returns true for leapp remediation feature on template' do
|
|
28
|
+
remediation_label = 'leapp_remediation_plan'
|
|
29
|
+
RemoteExecutionFeature.find_by(label: remediation_label).update(job_template: job_template)
|
|
30
|
+
job_invocation.task.stubs(:input).returns({})
|
|
31
|
+
assert helper.with_leapp_report(job_invocation)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
test 'returns false when no leapp features apply' do
|
|
35
|
+
job_invocation.task.stubs(:input).returns({ 'job_features' => ['some_other_feature'] })
|
|
36
|
+
assert_not helper.with_leapp_report(job_invocation)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
20
40
|
describe 'correct_feature?' do
|
|
21
41
|
test 'returns true when feature is listed in job_features' do
|
|
22
42
|
job_invocation.task.stubs(:input).returns({ 'job_features' => [feature_label] })
|
|
@@ -12,7 +12,7 @@ export const usePreupgradeTableState = (data, isExpanded) => {
|
|
|
12
12
|
|
|
13
13
|
const [status, setStatus] = useState(STATUS.RESOLVED);
|
|
14
14
|
const [error, setError] = useState(null);
|
|
15
|
-
const [
|
|
15
|
+
const [hasReports, setHasReports] = useState(false);
|
|
16
16
|
const [rows, setRows] = useState([]);
|
|
17
17
|
const [totalCount, setTotalCount] = useState(0);
|
|
18
18
|
const [searchValue, setSearchValue] = useState('');
|
|
@@ -24,14 +24,15 @@ export const usePreupgradeTableState = (data, isExpanded) => {
|
|
|
24
24
|
const [expandedRowIds, setExpandedRowIds] = useState(new Set());
|
|
25
25
|
|
|
26
26
|
// eslint-disable-next-line camelcase
|
|
27
|
-
const isLeappJob = data?.
|
|
27
|
+
const isLeappJob = Boolean(data?.has_leapp_report);
|
|
28
28
|
// eslint-disable-next-line camelcase
|
|
29
29
|
const jobStatusLabel = data?.status_label;
|
|
30
30
|
|
|
31
31
|
useEffect(() => {
|
|
32
32
|
const fetchKey = `${data.id}:${jobStatusLabel}`;
|
|
33
|
-
if (!isLeappJob || !isExpanded || lastFetchedKeyRef.current === fetchKey)
|
|
33
|
+
if (!isLeappJob || !isExpanded || lastFetchedKeyRef.current === fetchKey) {
|
|
34
34
|
return undefined;
|
|
35
|
+
}
|
|
35
36
|
|
|
36
37
|
let ignore = false;
|
|
37
38
|
setStatus(STATUS.PENDING);
|
|
@@ -41,22 +42,29 @@ export const usePreupgradeTableState = (data, isExpanded) => {
|
|
|
41
42
|
key: `GET_LEAPP_REPORT_LIST_${data.id}`,
|
|
42
43
|
url: `/api/v2/job_invocations/${data.id}/preupgrade_reports`,
|
|
43
44
|
handleSuccess: res => {
|
|
44
|
-
if (ignore)
|
|
45
|
+
if (ignore) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
45
49
|
lastFetchedKeyRef.current = fetchKey;
|
|
46
50
|
const payload = res.data || res;
|
|
47
51
|
const rawResults = payload.results;
|
|
48
52
|
const resultsArray = rawResults ? [].concat(rawResults) : [];
|
|
49
53
|
|
|
50
|
-
if (resultsArray
|
|
51
|
-
|
|
54
|
+
if (resultsArray.length > 0) {
|
|
55
|
+
setHasReports(true);
|
|
52
56
|
} else {
|
|
57
|
+
setHasReports(false);
|
|
53
58
|
setRows([]);
|
|
54
59
|
setTotalCount(0);
|
|
55
60
|
setStatus(STATUS.RESOLVED);
|
|
56
61
|
}
|
|
57
62
|
},
|
|
58
63
|
handleError: err => {
|
|
59
|
-
if (ignore)
|
|
64
|
+
if (ignore) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
60
68
|
setError(err);
|
|
61
69
|
setStatus(STATUS.ERROR);
|
|
62
70
|
},
|
|
@@ -69,10 +77,15 @@ export const usePreupgradeTableState = (data, isExpanded) => {
|
|
|
69
77
|
}, [isExpanded, data.id, isLeappJob, dispatch, jobStatusLabel]);
|
|
70
78
|
|
|
71
79
|
useEffect(() => {
|
|
72
|
-
if (!isLeappJob || !isExpanded || !
|
|
80
|
+
if (!isLeappJob || !isExpanded || !hasReports || !data.id) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const entriesFetchKey = `${data.id}_P${pagination.page}_PP${pagination.perPage}_S${searchValue}_O${sortBy.index}${sortBy.direction}_J${jobStatusLabel}`;
|
|
73
85
|
|
|
74
|
-
|
|
75
|
-
|
|
86
|
+
if (lastEntriesFetchKeyRef.current === entriesFetchKey) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
76
89
|
|
|
77
90
|
let ignore = false;
|
|
78
91
|
setStatus(STATUS.PENDING);
|
|
@@ -84,15 +97,19 @@ export const usePreupgradeTableState = (data, isExpanded) => {
|
|
|
84
97
|
dispatch(
|
|
85
98
|
APIActions.get({
|
|
86
99
|
key: `GET_LEAPP_REPORT_ENTRIES_${entriesFetchKey}`,
|
|
87
|
-
url:
|
|
100
|
+
url: '/api/v2/preupgrade_report_entries',
|
|
88
101
|
params: {
|
|
89
102
|
page: pagination.page,
|
|
90
103
|
per_page: pagination.perPage,
|
|
104
|
+
job_invocation_id: data.id,
|
|
91
105
|
...(searchValue && { search: searchValue }),
|
|
92
106
|
...(orderParam && { order: orderParam }),
|
|
93
107
|
},
|
|
94
108
|
handleSuccess: res => {
|
|
95
|
-
if (ignore)
|
|
109
|
+
if (ignore) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
96
113
|
lastEntriesFetchKeyRef.current = entriesFetchKey;
|
|
97
114
|
const payload = res.data || res;
|
|
98
115
|
const fetchedResults = payload.results;
|
|
@@ -102,7 +119,10 @@ export const usePreupgradeTableState = (data, isExpanded) => {
|
|
|
102
119
|
setExpandedRowIds(new Set());
|
|
103
120
|
},
|
|
104
121
|
handleError: err => {
|
|
105
|
-
if (ignore)
|
|
122
|
+
if (ignore) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
106
126
|
setError(err);
|
|
107
127
|
setStatus(STATUS.ERROR);
|
|
108
128
|
},
|
|
@@ -115,7 +135,8 @@ export const usePreupgradeTableState = (data, isExpanded) => {
|
|
|
115
135
|
}, [
|
|
116
136
|
isExpanded,
|
|
117
137
|
isLeappJob,
|
|
118
|
-
|
|
138
|
+
hasReports,
|
|
139
|
+
data.id,
|
|
119
140
|
searchValue,
|
|
120
141
|
pagination.page,
|
|
121
142
|
pagination.perPage,
|
|
@@ -137,8 +158,13 @@ export const usePreupgradeTableState = (data, isExpanded) => {
|
|
|
137
158
|
const toggleRowExpansion = (id, isOpen) => {
|
|
138
159
|
setExpandedRowIds(prev => {
|
|
139
160
|
const next = new Set(prev);
|
|
140
|
-
|
|
141
|
-
|
|
161
|
+
|
|
162
|
+
if (isOpen) {
|
|
163
|
+
next.add(id);
|
|
164
|
+
} else {
|
|
165
|
+
next.delete(id);
|
|
166
|
+
}
|
|
167
|
+
|
|
142
168
|
return next;
|
|
143
169
|
});
|
|
144
170
|
};
|
|
@@ -147,7 +173,8 @@ export const usePreupgradeTableState = (data, isExpanded) => {
|
|
|
147
173
|
isLeappJob,
|
|
148
174
|
status,
|
|
149
175
|
error,
|
|
150
|
-
|
|
176
|
+
hasReports,
|
|
177
|
+
jobInvocationId: data.id,
|
|
151
178
|
rows,
|
|
152
179
|
totalCount,
|
|
153
180
|
pagination,
|
|
@@ -49,7 +49,7 @@ const mockJobId = 42;
|
|
|
49
49
|
const mockReportId = 999;
|
|
50
50
|
const mockJobData = {
|
|
51
51
|
id: mockJobId,
|
|
52
|
-
|
|
52
|
+
has_leapp_report: true,
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
const mockEntries = Array.from({ length: 12 }, (_, i) => ({
|
|
@@ -122,6 +122,42 @@ describe('PreupgradeReportsTable', () => {
|
|
|
122
122
|
const waitForTable = () =>
|
|
123
123
|
waitFor(() => screen.getByText('Report Entry 1', { selector: 'td' }));
|
|
124
124
|
|
|
125
|
+
it('loads entries for the whole job invocation when multiple preupgrade reports exist', async () => {
|
|
126
|
+
const host2Entry = {
|
|
127
|
+
id: 501,
|
|
128
|
+
title: 'Host 2 Issue',
|
|
129
|
+
hostname: 'host2.example.com',
|
|
130
|
+
host_id: 202,
|
|
131
|
+
severity: 'medium',
|
|
132
|
+
detail: {},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
APIActions.get.mockImplementation(({ key, handleSuccess, params }) => {
|
|
136
|
+
return () => {
|
|
137
|
+
if (key.includes('GET_LEAPP_REPORT_LIST')) {
|
|
138
|
+
handleSuccess({ results: [{ id: 1 }, { id: 2 }] });
|
|
139
|
+
}
|
|
140
|
+
if (key.includes('GET_LEAPP_REPORT_ENTRIES')) {
|
|
141
|
+
expect(params.job_invocation_id).toBe(mockJobId);
|
|
142
|
+
expect(params.search).toBeUndefined();
|
|
143
|
+
handleSuccess({
|
|
144
|
+
results: [host2Entry, ...mockEntries],
|
|
145
|
+
subtotal: mockEntries.length + 1,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return { type: 'MOCK_API_SUCCESS' };
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
renderComponent();
|
|
153
|
+
expandSection();
|
|
154
|
+
await waitFor(() =>
|
|
155
|
+
expect(
|
|
156
|
+
screen.getByText('Host 2 Issue', { selector: 'td' })
|
|
157
|
+
).toBeInTheDocument()
|
|
158
|
+
);
|
|
159
|
+
});
|
|
160
|
+
|
|
125
161
|
it('renders data', async () => {
|
|
126
162
|
renderComponent();
|
|
127
163
|
expandSection();
|
|
@@ -132,12 +168,24 @@ describe('PreupgradeReportsTable', () => {
|
|
|
132
168
|
});
|
|
133
169
|
|
|
134
170
|
it('does not render anything for non-Leapp jobs', () => {
|
|
135
|
-
renderComponent({ id: 55,
|
|
171
|
+
renderComponent({ id: 55, has_leapp_report: false });
|
|
136
172
|
expect(
|
|
137
173
|
screen.queryByText('Leapp preupgrade report')
|
|
138
174
|
).not.toBeInTheDocument();
|
|
139
175
|
});
|
|
140
176
|
|
|
177
|
+
it('renders when has_leapp_report is true (e.g. remediation jobs)', async () => {
|
|
178
|
+
renderComponent({
|
|
179
|
+
id: mockJobId,
|
|
180
|
+
has_leapp_report: true,
|
|
181
|
+
});
|
|
182
|
+
expandSection();
|
|
183
|
+
await waitForTable();
|
|
184
|
+
expect(
|
|
185
|
+
screen.getByText('Report Entry 1', { selector: 'td' })
|
|
186
|
+
).toBeInTheDocument();
|
|
187
|
+
});
|
|
188
|
+
|
|
141
189
|
it('refetches when status_label transitions (e.g. Running → Succeeded)', async () => {
|
|
142
190
|
const store = configureStore({
|
|
143
191
|
reducer: mockReducer,
|
|
@@ -390,7 +438,7 @@ describe('PreupgradeReportsTable', () => {
|
|
|
390
438
|
);
|
|
391
439
|
});
|
|
392
440
|
|
|
393
|
-
it('Fix Selected dispatches
|
|
441
|
+
it('Fix Selected dispatches bulk_remediate with fixable entry ids', async () => {
|
|
394
442
|
renderComponent();
|
|
395
443
|
expandSection();
|
|
396
444
|
await waitForTable();
|
|
@@ -407,13 +455,10 @@ describe('PreupgradeReportsTable', () => {
|
|
|
407
455
|
|
|
408
456
|
expect(APIActions.post).toHaveBeenCalledWith(
|
|
409
457
|
expect.objectContaining({
|
|
410
|
-
url: expect.stringContaining('/
|
|
458
|
+
url: expect.stringContaining('/bulk_remediate'),
|
|
411
459
|
params: {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
host_ids: [100],
|
|
415
|
-
inputs: { remediation_ids: '1' },
|
|
416
|
-
},
|
|
460
|
+
job_invocation_id: mockJobId,
|
|
461
|
+
ids: [1],
|
|
417
462
|
},
|
|
418
463
|
})
|
|
419
464
|
);
|
|
@@ -570,13 +615,89 @@ describe('PreupgradeReportsTable', () => {
|
|
|
570
615
|
expect.objectContaining({
|
|
571
616
|
url: expect.stringContaining('/bulk_remediate'),
|
|
572
617
|
params: {
|
|
573
|
-
|
|
618
|
+
job_invocation_id: mockJobId,
|
|
574
619
|
excluded_ids: [],
|
|
575
620
|
},
|
|
576
621
|
})
|
|
577
622
|
);
|
|
578
623
|
});
|
|
579
624
|
|
|
625
|
+
it('keeps Fix Selected enabled on page 1 when select-all is active but fixable rows are only on later pages', async () => {
|
|
626
|
+
const entriesFixableOnLaterPages = mockEntries.map((entry, index) => {
|
|
627
|
+
if (index < 5) {
|
|
628
|
+
return {
|
|
629
|
+
...entry,
|
|
630
|
+
detail: {
|
|
631
|
+
...entry.detail,
|
|
632
|
+
remediations:
|
|
633
|
+
index === 1
|
|
634
|
+
? [{ type: 'hint', context: 'Manual fix only' }]
|
|
635
|
+
: null,
|
|
636
|
+
},
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (index === 5) {
|
|
641
|
+
return {
|
|
642
|
+
...entry,
|
|
643
|
+
detail: {
|
|
644
|
+
remediations: [{ type: 'command', context: ['echo', 'fix'] }],
|
|
645
|
+
},
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
return {
|
|
650
|
+
...entry,
|
|
651
|
+
detail: { ...entry.detail, remediations: null },
|
|
652
|
+
};
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
const fixableEntryCount = entriesFixableOnLaterPages.filter(entry =>
|
|
656
|
+
entry.detail?.remediations?.some(r => r.type === 'command')
|
|
657
|
+
).length;
|
|
658
|
+
|
|
659
|
+
APIActions.get.mockImplementation(({ key, handleSuccess, params }) => {
|
|
660
|
+
return () => {
|
|
661
|
+
if (key.includes('GET_LEAPP_REPORT_LIST')) {
|
|
662
|
+
handleSuccess({ results: [{ id: mockReportId }] });
|
|
663
|
+
}
|
|
664
|
+
if (key.includes('GET_LEAPP_REPORT_ENTRIES')) {
|
|
665
|
+
const page = Number(params?.page ?? 1);
|
|
666
|
+
const perPage = Number(params?.per_page ?? 5);
|
|
667
|
+
const start = (page - 1) * perPage;
|
|
668
|
+
const results = entriesFixableOnLaterPages.slice(start, start + perPage);
|
|
669
|
+
handleSuccess({
|
|
670
|
+
id: mockReportId,
|
|
671
|
+
results,
|
|
672
|
+
total: entriesFixableOnLaterPages.length,
|
|
673
|
+
subtotal: entriesFixableOnLaterPages.length,
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
if (key.includes('GET_FIXABLE_COUNT')) {
|
|
677
|
+
handleSuccess({
|
|
678
|
+
total: fixableEntryCount,
|
|
679
|
+
subtotal: fixableEntryCount,
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
return { type: 'MOCK_API_SUCCESS' };
|
|
683
|
+
};
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
renderComponent();
|
|
687
|
+
expandSection();
|
|
688
|
+
await waitFor(() =>
|
|
689
|
+
screen.getByText('Report Entry 1', { selector: 'td' })
|
|
690
|
+
);
|
|
691
|
+
|
|
692
|
+
fireEvent.click(screen.getByLabelText('Select all'));
|
|
693
|
+
|
|
694
|
+
await waitFor(() =>
|
|
695
|
+
expect(
|
|
696
|
+
screen.getByRole('button', { name: 'Fix Selected' })
|
|
697
|
+
).not.toBeDisabled()
|
|
698
|
+
);
|
|
699
|
+
});
|
|
700
|
+
|
|
580
701
|
it('fetches fixable count on demand when Select All is clicked', async () => {
|
|
581
702
|
let fixableCountFetched = false;
|
|
582
703
|
|
|
@@ -29,10 +29,16 @@ import { getControllerSearchProps, STATUS } from 'foremanReact/constants';
|
|
|
29
29
|
import SearchBar from 'foremanReact/components/SearchBar';
|
|
30
30
|
import { APIActions } from 'foremanReact/redux/API';
|
|
31
31
|
import { usePreupgradeTableState } from './PreupgradeReportsTableHelpers';
|
|
32
|
-
import { entryFixable } from '../PreupgradeReports/PreupgradeReportsHelpers';
|
|
33
32
|
import ReportDetails, { renderSeverityLabel } from './ReportDetails';
|
|
34
33
|
import './PreupgradeReportsTable.scss';
|
|
35
34
|
|
|
35
|
+
const entryWithFixKind = kind => entry =>
|
|
36
|
+
entry.detail &&
|
|
37
|
+
entry.detail.remediations &&
|
|
38
|
+
entry.detail.remediations.some(remediation => remediation.type === kind);
|
|
39
|
+
|
|
40
|
+
const entryFixable = entryWithFixKind('command');
|
|
41
|
+
|
|
36
42
|
const isRowFixable = entryFixable;
|
|
37
43
|
|
|
38
44
|
const submitJobInvocation = (
|
|
@@ -89,7 +95,8 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
89
95
|
isLeappJob,
|
|
90
96
|
status,
|
|
91
97
|
error,
|
|
92
|
-
|
|
98
|
+
hasReports,
|
|
99
|
+
jobInvocationId,
|
|
93
100
|
rows,
|
|
94
101
|
totalCount,
|
|
95
102
|
pagination,
|
|
@@ -113,21 +120,25 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
113
120
|
|
|
114
121
|
useEffect(() => {
|
|
115
122
|
setFixableCount(null);
|
|
116
|
-
}, [searchValue,
|
|
123
|
+
}, [searchValue, jobInvocationId]);
|
|
117
124
|
|
|
118
125
|
const searchProps = useMemo(() => {
|
|
119
|
-
if (!
|
|
126
|
+
if (!hasReports || !jobInvocationId) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
|
|
120
130
|
const baseProps = getControllerSearchProps('preupgrade_report_entries');
|
|
131
|
+
|
|
121
132
|
return {
|
|
122
133
|
...baseProps,
|
|
123
134
|
autocomplete: {
|
|
124
135
|
...baseProps.autocomplete,
|
|
125
136
|
url: foremanUrl(
|
|
126
|
-
`/api/v2/
|
|
137
|
+
`/api/v2/preupgrade_report_entries/auto_complete_search?job_invocation_id=${jobInvocationId}`
|
|
127
138
|
),
|
|
128
139
|
},
|
|
129
140
|
};
|
|
130
|
-
}, [
|
|
141
|
+
}, [hasReports, jobInvocationId]);
|
|
131
142
|
|
|
132
143
|
const columns = useMemo(
|
|
133
144
|
() => ({
|
|
@@ -203,9 +214,10 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
203
214
|
if (fixableCount === null) {
|
|
204
215
|
dispatch(
|
|
205
216
|
APIActions.get({
|
|
206
|
-
key: `GET_FIXABLE_COUNT_${
|
|
207
|
-
url:
|
|
217
|
+
key: `GET_FIXABLE_COUNT_${jobInvocationId}`,
|
|
218
|
+
url: '/api/v2/preupgrade_report_entries',
|
|
208
219
|
params: {
|
|
220
|
+
job_invocation_id: jobInvocationId,
|
|
209
221
|
search: [searchValue, 'fix_type = command']
|
|
210
222
|
.filter(Boolean)
|
|
211
223
|
.join(' AND '),
|
|
@@ -226,7 +238,7 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
226
238
|
originalSelectAll(...args);
|
|
227
239
|
}
|
|
228
240
|
},
|
|
229
|
-
[dispatch,
|
|
241
|
+
[dispatch, jobInvocationId, searchValue, fixableCount, originalSelectAll]
|
|
230
242
|
);
|
|
231
243
|
|
|
232
244
|
const selectedIds = Array.from(inclusionSet);
|
|
@@ -244,19 +256,6 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
244
256
|
[globalHostId]
|
|
245
257
|
);
|
|
246
258
|
|
|
247
|
-
const hostIdsForSelected = useMemo(
|
|
248
|
-
() =>
|
|
249
|
-
Array.from(
|
|
250
|
-
new Set(
|
|
251
|
-
rows
|
|
252
|
-
.filter(e => selectedIds.includes(e.id))
|
|
253
|
-
.map(getHostId)
|
|
254
|
-
.filter(Boolean)
|
|
255
|
-
)
|
|
256
|
-
),
|
|
257
|
-
[rows, selectedIds, getHostId]
|
|
258
|
-
);
|
|
259
|
-
|
|
260
259
|
const allHostIds = useMemo(
|
|
261
260
|
() => Array.from(new Set(rows.map(getHostId).filter(Boolean))),
|
|
262
261
|
[rows, getHostId]
|
|
@@ -271,11 +270,14 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
271
270
|
const newDirection = (parts[1] || 'ASC').toLowerCase();
|
|
272
271
|
sortChanged =
|
|
273
272
|
newIndex !== sortBy.index || newDirection !== sortBy.direction;
|
|
274
|
-
|
|
273
|
+
|
|
274
|
+
if (sortChanged) {
|
|
275
275
|
setSortBy({ index: newIndex, direction: newDirection });
|
|
276
|
+
}
|
|
276
277
|
}
|
|
277
278
|
|
|
278
279
|
let newPage = pagination.page;
|
|
280
|
+
|
|
279
281
|
if (sortChanged) {
|
|
280
282
|
newPage = 1;
|
|
281
283
|
} else if (newParams.page !== undefined) {
|
|
@@ -300,53 +302,42 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
300
302
|
};
|
|
301
303
|
|
|
302
304
|
const handleFixSelected = () => {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
dispatch(
|
|
308
|
-
APIActions.post({
|
|
309
|
-
key: `BULK_REMEDIATE_${reportId}`,
|
|
310
|
-
url: foremanUrl(
|
|
311
|
-
`/api/v2/preupgrade_reports/${reportId}/preupgrade_report_entries/bulk_remediate`
|
|
312
|
-
),
|
|
313
|
-
params: {
|
|
314
|
-
search: searchValue,
|
|
315
|
-
excluded_ids: Array.from(exclusionSet),
|
|
316
|
-
},
|
|
317
|
-
handleSuccess: response => {
|
|
318
|
-
const result = response.data || response;
|
|
319
|
-
if (result?.id) {
|
|
320
|
-
window.location.assign(
|
|
321
|
-
foremanUrl(`/job_invocations/${result.id}`)
|
|
322
|
-
);
|
|
323
|
-
} else {
|
|
324
|
-
setIsSubmitting(false);
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
handleError: err => {
|
|
328
|
-
setSubmitError(err);
|
|
329
|
-
setIsSubmitting(false);
|
|
330
|
-
},
|
|
331
|
-
})
|
|
332
|
-
);
|
|
333
|
-
} else {
|
|
334
|
-
if (selectedIds.length === 0) return;
|
|
335
|
-
|
|
336
|
-
const hostIds =
|
|
337
|
-
hostIdsForSelected.length > 0
|
|
338
|
-
? hostIdsForSelected
|
|
339
|
-
: [globalHostId].filter(Boolean);
|
|
340
|
-
|
|
341
|
-
submitJobInvocation(
|
|
342
|
-
dispatch,
|
|
343
|
-
setSubmitError,
|
|
344
|
-
'leapp_remediation_plan',
|
|
345
|
-
hostIds,
|
|
346
|
-
selectedIds.join(','),
|
|
347
|
-
setIsSubmitting
|
|
348
|
-
);
|
|
305
|
+
const isBulkSelection = areAllRowsSelected() || exclusionSet.size > 0;
|
|
306
|
+
|
|
307
|
+
if (!isBulkSelection && selectedIds.length === 0) {
|
|
308
|
+
return;
|
|
349
309
|
}
|
|
310
|
+
|
|
311
|
+
setSubmitError(null);
|
|
312
|
+
setIsSubmitting(true);
|
|
313
|
+
|
|
314
|
+
dispatch(
|
|
315
|
+
APIActions.post({
|
|
316
|
+
key: `BULK_REMEDIATE_${jobInvocationId}`,
|
|
317
|
+
url: foremanUrl('/api/v2/preupgrade_report_entries/bulk_remediate'),
|
|
318
|
+
params: {
|
|
319
|
+
job_invocation_id: jobInvocationId,
|
|
320
|
+
...(isBulkSelection
|
|
321
|
+
? {
|
|
322
|
+
...(searchValue && { search: searchValue }),
|
|
323
|
+
excluded_ids: Array.from(exclusionSet),
|
|
324
|
+
}
|
|
325
|
+
: { ids: selectedIds }),
|
|
326
|
+
},
|
|
327
|
+
handleSuccess: response => {
|
|
328
|
+
const result = response.data || response;
|
|
329
|
+
if (result?.id) {
|
|
330
|
+
window.location.assign(foremanUrl(`/job_invocations/${result.id}`));
|
|
331
|
+
} else {
|
|
332
|
+
setIsSubmitting(false);
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
handleError: err => {
|
|
336
|
+
setSubmitError(err);
|
|
337
|
+
setIsSubmitting(false);
|
|
338
|
+
},
|
|
339
|
+
})
|
|
340
|
+
);
|
|
350
341
|
};
|
|
351
342
|
|
|
352
343
|
const handleRunUpgrade = () => {
|
|
@@ -366,7 +357,9 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
366
357
|
[columns]
|
|
367
358
|
);
|
|
368
359
|
|
|
369
|
-
if (!isLeappJob)
|
|
360
|
+
if (!isLeappJob) {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
370
363
|
|
|
371
364
|
const hasAnySelection =
|
|
372
365
|
areAllRowsSelected() || exclusionSet.size > 0 || selectedIds.length > 0;
|
|
@@ -375,8 +368,8 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
375
368
|
status === STATUS.PENDING ||
|
|
376
369
|
isSubmitting ||
|
|
377
370
|
!hasAnySelection ||
|
|
378
|
-
//
|
|
379
|
-
(areAllRowsSelected() &&
|
|
371
|
+
// Global select-all with zero fixable entries in the report (not per-page)
|
|
372
|
+
(areAllRowsSelected() && fixableCount === 0);
|
|
380
373
|
|
|
381
374
|
const isRunUpgradeDisabled =
|
|
382
375
|
status === STATUS.PENDING ||
|
|
@@ -416,7 +409,7 @@ const PreupgradeReportsTable = ({ data = {} }) => {
|
|
|
416
409
|
</ToolbarItem>
|
|
417
410
|
)}
|
|
418
411
|
|
|
419
|
-
{
|
|
412
|
+
{hasReports && searchProps && (
|
|
420
413
|
<ToolbarItem className="leapp-searchbar-item">
|
|
421
414
|
<SearchBar
|
|
422
415
|
data={searchProps}
|
|
@@ -547,7 +540,7 @@ PreupgradeReportsTable.propTypes = {
|
|
|
547
540
|
data: PropTypes.shape({
|
|
548
541
|
id: PropTypes.number,
|
|
549
542
|
// eslint-disable-next-line camelcase
|
|
550
|
-
|
|
543
|
+
has_leapp_report: PropTypes.bool,
|
|
551
544
|
// eslint-disable-next-line camelcase
|
|
552
545
|
status_label: PropTypes.string,
|
|
553
546
|
targeting: PropTypes.shape({
|
data/webpack/index.js
CHANGED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import componentRegistry from 'foremanReact/components/componentRegistry';
|
|
2
|
-
|
|
3
|
-
import injectReducer from 'foremanReact/redux/reducers/registerReducer';
|
|
4
|
-
|
|
5
|
-
import PreupgradeReports from './components/PreupgradeReports';
|
|
6
|
-
import reducer from './reducer';
|
|
7
|
-
|
|
8
|
-
componentRegistry.register({
|
|
9
|
-
name: 'PreupgradeReports',
|
|
10
|
-
type: PreupgradeReports,
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
injectReducer('foremanLeapp', reducer);
|