katello 3.8.0.rc1 → 3.8.0.rc2

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 (123) 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/registry/registry_proxies_controller.rb +1 -1
  5. data/app/controllers/katello/api/v2/environments_controller.rb +0 -1
  6. data/app/controllers/katello/api/v2/ostree_branches_controller.rb +1 -1
  7. data/app/controllers/katello/api/v2/repository_sets_controller.rb +10 -1
  8. data/app/controllers/katello/remote_execution_controller.rb +6 -6
  9. data/app/helpers/katello/hosts_and_hostgroups_helper.rb +37 -9
  10. data/app/lib/katello/resources/registry.rb +4 -4
  11. data/app/models/katello/authorization/repository.rb +2 -1
  12. data/app/models/katello/content_view.rb +12 -4
  13. data/app/models/katello/glue/candlepin/owner.rb +0 -8
  14. data/app/models/katello/glue/candlepin/pool.rb +11 -11
  15. data/app/models/katello/kt_environment.rb +0 -6
  16. data/app/models/katello/product_content.rb +4 -1
  17. data/app/models/katello/rpm.rb +13 -5
  18. data/app/services/katello/ui_notifications/pulp/proxy_disk_space.rb +3 -1
  19. data/app/views/overrides/activation_keys/_host_environment_select.html.erb +2 -3
  20. data/config/katello.yaml.example +5 -0
  21. data/config/routes.rb +1 -0
  22. data/db/seeds.d/75-job_templates.rb +5 -2
  23. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/views/environment-details.html +43 -8
  24. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/discovery.controller.js +17 -2
  25. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/views/discovery-create.html +1 -1
  26. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/views/discovery.html +1 -1
  27. data/engines/bastion_katello/app/assets/stylesheets/bastion_katello/bastion_katello.scss +5 -0
  28. data/lib/katello/version.rb +1 -1
  29. data/package.json +11 -7
  30. data/webpack/__mocks__/foremanReact/components/BreadcrumbBar.js +3 -0
  31. data/webpack/__mocks__/foremanReact/redux/actions/toasts.js +8 -0
  32. data/webpack/__mocks__/foremanReact/redux.js +3 -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/mockRequest.js +3 -3
  44. data/webpack/move_to_foreman/common/helpers.js +45 -8
  45. data/webpack/move_to_foreman/components/common/{emptyState → EmptyState}/index.js +16 -3
  46. data/webpack/move_to_foreman/components/common/table/components/Table.js +1 -1
  47. data/webpack/move_to_foreman/components/common/table/components/__snapshots__/CollapseSubscriptionGroupButton.test.js.snap +2 -2
  48. data/webpack/move_to_foreman/components/common/table/components/__snapshots__/TableSelectionCell.test.js.snap +1 -1
  49. data/webpack/move_to_foreman/components/common/table/components/__snapshots__/TableSelectionHeaderCell.test.js.snap +1 -1
  50. data/webpack/move_to_pf/LoadingState/LoadingState.js +27 -14
  51. data/webpack/move_to_pf/LoadingState/LoadingState.test.js +8 -4
  52. data/webpack/move_to_pf/Select/Select.js +40 -0
  53. data/webpack/move_to_pf/react-bootstrap-select/index.js +12 -1
  54. data/webpack/redux/actions/RedHatRepositories/enabled.js +0 -1
  55. data/webpack/redux/actions/RedHatRepositories/helpers.js +5 -5
  56. data/webpack/redux/actions/RedHatRepositories/sets.js +1 -1
  57. data/webpack/redux/consts.js +6 -0
  58. data/webpack/redux/reducers/index.js +2 -0
  59. data/webpack/scenes/RedHatRepositories/components/EnabledRepository.js +14 -23
  60. data/webpack/scenes/RedHatRepositories/components/EnabledRepositoryContent.js +34 -0
  61. data/webpack/scenes/RedHatRepositories/components/RepositorySetRepository.js +1 -1
  62. data/webpack/scenes/RedHatRepositories/components/SearchBar.js +1 -0
  63. data/webpack/scenes/RedHatRepositories/components/__tests__/EnabledRepository.test.js +36 -0
  64. data/webpack/scenes/RedHatRepositories/components/__tests__/EnabledRepositoryContent.test.js +27 -0
  65. data/webpack/scenes/RedHatRepositories/components/__tests__/__snapshots__/EnabledRepository.test.js.snap +25 -0
  66. data/webpack/scenes/RedHatRepositories/components/__tests__/__snapshots__/EnabledRepositoryContent.test.js.snap +47 -0
  67. data/webpack/scenes/RedHatRepositories/components/__tests__/__snapshots__/RecommendedRepositorySetsToggler.test.js.snap +3 -1
  68. data/webpack/scenes/RedHatRepositories/index.js +7 -3
  69. data/webpack/scenes/RedHatRepositories/index.scss +1 -0
  70. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailActions.js +3 -8
  71. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailProducts.js +5 -3
  72. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailReducer.js +1 -1
  73. data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.js +44 -6
  74. data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.scss +4 -0
  75. data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailReducer.test.js +3 -1
  76. data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetails.test.js +2 -1
  77. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetailProducts.test.js.snap +113 -23
  78. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +23 -14
  79. data/webpack/scenes/Subscriptions/Details/__tests__/subscriptionDetails.fixtures.js +3 -4
  80. data/webpack/scenes/Subscriptions/Details/index.js +2 -2
  81. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +78 -34
  82. data/webpack/scenes/Subscriptions/Manifest/ManifestActions.js +5 -24
  83. data/webpack/scenes/Subscriptions/Manifest/ManifestHistoryReducer.js +9 -1
  84. data/webpack/scenes/Subscriptions/Manifest/__tests__/ManageManifestModal.test.js +3 -0
  85. data/webpack/scenes/Subscriptions/Manifest/__tests__/ManifestActions.test.js +20 -8
  86. data/webpack/scenes/Subscriptions/Manifest/__tests__/ManifestHistoryReducer.test.js +3 -1
  87. data/webpack/scenes/Subscriptions/Manifest/__tests__/__snapshots__/ManageManifestModal.test.js.snap +34 -7
  88. data/webpack/scenes/Subscriptions/Manifest/__tests__/manifest.fixtures.js +9 -16
  89. data/webpack/scenes/Subscriptions/Manifest/index.js +1 -0
  90. data/webpack/scenes/Subscriptions/SubscriptionActions.js +5 -26
  91. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +1 -0
  92. data/webpack/scenes/Subscriptions/SubscriptionHelpers.js +3 -0
  93. data/webpack/scenes/Subscriptions/SubscriptionReducer.js +11 -4
  94. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +31 -36
  95. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsActions.js +3 -12
  96. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +57 -27
  97. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsReducer.js +2 -3
  98. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsTableSchema.js +10 -5
  99. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsActions.test.js +10 -5
  100. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsPage.test.js +50 -5
  101. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsReducer.test.js +8 -3
  102. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/__snapshots__/UpstreamSubscriptionsPage.test.js.snap +21 -11
  103. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/upstreamSubscriptions.fixtures.js +5 -8
  104. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsPage.test.js +2 -0
  105. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsReducer.test.js +9 -3
  106. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +14 -2
  107. data/webpack/scenes/Subscriptions/__tests__/subscriptions.fixtures.js +11 -17
  108. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/EntitlementsInlineEditFormatter.js +8 -5
  109. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTable.js +45 -58
  110. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableHelpers.js +11 -4
  111. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableSchema.js +2 -2
  112. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/EntitlementsInlineEditFormatter.test.js +110 -0
  113. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/SubscriptionsTable.test.js +16 -3
  114. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/EntitlementsInlineEditFormatter.test.js.snap +228 -0
  115. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionsTable.test.js.snap +392 -365
  116. data/webpack/scenes/Subscriptions/index.js +1 -0
  117. data/webpack/scenes/Tasks/helpers.js +52 -0
  118. data/webpack/services/api/index.js +17 -1
  119. data/webpack/services/api/testHelpers.js +28 -0
  120. data/webpack/test_setup.js +2 -0
  121. metadata +24 -5
  122. data/config/katello.yaml +0 -89
  123. data/webpack/services/api/fixtures.js +0 -353
@@ -1,9 +1,9 @@
1
1
  const repoTypeSearchQueryMap = {
2
- rpm: '(name ~ rpms) and (name !~ source rpm) and (name !~ debug rpm)',
3
- sourceRpm: 'name ~ source rpm',
4
- debugRpm: 'name ~ debug rpm',
5
- kickstart: 'name ~ kickstart',
6
- ostree: 'name ~ ostree',
2
+ rpm: '(name !~ source rpm) and (name !~ debug rpm) and (content_type = yum)',
3
+ sourceRpm: '(name ~ source rpm) and (content_type = yum)',
4
+ debugRpm: '(name ~ debug rpm) and (content_type = yum)',
5
+ kickstart: 'content_type = kickstart',
6
+ ostree: 'content_type = ostree',
7
7
  beta: 'name ~ beta',
8
8
  };
9
9
 
@@ -28,7 +28,7 @@ export const loadRepositorySets = (extendedParams = {}) => (dispatch, getState)
28
28
  ]);
29
29
 
30
30
  const params = {
31
- ...{ organization_id: orgId() },
31
+ ...{ organization_id: orgId(), with_active_subscription: true },
32
32
  ...propsToSnakeCase(extendedParams),
33
33
  search,
34
34
  };
@@ -17,3 +17,9 @@ export const REPOSITORY_SETS_UPDATE_RECOMMENDED = 'REPOSITORY_SETS_UPDATE_RECOMM
17
17
 
18
18
  export const REPOSITORY_ENABLED = 'REPOSITORY_ENABLED';
19
19
  export const REPOSITORY_DISABLED = 'REPOSITORY_DISABLED';
20
+
21
+ export const GET_ORGANIZATIONS_LIST_SUCCESS = 'GET_ORGANIZATIONS_LIST_SUCCESS';
22
+ export const GET_ORGANIZATIONS_LIST_FAILURE = 'GET_ORGANIZATIONS_LIST_FAILURE';
23
+ export const CHANGE_CURRENT_ORGANIZATION_SUCCESS = 'CHANGE_CURRENT_ORGANIZATION_SUCCESS';
24
+ export const CHANGE_CURRENT_ORGANIZATION_FAILURE = 'CHANGE_CURRENT_ORGANIZATION_FAILURE';
25
+ export const GET_ORGANIZATIONS_LIST_REQUEST = 'GET_ORGANIZATIONS_LIST_REQUEST';
@@ -5,6 +5,7 @@ import { subscriptions } from '../../scenes/Subscriptions';
5
5
  import { upstreamSubscriptions } from '../../scenes/Subscriptions/UpstreamSubscriptions';
6
6
  import { manifestHistory } from '../../scenes/Subscriptions/Manifest';
7
7
  import { subscriptionDetails } from '../../scenes/Subscriptions/Details';
8
+ import { setOrganization } from '../../components/SelectOrg/SetOrganization';
8
9
 
9
10
  export default combineReducers({
10
11
  organization,
@@ -13,4 +14,5 @@ export default combineReducers({
13
14
  upstreamSubscriptions,
14
15
  manifestHistory,
15
16
  subscriptionDetails,
17
+ setOrganization,
16
18
  });
@@ -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
  }
@@ -4,9 +4,9 @@ import {
4
4
  SUBSCRIPTION_DETAILS_SUCCESS,
5
5
  SUBSCRIPTION_DETAILS_FAILURE,
6
6
  } from './SubscriptionDetailConstants';
7
- import { getResponseError } from '../../../move_to_foreman/common/helpers.js';
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
@@ -17,12 +17,7 @@ export const loadSubscriptionDetails = subscriptionId => (dispatch) => {
17
17
  response: data,
18
18
  });
19
19
  })
20
- .catch((result) => {
21
- dispatch({
22
- type: SUBSCRIPTION_DETAILS_FAILURE,
23
- error: getResponseError(result.response),
24
- });
25
- });
20
+ .catch(result => dispatch(apiError(SUBSCRIPTION_DETAILS_FAILURE, result)));
26
21
  };
27
22
 
28
23
  export default loadSubscriptionDetails;
@@ -1,15 +1,17 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
+ import { ListGroup, ListGroupItem } from 'patternfly-react';
4
+ import './SubscriptionDetails.scss';
3
5
 
4
6
  const SubscriptionDetailProducts = ({ subscriptionDetails }) => (
5
7
  <div>
6
8
  <h2>{__('Provided Products')}</h2>
7
- <ul>
9
+ <ListGroup className="scrolld-list">
8
10
  {subscriptionDetails.provided_products &&
9
11
  subscriptionDetails.provided_products.map(prod => (
10
- <li key={prod.id}>{prod.name}</li>
12
+ <ListGroupItem key={prod.id}> {prod.name} </ListGroupItem>
11
13
  ))}
12
- </ul>
14
+ </ListGroup>
13
15
  </div>
14
16
  );
15
17
 
