diff --git a/__tests__/pages/Organizations/screens/Organization/OrganizationDetail.test.jsx b/__tests__/pages/Organizations/screens/Organization/OrganizationDetail.test.jsx index 11ad3a144f..e3b303d952 100644 --- a/__tests__/pages/Organizations/screens/Organization/OrganizationDetail.test.jsx +++ b/__tests__/pages/Organizations/screens/Organization/OrganizationDetail.test.jsx @@ -5,16 +5,114 @@ import { I18nProvider } from '@lingui/react'; import OrganizationDetail from '../../../../../src/pages/Organizations/screens/Organization/OrganizationDetail'; describe('', () => { + const mockDetails = { + name: 'Foo', + description: 'Bar', + custom_virtualenv: 'Fizz', + created: 'Bat', + modified: 'Boo' + }; + test('initially renders succesfully', () => { mount( ); }); + + test('should request instance groups from api', () => { + const getOrganizationInstanceGroups = jest.fn(); + mount( + + + + + + ).find('OrganizationDetail'); + + expect(getOrganizationInstanceGroups).toHaveBeenCalledTimes(1); + }); + + test('should handle setting instance groups to state', async () => { + const mockInstanceGroups = [ + { name: 'One', id: 1 }, + { name: 'Two', id: 2 } + ]; + const getOrganizationInstanceGroups = jest.fn(() => ( + Promise.resolve({ data: { results: mockInstanceGroups } }) + )); + const wrapper = mount( + + + + + + ).find('OrganizationDetail'); + + await getOrganizationInstanceGroups(); + expect(wrapper.state().instanceGroups).toEqual(mockInstanceGroups); + }); + + test('should render Details', async () => { + const wrapper = mount( + + + + + + ); + + const detailWrapper = wrapper.find('Detail'); + expect(detailWrapper.length).toBe(5); + + const nameDetail = detailWrapper.findWhere(node => node.props().label === 'Name'); + const descriptionDetail = detailWrapper.findWhere(node => node.props().label === 'Description'); + const custom_virtualenvDetail = detailWrapper.findWhere(node => node.props().label === 'Ansible Environment'); + const createdDetail = detailWrapper.findWhere(node => node.props().label === 'Created'); + const modifiedDetail = detailWrapper.findWhere(node => node.props().label === 'Last Modified'); + + expect(nameDetail.find('h6').text()).toBe('Name'); + expect(nameDetail.find('p').text()).toBe('Foo'); + + expect(descriptionDetail.find('h6').text()).toBe('Description'); + expect(descriptionDetail.find('p').text()).toBe('Bar'); + + expect(custom_virtualenvDetail.find('h6').text()).toBe('Ansible Environment'); + expect(custom_virtualenvDetail.find('p').text()).toBe('Fizz'); + + expect(createdDetail.find('h6').text()).toBe('Created'); + expect(createdDetail.find('p').text()).toBe('Bat'); + + expect(modifiedDetail.find('h6').text()).toBe('Last Modified'); + expect(modifiedDetail.find('p').text()).toBe('Boo'); + }); }); diff --git a/src/api.js b/src/api.js index d0281a09a4..028959b186 100644 --- a/src/api.js +++ b/src/api.js @@ -70,6 +70,12 @@ class APIClient { return this.http.get(endpoint); } + getOrganizationInstanceGroups (id, params = {}) { + const endpoint = `${API_ORGANIZATIONS}${id}/instance_groups/`; + + return this.http.get(endpoint, { params }); + } + getOrganizationNotifications (id, params = {}) { const endpoint = `${API_ORGANIZATIONS}${id}/notification_templates/`; diff --git a/src/components/BasicChip/BasicChip.jsx b/src/components/BasicChip/BasicChip.jsx new file mode 100644 index 0000000000..a1c2d55950 --- /dev/null +++ b/src/components/BasicChip/BasicChip.jsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { Chip } from '@patternfly/react-core'; +import './basicChip.scss'; + +const BasicChip = ({ text }) => ( + + {text} + +); + +export default BasicChip; diff --git a/src/components/BasicChip/basicChip.scss b/src/components/BasicChip/basicChip.scss new file mode 100644 index 0000000000..de0aa5739b --- /dev/null +++ b/src/components/BasicChip/basicChip.scss @@ -0,0 +1,10 @@ +.awx-c-chip--basic { + padding: 6px 8px; + height: 30px; + margin-right: 10px; + margin-bottom: 10px; + + .pf-c-button { + display: none; + } +} \ No newline at end of file diff --git a/src/components/Tabs/tabs.scss b/src/components/Tabs/tabs.scss index 15c557dea8..e13b650347 100644 --- a/src/components/Tabs/tabs.scss +++ b/src/components/Tabs/tabs.scss @@ -1,6 +1,8 @@ .pf-c-card__header { --pf-c-card__header--PaddingBottom: 0; --pf-c-card__header--PaddingX: 0; + --pf-c-card__header--PaddingRight: 0; + --pf-c-card__header--PaddingLeft: 0; --pf-c-card__header--PaddingTop: 0; } diff --git a/src/pages/Organizations/screens/Organization/Organization.jsx b/src/pages/Organizations/screens/Organization/Organization.jsx index 83bc7bdd59..2b63bf0877 100644 --- a/src/pages/Organizations/screens/Organization/Organization.jsx +++ b/src/pages/Organizations/screens/Organization/Organization.jsx @@ -127,16 +127,18 @@ class Organization extends Component { /> )} /> - ( - - )} - /> + {organization && ( + ( + + )} + /> + )}

