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.

Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/common/index.js +1 -0
  3. data/app/assets/javascripts/katello/sync_management/index.js +1 -0
  4. data/app/controllers/katello/api/v2/host_packages_controller.rb +1 -5
  5. data/app/controllers/katello/remote_execution_controller.rb +6 -6
  6. data/app/helpers/katello/hosts_and_hostgroups_helper.rb +37 -9
  7. data/app/lib/actions/katello/host/hypervisors_update.rb +82 -22
  8. data/app/lib/actions/pulp/consumer/abstract_content_action.rb +12 -0
  9. data/app/lib/actions/pulp/consumer/content_install.rb +1 -1
  10. data/app/lib/actions/pulp/consumer/content_uninstall.rb +1 -1
  11. data/app/lib/actions/pulp/consumer/content_update.rb +1 -1
  12. data/app/models/katello/concerns/subscription_facet_host_extensions.rb +1 -1
  13. data/app/models/katello/content_view.rb +12 -4
  14. data/app/models/katello/glue/candlepin/pool.rb +11 -11
  15. data/app/models/katello/host/content_facet.rb +2 -1
  16. data/app/models/katello/rpm.rb +14 -6
  17. data/app/models/katello/subscription_status.rb +1 -1
  18. data/app/services/katello/candlepin/consumer.rb +8 -0
  19. data/app/views/overrides/activation_keys/_host_environment_select.html.erb +2 -3
  20. data/config/routes.rb +1 -0
  21. data/db/migrate/20180612163403_add_foreign_key_to_hypervisor_id.rb +3 -0
  22. data/db/seeds.d/75-job_templates.rb +5 -2
  23. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-repository-sets-modal.controller.js +4 -3
  24. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-subscriptions-modal.controller.js +4 -1
  25. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-packages-installed.controller.js +1 -1
  26. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/views/discovery-create.html +1 -1
  27. data/engines/bastion_katello/app/assets/stylesheets/bastion_katello/bastion_katello.scss +5 -0
  28. data/lib/katello/tasks/clean_backend_objects.rake +12 -3
  29. data/lib/katello/version.rb +1 -1
  30. data/package.json +10 -7
  31. data/webpack/__mocks__/foremanReact/redux.js +3 -0
  32. data/webpack/__mocks__/foremanReact/redux/actions/toasts.js +2 -0
  33. data/webpack/components/Search/Search.test.js +3 -1
  34. data/webpack/components/SelectOrg/SelectOrg.scss +3 -0
  35. data/webpack/components/SelectOrg/SelectOrgAction.js +41 -0
  36. data/webpack/components/SelectOrg/SelectOrgReducer.js +33 -0
  37. data/webpack/components/SelectOrg/SetOrganization.js +116 -0
  38. data/webpack/components/WithOrganization/withOrganization.js +28 -0
  39. data/webpack/containers/Application/config.js +9 -2
  40. data/webpack/containers/Application/index.js +4 -2
  41. data/webpack/global_test_setup.js +6 -0
  42. data/webpack/helpers/caret.js +6 -0
  43. data/webpack/move_to_foreman/components/common/{emptyState → EmptyState}/index.js +16 -3
  44. data/webpack/move_to_foreman/components/common/table/components/Table.js +1 -1
  45. data/webpack/move_to_foreman/components/common/table/components/__snapshots__/CollapseSubscriptionGroupButton.test.js.snap +2 -2
  46. data/webpack/move_to_foreman/components/common/table/components/__snapshots__/TableSelectionCell.test.js.snap +1 -1
  47. data/webpack/move_to_foreman/components/common/table/components/__snapshots__/TableSelectionHeaderCell.test.js.snap +1 -1
  48. data/webpack/move_to_pf/LoadingState/LoadingState.js +27 -14
  49. data/webpack/move_to_pf/LoadingState/LoadingState.test.js +8 -4
  50. data/webpack/move_to_pf/Select/Select.js +40 -0
  51. data/webpack/move_to_pf/react-bootstrap-select/index.js +12 -1
  52. data/webpack/redux/actions/RedHatRepositories/enabled.js +0 -1
  53. data/webpack/redux/actions/RedHatRepositories/helpers.js +5 -5
  54. data/webpack/redux/consts.js +6 -0
  55. data/webpack/redux/reducers/index.js +2 -0
  56. data/webpack/scenes/Products/ProductActions.js +24 -0
  57. data/webpack/scenes/Products/ProductConstants.js +3 -0
  58. data/webpack/scenes/Products/__tests__/ProductActions.test.js +40 -0
  59. data/webpack/scenes/Products/__tests__/products.fixtures.js +90 -0
  60. data/webpack/scenes/RedHatRepositories/components/EnabledRepository.js +14 -23
  61. data/webpack/scenes/RedHatRepositories/components/EnabledRepositoryContent.js +34 -0
  62. data/webpack/scenes/RedHatRepositories/components/RepositorySetRepository.js +1 -1
  63. data/webpack/scenes/RedHatRepositories/components/SearchBar.js +1 -0
  64. data/webpack/scenes/RedHatRepositories/components/__tests__/EnabledRepository.test.js +36 -0
  65. data/webpack/scenes/RedHatRepositories/components/__tests__/EnabledRepositoryContent.test.js +27 -0
  66. data/webpack/scenes/RedHatRepositories/components/__tests__/__snapshots__/EnabledRepository.test.js.snap +25 -0
  67. data/webpack/scenes/RedHatRepositories/components/__tests__/__snapshots__/EnabledRepositoryContent.test.js.snap +47 -0
  68. data/webpack/scenes/RedHatRepositories/components/__tests__/__snapshots__/RecommendedRepositorySetsToggler.test.js.snap +3 -1
  69. data/webpack/scenes/RedHatRepositories/index.js +7 -3
  70. data/webpack/scenes/RedHatRepositories/index.scss +1 -0
  71. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailActions.js +1 -1
  72. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailEnabledProducts.js +54 -0
  73. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailProduct.js +29 -0
  74. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailReducer.js +29 -0
  75. data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.js +67 -22
  76. data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.scss +9 -0
  77. data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailEnabledProducts.test.js +18 -0
  78. data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailProduct.test.js +13 -0
  79. data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetails.test.js +6 -0
  80. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetailEnabledProducts.test.js.snap +45 -0
  81. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetailProduct.test.js.snap +67 -0
  82. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +497 -410
  83. data/webpack/scenes/Subscriptions/Details/__tests__/subscriptionDetails.fixtures.js +4 -0
  84. data/webpack/scenes/Subscriptions/Details/index.js +3 -1
  85. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +78 -34
  86. data/webpack/scenes/Subscriptions/Manifest/ManifestHistoryReducer.js +8 -0
  87. data/webpack/scenes/Subscriptions/Manifest/__tests__/ManageManifestModal.test.js +3 -0
  88. data/webpack/scenes/Subscriptions/Manifest/__tests__/__snapshots__/ManageManifestModal.test.js.snap +34 -7
  89. data/webpack/scenes/Subscriptions/Manifest/index.js +1 -0
  90. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +1 -0
  91. data/webpack/scenes/Subscriptions/SubscriptionHelpers.js +3 -0
  92. data/webpack/scenes/Subscriptions/SubscriptionReducer.js +6 -2
  93. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +31 -36
  94. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +2 -7
  95. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsPage.test.js +1 -1
  96. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/__snapshots__/UpstreamSubscriptionsPage.test.js.snap +3 -6
  97. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsPage.test.js +2 -0
  98. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +14 -2
  99. data/webpack/scenes/Subscriptions/__tests__/subscriptions.fixtures.js +4 -3
  100. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/EntitlementsInlineEditFormatter.js +8 -5
  101. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTable.js +29 -19
  102. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableHelpers.js +9 -2
  103. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableSchema.js +2 -2
  104. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/EntitlementsInlineEditFormatter.test.js +110 -0
  105. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/SubscriptionsTable.test.js +15 -3
  106. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/EntitlementsInlineEditFormatter.test.js.snap +228 -0
  107. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionsTable.test.js.snap +54 -21
  108. data/webpack/scenes/Subscriptions/index.js +1 -0
  109. data/webpack/scenes/Tasks/helpers.js +52 -0
  110. data/webpack/services/api/index.js +17 -1
  111. data/webpack/test_setup.js +2 -0
  112. metadata +31 -4
  113. data/config/katello.yaml +0 -89
