foreman_leapp 0.0.5 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -20
  3. data/app/controllers/api/v2/concerns/api_authorizer.rb +27 -0
  4. data/app/controllers/api/v2/preupgrade_reports_controller.rb +21 -2
  5. data/app/controllers/preupgrade_reports_controller.rb +11 -1
  6. data/app/lib/actions/preupgrade_job.rb +2 -1
  7. data/app/lib/helpers/job_helper.rb +3 -4
  8. data/app/models/preupgrade_report.rb +1 -0
  9. data/app/models/preupgrade_report_entry.rb +1 -0
  10. data/app/views/api/v2/preupgrade_report_entries/base.json.rabl +1 -1
  11. data/app/views/api/v2/preupgrade_reports/job_invocation.json.rabl +3 -0
  12. data/app/views/foreman_leapp/job_templates/leapp_check.erb +15 -0
  13. data/app/views/foreman_leapp/job_templates/{preupgrade.erb → leapp_preupgrade.erb} +5 -2
  14. data/app/views/foreman_leapp/job_templates/leapp_remediation.erb +29 -0
  15. data/app/views/foreman_leapp/job_templates/leapp_upgrade.erb +26 -0
  16. data/app/views/job_invocations/_leapp_preupgrade_report.html.erb +2 -1
  17. data/config/routes.rb +2 -1
  18. data/db/migrate/20200429080939_report_entries_flags.rb +5 -0
  19. data/db/seeds.d/10_leapp_preupgrade.rb +1 -1
  20. data/lib/foreman_leapp/engine.rb +7 -6
  21. data/lib/foreman_leapp/version.rb +1 -1
  22. data/package.json +3 -2
  23. data/test/functional/api/v2/preupgrade_reports_controller_test.rb +89 -6
  24. data/test/functional/preupgrade_reports_controller_test.rb +27 -4
  25. data/test/unit/actions/preupgrade_job_test.rb +1 -1
  26. data/test/unit/helpers/job_helper_test.rb +3 -10
  27. data/webpack/__mocks__/foremanReact/Root/Context/ForemanContext.js +4 -0
  28. data/webpack/__mocks__/foremanReact/common/I18n.js +1 -1
  29. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +2 -0
  30. data/webpack/__mocks__/foremanReact/components/common/EmptyState.js +1 -0
  31. data/webpack/components/PreupgradeReports/PreupgradeReports.js +119 -8
  32. data/webpack/components/PreupgradeReports/PreupgradeReportsActions.js +1 -1
  33. data/webpack/components/PreupgradeReports/PreupgradeReportsHelpers.js +152 -0
  34. data/webpack/components/PreupgradeReports/PreupgradeReportsReducer.js +2 -0
  35. data/webpack/components/PreupgradeReports/PreupgradeReportsSelectors.js +11 -0
  36. data/webpack/components/PreupgradeReports/__tests__/PreupgradeReports.fixtures.js +72 -2
  37. data/webpack/components/PreupgradeReports/__tests__/PreupgradeReports.test.js +26 -1
  38. data/webpack/components/PreupgradeReports/__tests__/PreupgradeReportsHelpers.test.js +78 -0
  39. data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReports.test.js.snap +60 -5
  40. data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReportsHelpers.test.js.snap +489 -0
  41. data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReportsReducer.test.js.snap +40 -1
  42. data/webpack/components/PreupgradeReports/__tests__/__snapshots__/PreupgradeReportsSelectors.test.js.snap +36 -1
  43. data/webpack/components/PreupgradeReports/components/EntriesFilter.js +121 -0
  44. data/webpack/components/PreupgradeReports/components/EntriesFilter.scss +3 -0
  45. data/webpack/components/PreupgradeReports/components/EntriesFilter.test.js +30 -0
  46. data/webpack/components/PreupgradeReports/components/FixSelectedButton.js +35 -0
  47. data/webpack/components/PreupgradeReports/components/FixSelectedButton.test.js +15 -0
  48. data/webpack/components/PreupgradeReports/components/NoReports.js +35 -0
  49. data/webpack/components/PreupgradeReports/components/NoReports.test.js +15 -0
  50. data/webpack/components/PreupgradeReports/components/UpgradeAllButton.js +29 -0
  51. data/webpack/components/PreupgradeReports/components/UpgradeAllButton.test.js +17 -0
  52. data/webpack/components/PreupgradeReports/components/__snapshots__/EntriesFilter.test.js.snap +330 -0
  53. data/webpack/components/PreupgradeReports/components/__snapshots__/FixSelectedButton.test.js.snap +40 -0
  54. data/webpack/components/PreupgradeReports/components/__snapshots__/NoReports.test.js.snap +19 -0
  55. data/webpack/components/PreupgradeReports/components/__snapshots__/UpgradeAllButton.test.js.snap +29 -0
  56. data/webpack/components/PreupgradeReports/index.js +28 -5
  57. data/webpack/components/PreupgradeReportsList/PreupgradeReportList.scss +37 -0
  58. data/webpack/components/PreupgradeReportsList/__tests__/PreupgradeReportsList.test.js +28 -2
  59. data/webpack/components/PreupgradeReportsList/__tests__/__snapshots__/PreupgradeReportsList.test.js.snap +119 -0
  60. data/webpack/components/PreupgradeReportsList/components/InfoItem.js +1 -1
  61. data/webpack/components/PreupgradeReportsList/components/InhibitorInfoItem.js +33 -0
  62. data/webpack/components/PreupgradeReportsList/components/PreupgradeReportEntry.js +50 -6
  63. data/webpack/components/PreupgradeReportsList/components/PreupgradeReportsListHeader.js +56 -0
  64. data/webpack/components/PreupgradeReportsList/components/SortableHeaderItem.js +50 -0
  65. data/webpack/components/PreupgradeReportsList/components/__tests__/InhibitorInfoItem.test.js +27 -0
  66. data/webpack/components/PreupgradeReportsList/components/__tests__/PreupgradeReportEntry.fixtures.js +38 -0
  67. data/webpack/components/PreupgradeReportsList/components/__tests__/PreupgradeReportEntry.test.js +2 -0
  68. data/webpack/components/PreupgradeReportsList/components/__tests__/PreupgradeReportsListHeader.test.js +14 -0
  69. data/webpack/components/PreupgradeReportsList/components/__tests__/SortableHeaderItem.test.js +29 -0
  70. data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/InhibitorInfoItem.test.js.snap +32 -0
  71. data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/PreupgradeReportEntry.test.js.snap +95 -14
  72. data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/PreupgradeReportsListHeader.test.js.snap +113 -0
  73. data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/SortableHeaderItem.test.js.snap +36 -0
  74. data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/helpers.test.js.snap +191 -29
  75. data/webpack/components/PreupgradeReportsList/components/__tests__/helpers.test.js +19 -8
  76. data/webpack/components/PreupgradeReportsList/components/foreman_leapp.scss +15 -0
  77. data/webpack/components/PreupgradeReportsList/components/helpers.js +177 -21
  78. data/webpack/components/PreupgradeReportsList/components/images/i_severity-critical.svg +61 -0
  79. data/webpack/components/PreupgradeReportsList/components/images/i_severity-high.svg +61 -0
  80. data/webpack/components/PreupgradeReportsList/components/images/i_severity-low.svg +62 -0
  81. data/webpack/components/PreupgradeReportsList/components/images/i_severity-med.svg +62 -0
  82. data/webpack/components/PreupgradeReportsList/index.js +48 -10
  83. data/webpack/csrf.js +4 -0
  84. metadata +61 -10
  85. data/app/views/foreman_leapp/job_templates/remediation.erb +0 -17
  86. data/app/views/foreman_leapp/job_templates/upgrade.erb +0 -16
  87. data/webpack/components/PreupgradeReportsList/components/StringInfoItem.js +0 -49
  88. data/webpack/components/PreupgradeReportsList/components/__tests__/StringInfoItem.test.js +0 -13
  89. data/webpack/components/PreupgradeReportsList/components/__tests__/__snapshots__/StringInfoItem.test.js.snap +0 -12