@@ -26,7 +26,7 @@ export default (state = initialState, action) => {
26
26
 
27
27
  case SUBSCRIPTION_DETAILS_FAILURE: {
28
28
  return state.merge({
29
- error: action.error,
29
+ error: action.payload.message,
30
30
  loading: false,
31
31
  });
32
32
  }
@@ -1,33 +1,70 @@
1
1
  import React, { Component } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { Grid, Row, Col } from 'patternfly-react';
4
+ import BreadcrumbsBar from 'foremanReact/components/BreadcrumbBar';
4
5
  import SubscriptionDetailInfo from './SubscriptionDetailInfo';
5
6
  import SubscriptionDetailAssociations from './SubscriptionDetailAssociations';
6
7
  import SubscriptionDetailProducts from './SubscriptionDetailProducts';
7
8
  import { LoadingState } from '../../../move_to_pf/LoadingState';
8
9
  import { notify } from '../../../move_to_foreman/foreman_toast_notifications';
10
+ import api from '../../../services/api';
9
11
 
10
12
  class SubscriptionDetails extends Component {
13
+ constructor() {
14
+ super();
15
+ this.handleBreadcrumbSwitcherItem = this.handleBreadcrumbSwitcherItem.bind(this);
16
+ }
11
17
  componentDidMount() {
12
18
  // eslint-disable-next-line react/prop-types
13
19
  const routerParams = this.props.match.params;
14
20
  this.props.loadSubscriptionDetails(parseInt(routerParams.id, 10));
15
21
  }
16
22
 
23
+ componentDidUpdate(prevProps) {
24
+ const routerParams = this.props.match.params;
25
+ if (routerParams.id !== prevProps.match.params.id) {
26
+ this.props.loadSubscriptionDetails(parseInt(routerParams.id, 10));
27
+ }
28
+ }
29
+
30
+ handleBreadcrumbSwitcherItem(e, url) {
31
+ this.props.history.push(url);
32
+ e.preventDefault();
33
+ }
34
+
17
35
  render() {
18
36
  const { subscriptionDetails } = this.props;
37
+ const resource = {
38
+ nameField: 'name',
39
+ resourceUrl: api.getApiUrl('/subscriptions'),
40
+ switcherItemUrl: '/subscriptions/:id',
41
+ };
19
42
 
20
- if (subscriptionDetails.error) { notify({ message: subscriptionDetails.error }); }
43
+ if (subscriptionDetails.error) {
44
+ notify({ message: subscriptionDetails.error });
45
+ }
21
46
 
22
47
  return (
23
48
  <Grid bsClass="container-fluid">
49
+ {!subscriptionDetails.loading && <BreadcrumbsBar
50
+ onSwitcherItemClick={(e, url) => this.handleBreadcrumbSwitcherItem(e, url)}
51
+ data={{
52
+ isSwitchable: true,
53
+ breadcrumbItems: [
54
+ {
55
+ caption: __('Subscriptions'),
56
+ onClick: () =>
57
+ this.props.history.push('/subscriptions'),
58
+ },
59
+ {
60
+ caption: String(subscriptionDetails.name),
61
+ },
62
+ ],
63
+ resource,
64
+ }}
65
+ />}
24
66
  <div>
25
67
  <LoadingState loading={subscriptionDetails.loading} loadingText={__('Loading')}>
26
- <Row>
27
- <Col sm={12}>
28
- <h1>{subscriptionDetails.name}</h1>
29
- </Col>
30
- </Row>
31
68
  <Row>
32
69
  <Col sm={6}>
33
70
  <SubscriptionDetailInfo
@@ -53,6 +90,7 @@ class SubscriptionDetails extends Component {
53
90
  SubscriptionDetails.propTypes = {
54
91
  loadSubscriptionDetails: PropTypes.func.isRequired,
55
92
  subscriptionDetails: PropTypes.shape({}).isRequired,
93
+ history: PropTypes.shape({ push: PropTypes.func.isRequired }).isRequired,
56
94
  };
57
95
 
58
96
  export default SubscriptionDetails;
@@ -0,0 +1,4 @@
1
+ .scrolld-list {
2
+ max-height: 400px;
3
+ overflow-y: auto;
4
+ }
@@ -30,7 +30,9 @@ describe('subscriptions reducer', () => {
30
30
  const error = 'nothing worked';
31
31
  expect(reducer(initialState, {
32
32
  type: types.SUBSCRIPTION_DETAILS_FAILURE,
33
- error,
33
+ payload: {
34
+ message: error,
35
+ },
34
36
  })).toEqual({
35
37
  ...initialState,
36
38
  error,
@@ -13,13 +13,14 @@ jest.mock('../../../../move_to_foreman/foreman_toast_notifications');
13
13
  describe('subscriptions details page', () => {
14
14
  it('should render and contain appropiate components', async () => {
15
15
  const match = { params: { id: 1 } };
16
+ const noop = () => {};
16
17
 
17
18
  const wrapper = shallow(<SubscriptionDetails
18
19
  loadSubscriptionDetails={loadSubscriptionDetails}
19
20
  subscriptionDetails={successState}
21
+ history={{ push: noop }}
20
22
  match={match}
21
23
  />);
22
- expect(wrapper.find('h1').text()).toEqual(successState.name);
23
24
  expect(wrapper.find(SubscriptionDetailAssociations)).toHaveLength(1);
24
25
  expect(wrapper.find(SubscriptionDetailInfo)).toHaveLength(1);
25
26
  expect(wrapper.find(SubscriptionDetailProducts)).toHaveLength(1);