Access

} diff --git a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx index b7683ec5e1..d3e6168149 100644 --- a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx +++ b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx @@ -1,15 +1,144 @@ -import React from 'react'; -import { withRouter, Link } from 'react-router-dom'; -import { Trans } from '@lingui/macro'; -import { CardBody } from '@patternfly/react-core'; +import React, { Component } from 'react'; +import { Link } from 'react-router-dom'; +import { I18n } from '@lingui/react'; +import { Trans, t } from '@lingui/macro'; +import { + CardBody, + Button, + Text, + TextContent, + TextVariants, +} from '@patternfly/react-core'; +import BasicChip from '../../../../components/BasicChip/BasicChip'; -const OrganizationDetail = ({ match, organization }) => ( - -

{`${organization && organization.name} Detail View`}

- - Edit Details - -
-); +const detailWrapperStyle = { + display: 'flex' +}; -export default withRouter(OrganizationDetail); +const detailLabelStyle = { + minWidth: '150px', + marginRight: '20px', + textAlign: 'right' +}; + +const Detail = ({ label, value }) => { + let detail = null; + if (value) { + detail = ( + + { label } + { value } + + ); + } + return detail; +}; + +class OrganizationDetail extends Component { + constructor (props) { + super(props); + + this.state = { + instanceGroups: [], + error: false + }; + + this.loadInstanceGroups = this.loadInstanceGroups.bind(this); + } + + componentDidMount () { + this.loadInstanceGroups(); + } + + async loadInstanceGroups () { + const { + api, + match + } = this.props; + try { + const { + data + } = await api.getOrganizationInstanceGroups(match.params.id); + this.setState({ + instanceGroups: [...data.results] + }); + } catch (err) { + this.setState({ error: true }); + } + } + + render () { + const { + error, + instanceGroups, + } = this.state; + + const { + organization: { + name, + description, + custom_virtualenv, + created, + modified + }, + match + } = this.props; + + return ( + + {({ i18n }) => ( + +
+ + + {(instanceGroups && instanceGroups.length > 0) && ( + + + Instance Groups + +
+ {instanceGroups.map(instanceGroup => ( + + ))} +
+
+ )} + + + +
+
+ + + +
+ {error ? 'error!' : ''} +
+ )} +
+ ); + } +} + +export default OrganizationDetail;