@@ -4,13 +4,36 @@ require 'test_plugin_helper'
4
4
 
5
5
  class PreupgradeReportsControllerTest < ActionController::TestCase
6
6
  setup do
7
+ @user = FactoryBot.create(:user, admin: false)
7
8
  @host = FactoryBot.create :host
8
9
  FactoryBot.create :preupgrade_report, host: @host
9
10
  end
10
11
 
11
- test 'should get index' do
12
- get :index, session: set_session_user
13
- response = ActiveSupport::JSON.decode(@response.body)
14
- assert_equal @host.id, response['results'].first['host_id']
12
+ test 'should get :index' do
13
+ get :index
14
+ assert_response :success
15
+ assert_not_empty JSON.parse(@response.body)['results']
16
+ end
17
+
18
+ test 'should get :index with :view_job_invocations & :view_hosts' do
19
+ setup_user 'view', 'job_invocations', nil, @user
20
+ setup_user 'view', 'hosts', nil, @user
21
+ get :index, session: set_session_user(@user)
22
+ assert_response :success
23
+ assert_not_empty JSON.parse(@response.body)['results']
24
+ end
25
+
26
+ test 'should not get :index without :view_job_invocations' do
27
+ setup_user 'view', 'hosts', nil, @user
28
+ get :index, session: set_session_user(@user)
29
+ assert_response :forbidden
30
+ assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_job_invocations'
31
+ end
32
+
33
+ test 'should not get :index without :view_hosts' do
34
+ setup_user 'view', 'job_invocations', nil, @user
35
+ get :index, session: set_session_user(@user)
36
+ assert_response :forbidden
37
+ assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_hosts'
15
38
  end