@@ -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
+ ];
@@ -1,12 +1,14 @@
1
1
  import React, { Component } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import cx from 'classnames';
4
- import { ListView, Spinner, OverlayTrigger, Tooltip } from 'patternfly-react';
3
+ import { ListView } from 'patternfly-react';
5
4
  import { connect } from 'react-redux';
6
5
 
7
6
  import RepositoryTypeIcon from './RepositoryTypeIcon';
8
7
  import { setRepositoryDisabled } from '../../../redux/actions/RedHatRepositories/enabled';
9
8
  import api from '../../../services/api';
9
+ import { notify } from '../../../move_to_foreman/foreman_toast_notifications';
10
+ import { getResponseErrorMsgs } from '../../../move_to_foreman/common/helpers';
11
+ import EnabledRepositoryContent from './EnabledRepositoryContent';
10
12
 
11
13
  class EnabledRepository extends Component {
12
14
  constructor(props) {
@@ -49,9 +51,12 @@ class EnabledRepository extends Component {
49
51
  api
50
52
  .put(url, data)
51
53
  .then(this.setDisabled)
52
- .catch(() => {
54
+ .catch(({ response }) => {
55
+ const errors = getResponseErrorMsgs(response);
56
+ errors.forEach((error) => {
57
+ notify({ message: error, type: 'error' });
58
+ });
53
59
  this.setState({ loading: false });
54
- // TODO: Add error component
55
60
  });
56
61
  };
57
62
 
@@ -67,25 +72,11 @@ class EnabledRepository extends Component {
67
72
  <ListView.Item
68
73
  key={id}
69
74
  actions={
70
- <Spinner loading={this.state.loading} inline>
71
- <OverlayTrigger
72
- overlay={<Tooltip id={this.disableTooltipId}>{__('Disable')}</Tooltip>}
73
- placement="bottom"
74
- trigger={['hover', 'focus']}
75
- rootClose={false}
76
- >
77
- <button
78
- onClick={this.disableRepository}
79
- style={{
80
- backgroundColor: 'initial',
81
- border: 'none',
82
- color: '#0388ce',
83
- }}
84
- >
85
- <i className={cx('fa-2x', 'fa fa-minus-circle')} />
86
- </button>
87
- </OverlayTrigger>
88
- </Spinner>
75
+ <EnabledRepositoryContent
76
+ loading={this.state.loading}
77
+ disableTooltipId={this.disableTooltipId}
78
+ disableRepository={this.disableRepository}
79
+ />
89
80
  }
90
81
  leftContent={<RepositoryTypeIcon id={id} type={type} />}
91
82
  heading={name}
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import cx from 'classnames';
4
+ import { Spinner, OverlayTrigger, Tooltip } from 'patternfly-react';
5
+
6
+ const EnabledRepositoryContent = ({ loading, disableTooltipId, disableRepository }) => (
7
+ <Spinner loading={loading} inline>
8
+ <OverlayTrigger
9
+ overlay={<Tooltip id={disableTooltipId}>{__('Disable')}</Tooltip>}
10
+ placement="bottom"
11
+ trigger={['hover', 'focus']}
12
+ rootClose={false}
13
+ >
14
+ <button
15
+ onClick={disableRepository}
16
+ style={{
17
+ backgroundColor: 'initial',
18
+ border: 'none',
19
+ color: '#0388ce',
20
+ }}
21
+ >
22
+ <i className={cx('fa-2x', 'fa fa-minus-circle')} />
23
+ </button>
24
+ </OverlayTrigger>
25
+ </Spinner>
26
+ );
27
+
28
+ EnabledRepositoryContent.propTypes = {
29
+ loading: PropTypes.bool.isRequired,
30
+ disableTooltipId: PropTypes.string.isRequired,
31
+ disableRepository: PropTypes.func.isRequired,
32
+ };
33
+
34
+ export default EnabledRepositoryContent;
@@ -50,7 +50,7 @@ class RepositorySetRepository extends Component {
50
50
  const data = {
51
51
  id: contentId,
52
52
  product_id: productId,
53
- basearch: arch == UNSPECIFIED_ARCH ? undefined : arch,
53
+ basearch: arch === UNSPECIFIED_ARCH ? undefined : arch,
54
54
  releasever: releasever || undefined,
55
55
  };
56
56
 
@@ -97,6 +97,7 @@ class SearchBar extends Component {
97
97
  <MultiSelect
98
98
  value={this.state.filters}
99
99
  options={filterOptions}
100
+ noneSelectedText={__('Filter by type')}
100
101
  onChange={(e) => {
101
102
  const values = [...e.target.options]
102
103
  .filter(({ selected }) => selected)
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import thunk from 'redux-thunk';
3
+ import { shallow } from 'enzyme';
4
+ import toJson from 'enzyme-to-json';
5
+ import configureMockStore from 'redux-mock-store';
6
+ import EnabledRepository from '../EnabledRepository';
7
+
8
+ jest.mock('../../../../move_to_foreman/foreman_toast_notifications');
9
+
10
+ const mockStore = configureMockStore([thunk]);
11
+ const store = mockStore({});
12
+
13
+ describe('Enabled Repositories Component', () => {
14
+ let shallowWrapper;
15
+ beforeEach(() => {
16
+ shallowWrapper = shallow(<EnabledRepository
17
+ store={store}
18
+ id={1}
19
+ contentId={1}
20
+ productId={1}
21
+ name="foo"
22
+ type="foo"
23
+ arch="foo"
24
+ releaseVer="1.1.1"
25
+ setRepositoryDisabled={() => {}}
26
+ />);
27
+ });
28
+
29
+ afterEach(() => {
30
+ store.clearActions();
31
+ });
32
+
33
+ it('should render', async () => {
34
+ expect(toJson(shallowWrapper)).toMatchSnapshot();
35
+ });
36
+ });
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import { shallow } from 'enzyme';
3
+ import toJson from 'enzyme-to-json';
4
+ import EnabledRepositoryContent from '../EnabledRepositoryContent';
5
+
6
+ describe('Enabled Repositories Content Component', () => {
7
+ const mockCallBack = jest.fn();
8
+
9
+ let shallowWrapper;
10
+ beforeEach(() => {
11
+ shallowWrapper = shallow(<EnabledRepositoryContent
12
+ loading
13
+ disableTooltipId="disable-1"
14
+ disableRepository={mockCallBack}
15
+ />);
16
+ });
17
+
18
+ it('should render', async () => {
19
+ expect(toJson(shallowWrapper)).toMatchSnapshot();
20
+ });
21
+
22
+ it('should run disableRepository on click', async () => {
23
+ expect(mockCallBack).not.toHaveBeenCalled();
24
+ shallowWrapper.find('button').at(0).simulate('click');
25
+ expect(mockCallBack).toHaveBeenCalled();
26
+ });
27
+ });
@@ -0,0 +1,25 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Enabled Repositories Component should render 1`] = `
4
+ <EnabledRepository
5
+ arch="foo"
6
+ contentId={1}
7
+ id={1}
8
+ name="foo"
9
+ productId={1}
10
+ releaseVer="1.1.1"
11
+ releasever=""
12
+ setRepositoryDisabled={[Function]}
13
+ store={
14
+ Object {
15
+ "clearActions": [Function],
16
+ "dispatch": [Function],
17
+ "getActions": [Function],
18
+ "getState": [Function],
19
+ "replaceReducer": [Function],
20
+ "subscribe": [Function],
21
+ }
22
+ }
23
+ type="foo"
24
+ />
25
+ `;
@@ -0,0 +1,47 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Enabled Repositories Content Component should render 1`] = `
4
+ <Spinner
5
+ className=""
6
+ inline={true}
7
+ inverse={false}
8
+ loading={true}
9
+ size="md"
10
+ >
11
+ <OverlayTrigger
12
+ defaultOverlayShown={false}
13
+ overlay={
14
+ <Tooltip
15
+ bsClass="tooltip"
16
+ id="disable-1"
17
+ placement="right"
18
+ >
19
+ Disable
20
+ </Tooltip>
21
+ }
22
+ placement="bottom"
23
+ rootClose={false}
24
+ trigger={
25
+ Array [
26
+ "hover",
27
+ "focus",
28
+ ]
29
+ }
30
+ >
31
+ <button
32
+ onClick={[MockFunction]}
33
+ style={
34
+ Object {
35
+ "backgroundColor": "initial",
36
+ "border": "none",
37
+ "color": "#0388ce",
38
+ }
39
+ }
40
+ >
41
+ <i
42
+ className="fa-2x fa fa-minus-circle"
43
+ />
44
+ </button>
45
+ </OverlayTrigger>
46
+ </Spinner>
47
+ `;
@@ -30,8 +30,10 @@ exports[`RecommendedRepositorySetsToggler rendering renders recommended-reposito
30
30
  />
31
31
  some-children
32
32
  <FieldLevelHelp
33
- close="true"
33
+ buttonClass=""
34
34
  content="some-help"
35
+ placement="top"
36
+ rootClose={true}
35
37
  />
36
38
  </div>
37
39
  `;
@@ -7,7 +7,6 @@ import PropTypes from 'prop-types';
7
7
  import { connect } from 'react-redux';
8
8
  import { Grid, Row, Col } from 'react-bootstrap';
9
9
  import { LoadingState } from '../../move_to_pf/LoadingState';
10
-
11
10
  import { createEnabledRepoParams, loadEnabledRepos } from '../../redux/actions/RedHatRepositories/enabled';
12
11
  import { loadRepositorySets, updateRecommendedRepositorySets } from '../../redux/actions/RedHatRepositories/sets';
13
12
  import SearchBar from './components/SearchBar';
@@ -31,7 +30,6 @@ class RedHatRepositoriesPage extends Component {
31
30
  return (
32
31
  <Grid id="redhatRepositoriesPage" bsClass="container-fluid">
33
32
  <h1>{__('Red Hat Repositories')}</h1>
34
-
35
33
  <Row className="toolbar-pf">
36
34
  <Col sm={12}>
37
35
  <SearchBar repoParams={repoParams} />
@@ -87,9 +85,15 @@ RedHatRepositoriesPage.propTypes = {
87
85
  updateRecommendedRepositorySets: PropTypes.func.isRequired,
88
86
  enabledRepositories: PropTypes.shape({}).isRequired,
89
87
  repositorySets: PropTypes.shape({}).isRequired,
88
+ history: PropTypes.shape({}).isRequired,
89
+ location: PropTypes.shape({}).isRequired,
90
90
  };
91
91
 
92
- const mapStateToProps = ({ katello: { redHatRepositories: { enabled, sets } } }) => ({
92
+ const mapStateToProps = ({
93
+ katello: {
94
+ redHatRepositories: { enabled, sets },
95
+ },
96
+ }) => ({
93
97
  enabledRepositories: enabled,
94
98
  repositorySets: sets,
95
99
  });
@@ -46,6 +46,7 @@
46
46
 
47
47
  h2 {
48
48
  margin: 0;
49
+ margin-right: 40px;
49
50
  }
50
51
  }
51
52
  }
@@ -6,7 +6,7 @@ import {
6
6
  } from './SubscriptionDetailConstants';
7
7
  import { apiError } from '../../../move_to_foreman/common/helpers.js';
8
8
 
9
- export const loadSubscriptionDetails = subscriptionId => (dispatch) => {
9
+ export const loadSubscriptionDetails = subscriptionId => (dispatch, getState) => {
10
10
  dispatch({ type: SUBSCRIPTION_DETAILS_REQUEST });
11
11
 
12
12
  return api
@@ -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;