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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/katello/common/index.js +1 -0
- data/app/assets/javascripts/katello/sync_management/index.js +1 -0
- data/app/controllers/katello/api/v2/host_packages_controller.rb +1 -5
- data/app/controllers/katello/remote_execution_controller.rb +6 -6
- data/app/helpers/katello/hosts_and_hostgroups_helper.rb +37 -9
- data/app/lib/actions/katello/host/hypervisors_update.rb +82 -22
- data/app/lib/actions/pulp/consumer/abstract_content_action.rb +12 -0
- data/app/lib/actions/pulp/consumer/content_install.rb +1 -1
- data/app/lib/actions/pulp/consumer/content_uninstall.rb +1 -1
- data/app/lib/actions/pulp/consumer/content_update.rb +1 -1
- data/app/models/katello/concerns/subscription_facet_host_extensions.rb +1 -1
- data/app/models/katello/content_view.rb +12 -4
- data/app/models/katello/glue/candlepin/pool.rb +11 -11
- data/app/models/katello/host/content_facet.rb +2 -1
- data/app/models/katello/rpm.rb +14 -6
- data/app/models/katello/subscription_status.rb +1 -1
- data/app/services/katello/candlepin/consumer.rb +8 -0
- data/app/views/overrides/activation_keys/_host_environment_select.html.erb +2 -3
- data/config/routes.rb +1 -0
- data/db/migrate/20180612163403_add_foreign_key_to_hypervisor_id.rb +3 -0
- data/db/seeds.d/75-job_templates.rb +5 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-repository-sets-modal.controller.js +4 -3
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-subscriptions-modal.controller.js +4 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-packages-installed.controller.js +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/views/discovery-create.html +1 -1
- data/engines/bastion_katello/app/assets/stylesheets/bastion_katello/bastion_katello.scss +5 -0
- data/lib/katello/tasks/clean_backend_objects.rake +12 -3
- data/lib/katello/version.rb +1 -1
- data/package.json +10 -7
- data/webpack/__mocks__/foremanReact/redux.js +3 -0
- data/webpack/__mocks__/foremanReact/redux/actions/toasts.js +2 -0
- data/webpack/components/Search/Search.test.js +3 -1
- data/webpack/components/SelectOrg/SelectOrg.scss +3 -0
- data/webpack/components/SelectOrg/SelectOrgAction.js +41 -0
- data/webpack/components/SelectOrg/SelectOrgReducer.js +33 -0
- data/webpack/components/SelectOrg/SetOrganization.js +116 -0
- data/webpack/components/WithOrganization/withOrganization.js +28 -0
- data/webpack/containers/Application/config.js +9 -2
- data/webpack/containers/Application/index.js +4 -2
- data/webpack/global_test_setup.js +6 -0
- data/webpack/helpers/caret.js +6 -0
- data/webpack/move_to_foreman/components/common/{emptyState → EmptyState}/index.js +16 -3
- data/webpack/move_to_foreman/components/common/table/components/Table.js +1 -1
- data/webpack/move_to_foreman/components/common/table/components/__snapshots__/CollapseSubscriptionGroupButton.test.js.snap +2 -2
- data/webpack/move_to_foreman/components/common/table/components/__snapshots__/TableSelectionCell.test.js.snap +1 -1
- data/webpack/move_to_foreman/components/common/table/components/__snapshots__/TableSelectionHeaderCell.test.js.snap +1 -1
- data/webpack/move_to_pf/LoadingState/LoadingState.js +27 -14
- data/webpack/move_to_pf/LoadingState/LoadingState.test.js +8 -4
- data/webpack/move_to_pf/Select/Select.js +40 -0
- data/webpack/move_to_pf/react-bootstrap-select/index.js +12 -1
- data/webpack/redux/actions/RedHatRepositories/enabled.js +0 -1
- data/webpack/redux/actions/RedHatRepositories/helpers.js +5 -5
- data/webpack/redux/consts.js +6 -0
- data/webpack/redux/reducers/index.js +2 -0
- data/webpack/scenes/Products/ProductActions.js +24 -0
- data/webpack/scenes/Products/ProductConstants.js +3 -0
- data/webpack/scenes/Products/__tests__/ProductActions.test.js +40 -0
- data/webpack/scenes/Products/__tests__/products.fixtures.js +90 -0
- data/webpack/scenes/RedHatRepositories/components/EnabledRepository.js +14 -23
- data/webpack/scenes/RedHatRepositories/components/EnabledRepositoryContent.js +34 -0
- data/webpack/scenes/RedHatRepositories/components/RepositorySetRepository.js +1 -1
- data/webpack/scenes/RedHatRepositories/components/SearchBar.js +1 -0
- data/webpack/scenes/RedHatRepositories/components/__tests__/EnabledRepository.test.js +36 -0
- data/webpack/scenes/RedHatRepositories/components/__tests__/EnabledRepositoryContent.test.js +27 -0
- data/webpack/scenes/RedHatRepositories/components/__tests__/__snapshots__/EnabledRepository.test.js.snap +25 -0
- data/webpack/scenes/RedHatRepositories/components/__tests__/__snapshots__/EnabledRepositoryContent.test.js.snap +47 -0
- data/webpack/scenes/RedHatRepositories/components/__tests__/__snapshots__/RecommendedRepositorySetsToggler.test.js.snap +3 -1
- data/webpack/scenes/RedHatRepositories/index.js +7 -3
- data/webpack/scenes/RedHatRepositories/index.scss +1 -0
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetailActions.js +1 -1
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetailEnabledProducts.js +54 -0
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetailProduct.js +29 -0
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetailReducer.js +29 -0
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.js +67 -22
- data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.scss +9 -0
- data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailEnabledProducts.test.js +18 -0
- data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailProduct.test.js +13 -0
- data/webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetails.test.js +6 -0
- data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetailEnabledProducts.test.js.snap +45 -0
- data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetailProduct.test.js.snap +67 -0
- data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +497 -410
- data/webpack/scenes/Subscriptions/Details/__tests__/subscriptionDetails.fixtures.js +4 -0
- data/webpack/scenes/Subscriptions/Details/index.js +3 -1
- data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +78 -34
- data/webpack/scenes/Subscriptions/Manifest/ManifestHistoryReducer.js +8 -0
- data/webpack/scenes/Subscriptions/Manifest/__tests__/ManageManifestModal.test.js +3 -0
- data/webpack/scenes/Subscriptions/Manifest/__tests__/__snapshots__/ManageManifestModal.test.js.snap +34 -7
- data/webpack/scenes/Subscriptions/Manifest/index.js +1 -0
- data/webpack/scenes/Subscriptions/SubscriptionConstants.js +1 -0
- data/webpack/scenes/Subscriptions/SubscriptionHelpers.js +3 -0
- data/webpack/scenes/Subscriptions/SubscriptionReducer.js +6 -2
- data/webpack/scenes/Subscriptions/SubscriptionsPage.js +31 -36
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +2 -7
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsPage.test.js +1 -1
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/__snapshots__/UpstreamSubscriptionsPage.test.js.snap +3 -6
- data/webpack/scenes/Subscriptions/__tests__/SubscriptionsPage.test.js +2 -0
- data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +14 -2
- data/webpack/scenes/Subscriptions/__tests__/subscriptions.fixtures.js +4 -3
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/EntitlementsInlineEditFormatter.js +8 -5
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTable.js +29 -19
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableHelpers.js +9 -2
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableSchema.js +2 -2
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/EntitlementsInlineEditFormatter.test.js +110 -0
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/SubscriptionsTable.test.js +15 -3
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/EntitlementsInlineEditFormatter.test.js.snap +228 -0
- data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionsTable.test.js.snap +54 -21
- data/webpack/scenes/Subscriptions/index.js +1 -0
- data/webpack/scenes/Tasks/helpers.js +52 -0
- data/webpack/services/api/index.js +17 -1
- data/webpack/test_setup.js +2 -0
- metadata +31 -4
- data/config/katello.yaml +0 -89
@@ -193,13 +193,9 @@ class UpstreamSubscriptionsPage extends Component {
|
|
193
193
|
description: __('Subscription Allocations allow you to export subscriptions from the Red Hat Customer Portal to ' +
|
194
194
|
'an on-premise subscription management application such as Red Hat Satellite.'),
|
195
195
|
docUrl: 'http://redhat.com',
|
196
|
-
documentation: {
|
197
|
-
title: __('Learn more about Subscription Allocations'),
|
198
|
-
url: 'http://redhat.com',
|
199
|
-
},
|
200
196
|
action: {
|
201
|
-
title: __('
|
202
|
-
url: '
|
197
|
+
title: __('Import a Manifest to Begin'),
|
198
|
+
url: '/subscriptions',
|
203
199
|
},
|
204
200
|
});
|
205
201
|
|
@@ -270,7 +266,6 @@ class UpstreamSubscriptionsPage extends Component {
|
|
270
266
|
}
|
271
267
|
|
272
268
|
UpstreamSubscriptionsPage.propTypes = {
|
273
|
-
history: PropTypes.shape({ push: PropTypes.func }).isRequired,
|
274
269
|
loadUpstreamSubscriptions: PropTypes.func.isRequired,
|
275
270
|
saveUpstreamSubscriptions: PropTypes.func.isRequired,
|
276
271
|
upstreamSubscriptions: PropTypes.shape({
|
data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsPage.test.js
CHANGED
@@ -10,6 +10,7 @@ jest.mock('foremanReact/components/BreadcrumbBar');
|
|
10
10
|
|
11
11
|
describe('upstream subscriptions page', () => {
|
12
12
|
let shallowWrapper;
|
13
|
+
const mockHistory = { push: () => {} };
|
13
14
|
beforeEach(() => {
|
14
15
|
shallowWrapper = shallow(<UpstreamSubscriptionsPage
|
15
16
|
upstreamSubscriptions={successState}
|
@@ -18,7 +19,6 @@ describe('upstream subscriptions page', () => {
|
|
18
19
|
history={mockHistory}
|
19
20
|
/>);
|
20
21
|
});
|
21
|
-
const mockHistory = { push: () => {} };
|
22
22
|
|
23
23
|
it('should render', async () => {
|
24
24
|
expect(toJson(shallowWrapper)).toMatchSnapshot();
|
@@ -25,6 +25,7 @@ exports[`upstream subscriptions page should render 1`] = `
|
|
25
25
|
<LoadingState
|
26
26
|
loading={false}
|
27
27
|
loadingText="Loading"
|
28
|
+
timeout={300}
|
28
29
|
>
|
29
30
|
<Row
|
30
31
|
bsClass="row"
|
@@ -141,15 +142,11 @@ exports[`upstream subscriptions page should render 1`] = `
|
|
141
142
|
emptyState={
|
142
143
|
Object {
|
143
144
|
"action": Object {
|
144
|
-
"title": "
|
145
|
-
"url": "
|
145
|
+
"title": "Import a Manifest to Begin",
|
146
|
+
"url": "/subscriptions",
|
146
147
|
},
|
147
148
|
"description": "Subscription Allocations allow you to export subscriptions from the Red Hat Customer Portal to an on-premise subscription management application such as Red Hat Satellite.",
|
148
149
|
"docUrl": "http://redhat.com",
|
149
|
-
"documentation": Object {
|
150
|
-
"title": "Learn more about Subscription Allocations",
|
151
|
-
"url": "http://redhat.com",
|
152
|
-
},
|
153
150
|
"header": "There are no Subscription Allocations to display",
|
154
151
|
}
|
155
152
|
}
|
@@ -10,9 +10,11 @@ jest.mock('../../../move_to_foreman/foreman_toast_notifications');
|
|
10
10
|
|
11
11
|
describe('subscriptions page', () => {
|
12
12
|
const noop = () => {};
|
13
|
+
const organization = { owner_details: { upstreamConsumer: 'blah' } };
|
13
14
|
|
14
15
|
it('should render', async () => {
|
15
16
|
const page = shallow(<SubscriptionsPage
|
17
|
+
organization={organization}
|
16
18
|
subscriptions={successState}
|
17
19
|
loadSetting={loadSetting}
|
18
20
|
loadSubscriptions={loadSubscriptions}
|
@@ -53,6 +53,7 @@ exports[`subscriptions page should render 1`] = `
|
|
53
53
|
>
|
54
54
|
<LinkContainer
|
55
55
|
activeClassName="active"
|
56
|
+
disabled={false}
|
56
57
|
exact={false}
|
57
58
|
replace={false}
|
58
59
|
strict={false}
|
@@ -93,7 +94,7 @@ exports[`subscriptions page should render 1`] = `
|
|
93
94
|
title="Delete"
|
94
95
|
tooltipId="delete-subscriptions-button-tooltip"
|
95
96
|
tooltipPlacement="top"
|
96
|
-
tooltipText="This is disabled because no subscriptions are selected"
|
97
|
+
tooltipText="This is disabled because no subscriptions are selected."
|
97
98
|
/>
|
98
99
|
</FormGroup>
|
99
100
|
</div>
|
@@ -111,13 +112,23 @@ exports[`subscriptions page should render 1`] = `
|
|
111
112
|
id="subscriptions-table"
|
112
113
|
>
|
113
114
|
<SubscriptionsTable
|
115
|
+
emptyState={
|
116
|
+
Object {
|
117
|
+
"action": Object {
|
118
|
+
"onClick": [Function],
|
119
|
+
"title": "Import a Manifest",
|
120
|
+
},
|
121
|
+
"description": "Import a Manifest to manage your Entitlements.",
|
122
|
+
"header": "There are no Subscriptions to display",
|
123
|
+
}
|
124
|
+
}
|
114
125
|
loadSubscriptions={[Function]}
|
115
126
|
onDeleteSubscriptions={[Function]}
|
116
127
|
onSubscriptionDeleteModalClose={[Function]}
|
117
128
|
subscriptionDeleteModalOpen={false}
|
118
129
|
subscriptions={
|
119
130
|
Object {
|
120
|
-
"availableQuantities":
|
131
|
+
"availableQuantities": null,
|
121
132
|
"itemCount": 81,
|
122
133
|
"loading": false,
|
123
134
|
"pagination": Object {
|
@@ -184,6 +195,7 @@ exports[`subscriptions page should render 1`] = `
|
|
184
195
|
"tasks": Array [],
|
185
196
|
}
|
186
197
|
}
|
198
|
+
task={null}
|
187
199
|
toggleDeleteButton={[Function]}
|
188
200
|
updateQuantity={[Function]}
|
189
201
|
/>
|
@@ -10,7 +10,7 @@ export const initialState = Immutable({
|
|
10
10
|
},
|
11
11
|
itemCount: 0,
|
12
12
|
quantitiesLoading: false,
|
13
|
-
availableQuantities:
|
13
|
+
availableQuantities: null,
|
14
14
|
tasks: [],
|
15
15
|
});
|
16
16
|
|
@@ -243,7 +243,7 @@ export const successState = Immutable({
|
|
243
243
|
},
|
244
244
|
itemCount: 81,
|
245
245
|
quantitiesLoading: false,
|
246
|
-
availableQuantities:
|
246
|
+
availableQuantities: null,
|
247
247
|
tasks: [],
|
248
248
|
});
|
249
249
|
|
@@ -256,7 +256,7 @@ export const errorState = Immutable({
|
|
256
256
|
itemCount: 0,
|
257
257
|
results: [],
|
258
258
|
quantitiesLoading: false,
|
259
|
-
availableQuantities:
|
259
|
+
availableQuantities: null,
|
260
260
|
tasks: [],
|
261
261
|
});
|
262
262
|
|
@@ -278,6 +278,7 @@ export const loadingQuantitiesState = Immutable({
|
|
278
278
|
export const quantitiesErrorState = Immutable({
|
279
279
|
...successState,
|
280
280
|
quantitiesLoading: false,
|
281
|
+
availableQuantities: {},
|
281
282
|
});
|
282
283
|
|
283
284
|
export const successActions = [
|
data/webpack/scenes/Subscriptions/components/SubscriptionsTable/EntitlementsInlineEditFormatter.js
CHANGED
@@ -34,15 +34,18 @@ export const entitlementsInlineEditFormatter =
|
|
34
34
|
);
|
35
35
|
},
|
36
36
|
renderEdit: (value, additionalData) => {
|
37
|
-
const { availableQuantity } = additionalData.rowData;
|
37
|
+
const { availableQuantity, availableQuantityLoaded } = additionalData.rowData;
|
38
38
|
|
39
39
|
const className = inlineEditController.hasChanged(additionalData)
|
40
40
|
? 'editable editing changed'
|
41
41
|
: 'editable editing';
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
let maxMessage;
|
44
|
+
if (availableQuantityLoaded && (availableQuantity !== undefined)) {
|
45
|
+
maxMessage = (availableQuantity < 1)
|
46
|
+
? __('Unlimited')
|
47
|
+
: sprintf(__('Max %(availableQuantity)s'), { availableQuantity });
|
48
|
+
}
|
46
49
|
|
47
50
|
const validation = validateQuantity(value, availableQuantity);
|
48
51
|
|
@@ -55,7 +58,7 @@ export const entitlementsInlineEditFormatter =
|
|
55
58
|
// The same issue prevents from correct switching inputs on TAB.
|
56
59
|
// See the reactabular code for details:
|
57
60
|
// https://github.com/reactabular/reactabular/blob/master/packages/reactabular-table/src/body-row.js#L58
|
58
|
-
<Spinner loading={
|
61
|
+
<Spinner loading={!availableQuantityLoaded} size="xs">
|
59
62
|
<FormGroup
|
60
63
|
validationState={validation.state}
|
61
64
|
>
|
@@ -11,19 +11,11 @@ import Dialog from '../../../../move_to_foreman/components/common/Dialog';
|
|
11
11
|
import { recordsValid } from '../../SubscriptionValidations';
|
12
12
|
import { createSubscriptionsTableSchema } from './SubscriptionsTableSchema';
|
13
13
|
import { buildTableRows, groupSubscriptionsByProductId, buildPools } from './SubscriptionsTableHelpers';
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
title: __('Learn more about adding Subscriptions to Allocations'),
|
20
|
-
url: 'http://redhat.com',
|
21
|
-
},
|
22
|
-
action: {
|
23
|
-
title: __('Add Subscriptions'),
|
24
|
-
url: 'subscriptions/add',
|
25
|
-
},
|
26
|
-
};
|
14
|
+
import { renderTaskStartedToast } from '../../../Tasks/helpers';
|
15
|
+
import {
|
16
|
+
BLOCKING_FOREMAN_TASK_TYPES,
|
17
|
+
MANIFEST_TASKS_BULK_SEARCH_ID,
|
18
|
+
} from '../../SubscriptionConstants';
|
27
19
|
|
28
20
|
class SubscriptionsTable extends Component {
|
29
21
|
constructor(props) {
|
@@ -117,7 +109,15 @@ class SubscriptionsTable extends Component {
|
|
117
109
|
confirmEdit() {
|
118
110
|
this.showUpdateConfirm(false);
|
119
111
|
if (Object.keys(this.state.updatedQuantity).length > 0) {
|
120
|
-
this.props.updateQuantity(buildPools(this.state.updatedQuantity))
|
112
|
+
this.props.updateQuantity(buildPools(this.state.updatedQuantity))
|
113
|
+
.then(() =>
|
114
|
+
this.props.bulkSearch({
|
115
|
+
search_id: MANIFEST_TASKS_BULK_SEARCH_ID,
|
116
|
+
type: 'all',
|
117
|
+
active_only: true,
|
118
|
+
action_types: BLOCKING_FOREMAN_TASK_TYPES,
|
119
|
+
}))
|
120
|
+
.then(() => renderTaskStartedToast(this.props.task));
|
121
121
|
}
|
122
122
|
this.enableEditing(false);
|
123
123
|
}
|
@@ -140,8 +140,9 @@ class SubscriptionsTable extends Component {
|
|
140
140
|
}
|
141
141
|
|
142
142
|
render() {
|
143
|
-
const { subscriptions } = this.props;
|
143
|
+
const { subscriptions, emptyState } = this.props;
|
144
144
|
const { groupedSubscriptions } = this.state;
|
145
|
+
const allSubscriptionResults = subscriptions.results;
|
145
146
|
|
146
147
|
const groupingController = {
|
147
148
|
isCollapseable: ({ rowData }) =>
|
@@ -185,7 +186,8 @@ class SubscriptionsTable extends Component {
|
|
185
186
|
},
|
186
187
|
};
|
187
188
|
|
188
|
-
const checkAllRowsSelected = () =>
|
189
|
+
const checkAllRowsSelected = () =>
|
190
|
+
allSubscriptionResults.length === this.state.selectedRows.length;
|
189
191
|
|
190
192
|
const updateDeleteButton = () => {
|
191
193
|
this.props.toggleDeleteButton(this.state.selectedRows.length > 0);
|
@@ -201,7 +203,7 @@ class SubscriptionsTable extends Component {
|
|
201
203
|
);
|
202
204
|
} else {
|
203
205
|
this.setState(
|
204
|
-
{ selectedRows:
|
206
|
+
{ selectedRows: allSubscriptionResults.map(row => row.id) },
|
205
207
|
updateDeleteButton,
|
206
208
|
);
|
207
209
|
}
|
@@ -229,7 +231,7 @@ class SubscriptionsTable extends Component {
|
|
229
231
|
};
|
230
232
|
|
231
233
|
let bodyMessage;
|
232
|
-
if (
|
234
|
+
if (allSubscriptionResults.length === 0 && subscriptions.searchIsActive) {
|
233
235
|
bodyMessage = __('No subscriptions match your search criteria.');
|
234
236
|
}
|
235
237
|
|
@@ -243,7 +245,7 @@ class SubscriptionsTable extends Component {
|
|
243
245
|
<LoadingState loading={subscriptions.loading} loadingText={__('Loading')}>
|
244
246
|
<ForemanTable
|
245
247
|
columns={columnsDefinition}
|
246
|
-
emptyState={
|
248
|
+
emptyState={emptyState}
|
247
249
|
bodyMessage={bodyMessage}
|
248
250
|
rows={this.state.rows}
|
249
251
|
components={{
|
@@ -329,6 +331,7 @@ class SubscriptionsTable extends Component {
|
|
329
331
|
SubscriptionsTable.propTypes = {
|
330
332
|
loadSubscriptions: PropTypes.func.isRequired,
|
331
333
|
updateQuantity: PropTypes.func.isRequired,
|
334
|
+
emptyState: PropTypes.shape({}).isRequired,
|
332
335
|
subscriptions: PropTypes.shape({
|
333
336
|
results: PropTypes.array,
|
334
337
|
}).isRequired,
|
@@ -336,6 +339,13 @@ SubscriptionsTable.propTypes = {
|
|
336
339
|
onDeleteSubscriptions: PropTypes.func.isRequired,
|
337
340
|
onSubscriptionDeleteModalClose: PropTypes.func.isRequired,
|
338
341
|
toggleDeleteButton: PropTypes.func.isRequired,
|
342
|
+
task: PropTypes.shape({}),
|
343
|
+
bulkSearch: PropTypes.func,
|
344
|
+
};
|
345
|
+
|
346
|
+
SubscriptionsTable.defaultProps = {
|
347
|
+
task: { humanized: {} },
|
348
|
+
bulkSearch: undefined,
|
339
349
|
};
|
340
350
|
|
341
351
|
export default SubscriptionsTable;
|
data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableHelpers.js
CHANGED
@@ -1,15 +1,22 @@
|
|
1
1
|
const buildTableRow = (subscription, availableQuantities, updatedQuantity) => {
|
2
|
+
const availableQuantityLoaded = !!availableQuantities;
|
3
|
+
const availableQuantity = availableQuantityLoaded
|
4
|
+
? availableQuantities[subscription.id]
|
5
|
+
: null;
|
6
|
+
|
2
7
|
if (updatedQuantity[subscription.id]) {
|
3
8
|
return {
|
4
9
|
...subscription,
|
5
10
|
entitlementsChanged: true,
|
6
11
|
quantity: updatedQuantity[subscription.id],
|
7
|
-
availableQuantity
|
12
|
+
availableQuantity,
|
13
|
+
availableQuantityLoaded,
|
8
14
|
};
|
9
15
|
}
|
10
16
|
return {
|
11
17
|
...subscription,
|
12
|
-
availableQuantity
|
18
|
+
availableQuantity,
|
19
|
+
availableQuantityLoaded,
|
13
20
|
};
|
14
21
|
};
|
15
22
|
|
@@ -97,9 +97,9 @@ export const createSubscriptionsTableSchema = (
|
|
97
97
|
},
|
98
98
|
cell: {
|
99
99
|
formatters: [
|
100
|
-
|
100
|
+
(value, { rowData }) => (
|
101
101
|
<td>
|
102
|
-
<Icon type="fa" name={
|
102
|
+
<Icon type="fa" name={rowData.virt_who ? 'check' : 'minus'} />
|
103
103
|
</td>
|
104
104
|
),
|
105
105
|
],
|
@@ -0,0 +1,110 @@
|
|
1
|
+
// import React from 'react';
|
2
|
+
import { shallow } from 'enzyme';
|
3
|
+
import toJson from 'enzyme-to-json';
|
4
|
+
import editFormatter from '../EntitlementsInlineEditFormatter';
|
5
|
+
|
6
|
+
describe('EntitlementsInlineEditFormatter', () => {
|
7
|
+
const data = rowData => ({
|
8
|
+
rowData,
|
9
|
+
});
|
10
|
+
|
11
|
+
const mockController = (options = {}) => {
|
12
|
+
const { editing = true, changed = false } = options;
|
13
|
+
return {
|
14
|
+
isEditing: () => editing,
|
15
|
+
hasChanged: () => changed,
|
16
|
+
};
|
17
|
+
};
|
18
|
+
|
19
|
+
describe('edit mode', () => {
|
20
|
+
describe('when available quantities are being loaded', () => {
|
21
|
+
it('renders spinner', async () => {
|
22
|
+
const controller = mockController();
|
23
|
+
const value = 100;
|
24
|
+
const formatter = editFormatter(controller)(value, data({
|
25
|
+
availableQuantityLoaded: false,
|
26
|
+
}));
|
27
|
+
|
28
|
+
expect(toJson(shallow(formatter))).toMatchSnapshot();
|
29
|
+
});
|
30
|
+
});
|
31
|
+
|
32
|
+
describe('when available quantities are loaded', () => {
|
33
|
+
it('renders edit field and max available', async () => {
|
34
|
+
const controller = mockController();
|
35
|
+
const value = 100;
|
36
|
+
const formatter = editFormatter(controller)(value, data({
|
37
|
+
availableQuantityLoaded: true,
|
38
|
+
availableQuantity: 500,
|
39
|
+
}));
|
40
|
+
|
41
|
+
expect(toJson(shallow(formatter))).toMatchSnapshot();
|
42
|
+
});
|
43
|
+
|
44
|
+
it('renders edit field and unlimited message', async () => {
|
45
|
+
const controller = mockController();
|
46
|
+
const value = 100;
|
47
|
+
const formatter = editFormatter(controller)(value, data({
|
48
|
+
availableQuantityLoaded: true,
|
49
|
+
availableQuantity: -1,
|
50
|
+
}));
|
51
|
+
|
52
|
+
expect(toJson(shallow(formatter))).toMatchSnapshot();
|
53
|
+
});
|
54
|
+
|
55
|
+
it('renders validation message', async () => {
|
56
|
+
const controller = mockController();
|
57
|
+
const value = 200;
|
58
|
+
const formatter = editFormatter(controller)(value, data({
|
59
|
+
availableQuantityLoaded: true,
|
60
|
+
availableQuantity: 100,
|
61
|
+
}));
|
62
|
+
|
63
|
+
expect(toJson(shallow(formatter))).toMatchSnapshot();
|
64
|
+
});
|
65
|
+
|
66
|
+
it('renders changed values', async () => {
|
67
|
+
const controller = mockController({ changed: true });
|
68
|
+
const value = 100;
|
69
|
+
const formatter = editFormatter(controller)(value, data({
|
70
|
+
availableQuantityLoaded: true,
|
71
|
+
availableQuantity: 200,
|
72
|
+
}));
|
73
|
+
|
74
|
+
expect(toJson(shallow(formatter))).toMatchSnapshot();
|
75
|
+
});
|
76
|
+
});
|
77
|
+
|
78
|
+
describe('when available quantities failed to load', () => {
|
79
|
+
it('renders just the edit field', async () => {
|
80
|
+
const controller = mockController();
|
81
|
+
const value = 200;
|
82
|
+
const formatter = editFormatter(controller)(value, data({
|
83
|
+
availableQuantityLoaded: true,
|
84
|
+
}));
|
85
|
+
|
86
|
+
expect(toJson(shallow(formatter))).toMatchSnapshot();
|
87
|
+
});
|
88
|
+
});
|
89
|
+
});
|
90
|
+
|
91
|
+
describe('value mode', () => {
|
92
|
+
it('renders the value', async () => {
|
93
|
+
const controller = mockController({ editing: false });
|
94
|
+
const value = 200;
|
95
|
+
const formatter = editFormatter(controller)(value, data({}));
|
96
|
+
|
97
|
+
expect(toJson(shallow(formatter))).toMatchSnapshot();
|
98
|
+
});
|
99
|
+
|
100
|
+
it('renders unlimited for -1', async () => {
|
101
|
+
const controller = mockController({ editing: false });
|
102
|
+
const value = 200;
|
103
|
+
const formatter = editFormatter(controller)(value, data({
|
104
|
+
available: -1,
|
105
|
+
}));
|
106
|
+
|
107
|
+
expect(toJson(shallow(formatter))).toMatchSnapshot();
|
108
|
+
});
|
109
|
+
});
|
110
|
+
});
|