Project

General

Profile

« Previous | Next » 

Revision 0fc33e91

Added by John Mitsch almost 6 years ago

Fixes #23687 - Adds subscription details page

This rewrites the subscription details page in React. Links in the
main subs table will used this page. There will be a follow-up change
for the Product Content tab.

View differences:

webpack/containers/Application/config.js
import Repos from '../../scenes/RedHatRepositories';
import Subscriptions from '../../scenes/Subscriptions';
import UpstreamSubscriptions from '../../scenes/Subscriptions/UpstreamSubscriptions/index';
import SubscriptionDetails from '../../scenes/Subscriptions/Details';
// eslint-disable-next-line import/prefer-default-export
export const links = [
......
path: 'xui/subscriptions/add',
component: UpstreamSubscriptions,
},
{
path: 'xui/subscriptions/:id',
component: SubscriptionDetails,
},
];
webpack/move_to_foreman/common/helpers.js
urlBuilder(controller, action, id = undefined) {
return `/${controller}/${id ? `${id}/` : ''}${action}`;
},
urlWithSearch(base, searchQuery) {
return `/${base}?search=${searchQuery}`;
},
};
export const KEY_CODES = {
......
/>
</Table.SelectionCell>
);
export const getResponseError = ({ data }) => data && (data.displayMessage || data.error);
webpack/redux/reducers/index.js
import { subscriptions } from '../../scenes/Subscriptions';
import { upstreamSubscriptions } from '../../scenes/Subscriptions/UpstreamSubscriptions';
import { manifestHistory } from '../../scenes/Subscriptions/Manifest';
import { subscriptionDetails } from '../../scenes/Subscriptions/Details';
export default combineReducers({
organization,
......
subscriptions,
upstreamSubscriptions,
manifestHistory,
subscriptionDetails,
});
webpack/scenes/Subscriptions/Details/SubscriptionAttributes.js
export default {
name: __('Name'),
description: __('Description'),
virt_who: __('Requires Virt-Who'),
consumed: __('Consumed'),
start_date: __('Starts'),
end_date: __('Ends'),
product_id: __('Product ID'),
contract_number: __('Contract Number'),
account_number: __('Account Number'),
support_level: __('Support Level'),
support_type: __('Support Type'),
arch: __('Architecture(s)'),
type: __('Type'),
mutli_entitlement: __('Multi-entitlement'),
stacking_id: __('Stacking ID'),
};
webpack/scenes/Subscriptions/Details/SubscriptionDetailActions.js
import api, { orgId } from '../../../services/api';
import {
SUBSCRIPTION_DETAILS_REQUEST,
SUBSCRIPTION_DETAILS_SUCCESS,
SUBSCRIPTION_DETAILS_FAILURE,
} from './SubscriptionDetailConstants';
import { getResponseError } from '../../../move_to_foreman/common/helpers.js';
export const loadSubscriptionDetails = subscriptionId => (dispatch) => {
dispatch({ type: SUBSCRIPTION_DETAILS_REQUEST });
return api
.get(`/organizations/${orgId}/subscriptions/${subscriptionId}`)
.then(({ data }) => {
dispatch({
type: SUBSCRIPTION_DETAILS_SUCCESS,
response: data,
});
})
.catch((result) => {
dispatch({
type: SUBSCRIPTION_DETAILS_FAILURE,
error: getResponseError(result.response),
});
});
};
export default loadSubscriptionDetails;
webpack/scenes/Subscriptions/Details/SubscriptionDetailAssociations.js
import React from 'react';
import PropTypes from 'prop-types';
import { Table } from 'react-bootstrap';
import helpers from '../../../move_to_foreman/common/helpers.js';
const SubscriptionDetailAssociations = ({ subscriptionDetails }) => {
const searchQuery = 'subscription_id="%s"'.replace('%s', subscriptionDetails.id);
return (
<div>
<h2>{__('Associations')}</h2>
<Table striped bordered condensed hover>
<thead>
<tr>
<td><b>{__('Resource')}</b></td>
<td><b>{__('Quantity')}</b></td>
</tr>
</thead>
<tbody>
<tr>
<td>{__('Content Hosts')}</td>
<td>
<a href={helpers.urlWithSearch('content_hosts', searchQuery)}>
{subscriptionDetails.host_count}
</a>
</td>
</tr>
<tr>
<td>{__('Activation Keys')}</td>
<td>
<a href={helpers.urlWithSearch('activation_keys', searchQuery)}>
{subscriptionDetails.activation_keys &&
subscriptionDetails.activation_keys.length}
</a>
</td>
</tr>
</tbody>
</Table>
</div>
);
};
SubscriptionDetailAssociations.propTypes = {
subscriptionDetails: PropTypes.shape({}).isRequired,
};
export default SubscriptionDetailAssociations;
webpack/scenes/Subscriptions/Details/SubscriptionDetailConstants.js
export const SUBSCRIPTION_DETAILS_REQUEST = 'SUBSCRIPTION_DETAILS_REQUEST';
export const SUBSCRIPTION_DETAILS_SUCCESS = 'SUBSCRIPTION_DETAILS_SUCCESS';
export const SUBSCRIPTION_DETAILS_FAILURE = 'SUBSCRIPTION_DETAILS_FAILURE';
webpack/scenes/Subscriptions/Details/SubscriptionDetailInfo.js
import React from 'react';
import PropTypes from 'prop-types';
import { Table } from 'react-bootstrap';
import subscriptionAttributes from './SubscriptionAttributes';
const SubscriptionDetailInfo = ({ subscriptionDetails }) => {
const subscriptionLimits = (subDetails) => {
const limits = [];
if (subDetails.sockets) {
limits.push(__('Sockets: %s').replace('%s', subDetails.sockets));
}
if (subDetails.cores) {
limits.push(__('Cores: %s').replace('%s', subDetails.cores));
}
if (subDetails.ram) {
limits.push(__('RAM: %s GB').replace('%s', subDetails.ram));
}
if (limits.length > 0) {
return limits.join(', ');
}
return '';
};
const subscriptionDetailValue = (subDetails, key) => (subDetails[key] == null ? '' : String(subDetails[key]));
const formatInstanceBased = (subDetails) => {
if (subDetails.instance_multiplier == null ||
subDetails.instance_multiplier === '' ||
subDetails.instance_multiplier === 0) {
return __('No');
}
return __('Yes');
};
return (
<div>
<h2>{__('Subscription Info')}</h2>
<Table>
<tbody>
{Object.keys(subscriptionAttributes).map(key => (
<tr key={key}>
<td><b>{__(subscriptionAttributes[key])}</b></td>
<td>{subscriptionDetailValue(subscriptionDetails, key)}</td>
</tr>
))}
<tr>
<td><b>{__('Limits')}</b></td>
<td>{subscriptionLimits(subscriptionDetails)}</td>
</tr>
<tr>
<td><b>{__('Instance-based')}</b></td>
<td>{formatInstanceBased(subscriptionDetails)}</td>
</tr>
</tbody>
</Table>
</div>
);
};
SubscriptionDetailInfo.propTypes = {
subscriptionDetails: PropTypes.shape({}).isRequired,
};
export default SubscriptionDetailInfo;
webpack/scenes/Subscriptions/Details/SubscriptionDetailProducts.js
import React from 'react';
import PropTypes from 'prop-types';
const SubscriptionDetailProducts = ({ subscriptionDetails }) => (
<div>
<h2>{__('Provided Products')}</h2>
<ul>
{subscriptionDetails.provided_products &&
subscriptionDetails.provided_products.map(prod => (
<li key={prod.id}>{prod.name}</li>
))}
</ul>
</div>
);
SubscriptionDetailProducts.propTypes = {
subscriptionDetails: PropTypes.shape({}).isRequired,
};
export default SubscriptionDetailProducts;
webpack/scenes/Subscriptions/Details/SubscriptionDetailReducer.js
import Immutable from 'seamless-immutable';
import {
SUBSCRIPTION_DETAILS_REQUEST,
SUBSCRIPTION_DETAILS_SUCCESS,
SUBSCRIPTION_DETAILS_FAILURE,
} from './SubscriptionDetailConstants';
const initialState = Immutable({
loading: false,
});
export default (state = initialState, action) => {
switch (action.type) {
case SUBSCRIPTION_DETAILS_REQUEST: {
return state.set('loading', true);
}
case SUBSCRIPTION_DETAILS_SUCCESS: {
const subscriptionDetails = action.response;
return state.merge({
...subscriptionDetails,
loading: false,
});
}
case SUBSCRIPTION_DETAILS_FAILURE: {
return state.merge({
error: action.error,
loading: false,
});
}
default:
return state;
}
};
webpack/scenes/Subscriptions/Details/SubscriptionDetails.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Spinner, Grid, Row, Col } from 'patternfly-react';
import SubscriptionDetailInfo from './SubscriptionDetailInfo';
import SubscriptionDetailAssociations from './SubscriptionDetailAssociations';
import SubscriptionDetailProducts from './SubscriptionDetailProducts';
import { notify } from '../../../move_to_foreman/foreman_toast_notifications';
class SubscriptionDetails extends Component {
componentDidMount() {
// eslint-disable-next-line react/prop-types
const routerParams = this.props.match.params;
this.props.loadSubscriptionDetails(parseInt(routerParams.id, 10));
}
render() {
const { subscriptionDetails } = this.props;
if (subscriptionDetails.error) { notify({ message: subscriptionDetails.error }); }
return (
<Grid bsClass="container-fluid">
<div>
<Spinner loading={subscriptionDetails.loading}>
<Row>
<Col sm={12}>
<h1>{subscriptionDetails.name}</h1>
</Col>
</Row>
<Row>
<Col sm={6}>
<SubscriptionDetailInfo
subscriptionDetails={subscriptionDetails}
/>
</Col>
<Col sm={6}>
<SubscriptionDetailAssociations
subscriptionDetails={subscriptionDetails}
/>
<SubscriptionDetailProducts
subscriptionDetails={subscriptionDetails}
/>
</Col>
</Row>
</Spinner>
</div>
</Grid>
);
}
}
SubscriptionDetails.propTypes = {
loadSubscriptionDetails: PropTypes.func.isRequired,
subscriptionDetails: PropTypes.shape({}).isRequired,
};
export default SubscriptionDetails;
webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailActions.test.js
import thunk from 'redux-thunk';
import Immutable from 'seamless-immutable';
import configureMockStore from 'redux-mock-store';
import { mockRequest, mockErrorRequest, mockReset } from '../../../../mockRequest';
import { loadSubscriptionDetails } from '../SubscriptionDetailActions';
import {
loadSubscriptionsDetailsSuccessActions,
loadSubscriptionsDetailsFailureActions,
subDetails,
} from './subscriptionDetails.fixtures';
const mockStore = configureMockStore([thunk]);
const store = mockStore({ subscriptionDetails: Immutable({}) });
const endpoint = /\/organizations\/\d+\/subscriptions\/\d+/;
afterEach(() => {
store.clearActions();
mockReset();
});
describe('subscription detail actions', () => {
describe('loadSubscriptionDetails', () => {
it(
'creates SUBSCRIPTION_DETAILS_REQUEST and then fails with 500',
() => {
mockErrorRequest({
url: endpoint,
});
return store.dispatch(loadSubscriptionDetails(1))
.then(() => expect(store.getActions())
.toEqual(loadSubscriptionsDetailsFailureActions));
},
);
it(
'creates SUBSCRIPTION_DETAILS_SUCCESS and ends with success',
() => {
mockRequest({
url: endpoint,
response: subDetails,
});
return store.dispatch(loadSubscriptionDetails(1))
.then(() => expect(store.getActions())
.toEqual(loadSubscriptionsDetailsSuccessActions));
},
);
});
});
webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailAssociations.test.js
import React from 'react';
import TestRenderer from 'react-test-renderer';
import SubscriptionDetailAssociations from '../SubscriptionDetailAssociations';
import { successState } from './subscriptionDetails.fixtures';
describe('subscriptions detail associations page', () => {
it('renders correctly', () => {
const testRenderer = TestRenderer
.create(<SubscriptionDetailAssociations subscriptionDetails={successState} />);
const testInstance = testRenderer.root;
expect(testRenderer.toJSON()).toMatchSnapshot();
expect(testInstance.findAllByType('td')).toHaveLength(6);
expect(testInstance.findAllByType('a')).toHaveLength(2);
});
});
webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailInfo.test.js
import React from 'react';
import TestRenderer from 'react-test-renderer';
import SubscriptionDetailInfo from '../SubscriptionDetailInfo';
import { successState } from './subscriptionDetails.fixtures';
describe('subscriptions detail associations page', () => {
it('renders correctly', () => {
const testRenderer = TestRenderer
.create(<SubscriptionDetailInfo subscriptionDetails={successState} />);
const testInstance = testRenderer.root;
expect(testRenderer.toJSON()).toMatchSnapshot();
expect(testInstance.findByType('h2').children[0]).toBe('Subscription Info');
});
});
webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailProducts.test.js
import React from 'react';
import TestRenderer from 'react-test-renderer';
import SubscriptionDetailProducts from '../SubscriptionDetailProducts';
import { successState } from './subscriptionDetails.fixtures';
describe('subscription detail product page', () => {
it('renders correctly', () => {
const testRenderer = TestRenderer
.create(<SubscriptionDetailProducts subscriptionDetails={successState} />);
const testInstance = testRenderer.root;
expect(testRenderer.toJSON()).toMatchSnapshot();
expect(testInstance.findByType('h2').children[0]).toBe('Provided Products');
expect(testInstance.findAllByType('li')).toHaveLength(successState.provided_products.length);
});
});
webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetailReducer.test.js
import * as types from '../SubscriptionDetailConstants';
import {
initialState,
loadingState,
subDetails,
successState,
} from './subscriptionDetails.fixtures';
import reducer from '../SubscriptionDetailReducer';
describe('subscriptions reducer', () => {
it('should return the initial state', () => {
expect(reducer(undefined, {})).toEqual(initialState);
});
it('should keep loading state on SUBSCRIPTION_DETAILS_REQUEST', () => {
expect(reducer(initialState, {
type: types.SUBSCRIPTION_DETAILS_REQUEST,
})).toEqual(loadingState);
});
it('load subscription details on SUBSCRIPTION_DETAILS_SUCCESS', () => {
expect(reducer(initialState, {
type: types.SUBSCRIPTION_DETAILS_SUCCESS,
response: subDetails,
})).toEqual(successState);
});
it('load error on SUBSCRIPTION_DETAILS_FAILURE', () => {
const error = 'nothing worked';
expect(reducer(initialState, {
type: types.SUBSCRIPTION_DETAILS_FAILURE,
error,
})).toEqual({
...initialState,
error,
});
});
});
webpack/scenes/Subscriptions/Details/__tests__/SubscriptionDetails.test.js
import React from 'react';
import { shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import SubscriptionDetails from '../SubscriptionDetails';
import SubscriptionDetailAssociations from '../SubscriptionDetailAssociations';
import SubscriptionDetailInfo from '../SubscriptionDetailInfo';
import SubscriptionDetailProducts from '../SubscriptionDetailProducts';
import { loadSubscriptionDetails } from '../SubscriptionDetailActions';
import { successState } from './subscriptionDetails.fixtures';
jest.mock('../../../../move_to_foreman/foreman_toast_notifications');
describe('subscriptions details page', () => {
it('should render and contain appropiate components', async () => {
const match = { params: { id: 1 } };
const wrapper = shallow(<SubscriptionDetails
loadSubscriptionDetails={loadSubscriptionDetails}
subscriptionDetails={successState}
match={match}
/>);
expect(wrapper.find('h1').text()).toEqual(successState.name);
expect(wrapper.find(SubscriptionDetailAssociations)).toHaveLength(1);
expect(wrapper.find(SubscriptionDetailInfo)).toHaveLength(1);
expect(wrapper.find(SubscriptionDetailProducts)).toHaveLength(1);
expect(toJson(wrapper)).toMatchSnapshot();
});
});
webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetailAssociations.test.js.snap
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`subscriptions detail associations page renders correctly 1`] = `
<div>
<h2>
Associations
</h2>
<table
className="table table-striped table-bordered table-condensed table-hover"
>
<thead>
<tr>
<td>
<b>
Resource
</b>
</td>
<td>
<b>
Quantity
</b>
</td>
</tr>
</thead>
<tbody>
<tr>
<td>
Content Hosts
</td>
<td>
<a
href="/content_hosts?search=subscription_id=\\"48\\""
>
0
</a>
</td>
</tr>
<tr>
<td>
Activation Keys
</td>
<td>
<a
href="/activation_keys?search=subscription_id=\\"48\\""
>
0
</a>
</td>
</tr>
</tbody>
</table>
</div>
`;
webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetailInfo.test.js.snap
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`subscriptions detail associations page renders correctly 1`] = `
<div>
<h2>
Subscription Info
</h2>
<table
className="table"
>
<tbody>
<tr>
<td>
<b>
Name
</b>
</td>
<td>
OpenShift Employee Subscription
</td>
</tr>
<tr>
<td>
<b>
Description
</b>
</td>
<td>
OpenShift Enterprise
</td>
</tr>
<tr>
<td>
<b>
Requires Virt-Who
</b>
</td>
<td>
false
</td>
</tr>
<tr>
<td>
<b>
Consumed
</b>
</td>
<td>
0
</td>
</tr>
<tr>
<td>
<b>
Starts
</b>
</td>
<td>
2013-03-01 00:00:00 -0500
</td>
</tr>
<tr>
<td>
<b>
Ends
</b>
</td>
<td>
2021-12-31 23:59:59 -0500
</td>
</tr>
<tr>
<td>
<b>
Product ID
</b>
</td>
<td>
SER0421
</td>
</tr>
<tr>
<td>
<b>
Contract Number
</b>
</td>
<td>
10126160
</td>
</tr>
<tr>
<td>
<b>
Account Number
</b>
</td>
<td>
1212729
</td>
</tr>
<tr>
<td>
<b>
Support Level
</b>
</td>
<td>
Self-Support
</td>
</tr>
<tr>
<td>
<b>
Support Type
</b>
</td>
<td>
L1-L3
</td>
</tr>
<tr>
<td>
<b>
Architecture(s)
</b>
</td>
<td>
ia64,ppc,ppc64,ppc64le,s390,s390x,x86,x86_64
</td>
</tr>
<tr>
<td>
<b>
Type
</b>
</td>
<td>
NORMAL
</td>
</tr>
<tr>
<td>
<b>
Multi-entitlement
</b>
</td>
<td>
</td>
</tr>
<tr>
<td>
<b>
Stacking ID
</b>
</td>
<td>
SER0421
</td>
</tr>
<tr>
<td>
<b>
Limits
</b>
</td>
<td>
Cores: 4
</td>
</tr>
<tr>
<td>
<b>
Instance-based
</b>
</td>
<td>
Yes
</td>
</tr>
</tbody>
</table>
</div>
`;
webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetailProducts.test.js.snap
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`subscription detail product page renders correctly 1`] = `
<div>
<h2>
Provided Products
</h2>
<ul>
<li>
Red Hat OpenShift Container Platform
</li>
<li>
Oracle Java for RHEL Server
</li>
<li>
Red Hat OpenShift Enterprise JBoss EAP add-on
</li>
<li>
Red Hat CloudForms Beta
</li>
<li>
Red Hat CloudForms
</li>
<li>
Red Hat OpenShift Enterprise Client Tools
</li>
<li>
Red Hat Enterprise Linux Atomic Host
</li>
<li>
JBoss Enterprise Application Platform
</li>
<li>
Red Hat JBoss AMQ Clients
</li>
<li>
Red Hat Beta
</li>
<li>
Red Hat OpenShift Enterprise Infrastructure
</li>
<li>
Red Hat Enterprise Linux Fast Datapath Beta
</li>
<li>
Red Hat Ansible Engine
</li>
<li>
Red Hat OpenShift Enterprise Application Node
</li>
<li>
Red Hat OpenShift Enterprise JBoss FUSE add-on
</li>
<li>
Red Hat Software Collections Beta for RHEL Server
</li>
<li>
Red Hat Software Collections for RHEL Server
</li>
<li>
Red Hat Enterprise Linux Fast Datapath
</li>
<li>
Red Hat Enterprise Linux Server
</li>
<li>
Red Hat OpenShift Enterprise JBoss A-MQ add-on
</li>
<li>
JBoss Enterprise Web Server
</li>
<li>
Red Hat JBoss Core Services
</li>
</ul>
</div>
`;
webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`subscriptions details page should render and contain appropiate components 1`] = `
<Grid
bsClass="container-fluid"
componentClass="div"
fluid={false}
>
<div>
<Spinner
className=""
inline={false}
inverse={false}
loading={false}
size="md"
>
<Row
bsClass="row"
componentClass="div"
>
<Col
bsClass="col"
componentClass="div"
sm={12}
>
<h1>
OpenShift Employee Subscription
</h1>
</Col>
</Row>
<Row
bsClass="row"
componentClass="div"
>
<Col
bsClass="col"
componentClass="div"
sm={6}
>
<SubscriptionDetailInfo
subscriptionDetails={
Object {
"account_number": 1212729,
"activation_keys": Array [],
"arch": "ia64,ppc,ppc64,ppc64le,s390,s390x,x86,x86_64",
"available": 1,
"consumed": 0,
"contract_number": 10126160,
"cores": 4,
"cp_id": "4028f92a6317cfbd0163b419377f3bee",
"description": "OpenShift Enterprise",
"end_date": "2021-12-31 23:59:59 -0500",
"error": null,
"host_count": 0,
"id": 48,
"instance_multiplier": 1,
"loading": false,
"multi_entitlement": true,
"name": "OpenShift Employee Subscription",
"product_id": "SER0421",
"product_name": "OpenShift Employee Subscription",
"provided_products": Array [
Object {
"id": 1,
"name": "Red Hat OpenShift Container Platform",
},
Object {
"id": 2,
"name": "Oracle Java for RHEL Server",
},
Object {
"id": 3,
"name": "Red Hat OpenShift Enterprise JBoss EAP add-on",
},
Object {
"id": 4,
"name": "Red Hat CloudForms Beta",
},
Object {
"id": 5,
"name": "Red Hat CloudForms",
},
Object {
"id": 6,
"name": "Red Hat OpenShift Enterprise Client Tools",
},
Object {
"id": 7,
"name": "Red Hat Enterprise Linux Atomic Host",
},
Object {
"id": 8,
"name": "JBoss Enterprise Application Platform",
},
Object {
"id": 9,
"name": "Red Hat JBoss AMQ Clients",
},
Object {
"id": 10,
"name": "Red Hat Beta",
},
Object {
"id": 11,
"name": "Red Hat OpenShift Enterprise Infrastructure",
},
Object {
"id": 12,
"name": "Red Hat Enterprise Linux Fast Datapath Beta",
},
Object {
"id": 13,
"name": "Red Hat Ansible Engine",
},
Object {
"id": 14,
"name": "Red Hat OpenShift Enterprise Application Node",
},
Object {
"id": 15,
"name": "Red Hat OpenShift Enterprise JBoss FUSE add-on",
},
Object {
"id": 16,
"name": "Red Hat Software Collections Beta for RHEL Server",
},
Object {
"id": 17,
"name": "Red Hat Software Collections for RHEL Server",
},
Object {
"id": 18,
"name": "Red Hat Enterprise Linux Fast Datapath",
},
Object {
"id": 19,
"name": "Red Hat Enterprise Linux Server",
},
Object {
"id": 20,
"name": "Red Hat OpenShift Enterprise JBoss A-MQ add-on",
},
Object {
"id": 21,
"name": "JBoss Enterprise Web Server",
},
Object {
"id": 22,
"name": "Red Hat JBoss Core Services",
},
],
"quantity": 1,
"ram": null,
"sockets": null,
"stacking_id": "SER0421",
"start_date": "2013-03-01 00:00:00 -0500",
"subscription_id": 3,
"support_level": "Self-Support",
"support_type": "L1-L3",
"type": "NORMAL",
"unmapped_guest": false,
"upstream": true,
"virt_only": false,
"virt_who": false,
}
}
/>
</Col>
<Col
bsClass="col"
componentClass="div"
sm={6}
>
<SubscriptionDetailAssociations
subscriptionDetails={
Object {
"account_number": 1212729,
"activation_keys": Array [],
"arch": "ia64,ppc,ppc64,ppc64le,s390,s390x,x86,x86_64",
"available": 1,
"consumed": 0,
"contract_number": 10126160,
"cores": 4,
"cp_id": "4028f92a6317cfbd0163b419377f3bee",
"description": "OpenShift Enterprise",
"end_date": "2021-12-31 23:59:59 -0500",
"error": null,
"host_count": 0,
"id": 48,
"instance_multiplier": 1,
"loading": false,
"multi_entitlement": true,
"name": "OpenShift Employee Subscription",
"product_id": "SER0421",
"product_name": "OpenShift Employee Subscription",
"provided_products": Array [
Object {
"id": 1,
"name": "Red Hat OpenShift Container Platform",
},
Object {
"id": 2,
"name": "Oracle Java for RHEL Server",
},
Object {
"id": 3,
"name": "Red Hat OpenShift Enterprise JBoss EAP add-on",
},
Object {
"id": 4,
"name": "Red Hat CloudForms Beta",
},
Object {
"id": 5,
"name": "Red Hat CloudForms",
},
Object {
"id": 6,
"name": "Red Hat OpenShift Enterprise Client Tools",
},
Object {
"id": 7,
"name": "Red Hat Enterprise Linux Atomic Host",
},
Object {
"id": 8,
"name": "JBoss Enterprise Application Platform",
},
Object {
"id": 9,
"name": "Red Hat JBoss AMQ Clients",
},
Object {
"id": 10,
"name": "Red Hat Beta",
},
Object {
"id": 11,
"name": "Red Hat OpenShift Enterprise Infrastructure",
},
Object {
"id": 12,
"name": "Red Hat Enterprise Linux Fast Datapath Beta",
},
Object {
"id": 13,
"name": "Red Hat Ansible Engine",
},
Object {
"id": 14,
"name": "Red Hat OpenShift Enterprise Application Node",
},
Object {
"id": 15,
"name": "Red Hat OpenShift Enterprise JBoss FUSE add-on",
},
Object {
"id": 16,
"name": "Red Hat Software Collections Beta for RHEL Server",
},
Object {
"id": 17,
"name": "Red Hat Software Collections for RHEL Server",
},
Object {
"id": 18,
"name": "Red Hat Enterprise Linux Fast Datapath",
},
Object {
"id": 19,
"name": "Red Hat Enterprise Linux Server",
},
Object {
"id": 20,
"name": "Red Hat OpenShift Enterprise JBoss A-MQ add-on",
},
Object {
"id": 21,
"name": "JBoss Enterprise Web Server",
},
Object {
"id": 22,
"name": "Red Hat JBoss Core Services",
},
],
"quantity": 1,
"ram": null,
"sockets": null,
"stacking_id": "SER0421",
"start_date": "2013-03-01 00:00:00 -0500",
"subscription_id": 3,
"support_level": "Self-Support",
"support_type": "L1-L3",
"type": "NORMAL",
"unmapped_guest": false,
"upstream": true,
"virt_only": false,
"virt_who": false,
}
}
/>
<SubscriptionDetailProducts
subscriptionDetails={
Object {
"account_number": 1212729,
"activation_keys": Array [],
"arch": "ia64,ppc,ppc64,ppc64le,s390,s390x,x86,x86_64",
"available": 1,
"consumed": 0,
"contract_number": 10126160,
"cores": 4,
"cp_id": "4028f92a6317cfbd0163b419377f3bee",
"description": "OpenShift Enterprise",
"end_date": "2021-12-31 23:59:59 -0500",
"error": null,
"host_count": 0,
"id": 48,
"instance_multiplier": 1,
"loading": false,
"multi_entitlement": true,
"name": "OpenShift Employee Subscription",
"product_id": "SER0421",
"product_name": "OpenShift Employee Subscription",
"provided_products": Array [
Object {
"id": 1,
"name": "Red Hat OpenShift Container Platform",
},
Object {
"id": 2,
"name": "Oracle Java for RHEL Server",
},
Object {
"id": 3,
"name": "Red Hat OpenShift Enterprise JBoss EAP add-on",
},
Object {
"id": 4,
"name": "Red Hat CloudForms Beta",
},
Object {
"id": 5,
"name": "Red Hat CloudForms",
},
Object {
"id": 6,
"name": "Red Hat OpenShift Enterprise Client Tools",
},
Object {
"id": 7,
"name": "Red Hat Enterprise Linux Atomic Host",
},
Object {
"id": 8,
"name": "JBoss Enterprise Application Platform",
},
Object {
"id": 9,
"name": "Red Hat JBoss AMQ Clients",
},
Object {
"id": 10,
"name": "Red Hat Beta",
},
Object {
"id": 11,
"name": "Red Hat OpenShift Enterprise Infrastructure",
},
Object {
"id": 12,
"name": "Red Hat Enterprise Linux Fast Datapath Beta",
},
Object {
"id": 13,
"name": "Red Hat Ansible Engine",
},
Object {
"id": 14,
"name": "Red Hat OpenShift Enterprise Application Node",
},
Object {
"id": 15,
"name": "Red Hat OpenShift Enterprise JBoss FUSE add-on",
},
Object {
"id": 16,
"name": "Red Hat Software Collections Beta for RHEL Server",
},
Object {
"id": 17,
"name": "Red Hat Software Collections for RHEL Server",
},
Object {
"id": 18,
"name": "Red Hat Enterprise Linux Fast Datapath",
},
Object {
"id": 19,
"name": "Red Hat Enterprise Linux Server",
},
Object {
"id": 20,
"name": "Red Hat OpenShift Enterprise JBoss A-MQ add-on",
},
Object {
"id": 21,
"name": "JBoss Enterprise Web Server",
},
Object {
"id": 22,
"name": "Red Hat JBoss Core Services",
},
],
"quantity": 1,
"ram": null,
"sockets": null,
"stacking_id": "SER0421",
"start_date": "2013-03-01 00:00:00 -0500",
"subscription_id": 3,
"support_level": "Self-Support",
"support_type": "L1-L3",
"type": "NORMAL",
"unmapped_guest": false,
"upstream": true,
"virt_only": false,
"virt_who": false,
}
}
/>
</Col>
</Row>
</Spinner>
</div>
</Grid>
`;
webpack/scenes/Subscriptions/Details/__tests__/subscriptionDetails.fixtures.js
import Immutable from 'seamless-immutable';
export const initialState = Immutable({
loading: false,
});
export const loadingState = Immutable({
...initialState,
loading: true,
});
export const emptyState = Immutable({
...loadingState,
});
export const subDetails = Immutable({
error: null,
arch: 'ia64,ppc,ppc64,ppc64le,s390,s390x,x86,x86_64',
description: 'OpenShift Enterprise',
support_type: 'L1-L3',
id: 48,
cp_id: '4028f92a6317cfbd0163b419377f3bee',
subscription_id: 3,
name: 'OpenShift Employee Subscription',
start_date: '2013-03-01 00:00:00 -0500',
end_date: '2021-12-31 23:59:59 -0500',
available: 1,
quantity: 1,
consumed: 0,
account_number: 1212729,
contract_number: 10126160,
support_level: 'Self-Support',
product_id: 'SER0421',
sockets: null,
cores: 4,
ram: null,
instance_multiplier: 1,
stacking_id: 'SER0421',
multi_entitlement: true,
type: 'NORMAL',
product_name: 'OpenShift Employee Subscription',
unmapped_guest: false,
virt_only: false,
virt_who: false,
upstream: true,
host_count: 0,
provided_products: [
{
id: 1,
name: 'Red Hat OpenShift Container Platform',
},
{
id: 2,
name: 'Oracle Java for RHEL Server',
},
{
id: 3,
name: 'Red Hat OpenShift Enterprise JBoss EAP add-on',
},
{
id: 4,
name: 'Red Hat CloudForms Beta',
},
{
id: 5,
name: 'Red Hat CloudForms',
},
{
id: 6,
name: 'Red Hat OpenShift Enterprise Client Tools',
},
{
id: 7,
name: 'Red Hat Enterprise Linux Atomic Host',
},
{
id: 8,
name: 'JBoss Enterprise Application Platform',
},
{
id: 9,
name: 'Red Hat JBoss AMQ Clients',
},
{
id: 10,
name: 'Red Hat Beta',
},
{
id: 11,
name: 'Red Hat OpenShift Enterprise Infrastructure',
},
{
id: 12,
name: 'Red Hat Enterprise Linux Fast Datapath Beta',
},
{
id: 13,
name: 'Red Hat Ansible Engine',
},
{
id: 14,
name: 'Red Hat OpenShift Enterprise Application Node',
},
{
id: 15,
name: 'Red Hat OpenShift Enterprise JBoss FUSE add-on',
},
{
id: 16,
name: 'Red Hat Software Collections Beta for RHEL Server',
},
{
id: 17,
name: 'Red Hat Software Collections for RHEL Server',
},
{
id: 18,
name: 'Red Hat Enterprise Linux Fast Datapath',
},
{
id: 19,
name: 'Red Hat Enterprise Linux Server',
},
{
id: 20,
name: 'Red Hat OpenShift Enterprise JBoss A-MQ add-on',
},
{
id: 21,
name: 'JBoss Enterprise Web Server',
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff