katello 3.7.0.rc2 → 3.7.0

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/v2/repository_sets_controller.rb +10 -1
  3. data/app/models/katello/glue/candlepin/owner.rb +0 -8
  4. data/app/models/katello/product_content.rb +4 -1
  5. data/app/services/katello/ui_notifications/pulp/proxy_disk_space.rb +3 -1
  6. data/app/views/overrides/activation_keys/_host_environment_select.html.erb +1 -1
  7. data/lib/katello/version.rb +1 -1
  8. data/package.json +2 -1
  9. data/webpack/__mocks__/foremanReact/components/BreadcrumbBar.js +3 -0
  10. data/webpack/__mocks__/foremanReact/redux/actions/toasts.js +6 -0
  11. data/webpack/mockRequest.js +3 -3
  12. data/webpack/move_to_foreman/common/helpers.js +45 -8
  13. data/webpack/redux/actions/RedHatRepositories/sets.js +1 -1
  14. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailActions.js +2 -7
  15. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailReducer.js +1 -1
  16. data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.js +44 -6
  17. data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailReducer.test.js +3 -1
  18. data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetails.test.js +0 -1
  19. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +22 -14
  20. data/webpack/scenes/Subscriptions/Details/__tests__/subscriptionDetails.fixtures.js +3 -4
  21. data/webpack/scenes/Subscriptions/Details/index.js +2 -2
  22. data/webpack/scenes/Subscriptions/Manifest/ManifestActions.js +5 -24
  23. data/webpack/scenes/Subscriptions/Manifest/ManifestHistoryReducer.js +1 -1
  24. data/webpack/scenes/Subscriptions/Manifest/__tests__/ManifestActions.test.js +20 -8
  25. data/webpack/scenes/Subscriptions/Manifest/__tests__/ManifestHistoryReducer.test.js +3 -1
  26. data/webpack/scenes/Subscriptions/Manifest/__tests__/manifest.fixtures.js +9 -16
  27. data/webpack/scenes/Subscriptions/SubscriptionActions.js +5 -26
  28. data/webpack/scenes/Subscriptions/SubscriptionReducer.js +6 -2
  29. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +13 -10
  30. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsActions.js +3 -12
  31. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +55 -20
  32. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsReducer.js +2 -3
  33. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsTableSchema.js +10 -5
  34. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsActions.test.js +10 -5
  35. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsPage.test.js +50 -5
  36. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsReducer.test.js +8 -3
  37. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/__snapshots__/UpstreamSubscriptionsPage.test.js.snap +18 -5
  38. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/upstreamSubscriptions.fixtures.js +5 -8
  39. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsReducer.test.js +9 -3
  40. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +1 -0
  41. data/webpack/scenes/Subscriptions/__tests__/subscriptions.fixtures.js +10 -14
  42. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTable.js +16 -39
  43. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableHelpers.js +2 -2
  44. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/SubscriptionsTable.test.js +1 -0
  45. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionsTable.test.js.snap +349 -355
  46. data/webpack/scenes/Subscriptions/index.js +1 -2
  47. data/webpack/services/api/testHelpers.js +28 -0
  48. metadata +7 -5
  49. data/webpack/services/api/fixtures.js +0 -353