16
39
  end
@@ -11,7 +11,7 @@ module ForemanLeapp
11
11
  FactoryBot.create(:job_template, template: 'echo "1"', job_category: 'leapp',
12
12
  provider_type: 'SSH', name: 'Leapp preupgrade')
13
13
  end
14
- let(:job_invocation) { FactoryBot.create(:job_invocation, job_category: ::ForemanLeapp::JOB_CATEGORY) }
14
+ let(:job_invocation) { FactoryBot.create(:job_invocation) }
15
15
  let(:template_invocation) do
16
16
  FactoryBot.create(:template_invocation, template: job_template, job_invocation: job_invocation)
17
17
  end
@@ -5,12 +5,12 @@ require 'test_plugin_helper'
5
5
  module Helpers
6
6
  class JobHelperTest < ActionView::TestCase
7
7
  let(:helper) { ::Helpers::JobHelper }
8
- # let(:host) { FactoryBot.create(:host) }
8
+
9
9
  let(:job_template) do
10
10
  FactoryBot.create(:job_template, template: 'echo "1"', job_category: 'leapp',
11
11
  provider_type: 'SSH', name: 'Leapp preupgrade')
12
12
  end
13
- let(:job_invocation) { FactoryBot.create(:job_invocation, job_category: ::ForemanLeapp::JOB_CATEGORY) }
13
+ let(:job_invocation) { FactoryBot.create(:job_invocation) }
14
14
 
15
15
  describe 'correct_feature?' do
16
16
  setup do
@@ -18,17 +18,10 @@ module Helpers
18
18
  FactoryBot.create(:template_invocation, template: job_template, job_invocation: job_invocation)
19
19
  end
20
20
 
21
- it 'correct category & feature' do
21
+ it 'correct feature' do
22
22
  assert helper.correct_feature?(job_invocation, 'leapp_preupgrade')
23
23
  end
24
24
 
25
- it 'wrong category' do
26
- job_invocation = FactoryBot.create(:job_invocation, job_category: 'NOPE')
27
- FactoryBot.create(:template_invocation, template: job_template, job_invocation: job_invocation)
28
-
29
- assert_not helper.correct_feature?(job_invocation, 'leapp_preupgrade')
30
- end
31
-
32
25
  it 'wrong feature' do
