katello 3.8.0.rc2 → 3.8.0.rc3
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/controllers/katello/api/v2/repositories_controller.rb +37 -24
- 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/views/content-host-errata.html +1 -1
- data/lib/katello/version.rb +1 -1
- 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/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 +5 -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 +4 -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 -411
- data/webpack/scenes/Subscriptions/Details/__tests__/subscriptionDetails.fixtures.js +4 -0
- data/webpack/scenes/Subscriptions/Details/index.js +3 -1
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1e8d4def57738f812e6e9463c3a80a0ef587333
|
4
|
+
data.tar.gz: b2150d3ceeafdbd2b34ec05c8d85b69597183f10
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 560eabd60a83230da3567573dfa0be73d488d92e47e5c4a1124356f1f0b54a9b82614fae8a8c3d6fa86a589779d8db6d4bc6109ef1bd5e318e7fa54ac51ca2a4
|
7
|
+
data.tar.gz: 4aa5dfd8a7d86cb8e402685d1e1da7da3a03e32baa30ae1f991eccb524f127f623a1b053357f5bb09d0a24f7e82b81f167269519cc8102cc111c5d3194eb97db
|
@@ -69,6 +69,7 @@ module Katello
|
|
69
69
|
param :deb_id, String, :desc => N_("Id of a deb package to find repositories that contain the deb")
|
70
70
|
param :erratum_id, String, :desc => N_("Id of an erratum to find repositories that contain the erratum")
|
71
71
|
param :rpm_id, String, :desc => N_("Id of a rpm package to find repositories that contain the rpm")
|
72
|
+
param :file_id, String, :desc => N_("Id of a file to find repositories that contain the file")
|
72
73
|
param :ostree_branch_id, String, :desc => N_("Id of an ostree branch to find repositories that contain that branch")
|
73
74
|
param :library, :bool, :desc => N_("show repositories in Library and the default content view")
|
74
75
|
param :content_type, RepositoryTypeManager.repository_types.keys, :desc => N_("limit to only repositories of this type")
|
@@ -107,32 +108,9 @@ module Katello
|
|
107
108
|
query = index_relation_product(query)
|
108
109
|
query = query.where(:content_type => params[:content_type]) if params[:content_type]
|
109
110
|
query = query.where(:name => params[:name]) if params[:name]
|
110
|
-
|
111
|
-
if params[:deb_id]
|
112
|
-
query = query.joins(:debs).where("#{Deb.table_name}.id" => Deb.with_identifiers(params[:deb_id]))
|
113
|
-
end
|
114
|
-
|
115
|
-
if params[:erratum_id]
|
116
|
-
query = query.joins(:errata).where("#{Erratum.table_name}.id" => Erratum.with_identifiers(params[:erratum_id]))
|
117
|
-
end
|
118
|
-
|
119
|
-
if params[:rpm_id]
|
120
|
-
query = query.joins(:rpms).where("#{Rpm.table_name}.id" => Rpm.with_identifiers(params[:rpm_id]))
|
121
|
-
end
|
122
|
-
|
123
|
-
if params[:ostree_branch_id]
|
124
|
-
query = query.joins(:ostree_branches).where("#{OstreeBranch.table_name}.id" => OstreeBranch.with_identifiers(params[:ostree_branch_id]))
|
125
|
-
end
|
126
|
-
|
127
|
-
if params[:puppet_module_id]
|
128
|
-
query = query
|
129
|
-
.joins(:puppet_modules)
|
130
|
-
.where("#{PuppetModule.table_name}.id" => PuppetModule.with_identifiers(params[:puppet_module_id]))
|
131
|
-
end
|
132
|
-
|
111
|
+
query = index_relation_content_unit(query)
|
133
112
|
query = index_relation_content_view(query)
|
134
113
|
query = index_relation_environment(query)
|
135
|
-
|
136
114
|
query
|
137
115
|
end
|
138
116
|
|
@@ -171,6 +149,41 @@ module Katello
|
|
171
149
|
query
|
172
150
|
end
|
173
151
|
|
152
|
+
def index_relation_content_unit(query)
|
153
|
+
if params[:deb_id]
|
154
|
+
query = query.joins(:debs)
|
155
|
+
.where("#{Deb.table_name}.id" => Deb.with_identifiers(params[:deb_id]))
|
156
|
+
end
|
157
|
+
|
158
|
+
if params[:erratum_id]
|
159
|
+
query = query.joins(:errata)
|
160
|
+
.where("#{Erratum.table_name}.id" => Erratum.with_identifiers(params[:erratum_id]))
|
161
|
+
end
|
162
|
+
|
163
|
+
if params[:rpm_id]
|
164
|
+
query = query.joins(:rpms)
|
165
|
+
.where("#{Rpm.table_name}.id" => Rpm.with_identifiers(params[:rpm_id]))
|
166
|
+
end
|
167
|
+
|
168
|
+
if params[:file_id]
|
169
|
+
query = query.joins(:files)
|
170
|
+
.where("#{FileUnit.table_name}.id" => FileUnit.with_identifiers(params[:file_id]))
|
171
|
+
end
|
172
|
+
|
173
|
+
if params[:ostree_branch_id]
|
174
|
+
query = query.joins(:ostree_branches)
|
175
|
+
.where("#{OstreeBranch.table_name}.id" => OstreeBranch.with_identifiers(params[:ostree_branch_id]))
|
176
|
+
end
|
177
|
+
|
178
|
+
if params[:puppet_module_id]
|
179
|
+
query = query
|
180
|
+
.joins(:puppet_modules)
|
181
|
+
.where("#{PuppetModule.table_name}.id" => PuppetModule.with_identifiers(params[:puppet_module_id]))
|
182
|
+
end
|
183
|
+
|
184
|
+
query
|
185
|
+
end
|
186
|
+
|
174
187
|
api :POST, "/repositories", N_("Create a custom repository")
|
175
188
|
param :name, String, :required => true
|
176
189
|
param_group :repo_create
|
@@ -44,11 +44,14 @@ angular.module('Bastion.content-hosts').controller('ContentHostsBulkSubscription
|
|
44
44
|
});
|
45
45
|
};
|
46
46
|
|
47
|
-
|
47
|
+
|
48
|
+
$scope.contentNutupane = new Nutupane(Subscription, params,
|
49
|
+
'queryPaged', {disableAutoLoad: true});
|
48
50
|
$scope.controllerName = 'katello_subscriptions';
|
49
51
|
$scope.table = $scope.contentNutupane.table;
|
50
52
|
$scope.contentNutupane.setSearchKey('subscriptionSearch');
|
51
53
|
$scope.contentNutupane.masterOnly = true;
|
54
|
+
$scope.contentNutupane.load();
|
52
55
|
$scope.groupedSubscriptions = {};
|
53
56
|
|
54
57
|
$scope.$watch('table.rows', function (rows) {
|
@@ -17,7 +17,7 @@
|
|
17
17
|
Content View and Lifecycle Environment. In order to apply such Errata an Incremental Update is required.
|
18
18
|
</span>
|
19
19
|
|
20
|
-
<a ui-sref="errata
|
20
|
+
<a ui-sref="errata" translate>Click here to select Errata for an Incremental Update.</a>
|
21
21
|
</p>
|
22
22
|
</div>
|
23
23
|
|
data/lib/katello/version.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
import api, { orgId } from '../../services/api';
|
2
|
+
|
3
|
+
import {
|
4
|
+
PRODUCTS_REQUEST,
|
5
|
+
PRODUCTS_SUCCESS,
|
6
|
+
PRODUCTS_FAILURE,
|
7
|
+
} from './ProductConstants';
|
8
|
+
import { apiError } from '../../move_to_foreman/common/helpers.js';
|
9
|
+
|
10
|
+
export const loadProducts = (params = {}) => (dispatch) => {
|
11
|
+
dispatch({ type: PRODUCTS_REQUEST });
|
12
|
+
|
13
|
+
return api
|
14
|
+
.get(`/organizations/${orgId()}/products/`, {}, params)
|
15
|
+
.then(({ data }) => {
|
16
|
+
dispatch({
|
17
|
+
type: PRODUCTS_SUCCESS,
|
18
|
+
response: data,
|
19
|
+
});
|
20
|
+
})
|
21
|
+
.catch(result => dispatch(apiError(PRODUCTS_FAILURE, result)));
|
22
|
+
};
|
23
|
+
|
24
|
+
export default loadProducts;
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import thunk from 'redux-thunk';
|
2
|
+
import Immutable from 'seamless-immutable';
|
3
|
+
import configureMockStore from 'redux-mock-store';
|
4
|
+
import { mock, mockRequest, mockErrorRequest } from '../../../mockRequest';
|
5
|
+
import {
|
6
|
+
failureActions,
|
7
|
+
successActions,
|
8
|
+
requestSuccessResponse,
|
9
|
+
} from './products.fixtures';
|
10
|
+
import { loadProducts } from '../ProductActions';
|
11
|
+
|
12
|
+
const mockStore = configureMockStore([thunk]);
|
13
|
+
const store = mockStore({ e: Immutable({}) });
|
14
|
+
|
15
|
+
beforeEach(() => {
|
16
|
+
store.clearActions();
|
17
|
+
mock.reset();
|
18
|
+
});
|
19
|
+
|
20
|
+
describe('product actions', () => {
|
21
|
+
describe('loadProducts', () => {
|
22
|
+
it('handles failed PRODUCTS_REQUEST', () => {
|
23
|
+
mockErrorRequest({
|
24
|
+
url: '/katello/api/v2/organizations/1/products/',
|
25
|
+
status: 422,
|
26
|
+
});
|
27
|
+
return store.dispatch(loadProducts())
|
28
|
+
.then(() => expect(store.getActions()).toEqual(failureActions));
|
29
|
+
});
|
30
|
+
|
31
|
+
it('handles successful PRODUCTS_REQUEST', () => {
|
32
|
+
mockRequest({
|
33
|
+
url: '/katello/api/v2/organizations/1/products/',
|
34
|
+
response: requestSuccessResponse,
|
35
|
+
});
|
36
|
+
return store.dispatch(loadProducts())
|
37
|
+
.then(() => expect(store.getActions()).toEqual(successActions));
|
38
|
+
});
|
39
|
+
});
|
40
|
+
});
|
@@ -0,0 +1,90 @@
|
|
1
|
+
import Immutable from 'seamless-immutable';
|
2
|
+
import { toastErrorAction, failureAction } from '../../../services/api/testHelpers';
|
3
|
+
|
4
|
+
export const initialState = Immutable({
|
5
|
+
loading: true,
|
6
|
+
results: [],
|
7
|
+
pagination: {
|
8
|
+
page: 0,
|
9
|
+
perPage: 20,
|
10
|
+
},
|
11
|
+
});
|
12
|
+
|
13
|
+
export const loadingState = Immutable({
|
14
|
+
...initialState,
|
15
|
+
});
|
16
|
+
|
17
|
+
export const emptyState = Immutable({
|
18
|
+
...loadingState,
|
19
|
+
loading: false,
|
20
|
+
});
|
21
|
+
|
22
|
+
export const availableContent = Immutable({
|
23
|
+
enabled: true,
|
24
|
+
product_id: 114,
|
25
|
+
content: {
|
26
|
+
name: 'Red Hat Enterprise Linux 7 Server (RPMs)',
|
27
|
+
label: 'rhel-7-server-rpms',
|
28
|
+
vendor: 'Red Hat',
|
29
|
+
content_url: '/content/dist/rhel/server/7/$releasever/$basearch/os',
|
30
|
+
gpg_url: 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release',
|
31
|
+
id: '2456',
|
32
|
+
type: 'yum',
|
33
|
+
gpgUrl: 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release',
|
34
|
+
contentUrl: '/content/dist/rhel/server/7/$releasever/$basearch/os',
|
35
|
+
},
|
36
|
+
});
|
37
|
+
|
38
|
+
export const product = (content = []) => ({
|
39
|
+
id: 114,
|
40
|
+
cp_id: '69',
|
41
|
+
name: 'Red Hat Enterprise Linux Server',
|
42
|
+
label: 'Red_Hat_Enterprise_Linux_Server',
|
43
|
+
description: null,
|
44
|
+
provider_id: 2,
|
45
|
+
sync_plan_id: null,
|
46
|
+
sync_summary: {},
|
47
|
+
gpg_key_id: null,
|
48
|
+
ssl_ca_cert_id: null,
|
49
|
+
ssl_client_cert_id: null,
|
50
|
+
ssl_client_key_id: null,
|
51
|
+
sync_state: null,
|
52
|
+
last_sync: null,
|
53
|
+
last_sync_words: null,
|
54
|
+
organization_id: 1,
|
55
|
+
organization: {
|
56
|
+
name: 'Default Organization',
|
57
|
+
label: 'Default_Organization',
|
58
|
+
id: 1,
|
59
|
+
},
|
60
|
+
available_content: content,
|
61
|
+
sync_plan: null,
|
62
|
+
repository_count: 1,
|
63
|
+
});
|
64
|
+
|
65
|
+
export const requestSuccessResponse = Immutable({
|
66
|
+
results: [
|
67
|
+
product([availableContent]),
|
68
|
+
],
|
69
|
+
});
|
70
|
+
|
71
|
+
const request = {
|
72
|
+
type: 'PRODUCTS_REQUEST',
|
73
|
+
};
|
74
|
+
|
75
|
+
export const successActions = [
|
76
|
+
request,
|
77
|
+
{
|
78
|
+
type: 'PRODUCTS_SUCCESS',
|
79
|
+
response: requestSuccessResponse,
|
80
|
+
search: undefined,
|
81
|
+
},
|
82
|
+
];
|
83
|
+
|
84
|
+
export const failureActions = [
|
85
|
+
{
|
86
|
+
type: 'PRODUCTS_REQUEST',
|
87
|
+
},
|
88
|
+
failureAction('PRODUCTS_FAILURE'),
|
89
|
+
toastErrorAction(),
|
90
|
+
];
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { Col, ListView } from 'patternfly-react';
|
4
|
+
import SubscriptionDetailProduct from './SubscriptionDetailProduct';
|
5
|
+
|
6
|
+
const SubscriptionDetailEnabledProducts = ({ enabledProducts }) => {
|
7
|
+
const listItems = enabledProducts.results.map(product => ({
|
8
|
+
index: product.id,
|
9
|
+
title: product.name,
|
10
|
+
availableContent: (
|
11
|
+
product.available_content.map(c => (
|
12
|
+
{
|
13
|
+
enabled: c.enabled,
|
14
|
+
...c.content,
|
15
|
+
}
|
16
|
+
))
|
17
|
+
),
|
18
|
+
}));
|
19
|
+
|
20
|
+
if (listItems.length > 0) {
|
21
|
+
return (
|
22
|
+
<ListView>
|
23
|
+
{listItems.map(({
|
24
|
+
index,
|
25
|
+
title,
|
26
|
+
availableContent,
|
27
|
+
}) => (
|
28
|
+
<ListView.Item
|
29
|
+
key={index}
|
30
|
+
heading={title}
|
31
|
+
hideCloseIcon
|
32
|
+
>
|
33
|
+
|
34
|
+
<Col sm={12}>
|
35
|
+
{availableContent.map(content => (
|
36
|
+
<SubscriptionDetailProduct key={content.id} content={content} />
|
37
|
+
))}
|
38
|
+
</Col>
|
39
|
+
</ListView.Item>
|
40
|
+
))}
|
41
|
+
</ListView>
|
42
|
+
);
|
43
|
+
}
|
44
|
+
|
45
|
+
return (
|
46
|
+
<div>{ __('No products are enabled.') }</div>
|
47
|
+
);
|
48
|
+
};
|
49
|
+
|
50
|
+
SubscriptionDetailEnabledProducts.propTypes = {
|
51
|
+
enabledProducts: PropTypes.shape({}).isRequired,
|
52
|
+
};
|
53
|
+
|
54
|
+
export default SubscriptionDetailEnabledProducts;
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { Row, Col } from 'patternfly-react';
|
4
|
+
|
5
|
+
const SubscriptionDetailProduct = ({ content }) => (
|
6
|
+
<Row key={content.id}>
|
7
|
+
<Col sm={12}>
|
8
|
+
<Row><u>{content.name}</u></Row>
|
9
|
+
</Col>
|
10
|
+
<Col sm={3}>
|
11
|
+
<Row>{ __('Content Download URL') }</Row>
|
12
|
+
<Row>{ __('GPG Key URL') }</Row>
|
13
|
+
<Row>{ __('Repo Type') }</Row>
|
14
|
+
<Row>{ __('Enabled?') }</Row>
|
15
|
+
</Col>
|
16
|
+
<Col sm={9}>
|
17
|
+
<Row>{content.content_url}</Row>
|
18
|
+
<Row>{content.gpg_url}</Row>
|
19
|
+
<Row>{content.type}</Row>
|
20
|
+
<Row>{content.enabled ? __('yes') : __('no')}</Row>
|
21
|
+
</Col>
|
22
|
+
</Row>
|
23
|
+
);
|
24
|
+
|
25
|
+
SubscriptionDetailProduct.propTypes = {
|
26
|
+
content: PropTypes.shape({}).isRequired,
|
27
|
+
};
|
28
|
+
|
29
|
+
export default SubscriptionDetailProduct;
|
@@ -4,9 +4,18 @@ import {
|
|
4
4
|
SUBSCRIPTION_DETAILS_SUCCESS,
|
5
5
|
SUBSCRIPTION_DETAILS_FAILURE,
|
6
6
|
} from './SubscriptionDetailConstants';
|
7
|
+
import {
|
8
|
+
PRODUCTS_REQUEST,
|
9
|
+
PRODUCTS_SUCCESS,
|
10
|
+
PRODUCTS_FAILURE,
|
11
|
+
} from '../../Products/ProductConstants';
|
7
12
|
|
8
13
|
const initialState = Immutable({
|
9
14
|
loading: false,
|
15
|
+
enabledProducts: {
|
16
|
+
results: [],
|
17
|
+
total: 0,
|
18
|
+
},
|
10
19
|
});
|
11
20
|
|
12
21
|
export default (state = initialState, action) => {
|
@@ -15,6 +24,10 @@ export default (state = initialState, action) => {
|
|
15
24
|
return state.set('loading', true);
|
16
25
|
}
|
17
26
|
|
27
|
+
case PRODUCTS_REQUEST: {
|
28
|
+
return state.set('loading', true);
|
29
|
+
}
|
30
|
+
|
18
31
|
case SUBSCRIPTION_DETAILS_SUCCESS: {
|
19
32
|
const subscriptionDetails = action.response;
|
20
33
|
|
@@ -24,6 +37,15 @@ export default (state = initialState, action) => {
|
|
24
37
|
});
|
25
38
|
}
|
26
39
|
|
40
|
+
case PRODUCTS_SUCCESS: {
|
41
|
+
const enabledProducts = { enabledProducts: action.response };
|
42
|
+
|
43
|
+
return state.merge({
|
44
|
+
...enabledProducts,
|
45
|
+
loading: false,
|
46
|
+
});
|
47
|
+
}
|
48
|
+
|
27
49
|
case SUBSCRIPTION_DETAILS_FAILURE: {
|
28
50
|
return state.merge({
|
29
51
|
error: action.payload.message,
|
@@ -31,6 +53,13 @@ export default (state = initialState, action) => {
|
|
31
53
|
});
|
32
54
|
}
|
33
55
|
|
56
|
+
case PRODUCTS_FAILURE: {
|
57
|
+
return state.merge({
|
58
|
+
error: action.payload.message,
|
59
|
+
loading: false,
|
60
|
+
});
|
61
|
+
}
|
62
|
+
|
34
63
|
default:
|
35
64
|
return state;
|
36
65
|
}
|
@@ -1,10 +1,11 @@
|
|
1
1
|
import React, { Component } from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
|
-
import { Grid, Row, Col } from 'patternfly-react';
|
3
|
+
import { Nav, NavItem, TabPane, TabContent, TabContainer, Grid, Row, Col } from 'patternfly-react';
|
4
4
|
import BreadcrumbsBar from 'foremanReact/components/BreadcrumbBar';
|
5
5
|
import SubscriptionDetailInfo from './SubscriptionDetailInfo';
|
6
6
|
import SubscriptionDetailAssociations from './SubscriptionDetailAssociations';
|
7
7
|
import SubscriptionDetailProducts from './SubscriptionDetailProducts';
|
8
|
+
import SubscriptionDetailEnabledProducts from './SubscriptionDetailEnabledProducts';
|
8
9
|
import { LoadingState } from '../../../move_to_pf/LoadingState';
|
9
10
|
import { notify } from '../../../move_to_foreman/foreman_toast_notifications';
|
10
11
|
import api from '../../../services/api';
|
@@ -18,12 +19,22 @@ class SubscriptionDetails extends Component {
|
|
18
19
|
// eslint-disable-next-line react/prop-types
|
19
20
|
const routerParams = this.props.match.params;
|
20
21
|
this.props.loadSubscriptionDetails(parseInt(routerParams.id, 10));
|
22
|
+
this.props.loadProducts({
|
23
|
+
subscription_id: parseInt(routerParams.id, 10),
|
24
|
+
include_available_content: true,
|
25
|
+
enabled: true,
|
26
|
+
});
|
21
27
|
}
|
22
28
|
|
23
29
|
componentDidUpdate(prevProps) {
|
24
30
|
const routerParams = this.props.match.params;
|
25
31
|
if (routerParams.id !== prevProps.match.params.id) {
|
26
32
|
this.props.loadSubscriptionDetails(parseInt(routerParams.id, 10));
|
33
|
+
this.props.loadProducts({
|
34
|
+
subscription_id: parseInt(routerParams.id, 10),
|
35
|
+
include_available_content: true,
|
36
|
+
enabled: true,
|
37
|
+
});
|
27
38
|
}
|
28
39
|
}
|
29
40
|
|
@@ -34,6 +45,8 @@ class SubscriptionDetails extends Component {
|
|
34
45
|
|
35
46
|
render() {
|
36
47
|
const { subscriptionDetails } = this.props;
|
48
|
+
|
49
|
+
|
37
50
|
const resource = {
|
38
51
|
nameField: 'name',
|
39
52
|
resourceUrl: api.getApiUrl('/subscriptions'),
|
@@ -45,7 +58,7 @@ class SubscriptionDetails extends Component {
|
|
45
58
|
}
|
46
59
|
|
47
60
|
return (
|
48
|
-
<
|
61
|
+
<div>
|
49
62
|
{!subscriptionDetails.loading && <BreadcrumbsBar
|
50
63
|
onSwitcherItemClick={(e, url) => this.handleBreadcrumbSwitcherItem(e, url)}
|
51
64
|
data={{
|
@@ -63,32 +76,64 @@ class SubscriptionDetails extends Component {
|
|
63
76
|
resource,
|
64
77
|
}}
|
65
78
|
/>}
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
79
|
+
|
80
|
+
<TabContainer id="subscription-tabs-container" defaultActiveKey={1}>
|
81
|
+
<div>
|
82
|
+
<LoadingState loading={subscriptionDetails.loading} loadingText={__('Loading')}>
|
83
|
+
<Nav bsClass="nav nav-tabs">
|
84
|
+
<NavItem eventKey={1}>
|
85
|
+
<div>{__('Details')}</div>
|
86
|
+
</NavItem>
|
87
|
+
<NavItem eventKey={2}>
|
88
|
+
<div>{__('Enabled Products')}</div>
|
89
|
+
</NavItem>
|
90
|
+
</Nav>
|
91
|
+
<Grid bsClass="container-fluid">
|
92
|
+
<TabContent animation={false}>
|
93
|
+
<TabPane eventKey={1}>
|
94
|
+
<div>
|
95
|
+
<Row>
|
96
|
+
<Col sm={6}>
|
97
|
+
<SubscriptionDetailInfo
|
98
|
+
subscriptionDetails={subscriptionDetails}
|
99
|
+
/>
|
100
|
+
</Col>
|
101
|
+
<Col sm={6}>
|
102
|
+
<SubscriptionDetailAssociations
|
103
|
+
subscriptionDetails={subscriptionDetails}
|
104
|
+
/>
|
105
|
+
<SubscriptionDetailProducts
|
106
|
+
subscriptionDetails={subscriptionDetails}
|
107
|
+
/>
|
108
|
+
</Col>
|
109
|
+
</Row>
|
110
|
+
</div>
|
111
|
+
</TabPane>
|
112
|
+
|
113
|
+
<TabPane eventKey={2}>
|
114
|
+
<div>
|
115
|
+
<Row>
|
116
|
+
<Col sm={12}>
|
117
|
+
<SubscriptionDetailEnabledProducts
|
118
|
+
enabledProducts={subscriptionDetails.enabledProducts}
|
119
|
+
/>
|
120
|
+
</Col>
|
121
|
+
</Row>
|
122
|
+
</div>
|
123
|
+
</TabPane>
|
124
|
+
</TabContent>
|
125
|
+
</Grid>
|
126
|
+
</LoadingState>
|
127
|
+
</div>
|
128
|
+
</TabContainer>
|
129
|
+
</div>
|
86
130
|
);
|
87
131
|
}
|
88
132
|
}
|
89
133
|
|
90
134
|
SubscriptionDetails.propTypes = {
|
91
135
|
loadSubscriptionDetails: PropTypes.func.isRequired,
|
136
|
+
loadProducts: PropTypes.func.isRequired,
|
92
137
|
subscriptionDetails: PropTypes.shape({}).isRequired,
|
93
138
|
history: PropTypes.shape({ push: PropTypes.func.isRequired }).isRequired,
|
94
139
|
};
|