@@ -38,7 +38,7 @@ export default (state = initialState, action) => {
38
38
 
39
39
  case UPSTREAM_SUBSCRIPTIONS_FAILURE:
40
40
  return state.merge({
41
- error: action.error,
41
+ error: action.payload.message,
42
42
  loading: false,
43
43
  });
44
44
 
@@ -49,8 +49,7 @@ export default (state = initialState, action) => {
49
49
  return state.set('task', action.response).set('loading', false);
50
50
 
51
51
  case SAVE_UPSTREAM_SUBSCRIPTIONS_FAILURE: {
52
- const error = action.result.response.data;
53
- return state.set('error', error).set('loading', false);
52
+ return state.set('error', action.payload.message).set('loading', false);
54
53
  }
55
54
 
56
55
  default:
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
2
+ import { FormGroup, FormControl, ControlLabel, HelpBlock } from 'react-bootstrap';
3
3
  import helpers from '../../../move_to_foreman/common/helpers';
4
4
  import {
5
5
  headerFormatter,
@@ -71,7 +71,7 @@ export const columns = (controller, selectionController) => [
71
71
  },
72
72
  },
73
73
  {
74
- property: 'quantity',
74
+ property: 'available',
75
75
  header: {
76
76
  label: __('Available Entitlements'),
77
77
  formatters: [headerFormatter],
@@ -96,22 +96,27 @@ export const columns = (controller, selectionController) => [
96
96
  formatters: [
97
97
  (value, { rowData }) => (
98
98
  <td>
99
- <FormGroup>
99
+ <FormGroup
100
+ validationState={controller.quantityValidationInput(rowData)}
101
+ >
100
102
  <ControlLabel srOnly>{__('Number to Allocate')}</ControlLabel>
101
103
  <FormControl
102
104
  type="text"
103
105
  onBlur={e => controller.onChange(e.target.value, rowData)}
104
106
  defaultValue={rowData.updatedQuantity}
107
+ onChange={(e) => {
108
+ controller.onChange(e.target.value, rowData);
109
+ }}
105
110
  onKeyDown={(e) => {
106
111
  const key = e.charCode ? e.charCode : e.keyCode;
107
112
  if (key === 13) {
108
- controller.onChange(e.target.value, rowData);
109
113
  controller.saveUpstreamSubscriptions();
110
114
  e.preventDefault();
111
115
  }
112
116
  }}
113
117
  />
114
- <div>{__('Max')} {rowData.quantity}</div>
118
+ {controller.quantityValidationInput(rowData) === 'error' &&
119
+ <HelpBlock>{controller.quantityValidation(rowData)[1]}</HelpBlock>}
115
120
  </FormGroup>
116
121
  </td>
117
122
  ),
@@ -1,5 +1,3 @@
1
- import axios from 'axios';
2
- import MockAdapter from 'axios-mock-adapter';
3
1
  import configureMockStore from 'redux-mock-store';
4
2
  import thunk from 'redux-thunk';
5
3
  import Immutable from 'seamless-immutable';
@@ -13,10 +11,10 @@ import {
13
11
  import { getTaskSuccessResponse } from '../../../Tasks/__tests__/task.fixtures';
14
12
 
15
13
  import { loadUpstreamSubscriptions, saveUpstreamSubscriptions } from '../UpstreamSubscriptionsActions';
14
+ import { mock as mockApi, mockErrorRequest } from '../../../../mockRequest';
16
15
 
17
16
  const mockStore = configureMockStore([thunk]);
18
17
  const store = mockStore({ subscriptions: Immutable({}) });
19
- const mockApi = new MockAdapter(axios);
20
18
 
21
19
  afterEach(() => {
22
20
  store.clearActions();
@@ -28,7 +26,10 @@ describe('upstream subscription actions', () => {
28
26
 
29
27
  describe('creates UPSTREAM_SUBSCRIPTIONS_REQUEST', () => {
30
28
  it('and then fails with 422', () => {
31
- mockApi.onGet(url).reply(422);
29
+ mockErrorRequest({
30
+ url,
31
+ status: 422,
32
+ });
32
33
 
33
34
  return store.dispatch(loadUpstreamSubscriptions())
34
35
  .then(() => expect(store.getActions()).toEqual(getFailureActions));
@@ -48,7 +49,11 @@ describe('upstream subscription actions', () => {
48
49
  };
49
50
 
50
51
  it('and then fails with 422', () => {
51
- mockApi.onPost(url).reply(422);
52
+ mockErrorRequest({
53
+ url,
54
+ status: 422,
55
+ method: 'POST',
56
+ });
52
57
 
53
58
  return store.dispatch(saveUpstreamSubscriptions(subscriptionData))
54
59
  .then(() => expect(store.getActions()).toEqual(saveFailureActions));
@@ -6,17 +6,62 @@ import { successState } from './upstreamSubscriptions.fixtures';
6
6
  import { loadUpstreamSubscriptions, saveUpstreamSubscriptions } from '../UpstreamSubscriptionsActions';
7
7
 
8
8
  jest.mock('../../../../move_to_foreman/foreman_toast_notifications');
9
+ jest.mock('foremanReact/components/BreadcrumbBar');
9
10
 
10
11
  describe('upstream subscriptions page', () => {
11
- const mockHistory = { push: () => {} };
12
-
13
- it('should render', async () => {
14
- const page = shallow(<UpstreamSubscriptionsPage
12
+ let shallowWrapper;
13
+ beforeEach(() => {
14
+ shallowWrapper = shallow(<UpstreamSubscriptionsPage
15
15
  upstreamSubscriptions={successState}
16
16
  loadUpstreamSubscriptions={loadUpstreamSubscriptions}
17
17
  saveUpstreamSubscriptions={saveUpstreamSubscriptions}
18
18
  history={mockHistory}
19
19
  />);
20
- expect(toJson(page)).toMatchSnapshot();
20
+ });
21
+ const mockHistory = { push: () => {} };
22
+
23
+ it('should render', async () => {
24
+ expect(toJson(shallowWrapper)).toMatchSnapshot();
25
+ });
26
+
27
+ it('should validate correct subscription quantities', async () => {
28
+ const validPools = [
29
+ { available: 10, updatedQuantity: 5 },
30
+ { available: 10, updatedQuantity: '5' },
31
+ { available: 10, updatedQuantity: '10' },
32
+ { available: 10, updatedQuantity: '1' },
33
+ { available: -1, updatedQuantity: '1000' },
34
+ ];
35
+ validPools.forEach((pool, i) => {
36
+ // using object with index attribute to print out index on failure,
37
+ // jest doesn't support messages on failure :(
38
+ const result = shallowWrapper.instance().quantityValidation(pool)[0];
39
+ expect({ index: i, result }).toEqual({ index: i, result: true });
40
+ });
41
+ });
42
+
43
+ it('should invalidate incorrect subscription quantities', async () => {
44
+ const invalidPools = [
45
+ { available: 10, updatedQuantity: 11 },
46
+ { available: 10, updatedQuantity: 'foo' },
47
+ { available: 10, updatedQuantity: 0 },
48
+ { available: 10, updatedQuantity: '0' },
49
+ { available: 10, updatedQuantity: '11' },
50
+ { available: 10, updatedQuantity: '2.0' },
51
+ { available: 10, updatedQuantity: '2/3' },
52
+ { available: -1, updatedQuantity: '-1' },
53
+ { available: -1, updatedQuantity: '0' },
54
+ { available: -1, updatedQuantity: 'foo' },
55
+ { available: -1, updatedQuantity: '2/3' },
56
+ { available: -1, updatedQuantity: '2.0' },
57
+ { available: -1, updatedQuantity: '99999999999' },
58
+ ];
59
+
60
+ invalidPools.forEach((pool, i) => {
61
+ // using object with index attribute to print out index on failure,
62
+ // jest doesn't support messages on failure :(
63
+ const result = shallowWrapper.instance().quantityValidation(pool)[0];
64
+ expect({ index: i, result }).toEqual({ index: i, result: false });
65
+ });
21
66
  });
22
67
  });
@@ -37,7 +37,9 @@ describe('upstream subscriptions reducer', () => {
37
37
  it('should have error on UPSTREAM_SUBSCRIPTIONS_FAILURE', () => {
38
38
  expect(reducer(initialState, {
39
39
  type: types.UPSTREAM_SUBSCRIPTIONS_FAILURE,
40
- error: 'Unable to process request.',
40
+ payload: {
41
+ message: 'Unable to process request.',
42
+ },
41
43
  })).toEqual(errorState);
42
44
  });
43
45
 
@@ -48,10 +50,13 @@ describe('upstream subscriptions reducer', () => {
48
50
  })).toEqual(saveSuccessState);
49
51
  });
50
52
 
51
- it('should have error on SAVE_UPSTREAM_SUBSCRIPTIONS_SUCCESS', () => {
53
+ it('should have error on SAVE_UPSTREAM_SUBSCRIPTIONS_FAILURE', () => {
52
54
  expect(reducer(initialSaveState, {
53
55
  type: types.SAVE_UPSTREAM_SUBSCRIPTIONS_FAILURE,
54
- result: errorResult,
56
+ payload: {
57
+ message: 'Unable to process request.',
58
+ result: errorResult,
59
+ },
55
60
  })).toEqual(saveErrorState);
56
61
  });
57
62
  });
@@ -6,9 +6,22 @@ exports[`upstream subscriptions page should render 1`] = `
6
6
  componentClass="div"
7
7
  fluid={false}
8
8
  >
9
- <h1>
10
- Add Subscriptions
11
- </h1>
9
+ <BreadcrumbsBar
10
+ data={
11
+ Object {
12
+ "breadcrumbItems": Array [
13
+ Object {
14
+ "caption": "Subscriptions",
15
+ "onClick": [Function],
16
+ },
17
+ Object {
18
+ "caption": "Add Subscriptions",
19
+ },
20
+ ],
21
+ "isSwitchable": false,
22
+ }
23
+ }
24
+ />
12
25
  <LoadingState
13
26
  loading={false}
14
27
  loadingText="Loading"
@@ -107,7 +120,7 @@ exports[`upstream subscriptions page should render 1`] = `
107
120
  ],
108
121
  "label": "Available Entitlements",
109
122
  },
110
- "property": "quantity",
123
+ "property": "available",
111
124
  },
112
125
  Object {
113
126
  "cell": Object {
@@ -193,7 +206,7 @@ exports[`upstream subscriptions page should render 1`] = `
193
206
  block={false}
194
207
  bsClass="btn"
195
208
  bsStyle="primary"
196
- disabled={false}
209
+ disabled={true}
197
210
  onClick={[Function]}
198
211
  type="submit"
199
212
  >
@@ -1,5 +1,6 @@
1
1
  import Immutable from 'seamless-immutable';
2
2
  import { getTaskSuccessResponse } from '../../../Tasks/__tests__/task.fixtures';
3
+ import { toastErrorAction, failureAction } from '../../../../services/api/testHelpers';
3
4
 
4
5
  export const initialState = Immutable({
5
6
  loading: true,
@@ -135,10 +136,8 @@ export const getFailureActions = [
135
136
  {
136
137
  type: 'UPSTREAM_SUBSCRIPTIONS_REQUEST',
137
138
  },
138
- {
139
- result: new Error('Request failed with status code 422'),
140
- type: 'UPSTREAM_SUBSCRIPTIONS_FAILURE',
141
- },
139
+ failureAction('UPSTREAM_SUBSCRIPTIONS_FAILURE'),
140
+ toastErrorAction(),
142
141
  ];
143
142
 
144
143
  export const saveSuccessActions = [
@@ -155,8 +154,6 @@ export const saveFailureActions = [
155
154
  {
156
155
  type: 'SAVE_UPSTREAM_SUBSCRIPTIONS_REQUEST',
157
156
  },
158
- {
159
- result: new Error('Request failed with status code 422'),
160
- type: 'SAVE_UPSTREAM_SUBSCRIPTIONS_FAILURE',
161
- },
157
+ failureAction('SAVE_UPSTREAM_SUBSCRIPTIONS_FAILURE'),
158
+ toastErrorAction(),
162
159
  ];
@@ -34,14 +34,18 @@ describe('subscriptions reducer', () => {
34
34
  it('should have error on SUBSCRIPTIONS_FAILURE', () => {
35
35
  expect(reducer(initialState, {
36
36
  type: types.SUBSCRIPTIONS_FAILURE,
37
- error: 'Unable to process request.',
37
+ payload: {
38
+ message: 'Unable to process request.',
39
+ },
38
40
  })).toEqual(errorState);
39
41
  });
40
42
 
41
43
  it('should have error on UPDATE_QUANTITY_FAILURE', () => {
42
44
  expect(reducer(initialState, {
43
45
  type: types.UPDATE_QUANTITY_FAILURE,
44
- error: 'Unable to process request.',
46
+ payload: {
47
+ message: 'Unable to process request.',
48
+ },
45
49
  })).toEqual(errorState);
46
50
  });
47
51
 
@@ -61,7 +65,9 @@ describe('subscriptions reducer', () => {
61
65
  it('should have error on SUBSCRIPTIONS_QUANTITIES_FAILURE', () => {
62
66
  expect(reducer(successState, {
63
67
  type: types.SUBSCRIPTIONS_QUANTITIES_FAILURE,
64
- error: 'Unable to process request.',
68
+ payload: {
69
+ message: 'Unable to process request.',
70
+ },
65
71
  })).toEqual(quantitiesErrorState);
66
72
  });
67
73
  });
@@ -181,6 +181,7 @@ exports[`subscriptions page should render 1`] = `
181
181
  ],
182
182
  "search": undefined,
183
183
  "searchIsActive": false,
184
+ "tasks": Array [],
184
185
  }
185
186
  }
186
187
  toggleDeleteButton={[Function]}
@@ -1,4 +1,5 @@
1
1
  import Immutable from 'seamless-immutable';
2
+ import { toastErrorAction, failureAction } from '../../../services/api/testHelpers';
2
3
 
3
4
  export const initialState = Immutable({
4
5
  loading: true,
@@ -10,6 +11,7 @@ export const initialState = Immutable({
10
11
  itemCount: 0,
11
12
  quantitiesLoading: false,
12
13
  availableQuantities: {},
14
+ tasks: [],
13
15
  });
14
16
 
15
17
  export const loadingState = Immutable({
@@ -242,11 +244,11 @@ export const successState = Immutable({
242
244
  itemCount: 81,
243
245
  quantitiesLoading: false,
244
246
  availableQuantities: {},
247
+ tasks: [],
245
248
  });
246
249
 
247
250
  export const errorState = Immutable({
248
251
  loading: false,
249
- error: 'Unable to process request.',
250
252
  pagination: {
251
253
  page: 0,
252
254
  perPage: 20,
@@ -255,6 +257,7 @@ export const errorState = Immutable({
255
257
  results: [],
256
258
  quantitiesLoading: false,
257
259
  availableQuantities: {},
260
+ tasks: [],
258
261
  });
259
262
 
260
263
  export const quantitiesSuccessState = Immutable({
@@ -275,7 +278,6 @@ export const loadingQuantitiesState = Immutable({
275
278
  export const quantitiesErrorState = Immutable({
276
279
  ...successState,
277
280
  quantitiesLoading: false,
278
- quantitiesError: 'Unable to process request.',
279
281
  });
280
282
 
281
283
  export const successActions = [
@@ -307,10 +309,8 @@ export const failureActions = [
307
309
  {
308
310
  type: 'SUBSCRIPTIONS_REQUEST',
309
311
  },
310
- {
311
- error: 'Request failed with status code 422',
312
- type: 'SUBSCRIPTIONS_FAILURE',
313
- },
312
+ failureAction('SUBSCRIPTIONS_FAILURE'),
313
+ toastErrorAction(),
314
314
  ];
315
315
 
316
316
  export const poolsUpdate = [{
@@ -337,20 +337,16 @@ export const updateQuantityFailureActions = [
337
337
  type: 'UPDATE_QUANTITY_REQUEST',
338
338
  quantities: poolsUpdate,
339
339
  },
340
- {
341
- error: 'Request failed with status code 422',
342
- type: 'UPDATE_QUANTITY_FAILURE',
343
- },
340
+ failureAction('UPDATE_QUANTITY_FAILURE'),
341
+ toastErrorAction(),
344
342
  ];
345
343
 
346
344
  export const loadQuantitiesFailureActions = [
347
345
  {
348
346
  type: 'SUBSCRIPTIONS_QUANTITIES_REQUEST',
349
347
  },
350
- {
351
- error: 'Request failed with status code 500',
352
- type: 'SUBSCRIPTIONS_QUANTITIES_FAILURE',
353
- },
348
+ failureAction('SUBSCRIPTIONS_QUANTITIES_FAILURE', 'Request failed with status code 500'),
349
+ toastErrorAction('Request failed with status code 500'),
354
350
  ];
355
351
 
356
352
  export const loadQuantitiesSuccessActions = [
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import classNames from 'classnames';
4
4
  import { sprintf } from 'jed';
5
5
  import { cloneDeep, findIndex, isEqual } from 'lodash';
6
- import { Table, Alert } from 'patternfly-react';
6
+ import { Table } from 'patternfly-react';
7
7
  import { LoadingState } from '../../../../move_to_pf/LoadingState';
8
8
  import { Table as ForemanTable, TableBody as ForemanTableBody } from '../../../../move_to_foreman/components/common/table';
9
9
  import ConfirmDialog from '../../../../move_to_foreman/components/common/ConfirmDialog';
@@ -25,23 +25,6 @@ const emptyStateData = {
25
25
  },
26
26
  };
27
27
 
28
- const ErrorAlerts = ({ errors }) => {
29
- const alerts = errors.filter(Boolean).map(e => (
30
- <Alert type={Alert.ALERT_TYPE_ERROR} key={e}>
31
- <span>{e}</span>
32
- </Alert>
33
- ));
34
-
35
- return (
36
- <div>
37
- {alerts}
38
- </div>
39
- );
40
- };
41
- ErrorAlerts.propTypes = {
42
- errors: PropTypes.arrayOf(PropTypes.string).isRequired,
43
- };
44
-
45
28
  class SubscriptionsTable extends Component {
46
29
  constructor(props) {
47
30
  super(props);
@@ -49,7 +32,7 @@ class SubscriptionsTable extends Component {
49
32
  this.state = {
50
33
  rows: undefined,
51
34
  subscriptions: undefined,
52
- groupdSubscriptions: undefined,
35
+ groupedSubscriptions: undefined,
53
36
  updatedQuantity: {},
54
37
  editing: false,
55
38
  showUpdateConfirmDialog: false,
@@ -64,14 +47,14 @@ class SubscriptionsTable extends Component {
64
47
  nextProps.subscriptions !== undefined &&
65
48
  !isEqual(nextProps.subscriptions, prevState.subscriptions)
66
49
  ) {
67
- const groupdSubscriptions = groupSubscriptionsByProductId(nextProps.subscriptions);
50
+ const groupedSubscriptions = groupSubscriptionsByProductId(nextProps.subscriptions);
68
51
  const rows = buildTableRows(
69
- groupdSubscriptions,
52
+ groupedSubscriptions,
70
53
  nextProps.subscriptions.availableQuantities,
71
54
  prevState.updatedQuantity,
72
55
  );
73
56
 
74
- return { rows, groupdSubscriptions, subscriptions: nextProps.subscriptions };
57
+ return { rows, groupedSubscriptions, subscriptions: nextProps.subscriptions };
75
58
  }
76
59
 
77
60
  return null;
@@ -79,19 +62,19 @@ class SubscriptionsTable extends Component {
79
62
 
80
63
  toggleSubscriptionGroup(groupId) {
81
64
  const { subscriptions } = this.props;
82
- const { groupdSubscriptions, updatedQuantity } = this.state;
83
- const { open } = groupdSubscriptions[groupId];
65
+ const { groupedSubscriptions, updatedQuantity } = this.state;
66
+ const { open } = groupedSubscriptions[groupId];
84
67
 
85
- groupdSubscriptions[groupId].open = !open;
68
+ groupedSubscriptions[groupId].open = !open;
86
69
 
87
70
 
88
71
  const rows = buildTableRows(
89
- groupdSubscriptions,
72
+ groupedSubscriptions,
90
73
  subscriptions.availableQuantities,
91
74
  updatedQuantity,
92
75
  );
93
76
 
94
- this.setState({ rows, groupdSubscriptions });
77
+ this.setState({ rows, groupedSubscriptions });
95
78
  }
96
79
 
97
80
  enableEditing(editingState) {
@@ -102,11 +85,11 @@ class SubscriptionsTable extends Component {
102
85
  }
103
86
 
104
87
  updateRows(updatedQuantity) {
105
- const { groupdSubscriptions } = this.state;
88
+ const { groupedSubscriptions } = this.state;
106
89
  const { subscriptions } = this.props;
107
90
 
108
91
  const rows = buildTableRows(
109
- groupdSubscriptions,
92
+ groupedSubscriptions,
110
93
  subscriptions.availableQuantities,
111
94
  updatedQuantity,
112
95
  );
@@ -158,15 +141,15 @@ class SubscriptionsTable extends Component {
158
141
 
159
142
  render() {
160
143
  const { subscriptions } = this.props;
161
- const { groupdSubscriptions } = this.state;
144
+ const { groupedSubscriptions } = this.state;
162
145
 
163
146
  const groupingController = {
164
147
  isCollapseable: ({ rowData }) =>
165
148
  // it is the first subscription in the group
166
- rowData.id === groupdSubscriptions[rowData.product_id].subscriptions[0].id &&
149
+ rowData.id === groupedSubscriptions[rowData.product_id].subscriptions[0].id &&
167
150
  // the group contains more then one subscription
168
- groupdSubscriptions[rowData.product_id].subscriptions.length > 1,
169
- isCollapsed: ({ rowData }) => !groupdSubscriptions[rowData.product_id].open,
151
+ groupedSubscriptions[rowData.product_id].subscriptions.length > 1,
152
+ isCollapsed: ({ rowData }) => !groupedSubscriptions[rowData.product_id].open,
170
153
  toggle: ({ rowData }) => this.toggleSubscriptionGroup(rowData.product_id),
171
154
  };
172
155
 
@@ -258,12 +241,6 @@ class SubscriptionsTable extends Component {
258
241
 
259
242
  return (
260
243
  <LoadingState loading={subscriptions.loading} loadingText={__('Loading')}>
261
- <ErrorAlerts
262
- errors={[
263
- subscriptions.error,
264
- subscriptions.quantitiesError,
265
- ]}
266
- />
267
244
  <ForemanTable
268
245
  columns={columnsDefinition}
269
246
  emptyState={emptyStateData}