33
26
  assert_not helper.correct_feature?(job_invocation, 'leapp_preupgrade2')
34
27
  end
@@ -0,0 +1,4 @@
1
+ export const useForemanSettings = () => ({
2
+ perPage: 20,
3
+ perPageOptions: [5, 10, 20, 30, 50],
4
+ });
@@ -1 +1 @@
1
- export const translate = () => jest.fn();
1
+ export const translate = val => val;
@@ -0,0 +1,2 @@
1
+ const PaginationWrapper = () => jest.fn();
2
+ export default PaginationWrapper;
@@ -0,0 +1 @@
1
+ export const EmptyStatePattern = () => jest.fn();
@@ -1,12 +1,119 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
2
  import MessageBox from 'foremanReact/components/common/MessageBox';
3
- import { LoadingState } from 'patternfly-react';
3
+ import { LoadingState, Row } from 'patternfly-react';
4
4
  import PropTypes from 'prop-types';
5
5
 
6
6
  import PreupgradeReportsList from '../PreupgradeReportsList';
7
+ import UpgradeAllButton from './components/UpgradeAllButton';
8
+ import EntriesFilter from './components/EntriesFilter';
9
+ import FixSelectedButton from './components/FixSelectedButton';
7
10
 
8
- const PreupgradeReports = ({ preupgradeReports, loading, error }) => {
9
- if (Object.keys(error).length > 0) {
11
+ import {
12
+ flattenEntries,
13
+ isEmpty,
14
+ anyEntriesFixable,
15
+ filterEntries,
16
+ idsForInvocationFromEntries,
17
+ sortEntries,
18
+ fixableEntries,
19
+ } from './PreupgradeReportsHelpers';
20
+
21
+ import NoReports from './components/NoReports';
22
+
23
+ const PreupgradeReports = ({
24
+ preupgradeReports,
25
+ csrfToken,
26
+ newJobInvocationUrl,
27
+ }) => {
28
+ const [filterType, setFilterType] = useState('title');
29
+ const [filterValue, setFilterValue] = useState('');
30
+ const [checked, setChecked] = useState([]);
31
+ const [sort, setSort] = useState({ attribute: '', order: 'desc' });
32
+
33
+ const onFilterValueChange = value => {
34
+ setFilterValue(value);
35
+ };
36
+
37
+ const onFilterValueClear = () => setFilterValue('');
38
+
39
+ const onFilterTypeChange = value => {
40
+ onFilterValueClear();
41
+ setFilterType(value);
42
+ };
43
+
44
+ const isSelected = entry => checked.some(item => item.id === entry.id);
45
+
46
+ const anySelected = checked.length > 0;
47
+
48
+ const toggleSelected = (entry, isEntrySelected) => {
49
+ if (isEntrySelected) {
50
+ setChecked(checked.filter(item => item.id !== entry.id));
51
+ } else {
52
+ setChecked([entry, ...checked]);
53
+ }
54
+ };
55
+
56
+ const toggleSelectAll = () => {
57
+ const allFixable = fixableEntries(preupgradeReports);
58
+
59
+ if (checked.length === allFixable.length) {
60
+ setChecked([]);
61
+ } else {
62
+ setChecked(allFixable);
63
+ }
64
+ };
65
+
66
+ const changeSort = value => {
67
+ setSort({ ...sort, ...value });
68
+ };
69
+
70
+ return (
71
+ <React.Fragment>
72
+ <Row>
73
+ <div className="col-md-8">
74
+ <EntriesFilter
75
+ filterType={filterType}
76
+ onFilterTypeChange={onFilterTypeChange}
77
+ filterValue={filterValue}
78
+ onFilterValueChange={onFilterValueChange}
79
+ />
80
+ </div>
81
+ <div className="col-md-4">
82
+ <div className="btn-toolbar pull-right">
83
+ <FixSelectedButton
84
+ postUrl={newJobInvocationUrl}
85
+ disabled={!anyEntriesFixable(preupgradeReports) || !anySelected}
86
+ csrfToken={csrfToken}
87
+ ids={idsForInvocationFromEntries(checked)}
88
+ />
89
+ <UpgradeAllButton
90
+ postUrl={newJobInvocationUrl}
91
+ csrfToken={csrfToken}
92
+ preupgradeReports={preupgradeReports}
93
+ />
94
+ </div>
95
+ </div>
96
+ </Row>
97
+ <PreupgradeReportsList
98
+ allEntries={filterEntries(
99
+ filterType,
100
+ filterValue,
101
+ sortEntries(flattenEntries(preupgradeReports), sort)
102
+ )}
103
+ isSelected={isSelected}
104
+ toggleSelected={toggleSelected}
105
+ sort={sort}
106
+ changeSort={changeSort}
107
+ toggleSelectAll={toggleSelectAll}
108
+ />
109
+ </React.Fragment>
110
+ );
111
+ };
112
+
113
+ const withLoadingState = Component => props => {
114
+ const { error, loading, preupgradeReports, reportsExpected } = props;
115
+
116
+ if (!isEmpty(error)) {
10
117
  return (
11
118
  <MessageBox
12
119
  key="preupgrade-reports-error"
@@ -18,15 +125,19 @@ const PreupgradeReports = ({ preupgradeReports, loading, error }) => {
18
125
 
19
126
  return (
20
127
  <LoadingState loading={loading}>
21
- <PreupgradeReportsList preupgradeReports={preupgradeReports} />
128
+ {preupgradeReports.length > 0 ? (
129
+ <Component {...props} />
130
+ ) : (
131
+ <NoReports reportsExpected={reportsExpected} />
132
+ )}
22
133
  </LoadingState>
23
134
  );
24
135
  };
25
136
 
26
137
  PreupgradeReports.propTypes = {
27
138
  preupgradeReports: PropTypes.array.isRequired,
28
- loading: PropTypes.bool.isRequired,
29
- error: PropTypes.object.isRequired,
139
+ csrfToken: PropTypes.string.isRequired,
140
+ newJobInvocationUrl: PropTypes.string.isRequired,
30
141
  };
31
142
 
32
- export default PreupgradeReports;
143
+ export default withLoadingState(PreupgradeReports);
@@ -7,7 +7,7 @@ import {
7
7
  PREUPGRADE_REPORTS_FAILURE,
8
8
  } from '../../consts';
9
9
 
10
- export const getPreupgradeReports = url => async dispatch => {
10
+ export const getPreupgradeReportsAction = url => async dispatch => {
11
11
  dispatch({ type: PREUPGRADE_REPORTS_REQUEST });
12
12
 
13
13
  try {
@@ -0,0 +1,152 @@
1
+ import Immutable from 'seamless-immutable';
2
+
3
+ export const flattenEntries = reports =>
4
+ reports.reduce((memo, report) => [...memo, ...report.entries], []);
5
+
6
+ const entryWithFixKind = kind => entry =>
7
+ entry.detail &&
8
+ entry.detail.remediations &&
9
+ entry.detail.remediations.some(remediation => remediation.type === kind);
10
+
11
+ export const entryFixable = entryWithFixKind('command');
12
+
13
+ export const isInhibitor = entry =>
14
+ entry.flags && entry.flags.some(flag => flag === 'inhibitor');
15
+
16
+ export const filterByInhibitor = value => entry => {
17
+ const inhibitsUpgrade = isInhibitor(entry);
18
+
19
+ if (value === 'yes') {
20
+ return inhibitsUpgrade;
21
+ }
22
+
23
+ if (value === 'no') {
24
+ return !inhibitsUpgrade;
25
+ }
26
+
27
+ return true;
28
+ };
29
+
30
+ export const isEmpty = obj => Object.keys(obj).length === 0;
31
+
32
+ export const anyEntriesFixable = reports =>
33
+ reportsToEntries(reports, Array.prototype.some, entryFixable);
34
+
35
+ export const fixableEntries = reports =>
36
+ reportsToEntries(reports, Array.prototype.filter, entryFixable);
37
+
38
+ const reportsToEntries = (reports, iterator, predicate) =>
39
+ iterator.call(flattenEntries(reports), predicate);
40
+
41
+ export const idsForInvocationFromEntries = entries =>
42
+ entries.reduce(
43
+ (memo, entry) => {
44
+ if (entryFixable(entry)) {
45
+ memo.entryIds = [...memo.entryIds, entry.id];
46
+
47
+ if (!memo.hostIds.includes(entry.hostId)) {
48
+ memo.hostIds = [...memo.hostIds, entry.hostId];
49
+ }
50
+ }
51
+ return memo;
52
+ },
53
+ { hostIds: [], entryIds: [] }
54
+ );
55
+
56
+ export const idsForInvocationFromReports = reports =>
57
+ idsForInvocationFromEntries(flattenEntries(reports));
58
+
59
+ export const entriesPage = (entries, pagination) => {
60
+ const offset = (pagination.page - 1) * pagination.perPage;
61
+
62
+ return entries.slice(offset, offset + pagination.perPage);
63
+ };
64
+
65
+ export const filterEntries = (attribute, value, entries) => {
66
+ if (!value) {
67
+ return entries;
68
+ }
69
+
70
+ if (attribute === 'fix') {
71
+ return entries.filter(entryWithFixKind(value));
72
+ }
73
+
74
+ if (attribute === 'inhibitor') {
75
+ return entries.filter(filterByInhibitor(value));
76
+ }
77
+
78
+ return entries.filter(entry =>
79
+ entry[attribute].toLowerCase().includes(value.toLowerCase())
80
+ );
81
+ };
82
+
83
+ export const byText = attribute => (first, second) => {
84
+ const firstAttr = first[attribute].toLowerCase();
85
+ const secondAttr = second[attribute].toLowerCase();
86
+
87
+ if (firstAttr < secondAttr) {
88
+ return -1;
89
+ }
90
+
91
+ if (firstAttr > secondAttr) {
92
+ return 1;
93
+ }
94
+ return 0;
95
+ };
96
+
97
+ export const bySeverity = attribute => (first, second) => {
98
+ const sevList = ['info', 'low', 'medium', 'high'];
99
+
100
+ const firstAttr = first[attribute].toLowerCase();
101
+ const secondAttr = second[attribute].toLowerCase();
102
+
103
+ return sevList.indexOf(firstAttr) - sevList.indexOf(secondAttr);
104
+ };
105
+
106
+ export const byFix = (first, second) => {
107
+ const firstAttr = !!(first.detail && first.detail.remediations);
108
+ const secondAttr = !!(second.detail && second.detail.remediations);
109
+ return byBoolComparison(firstAttr, secondAttr);
110
+ };
111
+
112
+ export const byInhibitor = (first, second) =>
113
+ byBoolComparison(isInhibitor(first), isInhibitor(second));
114
+
115
+ const byBoolComparison = (first, second) => {
116
+ if (first === second) {
117
+ return 0;
118
+ }
119
+
120
+ if (first) {
121
+ return -1;
122
+ }
123
+ return 1;
124
+ };
125
+
126
+ export const sortEntries = (entries, sort) => {
127
+ const entriesCopy = Immutable.asMutable(entries);
128
+
129
+ if (!sort.attribute) {
130
+ return entriesCopy;
131
+ }
132
+
133
+ let sorted;
134
+
135
+ if (['title', 'hostname'].includes(sort.attribute)) {
136
+ sorted = entriesCopy.sort(byText(sort.attribute));
137
+ }
138
+
139
+ if (sort.attribute === 'severity') {
140
+ sorted = entriesCopy.sort(bySeverity(sort.attribute));
141
+ }
142
+
143
+ if (sort.attribute === 'fix') {
144
+ sorted = entriesCopy.sort(byFix);
145
+ }
146
+
147
+ if (sort.attribute === 'inhibitor') {
148
+ sorted = entriesCopy.sort(byInhibitor);
149
+ }
150
+
151
+ return sort.order === 'asc' ? sorted : sorted.reverse();
152
+ };
@@ -8,6 +8,7 @@ import {
8
8
 
9
9
  export const initialState = Immutable({
10
10
  loadingPreupgradeReports: false,
11
+ reportsExpected: false,
11
12
  preupgradeReports: [],
12
13
  error: {},
13
14
  });
@@ -21,6 +22,7 @@ const reducer = (state = initialState, action) => {
21
22
  return state.merge({
22
23
  loadingPreupgradeReports: false,
23
24
  preupgradeReports: payload.results,
25
+ reportsExpected: true,
24
26
  });
25
27
  case PREUPGRADE_REPORTS_FAILURE:
26
28
  return state.merge({
@@ -2,6 +2,17 @@ export const selectPreupgrade = state => state.foremanLeapp.preupgrade;
2
2
 
3
3
  export const selectPreupgradeReports = state =>
4
4
  selectPreupgrade(state).preupgradeReports;
5
+
5
6
  export const selectLoadingPreupgradeReports = state =>
6
7
  selectPreupgrade(state).loadingPreupgradeReports;
7
8
  export const selectError = state => selectPreupgrade(state).error;
9
+
10
+ export const selectReportsExpected = state =>
11
+ selectPreupgrade(state).reportsExpected;
12
+
13
+ export const selectRexState = state => state.foremanRemoteExecutionReducers;
14
+
15
+ export const selectJobInvocations = state =>
16
+ selectRexState(state).jobInvocations;
17
+ export const selectJobInvocationsPolling = state =>
18
+ selectJobInvocations(state).isPolling;
@@ -2,14 +2,84 @@ export const preupgradeReports = [
2
2
  {
3
3
  hostId: 5,
4
4
  entries: [
5
- { title: 'Fix me!', severity: 'Too severe to talk about' },
5
+ {
6
+ title: 'Fix me!',
7
+ severity: 'info',
8
+ id: 42,
9
+ hostname: 'host.example.com',
10
+ flags: [],
11
+ },
12
+ {
13
+ title: 'I am broken too',
14
+ severity: 'medium',
15
+ id: 43,
16
+ hostname: 'host.example.com',
17
+ flags: [],
18
+ },
19
+ ],
20
+ },
21
+ {
22
+ hostId: 6,
23
+ entries: [
24
+ {
25
+ title: 'Octocat is not happy',
26
+ severity: 'high',
27
+ id: 44,
28
+ hostname: 'foo.example.com',
29
+ flags: ['inhibitor'],
30
+ },
31
+ {
32
+ title: 'Not enough credits',
33
+ severity: 'low',
34
+ id: 45,
35
+ hostname: 'foo.example.com',
36
+ flags: [],
37
+ },
38
+ {
39
+ title: 'SELinux is turned off',
40
+ severity: 'medium',
41
+ id: 46,
42
+ hostname: 'foo.example.com',
43
+ flags: [],
44
+ },
45
+ {
46
+ title: 'Root password is too short',
47
+ severity: 'medium',
48
+ id: 47,
49
+ hostname: 'foo.example.com',
50
+ flags: [],
51
+ },
52
+ {
53
+ title: 'No chocolate chip cookies in cookie jar',
54
+ severity: 'high',
55
+ id: 49,
56
+ hostname: 'foo.example.com',
57
+ flags: [],
58
+ },
59
+ ],
60
+ },
61
+ ];
62
+
63
+ export const reportsWithRemediations = [
64
+ {
65
+ hostId: 5,
66
+ entries: [
67
+ {
68
+ title: 'Fix me!',
69
+ severity: 'info',
70
+ detail: { remediations: [{ type: 'hint' }] },
71
+ },
6
72
  { title: 'I am broken too', severity: 'medium' },
7
73
  ],
8
74
  },
9
75
  {
10
76
  hostId: 6,
11
77
  entries: [
12
- { title: 'Octocat is not happy', severity: 'high' },
78
+ {
79
+ title: 'Octocat is not happy',
80
+ severity: 'high',
81
+ detail: { remediations: [{ type: 'command' }] },
82
+ },
13
83
  { title: 'Not enough credits', severity: 'low' },
14
84
  ],
15
85
  },