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.
- checksums.yaml +4 -4
- data/app/controllers/katello/api/v2/repository_sets_controller.rb +10 -1
- data/app/models/katello/glue/candlepin/owner.rb +0 -8
- data/app/models/katello/product_content.rb +4 -1
- data/app/services/katello/ui_notifications/pulp/proxy_disk_space.rb +3 -1
- data/app/views/overrides/activation_keys/_host_environment_select.html.erb +1 -1
- data/lib/katello/version.rb +1 -1
- data/package.json +2 -1
- data/webpack/__mocks__/foremanReact/components/BreadcrumbBar.js +3 -0
- data/webpack/__mocks__/foremanReact/redux/actions/toasts.js +6 -0
- data/webpack/mockRequest.js +3 -3
- data/webpack/move_to_foreman/common/helpers.js +45 -8
- data/webpack/redux/actions/RedHatRepositories/sets.js +1 -1
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetailActions.js +2 -7
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetailReducer.js +1 -1
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.js +44 -6
- data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailReducer.test.js +3 -1
- data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetails.test.js +0 -1
- data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +22 -14
- data/webpack/scenes/Subscriptions/Details/__tests__/subscriptionDetails.fixtures.js +3 -4
- data/webpack/scenes/Subscriptions/Details/index.js +2 -2
- data/webpack/scenes/Subscriptions/Manifest/ManifestActions.js +5 -24
- data/webpack/scenes/Subscriptions/Manifest/ManifestHistoryReducer.js +1 -1
- data/webpack/scenes/Subscriptions/Manifest/__tests__/ManifestActions.test.js +20 -8
- data/webpack/scenes/Subscriptions/Manifest/__tests__/ManifestHistoryReducer.test.js +3 -1
- data/webpack/scenes/Subscriptions/Manifest/__tests__/manifest.fixtures.js +9 -16
- data/webpack/scenes/Subscriptions/SubscriptionActions.js +5 -26
- data/webpack/scenes/Subscriptions/SubscriptionReducer.js +6 -2
- data/webpack/scenes/Subscriptions/SubscriptionsPage.js +13 -10
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsActions.js +3 -12
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +55 -20
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsReducer.js +2 -3
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsTableSchema.js +10 -5
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsActions.test.js +10 -5
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsPage.test.js +50 -5
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsReducer.test.js +8 -3
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/__snapshots__/UpstreamSubscriptionsPage.test.js.snap +18 -5
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/upstreamSubscriptions.fixtures.js +5 -8
- data/webpack/scenes/Subscriptions/__tests__/SubscriptionsReducer.test.js +9 -3
- data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +1 -0
- data/webpack/scenes/Subscriptions/__tests__/subscriptions.fixtures.js +10 -14
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTable.js +16 -39
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableHelpers.js +2 -2
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/SubscriptionsTable.test.js +1 -0
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionsTable.test.js.snap +349 -355
- data/webpack/scenes/Subscriptions/index.js +1 -2
- data/webpack/services/api/testHelpers.js +28 -0
- metadata +7 -5
- data/webpack/services/api/fixtures.js +0 -353
@@ -1,5 +1,3 @@
|
|
1
|
-
import axios from 'axios';
|
2
|
-
import MockAdapter from 'axios-mock-adapter';
|
3
1
|
import thunk from 'redux-thunk';
|
4
2
|
import Immutable from 'seamless-immutable';
|
5
3
|
import configureMockStore from 'redux-mock-store';
|
@@ -15,12 +13,11 @@ import {
|
|
15
13
|
deleteManifestSuccessActions,
|
16
14
|
deleteManifestFailureActions,
|
17
15
|
} from './manifest.fixtures';
|
18
|
-
|
19
16
|
import { loadManifestHistory, uploadManifest, refreshManifest, deleteManifest } from '../ManifestActions';
|
17
|
+
import { mock as mockApi, mockErrorRequest } from '../../../../mockRequest';
|
20
18
|
|
21
19
|
const mockStore = configureMockStore([thunk]);
|
22
20
|
const store = mockStore({ manifest: Immutable({}) });
|
23
|
-
const mockApi = new MockAdapter(axios);
|
24
21
|
|
25
22
|
beforeEach(() => {
|
26
23
|
store.clearActions();
|
@@ -43,7 +40,10 @@ describe('manifest actions', () => {
|
|
43
40
|
const url = '/katello/api/v2/organizations/1/subscriptions/manifest_history';
|
44
41
|
|
45
42
|
it('and then fails with 422', () => {
|
46
|
-
|
43
|
+
mockErrorRequest({
|
44
|
+
url,
|
45
|
+
status: 422,
|
46
|
+
});
|
47
47
|
|
48
48
|
return store.dispatch(loadManifestHistory())
|
49
49
|
.then(() => expect(store.getActions()).toEqual(manifestHistoryFailureActions));
|
@@ -61,7 +61,11 @@ describe('manifest actions', () => {
|
|
61
61
|
const url = '/katello/api/v2/organizations/1/subscriptions/upload';
|
62
62
|
|
63
63
|
it('and then fails with 422', () => {
|
64
|
-
|
64
|
+
mockErrorRequest({
|
65
|
+
url,
|
66
|
+
status: 422,
|
67
|
+
method: 'POST',
|
68
|
+
});
|
65
69
|
|
66
70
|
return store.dispatch(uploadManifest())
|
67
71
|
.then(() => expect(store.getActions()).toEqual(uploadManifestFailureActions));
|
@@ -79,7 +83,11 @@ describe('manifest actions', () => {
|
|
79
83
|
const url = '/katello/api/v2/organizations/1/subscriptions/refresh_manifest';
|
80
84
|
|
81
85
|
it('and then fails with 422', () => {
|
82
|
-
|
86
|
+
mockErrorRequest({
|
87
|
+
url,
|
88
|
+
status: 422,
|
89
|
+
method: 'PUT',
|
90
|
+
});
|
83
91
|
|
84
92
|
return store.dispatch(refreshManifest())
|
85
93
|
.then(() => expect(store.getActions()).toEqual(refreshManifestFailureActions));
|
@@ -97,7 +105,11 @@ describe('manifest actions', () => {
|
|
97
105
|
const url = '/katello/api/v2/organizations/1/subscriptions/delete_manifest';
|
98
106
|
|
99
107
|
it('and then fails with 422', () => {
|
100
|
-
|
108
|
+
mockErrorRequest({
|
109
|
+
url,
|
110
|
+
status: 422,
|
111
|
+
method: 'POST',
|
112
|
+
});
|
101
113
|
|
102
114
|
return store.dispatch(deleteManifest())
|
103
115
|
.then(() => expect(store.getActions()).toEqual(deleteManifestFailureActions));
|
@@ -30,7 +30,9 @@ describe('manifest history reducer', () => {
|
|
30
30
|
it('should have error on MANIFEST_HISTORY_FAILURE', () => {
|
31
31
|
expect(reducer(manifestHistoryInitialState, {
|
32
32
|
type: types.MANIFEST_HISTORY_FAILURE,
|
33
|
-
|
33
|
+
payload: {
|
34
|
+
message: 'Unable to process request.',
|
35
|
+
},
|
34
36
|
})).toEqual(manifestHistoryErrorState);
|
35
37
|
});
|
36
38
|
});
|
@@ -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 manifestHistoryInitialState = Immutable({
|
4
5
|
loading: true,
|
@@ -149,10 +150,8 @@ export const manifestHistoryFailureActions = [
|
|
149
150
|
{
|
150
151
|
type: 'MANIFEST_HISTORY_REQUEST',
|
151
152
|
},
|
152
|
-
|
153
|
-
|
154
|
-
type: 'MANIFEST_HISTORY_FAILURE',
|
155
|
-
},
|
153
|
+
failureAction('MANIFEST_HISTORY_FAILURE'),
|
154
|
+
toastErrorAction(),
|
156
155
|
];
|
157
156
|
|
158
157
|
export const uploadManifestSuccessActions = [
|
@@ -169,10 +168,8 @@ export const uploadManifestFailureActions = [
|
|
169
168
|
{
|
170
169
|
type: 'UPLOAD_MANIFEST_REQUEST',
|
171
170
|
},
|
172
|
-
|
173
|
-
|
174
|
-
type: 'UPLOAD_MANIFEST_FAILURE',
|
175
|
-
},
|
171
|
+
failureAction('UPLOAD_MANIFEST_FAILURE'),
|
172
|
+
toastErrorAction(),
|
176
173
|
];
|
177
174
|
|
178
175
|
export const refreshManifestSuccessActions = [
|
@@ -189,10 +186,8 @@ export const refreshManifestFailureActions = [
|
|
189
186
|
{
|
190
187
|
type: 'REFRESH_MANIFEST_REQUEST',
|
191
188
|
},
|
192
|
-
|
193
|
-
|
194
|
-
type: 'REFRESH_MANIFEST_FAILURE',
|
195
|
-
},
|
189
|
+
failureAction('REFRESH_MANIFEST_FAILURE'),
|
190
|
+
toastErrorAction(),
|
196
191
|
];
|
197
192
|
|
198
193
|
export const deleteManifestSuccessActions = [
|
@@ -209,8 +204,6 @@ export const deleteManifestFailureActions = [
|
|
209
204
|
{
|
210
205
|
type: 'DELETE_MANIFEST_REQUEST',
|
211
206
|
},
|
212
|
-
|
213
|
-
|
214
|
-
type: 'DELETE_MANIFEST_FAILURE',
|
215
|
-
},
|
207
|
+
failureAction('DELETE_MANIFEST_FAILURE'),
|
208
|
+
toastErrorAction(),
|
216
209
|
];
|
@@ -16,7 +16,7 @@ import {
|
|
16
16
|
DELETE_SUBSCRIPTIONS_FAILURE,
|
17
17
|
} from './SubscriptionConstants';
|
18
18
|
import { filterRHSubscriptions } from './SubscriptionHelpers.js';
|
19
|
-
import {
|
19
|
+
import { apiError } from '../../move_to_foreman/common/helpers.js';
|
20
20
|
|
21
21
|
export const createSubscriptionParams = (extendedParams = {}) => ({
|
22
22
|
...{ organization_id: orgId() },
|
@@ -35,12 +35,7 @@ export const loadAvailableQuantities = (extendedParams = {}) => (dispatch) => {
|
|
35
35
|
response: data,
|
36
36
|
});
|
37
37
|
})
|
38
|
-
.catch(
|
39
|
-
dispatch({
|
40
|
-
type: SUBSCRIPTIONS_QUANTITIES_FAILURE,
|
41
|
-
error: getResponseError(result.response),
|
42
|
-
});
|
43
|
-
});
|
38
|
+
.catch(result => dispatch(apiError(SUBSCRIPTIONS_QUANTITIES_FAILURE, result)));
|
44
39
|
};
|
45
40
|
|
46
41
|
export const loadSubscriptions = (extendedParams = {}) => (dispatch) => {
|
@@ -60,12 +55,7 @@ export const loadSubscriptions = (extendedParams = {}) => (dispatch) => {
|
|
60
55
|
dispatch(loadAvailableQuantities({ poolIds }));
|
61
56
|
}
|
62
57
|
})
|
63
|
-
.catch(
|
64
|
-
dispatch({
|
65
|
-
type: SUBSCRIPTIONS_FAILURE,
|
66
|
-
error: getResponseError(result.response),
|
67
|
-
});
|
68
|
-
});
|
58
|
+
.catch(result => dispatch(apiError(SUBSCRIPTIONS_FAILURE, result)));
|
69
59
|
};
|
70
60
|
|
71
61
|
export const updateQuantity = (quantities = {}) => (dispatch) => {
|
@@ -83,12 +73,7 @@ export const updateQuantity = (quantities = {}) => (dispatch) => {
|
|
83
73
|
response: data,
|
84
74
|
});
|
85
75
|
})
|
86
|
-
.catch(
|
87
|
-
dispatch({
|
88
|
-
type: UPDATE_QUANTITY_FAILURE,
|
89
|
-
error: getResponseError(result.response),
|
90
|
-
});
|
91
|
-
});
|
76
|
+
.catch(result => dispatch(apiError(UPDATE_QUANTITY_FAILURE, result)));
|
92
77
|
};
|
93
78
|
|
94
79
|
export const deleteSubscriptions = poolIds => (dispatch) => {
|
@@ -106,13 +91,7 @@ export const deleteSubscriptions = poolIds => (dispatch) => {
|
|
106
91
|
response: data,
|
107
92
|
});
|
108
93
|
})
|
109
|
-
.catch(
|
110
|
-
dispatch({
|
111
|
-
type: DELETE_SUBSCRIPTIONS_FAILURE,
|
112
|
-
result,
|
113
|
-
});
|
114
|
-
});
|
94
|
+
.catch(result => dispatch(apiError(DELETE_SUBSCRIPTIONS_FAILURE, result)));
|
115
95
|
};
|
116
96
|
|
117
|
-
|
118
97
|
export default loadSubscriptions;
|
@@ -24,6 +24,7 @@ const initialState = Immutable({
|
|
24
24
|
...initialApiState,
|
25
25
|
quantitiesLoading: false,
|
26
26
|
availableQuantities: {},
|
27
|
+
tasks: [],
|
27
28
|
});
|
28
29
|
|
29
30
|
const mapQuantities = (pools) => {
|
@@ -72,10 +73,14 @@ export default (state = initialState, action) => {
|
|
72
73
|
return state.set('loading', false);
|
73
74
|
|
74
75
|
case SUBSCRIPTIONS_FAILURE:
|
76
|
+
return state
|
77
|
+
.set('loading', false)
|
78
|
+
.set('results', [])
|
79
|
+
.set('itemCount', 0);
|
80
|
+
|
75
81
|
case UPDATE_QUANTITY_FAILURE:
|
76
82
|
case DELETE_SUBSCRIPTIONS_FAILURE:
|
77
83
|
return state.merge({
|
78
|
-
error: action.error,
|
79
84
|
loading: false,
|
80
85
|
});
|
81
86
|
|
@@ -92,7 +97,6 @@ export default (state = initialState, action) => {
|
|
92
97
|
case SUBSCRIPTIONS_QUANTITIES_FAILURE: {
|
93
98
|
return state.merge({
|
94
99
|
quantitiesLoading: false,
|
95
|
-
quantitiesError: action.error,
|
96
100
|
});
|
97
101
|
}
|
98
102
|
|
@@ -38,36 +38,39 @@ class SubscriptionsPage extends Component {
|
|
38
38
|
}
|
39
39
|
|
40
40
|
static getDerivedStateFromProps(nextProps, prevState) {
|
41
|
-
const
|
41
|
+
const { tasks = [] } = nextProps;
|
42
|
+
const nextTaskId = tasks[0] && tasks[0].id;
|
42
43
|
|
43
|
-
if (
|
44
|
+
if (tasks.length === 0 && prevState.polledTask != null) {
|
44
45
|
return { showTaskModal: false, polledTask: undefined };
|
45
|
-
} else if (
|
46
|
+
} else if (tasks.length > 0 && nextTaskId !== prevState.polledTask) {
|
46
47
|
return {
|
47
48
|
showTaskModal: true,
|
48
49
|
manifestModalOpen: false,
|
49
|
-
polledTask:
|
50
|
+
polledTask: nextTaskId,
|
50
51
|
};
|
51
52
|
}
|
52
53
|
return null;
|
53
54
|
}
|
54
55
|
|
55
56
|
componentDidUpdate(prevProps) {
|
56
|
-
const { tasks } = this.props;
|
57
|
+
const { tasks = [] } = this.props;
|
58
|
+
const { tasks: prevTasks = [] } = prevProps;
|
59
|
+
|
57
60
|
const numberOfTasks = tasks.length;
|
58
|
-
const numberOfPrevTasks =
|
61
|
+
const numberOfPrevTasks = prevTasks.length;
|
59
62
|
let task;
|
60
63
|
|
61
64
|
if (numberOfTasks > 0) {
|
62
|
-
if (numberOfPrevTasks === 0 ||
|
63
|
-
[task] =
|
65
|
+
if (numberOfPrevTasks === 0 || prevTasks[0].id !== tasks[0].id) {
|
66
|
+
[task] = tasks;
|
64
67
|
this.handleDoneTask(task);
|
65
68
|
}
|
66
69
|
}
|
67
70
|
}
|
68
71
|
|
69
72
|
getDisabledReason(deleteButton) {
|
70
|
-
const { tasks, subscriptions } = this.props;
|
73
|
+
const { tasks = [], subscriptions } = this.props;
|
71
74
|
const { disconnected } = subscriptions;
|
72
75
|
let disabledReason = null;
|
73
76
|
|
@@ -132,7 +135,7 @@ class SubscriptionsPage extends Component {
|
|
132
135
|
}
|
133
136
|
|
134
137
|
render() {
|
135
|
-
const { tasks, subscriptions } = this.props;
|
138
|
+
const { tasks = [], subscriptions } = this.props;
|
136
139
|
const { disconnected } = subscriptions;
|
137
140
|
const taskInProgress = tasks.length > 0;
|
138
141
|
const disableManifestActions = taskInProgress || disconnected;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import api, { orgId } from '../../../services/api';
|
2
2
|
import { propsToSnakeCase } from '../../../services/index';
|
3
|
+
import { apiError } from '../../../move_to_foreman/common/helpers.js';
|
3
4
|
|
4
5
|
import {
|
5
6
|
UPSTREAM_SUBSCRIPTIONS_REQUEST,
|
@@ -27,12 +28,7 @@ export const loadUpstreamSubscriptions = (extendedParams = {}) => (dispatch) =>
|
|
27
28
|
search: extendedParams.search,
|
28
29
|
});
|
29
30
|
})
|
30
|
-
.catch(
|
31
|
-
dispatch({
|
32
|
-
type: UPSTREAM_SUBSCRIPTIONS_FAILURE,
|
33
|
-
result,
|
34
|
-
});
|
35
|
-
});
|
31
|
+
.catch(result => dispatch(apiError(UPSTREAM_SUBSCRIPTIONS_FAILURE, result)));
|
36
32
|
};
|
37
33
|
|
38
34
|
export const saveUpstreamSubscriptions = upstreamSubscriptions => (dispatch) => {
|
@@ -50,12 +46,7 @@ export const saveUpstreamSubscriptions = upstreamSubscriptions => (dispatch) =>
|
|
50
46
|
response: data,
|
51
47
|
});
|
52
48
|
})
|
53
|
-
.catch(
|
54
|
-
dispatch({
|
55
|
-
type: SAVE_UPSTREAM_SUBSCRIPTIONS_FAILURE,
|
56
|
-
result,
|
57
|
-
});
|
58
|
-
});
|
49
|
+
.catch(result => dispatch(apiError(SAVE_UPSTREAM_SUBSCRIPTIONS_FAILURE, result)));
|
59
50
|
};
|
60
51
|
|
61
52
|
export default loadUpstreamSubscriptions;
|
@@ -5,6 +5,7 @@ import PropTypes from 'prop-types';
|
|
5
5
|
import { LinkContainer } from 'react-router-bootstrap';
|
6
6
|
import { Grid, Row, Col } from 'react-bootstrap';
|
7
7
|
import { bindMethods, Button } from 'patternfly-react';
|
8
|
+
import BreadcrumbsBar from 'foremanReact/components/BreadcrumbBar';
|
8
9
|
import { LoadingState } from '../../../move_to_pf/LoadingState';
|
9
10
|
import { notify } from '../../../move_to_foreman/foreman_toast_notifications';
|
10
11
|
import helpers from '../../../move_to_foreman/common/helpers';
|
@@ -22,6 +23,7 @@ class UpstreamSubscriptionsPage extends Component {
|
|
22
23
|
bindMethods(this, [
|
23
24
|
'onChange',
|
24
25
|
'saveUpstreamSubscriptions',
|
26
|
+
'quantityValidationInput',
|
25
27
|
]);
|
26
28
|
}
|
27
29
|
|
@@ -31,18 +33,17 @@ class UpstreamSubscriptionsPage extends Component {
|
|
31
33
|
|
32
34
|
onChange(value, rowData) {
|
33
35
|
const { selectedRows } = this.state;
|
34
|
-
const newValue = parseInt(value, 10);
|
35
36
|
const pool = {
|
36
37
|
...rowData,
|
37
38
|
id: rowData.id,
|
38
|
-
updatedQuantity:
|
39
|
+
updatedQuantity: value,
|
39
40
|
selected: true,
|
40
41
|
};
|
41
42
|
|
42
43
|
const match = this.poolInSelectedRows(pool);
|
43
44
|
const index = _.indexOf(selectedRows, match);
|
44
45
|
|
45
|
-
if (
|
46
|
+
if (value) {
|
46
47
|
if (match) {
|
47
48
|
selectedRows.splice(index, 1, pool);
|
48
49
|
} else {
|
@@ -55,6 +56,25 @@ class UpstreamSubscriptionsPage extends Component {
|
|
55
56
|
this.setState({ selectedRows });
|
56
57
|
}
|
57
58
|
|
59
|
+
// eslint-disable-next-line class-methods-use-this
|
60
|
+
quantityValidation(pool) {
|
61
|
+
const origQuantity = pool.updatedQuantity;
|
62
|
+
if (origQuantity && helpers.stringIsInteger(origQuantity)) {
|
63
|
+
const parsedQuantity = parseInt(origQuantity, 10);
|
64
|
+
const aboveZeroMsg = [false, __('Please enter a positive number above zero')];
|
65
|
+
|
66
|
+
if (parsedQuantity.toString().length > 10) return [false, __('Please limit number to 10 digits')];
|
67
|
+
if (!pool.available) return [false, __('No pools available')];
|
68
|
+
// handling unlimited subscriptions, they show as -1
|
69
|
+
if (pool.available === -1) return parsedQuantity ? [true, ''] : aboveZeroMsg;
|
70
|
+
if (parsedQuantity > pool.available) return [false, __(`Quantity must not be above ${pool.available}`)];
|
71
|
+
if (parsedQuantity <= 0) return aboveZeroMsg;
|
72
|
+
} else {
|
73
|
+
return [false, __('Please enter digits only')];
|
74
|
+
}
|
75
|
+
return [true, ''];
|
76
|
+
}
|
77
|
+
|
58
78
|
poolInSelectedRows(pool) {
|
59
79
|
const { selectedRows } = this.state;
|
60
80
|
|
@@ -64,16 +84,30 @@ class UpstreamSubscriptionsPage extends Component {
|
|
64
84
|
);
|
65
85
|
}
|
66
86
|
|
87
|
+
quantityValidationInput(pool) {
|
88
|
+
if (!pool || pool.updatedQuantity === undefined) return null;
|
89
|
+
if (this.quantityValidation(pool)[0]) {
|
90
|
+
return 'success';
|
91
|
+
}
|
92
|
+
return 'error';
|
93
|
+
}
|
94
|
+
|
95
|
+
validateSelectedRows() {
|
96
|
+
return Array.isArray(this.state.selectedRows) &&
|
97
|
+
this.state.selectedRows.length &&
|
98
|
+
this.state.selectedRows.every(pool => this.quantityValidation(pool)[0]);
|
99
|
+
}
|
100
|
+
|
67
101
|
saveUpstreamSubscriptions() {
|
68
102
|
const updatedPools = _.map(
|
69
103
|
this.state.selectedRows,
|
70
|
-
pool => ({ ...pool, quantity: pool.updatedQuantity }),
|
104
|
+
pool => ({ ...pool, quantity: parseInt(pool.updatedQuantity, 10) }),
|
71
105
|
);
|
72
106
|
|
73
107
|
const updatedSubscriptions = { pools: updatedPools };
|
74
108
|
|
75
109
|
this.props.saveUpstreamSubscriptions(updatedSubscriptions).then(() => {
|
76
|
-
const { task
|
110
|
+
const { task } = this.props.upstreamSubscriptions;
|
77
111
|
|
78
112
|
// TODO: could probably factor this out into a task response component
|
79
113
|
if (task) {
|
@@ -88,18 +122,6 @@ class UpstreamSubscriptionsPage extends Component {
|
|
88
122
|
|
89
123
|
notify({ message: ReactDOMServer.renderToStaticMarkup(message), type: 'success' });
|
90
124
|
this.props.history.push('/subscriptions');
|
91
|
-
} else {
|
92
|
-
let errorMessages = [];
|
93
|
-
|
94
|
-
if (error.errors) {
|
95
|
-
errorMessages = error.errors;
|
96
|
-
} else if (error.message) {
|
97
|
-
errorMessages.push(error.message);
|
98
|
-
}
|
99
|
-
|
100
|
-
for (let i = 0; i < errorMessages.length; i += 1) {
|
101
|
-
notify({ message: errorMessages[i], type: 'error' });
|
102
|
-
}
|
103
125
|
}
|
104
126
|
});
|
105
127
|
}
|
@@ -121,7 +143,8 @@ class UpstreamSubscriptionsPage extends Component {
|
|
121
143
|
<Button
|
122
144
|
bsStyle="primary"
|
123
145
|
type="submit"
|
124
|
-
disabled={upstreamSubscriptions.loading
|
146
|
+
disabled={upstreamSubscriptions.loading ||
|
147
|
+
!this.validateSelectedRows()}
|
125
148
|
onClick={this.saveUpstreamSubscriptions}
|
126
149
|
>
|
127
150
|
{__('Submit')}
|
@@ -212,7 +235,19 @@ class UpstreamSubscriptionsPage extends Component {
|
|
212
235
|
|
213
236
|
return (
|
214
237
|
<Grid bsClass="container-fluid">
|
215
|
-
<
|
238
|
+
<BreadcrumbsBar data={{
|
239
|
+
isSwitchable: false,
|
240
|
+
breadcrumbItems: [
|
241
|
+
{
|
242
|
+
caption: __('Subscriptions'),
|
243
|
+
onClick: () => this.props.history.push('/subscriptions'),
|
244
|
+
},
|
245
|
+
{
|
246
|
+
caption: __('Add Subscriptions'),
|
247
|
+
},
|
248
|
+
],
|
249
|
+
}}
|
250
|
+
/>
|
216
251
|
|
217
252
|
<LoadingState loading={upstreamSubscriptions.loading} loadingText={__('Loading')}>
|
218
253
|
<Row>
|
@@ -240,8 +275,8 @@ UpstreamSubscriptionsPage.propTypes = {
|
|
240
275
|
saveUpstreamSubscriptions: PropTypes.func.isRequired,
|
241
276
|
upstreamSubscriptions: PropTypes.shape({
|
242
277
|
task: PropTypes.shape({}),
|
243
|
-
error: PropTypes.shape({}),
|
244
278
|
}).isRequired,
|
279
|
+
history: PropTypes.shape({ push: PropTypes.func.isRequired }).isRequired,
|
245
280
|
};
|
246
281
|
|
247
282
|
export default UpstreamSubscriptionsPage;
|