katello 3.7.0 → 3.7.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of katello might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/assets/javascripts/katello/common/index.js +1 -0
- data/app/assets/javascripts/katello/sync_management/index.js +1 -0
- data/app/controllers/katello/api/v2/host_packages_controller.rb +1 -5
- data/app/controllers/katello/remote_execution_controller.rb +6 -6
- data/app/helpers/katello/hosts_and_hostgroups_helper.rb +37 -9
- data/app/lib/actions/katello/host/hypervisors_update.rb +82 -22
- data/app/lib/actions/pulp/consumer/abstract_content_action.rb +12 -0
- data/app/lib/actions/pulp/consumer/content_install.rb +1 -1
- data/app/lib/actions/pulp/consumer/content_uninstall.rb +1 -1
- data/app/lib/actions/pulp/consumer/content_update.rb +1 -1
- data/app/models/katello/concerns/subscription_facet_host_extensions.rb +1 -1
- data/app/models/katello/content_view.rb +12 -4
- data/app/models/katello/glue/candlepin/pool.rb +11 -11
- data/app/models/katello/host/content_facet.rb +2 -1
- data/app/models/katello/rpm.rb +14 -6
- data/app/models/katello/subscription_status.rb +1 -1
- data/app/services/katello/candlepin/consumer.rb +8 -0
- data/app/views/overrides/activation_keys/_host_environment_select.html.erb +2 -3
- data/config/routes.rb +1 -0
- data/db/migrate/20180612163403_add_foreign_key_to_hypervisor_id.rb +3 -0
- data/db/seeds.d/75-job_templates.rb +5 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-repository-sets-modal.controller.js +4 -3
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-subscriptions-modal.controller.js +4 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-packages-installed.controller.js +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/views/discovery-create.html +1 -1
- data/engines/bastion_katello/app/assets/stylesheets/bastion_katello/bastion_katello.scss +5 -0
- data/lib/katello/tasks/clean_backend_objects.rake +12 -3
- data/lib/katello/version.rb +1 -1
- data/package.json +10 -7
- data/webpack/__mocks__/foremanReact/redux.js +3 -0
- data/webpack/__mocks__/foremanReact/redux/actions/toasts.js +2 -0
- data/webpack/components/Search/Search.test.js +3 -1
- data/webpack/components/SelectOrg/SelectOrg.scss +3 -0
- data/webpack/components/SelectOrg/SelectOrgAction.js +41 -0
- data/webpack/components/SelectOrg/SelectOrgReducer.js +33 -0
- data/webpack/components/SelectOrg/SetOrganization.js +116 -0
- data/webpack/components/WithOrganization/withOrganization.js +28 -0
- data/webpack/containers/Application/config.js +9 -2
- data/webpack/containers/Application/index.js +4 -2
- data/webpack/global_test_setup.js +6 -0
- data/webpack/helpers/caret.js +6 -0
- data/webpack/move_to_foreman/components/common/{emptyState → EmptyState}/index.js +16 -3
- data/webpack/move_to_foreman/components/common/table/components/Table.js +1 -1
- data/webpack/move_to_foreman/components/common/table/components/__snapshots__/CollapseSubscriptionGroupButton.test.js.snap +2 -2
- data/webpack/move_to_foreman/components/common/table/components/__snapshots__/TableSelectionCell.test.js.snap +1 -1
- data/webpack/move_to_foreman/components/common/table/components/__snapshots__/TableSelectionHeaderCell.test.js.snap +1 -1
- data/webpack/move_to_pf/LoadingState/LoadingState.js +27 -14
- data/webpack/move_to_pf/LoadingState/LoadingState.test.js +8 -4
- data/webpack/move_to_pf/Select/Select.js +40 -0
- data/webpack/move_to_pf/react-bootstrap-select/index.js +12 -1
- data/webpack/redux/actions/RedHatRepositories/enabled.js +0 -1
- data/webpack/redux/actions/RedHatRepositories/helpers.js +5 -5
- data/webpack/redux/consts.js +6 -0
- data/webpack/redux/reducers/index.js +2 -0
- data/webpack/scenes/Products/ProductActions.js +24 -0
- data/webpack/scenes/Products/ProductConstants.js +3 -0
- data/webpack/scenes/Products/__tests__/ProductActions.test.js +40 -0
- data/webpack/scenes/Products/__tests__/products.fixtures.js +90 -0
- data/webpack/scenes/RedHatRepositories/components/EnabledRepository.js +14 -23
- data/webpack/scenes/RedHatRepositories/components/EnabledRepositoryContent.js +34 -0
- data/webpack/scenes/RedHatRepositories/components/RepositorySetRepository.js +1 -1
- data/webpack/scenes/RedHatRepositories/components/SearchBar.js +1 -0
- data/webpack/scenes/RedHatRepositories/components/__tests__/EnabledRepository.test.js +36 -0
- data/webpack/scenes/RedHatRepositories/components/__tests__/EnabledRepositoryContent.test.js +27 -0
- data/webpack/scenes/RedHatRepositories/components/__tests__/__snapshots__/EnabledRepository.test.js.snap +25 -0
- data/webpack/scenes/RedHatRepositories/components/__tests__/__snapshots__/EnabledRepositoryContent.test.js.snap +47 -0
- data/webpack/scenes/RedHatRepositories/components/__tests__/__snapshots__/RecommendedRepositorySetsToggler.test.js.snap +3 -1
- data/webpack/scenes/RedHatRepositories/index.js +7 -3
- data/webpack/scenes/RedHatRepositories/index.scss +1 -0
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetailActions.js +1 -1
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetailEnabledProducts.js +54 -0
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetailProduct.js +29 -0
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetailReducer.js +29 -0
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.js +67 -22
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.scss +9 -0
- data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailEnabledProducts.test.js +18 -0
- data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailProduct.test.js +13 -0
- data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetails.test.js +6 -0
- data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetailEnabledProducts.test.js.snap +45 -0
- data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetailProduct.test.js.snap +67 -0
- data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +497 -410
- data/webpack/scenes/Subscriptions/Details/__tests__/subscriptionDetails.fixtures.js +4 -0
- data/webpack/scenes/Subscriptions/Details/index.js +3 -1
- data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +78 -34
- data/webpack/scenes/Subscriptions/Manifest/ManifestHistoryReducer.js +8 -0
- data/webpack/scenes/Subscriptions/Manifest/__tests__/ManageManifestModal.test.js +3 -0
- data/webpack/scenes/Subscriptions/Manifest/__tests__/__snapshots__/ManageManifestModal.test.js.snap +34 -7
- data/webpack/scenes/Subscriptions/Manifest/index.js +1 -0
- data/webpack/scenes/Subscriptions/SubscriptionConstants.js +1 -0
- data/webpack/scenes/Subscriptions/SubscriptionHelpers.js +3 -0
- data/webpack/scenes/Subscriptions/SubscriptionReducer.js +6 -2
- data/webpack/scenes/Subscriptions/SubscriptionsPage.js +31 -36
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +2 -7
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsPage.test.js +1 -1
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/__snapshots__/UpstreamSubscriptionsPage.test.js.snap +3 -6
- data/webpack/scenes/Subscriptions/__tests__/SubscriptionsPage.test.js +2 -0
- data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +14 -2
- data/webpack/scenes/Subscriptions/__tests__/subscriptions.fixtures.js +4 -3
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/EntitlementsInlineEditFormatter.js +8 -5
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTable.js +29 -19
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableHelpers.js +9 -2
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableSchema.js +2 -2
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/EntitlementsInlineEditFormatter.test.js +110 -0
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/SubscriptionsTable.test.js +15 -3
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/EntitlementsInlineEditFormatter.test.js.snap +228 -0
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionsTable.test.js.snap +54 -21
- data/webpack/scenes/Subscriptions/index.js +1 -0
- data/webpack/scenes/Tasks/helpers.js +52 -0
- data/webpack/services/api/index.js +17 -1
- data/webpack/test_setup.js +2 -0
- metadata +31 -4
- data/config/katello.yaml +0 -89
@@ -2,6 +2,7 @@ import { bindActionCreators } from 'redux';
|
|
2
2
|
import { connect } from 'react-redux';
|
3
3
|
import { withRouter } from 'react-router';
|
4
4
|
import reducer from './SubscriptionDetailReducer';
|
5
|
+
import { loadProducts } from '../../Products/ProductActions';
|
5
6
|
import * as subscriptionDetailActions from './SubscriptionDetailActions';
|
6
7
|
import SubscriptionDetails from './SubscriptionDetails';
|
7
8
|
|
@@ -11,7 +12,8 @@ const mapStateToProps = state => ({
|
|
11
12
|
});
|
12
13
|
|
13
14
|
// map action dispatchers to props
|
14
|
-
const
|
15
|
+
const actions = { ...subscriptionDetailActions, loadProducts };
|
16
|
+
const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);
|
15
17
|
|
16
18
|
export const subscriptionDetails = reducer;
|
17
19
|
|
@@ -1,13 +1,15 @@
|
|
1
1
|
import React, { Component } from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
|
-
import { Col, Tabs, Tab, Form, FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
|
3
|
+
import { Col, Tabs, Tab, Form, FormGroup, FormControl, ControlLabel, Row } from 'react-bootstrap';
|
4
4
|
import { bindMethods, Button, Icon, Modal, Spinner, OverlayTrigger, Tooltip } from 'patternfly-react';
|
5
5
|
import { isEqual } from 'lodash';
|
6
6
|
import TooltipButton from 'react-bootstrap-tooltip-button';
|
7
7
|
import { LoadingState } from '../../../move_to_pf/LoadingState';
|
8
8
|
import { Table } from '../../../move_to_foreman/components/common/table';
|
9
|
-
import { columns } from './ManifestHistoryTableSchema';
|
10
9
|
import ConfirmDialog from '../../../move_to_foreman/components/common/ConfirmDialog';
|
10
|
+
import { manifestExists } from '../SubscriptionHelpers';
|
11
|
+
import { columns } from './ManifestHistoryTableSchema';
|
12
|
+
import { renderTaskStartedToast } from '../../Tasks/helpers';
|
11
13
|
import DeleteManifestModalText from './DeleteManifestModalText';
|
12
14
|
import {
|
13
15
|
BLOCKING_FOREMAN_TASK_TYPES,
|
@@ -30,15 +32,11 @@ class ManageManifestModal extends Component {
|
|
30
32
|
'uploadManifest',
|
31
33
|
'refreshManifest',
|
32
34
|
'deleteManifest',
|
33
|
-
'manifestExists',
|
34
35
|
'disabledTooltipText',
|
36
|
+
'updateRepositoryUrl',
|
35
37
|
]);
|
36
38
|
}
|
37
39
|
|
38
|
-
componentDidMount() {
|
39
|
-
this.loadData();
|
40
|
-
}
|
41
|
-
|
42
40
|
static getDerivedStateFromProps(newProps, prevState) {
|
43
41
|
if (
|
44
42
|
!isEqual(newProps.showModal, prevState.showModal) ||
|
@@ -52,6 +50,10 @@ class ManageManifestModal extends Component {
|
|
52
50
|
return null;
|
53
51
|
}
|
54
52
|
|
53
|
+
componentDidMount() {
|
54
|
+
this.loadData();
|
55
|
+
}
|
56
|
+
|
55
57
|
componentDidUpdate(prevProp, prevState) {
|
56
58
|
const { actionInProgress } = this.state;
|
57
59
|
|
@@ -69,14 +71,27 @@ class ManageManifestModal extends Component {
|
|
69
71
|
this.props.onClose();
|
70
72
|
}
|
71
73
|
|
72
|
-
|
73
|
-
this.
|
74
|
+
updateRepositoryUrl(event) {
|
75
|
+
this.setState({ redhat_repository_url: event.target.value });
|
76
|
+
}
|
77
|
+
|
78
|
+
saveOrganization() {
|
79
|
+
this.props.saveOrganization({ redhat_repository_url: this.state.redhat_repository_url });
|
74
80
|
}
|
75
81
|
|
76
82
|
uploadManifest(fileList) {
|
77
83
|
this.setState({ actionInProgress: true });
|
78
84
|
if (fileList.length > 0) {
|
79
|
-
this.props
|
85
|
+
this.props
|
86
|
+
.uploadManifest(fileList[0])
|
87
|
+
.then(() =>
|
88
|
+
this.props.bulkSearch({
|
89
|
+
search_id: MANIFEST_TASKS_BULK_SEARCH_ID,
|
90
|
+
type: 'all',
|
91
|
+
active_only: true,
|
92
|
+
action_types: BLOCKING_FOREMAN_TASK_TYPES,
|
93
|
+
}))
|
94
|
+
.then(() => renderTaskStartedToast(this.props.taskDetails));
|
80
95
|
}
|
81
96
|
}
|
82
97
|
|
@@ -87,14 +102,16 @@ class ManageManifestModal extends Component {
|
|
87
102
|
|
88
103
|
deleteManifest() {
|
89
104
|
this.setState({ actionInProgress: true });
|
90
|
-
this.props
|
105
|
+
this.props
|
106
|
+
.deleteManifest()
|
91
107
|
.then(() =>
|
92
108
|
this.props.bulkSearch({
|
93
109
|
search_id: MANIFEST_TASKS_BULK_SEARCH_ID,
|
94
110
|
type: 'all',
|
95
111
|
active_only: true,
|
96
112
|
action_types: BLOCKING_FOREMAN_TASK_TYPES,
|
97
|
-
}))
|
113
|
+
}))
|
114
|
+
.then(() => renderTaskStartedToast(this.props.taskDetails));
|
98
115
|
this.showDeleteManifestModal(false);
|
99
116
|
}
|
100
117
|
|
@@ -111,15 +128,12 @@ class ManageManifestModal extends Component {
|
|
111
128
|
return __('This is disabled because no manifest exists');
|
112
129
|
}
|
113
130
|
|
114
|
-
manifestExists() {
|
115
|
-
const { organization } = this.props;
|
116
|
-
|
117
|
-
return organization.owner_details && organization.owner_details.upstreamConsumer;
|
118
|
-
}
|
119
|
-
|
120
131
|
render() {
|
121
132
|
const {
|
122
|
-
manifestHistory,
|
133
|
+
manifestHistory,
|
134
|
+
organization,
|
135
|
+
disableManifestActions,
|
136
|
+
disabledReason,
|
123
137
|
} = this.props;
|
124
138
|
|
125
139
|
const { actionInProgress } = this.state;
|
@@ -132,13 +146,23 @@ class ManageManifestModal extends Component {
|
|
132
146
|
url: 'http://redhat.com',
|
133
147
|
},
|
134
148
|
});
|
135
|
-
|
149
|
+
const buttonLoading = (
|
150
|
+
<span>
|
151
|
+
{__('Updating...')}
|
152
|
+
<span className="fa fa-spinner fa-spin" />
|
153
|
+
</span>);
|
136
154
|
const getManifestName = () => {
|
137
155
|
let name = __('No Manifest Uploaded');
|
138
156
|
|
139
|
-
if (
|
140
|
-
|
141
|
-
|
157
|
+
if (
|
158
|
+
organization.owner_details &&
|
159
|
+
organization.owner_details.upstreamConsumer
|
160
|
+
) {
|
161
|
+
const link = [
|
162
|
+
'https://',
|
163
|
+
organization.owner_details.upstreamConsumer.webUrl,
|
164
|
+
organization.owner_details.upstreamConsumer.uuid,
|
165
|
+
].join('/');
|
142
166
|
|
143
167
|
name = (
|
144
168
|
<a href={link}>{organization.owner_details.upstreamConsumer.name}</a>
|
@@ -151,7 +175,11 @@ class ManageManifestModal extends Component {
|
|
151
175
|
return (
|
152
176
|
<Modal show={this.state.showModal} onHide={this.hideModal}>
|
153
177
|
<Modal.Header>
|
154
|
-
<button
|
178
|
+
<button
|
179
|
+
className="close"
|
180
|
+
onClick={this.hideModal}
|
181
|
+
aria-label={__('Close')}
|
182
|
+
>
|
155
183
|
<Icon type="pf" name="close" />
|
156
184
|
</button>
|
157
185
|
<Modal.Title>{__('Manage Manifest')}</Modal.Title>
|
@@ -163,29 +191,43 @@ class ManageManifestModal extends Component {
|
|
163
191
|
<h5>{__('Red Hat Provider Details')}</h5>
|
164
192
|
<hr />
|
165
193
|
<FormGroup>
|
166
|
-
<
|
167
|
-
|
168
|
-
|
194
|
+
<Col sm={3}>
|
195
|
+
<ControlLabel htmlFor="cdnUrl">
|
196
|
+
{__('Red Hat CDN URL')}
|
197
|
+
</ControlLabel>
|
198
|
+
</Col>
|
169
199
|
<Col sm={9}>
|
170
200
|
<FormControl
|
171
201
|
id="cdnUrl"
|
172
202
|
type="text"
|
173
|
-
value={organization.redhat_repository_url || ''}
|
174
|
-
onChange={this.
|
203
|
+
value={this.state.redhat_repository_url || organization.redhat_repository_url || ''}
|
204
|
+
onChange={this.updateRepositoryUrl}
|
175
205
|
/>
|
176
206
|
</Col>
|
177
207
|
</FormGroup>
|
208
|
+
<FormGroup>
|
209
|
+
<Col smOffset={3} sm={3}>
|
210
|
+
<Button onClick={this.saveOrganization} disabled={organization.loading}>
|
211
|
+
{organization.loading ? buttonLoading : __('Update')}
|
212
|
+
</Button>
|
213
|
+
</Col>
|
214
|
+
</FormGroup>
|
178
215
|
<br />
|
179
216
|
|
180
217
|
<h5>{__('Subscription Manifest')}</h5>
|
181
218
|
<hr />
|
182
219
|
|
183
220
|
<FormGroup>
|
184
|
-
<ControlLabel
|
221
|
+
<ControlLabel
|
222
|
+
className="col-sm-3 control-label"
|
223
|
+
htmlFor="usmaFile"
|
224
|
+
>
|
185
225
|
<OverlayTrigger
|
186
226
|
overlay={
|
187
|
-
<Tooltip id="usma-tooltip">
|
188
|
-
|
227
|
+
<Tooltip id="usma-tooltip">
|
228
|
+
{__('Upstream Subscription Management Application')}
|
229
|
+
</Tooltip>
|
230
|
+
}
|
189
231
|
placement="bottom"
|
190
232
|
trigger={['hover', 'focus']}
|
191
233
|
rootClose={false}
|
@@ -213,7 +255,7 @@ class ManageManifestModal extends Component {
|
|
213
255
|
tooltipText={disabledReason}
|
214
256
|
tooltipPlacement="top"
|
215
257
|
title={__('Refresh')}
|
216
|
-
disabled={!
|
258
|
+
disabled={!manifestExists(organization) ||
|
217
259
|
actionInProgress || disableManifestActions}
|
218
260
|
/>
|
219
261
|
|
@@ -223,7 +265,7 @@ class ManageManifestModal extends Component {
|
|
223
265
|
tooltipText={this.disabledTooltipText()}
|
224
266
|
tooltipPlacement="top"
|
225
267
|
title={__('Delete')}
|
226
|
-
disabled={!
|
268
|
+
disabled={!manifestExists(organization) || actionInProgress}
|
227
269
|
/>
|
228
270
|
|
229
271
|
<ConfirmDialog
|
@@ -278,9 +320,11 @@ ManageManifestModal.propTypes = {
|
|
278
320
|
showModal: PropTypes.bool.isRequired,
|
279
321
|
onClose: PropTypes.func,
|
280
322
|
bulkSearch: PropTypes.func.isRequired,
|
323
|
+
taskDetails: PropTypes.shape({}),
|
281
324
|
};
|
282
325
|
|
283
326
|
ManageManifestModal.defaultProps = {
|
327
|
+
taskDetails: undefined,
|
284
328
|
disableManifestActions: false,
|
285
329
|
disabledReason: '',
|
286
330
|
onClose() {},
|
@@ -4,6 +4,8 @@ import {
|
|
4
4
|
MANIFEST_HISTORY_REQUEST,
|
5
5
|
MANIFEST_HISTORY_SUCCESS,
|
6
6
|
MANIFEST_HISTORY_FAILURE,
|
7
|
+
UPLOAD_MANIFEST_SUCCESS,
|
8
|
+
DELETE_MANIFEST_SUCCESS,
|
7
9
|
} from './ManifestConstants';
|
8
10
|
|
9
11
|
const initialState = Immutable({ loading: true, results: [] });
|
@@ -28,6 +30,12 @@ export default (state = initialState, action) => {
|
|
28
30
|
loading: false,
|
29
31
|
});
|
30
32
|
|
33
|
+
case UPLOAD_MANIFEST_SUCCESS:
|
34
|
+
return state.set('taskDetails', action.response);
|
35
|
+
|
36
|
+
case DELETE_MANIFEST_SUCCESS:
|
37
|
+
return state.set('taskDetails', action.response);
|
38
|
+
|
31
39
|
default:
|
32
40
|
return state;
|
33
41
|
}
|
@@ -4,6 +4,8 @@ import toJson from 'enzyme-to-json';
|
|
4
4
|
import ManageManifestModal from '../ManageManifestModal';
|
5
5
|
import { manifestHistorySuccessState } from './manifest.fixtures';
|
6
6
|
|
7
|
+
jest.mock('../../../../move_to_foreman/foreman_toast_notifications');
|
8
|
+
|
7
9
|
describe('manage manifest modal', () => {
|
8
10
|
const noop = () => {};
|
9
11
|
const organization = { id: 1, redhat_repository_url: 'https://redhat.com' };
|
@@ -17,6 +19,7 @@ describe('manage manifest modal', () => {
|
|
17
19
|
organization={organization}
|
18
20
|
loadOrganization={noop}
|
19
21
|
saveOrganization={noop}
|
22
|
+
bulkSearch={noop}
|
20
23
|
manifestHistory={manifestHistorySuccessState}
|
21
24
|
taskInProgress={false}
|
22
25
|
showModal
|
data/webpack/scenes/Subscriptions/Manifest/__tests__/__snapshots__/ManageManifestModal.test.js.snap
CHANGED
@@ -73,14 +73,19 @@ exports[`manage manifest modal should render 1`] = `
|
|
73
73
|
<FormGroup
|
74
74
|
bsClass="form-group"
|
75
75
|
>
|
76
|
-
<
|
77
|
-
bsClass="
|
78
|
-
|
79
|
-
|
80
|
-
srOnly={false}
|
76
|
+
<Col
|
77
|
+
bsClass="col"
|
78
|
+
componentClass="div"
|
79
|
+
sm={3}
|
81
80
|
>
|
82
|
-
|
83
|
-
|
81
|
+
<ControlLabel
|
82
|
+
bsClass="control-label"
|
83
|
+
htmlFor="cdnUrl"
|
84
|
+
srOnly={false}
|
85
|
+
>
|
86
|
+
Red Hat CDN URL
|
87
|
+
</ControlLabel>
|
88
|
+
</Col>
|
84
89
|
<Col
|
85
90
|
bsClass="col"
|
86
91
|
componentClass="div"
|
@@ -96,6 +101,27 @@ exports[`manage manifest modal should render 1`] = `
|
|
96
101
|
/>
|
97
102
|
</Col>
|
98
103
|
</FormGroup>
|
104
|
+
<FormGroup
|
105
|
+
bsClass="form-group"
|
106
|
+
>
|
107
|
+
<Col
|
108
|
+
bsClass="col"
|
109
|
+
componentClass="div"
|
110
|
+
sm={3}
|
111
|
+
smOffset={3}
|
112
|
+
>
|
113
|
+
<Button
|
114
|
+
active={false}
|
115
|
+
block={false}
|
116
|
+
bsClass="btn"
|
117
|
+
bsStyle="default"
|
118
|
+
disabled={false}
|
119
|
+
onClick={[Function]}
|
120
|
+
>
|
121
|
+
Update
|
122
|
+
</Button>
|
123
|
+
</Col>
|
124
|
+
</FormGroup>
|
99
125
|
<br />
|
100
126
|
<h5>
|
101
127
|
Subscription Manifest
|
@@ -215,6 +241,7 @@ exports[`manage manifest modal should render 1`] = `
|
|
215
241
|
<LoadingState
|
216
242
|
loading={false}
|
217
243
|
loadingText="Loading"
|
244
|
+
timeout={300}
|
218
245
|
>
|
219
246
|
<Table
|
220
247
|
columns={
|
@@ -15,6 +15,7 @@ import './Manifest.scss';
|
|
15
15
|
const mapStateToProps = state => ({
|
16
16
|
organization: state.katello.organization,
|
17
17
|
manifestHistory: state.katello.manifestHistory,
|
18
|
+
taskDetails: state.katello.manifestHistory.taskDetails,
|
18
19
|
});
|
19
20
|
|
20
21
|
// map action dispatchers to props
|
@@ -21,6 +21,7 @@ export const BLOCKING_FOREMAN_TASK_TYPES = [
|
|
21
21
|
'Actions::Katello::UpstreamSubscriptions::BindEntitlements',
|
22
22
|
'Actions::Katello::UpstreamSubscriptions::UpdateEntitlement',
|
23
23
|
'Actions::Katello::UpstreamSubscriptions::RemoveEntitlements',
|
24
|
+
'Actions::Katello::UpstreamSubscriptions::UpdateEntitlements',
|
24
25
|
];
|
25
26
|
|
26
27
|
export const MANIFEST_TASKS_BULK_SEARCH_ID = 'activeManifestTasksSearch';
|
@@ -1,3 +1,6 @@
|
|
1
1
|
// eslint-disable-next-line import/prefer-default-export
|
2
2
|
export const filterRHSubscriptions = subscriptions =>
|
3
3
|
subscriptions.filter(sub => sub.available >= 0);
|
4
|
+
|
5
|
+
export const manifestExists = organization =>
|
6
|
+
organization.owner_details && organization.owner_details.upstreamConsumer;
|
@@ -23,7 +23,7 @@ import { GET_SETTING_SUCCESS } from '../../move_to_foreman/Settings/SettingsCons
|
|
23
23
|
const initialState = Immutable({
|
24
24
|
...initialApiState,
|
25
25
|
quantitiesLoading: false,
|
26
|
-
availableQuantities:
|
26
|
+
availableQuantities: null,
|
27
27
|
tasks: [],
|
28
28
|
});
|
29
29
|
|
@@ -85,7 +85,10 @@ export default (state = initialState, action) => {
|
|
85
85
|
});
|
86
86
|
|
87
87
|
case SUBSCRIPTIONS_QUANTITIES_REQUEST:
|
88
|
-
return state.
|
88
|
+
return state.merge({
|
89
|
+
quantitiesLoading: true,
|
90
|
+
availableQuantities: null,
|
91
|
+
});
|
89
92
|
|
90
93
|
case SUBSCRIPTIONS_QUANTITIES_SUCCESS: {
|
91
94
|
return state.merge({
|
@@ -97,6 +100,7 @@ export default (state = initialState, action) => {
|
|
97
100
|
case SUBSCRIPTIONS_QUANTITIES_FAILURE: {
|
98
101
|
return state.merge({
|
99
102
|
quantitiesLoading: false,
|
103
|
+
availableQuantities: {},
|
100
104
|
});
|
101
105
|
}
|
102
106
|
|
@@ -1,15 +1,14 @@
|
|
1
1
|
import React, { Component } from 'react';
|
2
|
-
import ReactDOMServer from 'react-dom/server';
|
3
2
|
import PropTypes from 'prop-types';
|
4
3
|
import { LinkContainer } from 'react-router-bootstrap';
|
5
4
|
import { Grid, Row, Col, Form, FormGroup } from 'react-bootstrap';
|
6
5
|
import { Button } from 'patternfly-react';
|
7
6
|
import TooltipButton from 'react-bootstrap-tooltip-button';
|
8
|
-
import {
|
9
|
-
import helpers from '../../move_to_foreman/common/helpers';
|
7
|
+
import { renderTaskFinishedToast } from '../Tasks/helpers';
|
10
8
|
import ModalProgressBar from '../../move_to_foreman/components/common/ModalProgressBar';
|
11
9
|
import ManageManifestModal from './Manifest/';
|
12
10
|
import { SubscriptionsTable } from './components/SubscriptionsTable';
|
11
|
+
import { manifestExists } from './SubscriptionHelpers';
|
13
12
|
import Search from '../../components/Search/index';
|
14
13
|
import api, { orgId } from '../../services/api';
|
15
14
|
import { createSubscriptionParams } from './SubscriptionActions.js';
|
@@ -70,7 +69,7 @@ class SubscriptionsPage extends Component {
|
|
70
69
|
}
|
71
70
|
|
72
71
|
getDisabledReason(deleteButton) {
|
73
|
-
const { tasks = [], subscriptions } = this.props;
|
72
|
+
const { tasks = [], subscriptions, organization } = this.props;
|
74
73
|
const { disconnected } = subscriptions;
|
75
74
|
let disabledReason = null;
|
76
75
|
|
@@ -79,7 +78,9 @@ class SubscriptionsPage extends Component {
|
|
79
78
|
} else if (tasks.length > 0) {
|
80
79
|
disabledReason = __('This is disabled because a manifest related task is in progress.');
|
81
80
|
} else if (deleteButton && !disabledReason) {
|
82
|
-
disabledReason = __('This is disabled because no subscriptions are selected');
|
81
|
+
disabledReason = __('This is disabled because no subscriptions are selected.');
|
82
|
+
} else if (!manifestExists(organization)) {
|
83
|
+
disabledReason = __('This is disabled because no manifest has been uploaded.');
|
83
84
|
}
|
84
85
|
|
85
86
|
return disabledReason;
|
@@ -103,39 +104,14 @@ class SubscriptionsPage extends Component {
|
|
103
104
|
|
104
105
|
pollTaskUntilDone(taskToPoll.id, {}, POLL_TASK_INTERVAL)
|
105
106
|
.then((task) => {
|
106
|
-
|
107
|
-
return (
|
108
|
-
<ul>
|
109
|
-
{task.humanized.errors.map(error => (
|
110
|
-
<li key={error}> {error} </li>
|
111
|
-
))}
|
112
|
-
</ul>
|
113
|
-
);
|
114
|
-
}
|
115
|
-
|
116
|
-
const message = (
|
117
|
-
<span>
|
118
|
-
<span>
|
119
|
-
{`${__(`Task ${task.humanized.action} completed with a result of ${task.result}.`)} `}
|
120
|
-
</span>
|
121
|
-
{task.errors ? getErrors() : ''}
|
122
|
-
<a href={helpers.urlBuilder('foreman_tasks/tasks', '', task.id)}>
|
123
|
-
{__('Click here to go to the tasks page for the task.')}
|
124
|
-
</a>
|
125
|
-
</span>
|
126
|
-
);
|
127
|
-
|
128
|
-
notify({
|
129
|
-
message: ReactDOMServer.renderToStaticMarkup(message),
|
130
|
-
type: task.result,
|
131
|
-
});
|
132
|
-
|
107
|
+
renderTaskFinishedToast(task);
|
133
108
|
loadSubscriptions();
|
134
109
|
});
|
135
110
|
}
|
136
111
|
|
137
112
|
render() {
|
138
|
-
const { tasks = [], subscriptions } = this.props;
|
113
|
+
const { tasks = [], subscriptions, organization } = this.props;
|
114
|
+
const currentOrg = orgId();
|
139
115
|
const { disconnected } = subscriptions;
|
140
116
|
const taskInProgress = tasks.length > 0;
|
141
117
|
const disableManifestActions = taskInProgress || disconnected;
|
@@ -153,7 +129,7 @@ class SubscriptionsPage extends Component {
|
|
153
129
|
const getAutoCompleteParams = search => ({
|
154
130
|
endpoint: '/subscriptions/auto_complete_search',
|
155
131
|
params: {
|
156
|
-
organization_id:
|
132
|
+
organization_id: currentOrg,
|
157
133
|
search,
|
158
134
|
},
|
159
135
|
});
|
@@ -187,8 +163,18 @@ class SubscriptionsPage extends Component {
|
|
187
163
|
this.setState({ disableDeleteButton: !rowsSelected });
|
188
164
|
};
|
189
165
|
|
166
|
+
|
190
167
|
const csvParams = createSubscriptionParams({ search: this.state.searchQuery });
|
191
168
|
|
169
|
+
const emptyStateData = {
|
170
|
+
header: __('There are no Subscriptions to display'),
|
171
|
+
description: __('Import a Manifest to manage your Entitlements.'),
|
172
|
+
action: {
|
173
|
+
onClick: showManageManifestModal,
|
174
|
+
title: __('Import a Manifest'),
|
175
|
+
},
|
176
|
+
};
|
177
|
+
|
192
178
|
return (
|
193
179
|
<Grid bsClass="container-fluid">
|
194
180
|
<Row>
|
@@ -208,7 +194,10 @@ class SubscriptionsPage extends Component {
|
|
208
194
|
|
209
195
|
<div className="toolbar-pf-action-right">
|
210
196
|
<FormGroup>
|
211
|
-
<LinkContainer
|
197
|
+
<LinkContainer
|
198
|
+
to="subscriptions/add"
|
199
|
+
disabled={disableManifestActions || !manifestExists(organization)}
|
200
|
+
>
|
212
201
|
<TooltipButton
|
213
202
|
tooltipId="add-subscriptions-button-tooltip"
|
214
203
|
tooltipText={this.getDisabledReason()}
|
@@ -257,11 +246,14 @@ class SubscriptionsPage extends Component {
|
|
257
246
|
<SubscriptionsTable
|
258
247
|
loadSubscriptions={this.props.loadSubscriptions}
|
259
248
|
updateQuantity={this.props.updateQuantity}
|
249
|
+
emptyState={emptyStateData}
|
260
250
|
subscriptions={this.props.subscriptions}
|
261
251
|
subscriptionDeleteModalOpen={this.state.subscriptionDeleteModalOpen}
|
262
252
|
onSubscriptionDeleteModalClose={onSubscriptionDeleteModalClose}
|
263
253
|
onDeleteSubscriptions={onDeleteSubscriptions}
|
264
254
|
toggleDeleteButton={toggleDeleteButton}
|
255
|
+
task={task}
|
256
|
+
bulkSearch={this.props.bulkSearch}
|
265
257
|
/>
|
266
258
|
<ModalProgressBar
|
267
259
|
show={this.state.showTaskModal}
|
@@ -279,8 +271,10 @@ class SubscriptionsPage extends Component {
|
|
279
271
|
SubscriptionsPage.propTypes = {
|
280
272
|
loadSubscriptions: PropTypes.func.isRequired,
|
281
273
|
updateQuantity: PropTypes.func.isRequired,
|
282
|
-
subscriptions: PropTypes.shape().isRequired,
|
274
|
+
subscriptions: PropTypes.shape({}).isRequired,
|
275
|
+
organization: PropTypes.shape({}).isRequired,
|
283
276
|
pollBulkSearch: PropTypes.func.isRequired,
|
277
|
+
bulkSearch: PropTypes.func,
|
284
278
|
pollTaskUntilDone: PropTypes.func.isRequired,
|
285
279
|
loadSetting: PropTypes.func.isRequired,
|
286
280
|
tasks: PropTypes.arrayOf(PropTypes.shape({})),
|
@@ -289,6 +283,7 @@ SubscriptionsPage.propTypes = {
|
|
289
283
|
|
290
284
|
SubscriptionsPage.defaultProps = {
|
291
285
|
tasks: [],
|
286
|
+
bulkSearch: undefined,
|
292
287
|
};
|
293
288
|
|
294
289
|
export default SubscriptionsPage;
|