diff --git a/awx/ui_next/src/screens/Application/ApplicationAdd/ApplicationAdd.jsx b/awx/ui_next/src/screens/Application/ApplicationAdd/ApplicationAdd.jsx index 0537fa813c..34f40645d7 100644 --- a/awx/ui_next/src/screens/Application/ApplicationAdd/ApplicationAdd.jsx +++ b/awx/ui_next/src/screens/Application/ApplicationAdd/ApplicationAdd.jsx @@ -8,7 +8,7 @@ import ApplicationForm from '../shared/ApplicationForm'; import { ApplicationsAPI } from '../../../api'; import { CardBody } from '../../../components/Card'; -function ApplicationAdd() { +function ApplicationAdd({ onSuccessfulAdd }) { const history = useHistory(); const [submitError, setSubmitError] = useState(null); @@ -53,10 +53,9 @@ function ApplicationAdd() { const handleSubmit = async ({ ...values }) => { values.organization = values.organization.id; try { - const { - data: { id }, - } = await ApplicationsAPI.create(values); - history.push(`/applications/${id}/details`); + const { data } = await ApplicationsAPI.create(values); + onSuccessfulAdd(data); + history.push(`/applications/${data.id}/details`); } catch (err) { setSubmitError(err); } diff --git a/awx/ui_next/src/screens/Application/ApplicationAdd/ApplicationAdd.test.jsx b/awx/ui_next/src/screens/Application/ApplicationAdd/ApplicationAdd.test.jsx index 2bc0eba47e..dd480e8ab9 100644 --- a/awx/ui_next/src/screens/Application/ApplicationAdd/ApplicationAdd.test.jsx +++ b/awx/ui_next/src/screens/Application/ApplicationAdd/ApplicationAdd.test.jsx @@ -39,12 +39,16 @@ const options = { }, }; +const onSuccessfulAdd = jest.fn(); + describe('', () => { let wrapper; test('should render properly', async () => { ApplicationsAPI.readOptions.mockResolvedValue(options); await act(async () => { - wrapper = mountWithContexts(); + wrapper = mountWithContexts( + + ); }); expect(wrapper.find('ApplicationAdd').length).toBe(1); expect(wrapper.find('ApplicationForm').length).toBe(1); @@ -59,9 +63,12 @@ describe('', () => { ApplicationsAPI.create.mockResolvedValue({ data: { id: 8 } }); await act(async () => { - wrapper = mountWithContexts(, { - context: { router: { history } }, - }); + wrapper = mountWithContexts( + , + { + context: { router: { history } }, + } + ); }); await act(async () => { @@ -124,6 +131,7 @@ describe('', () => { redirect_uris: 'http://www.google.com', }); expect(history.location.pathname).toBe('/applications/8/details'); + expect(onSuccessfulAdd).toHaveBeenCalledWith({ id: 8 }); }); test('should cancel form properly', async () => { @@ -134,9 +142,12 @@ describe('', () => { ApplicationsAPI.create.mockResolvedValue({ data: { id: 8 } }); await act(async () => { - wrapper = mountWithContexts(, { - context: { router: { history } }, - }); + wrapper = mountWithContexts( + , + { + context: { router: { history } }, + } + ); }); await act(async () => { wrapper.find('Button[aria-label="Cancel"]').prop('onClick')(); @@ -157,7 +168,9 @@ describe('', () => { ApplicationsAPI.create.mockRejectedValue(error); ApplicationsAPI.readOptions.mockResolvedValue(options); await act(async () => { - wrapper = mountWithContexts(); + wrapper = mountWithContexts( + + ); }); await act(async () => { wrapper.find('Formik').prop('onSubmit')({ @@ -181,7 +194,9 @@ describe('', () => { }) ); await act(async () => { - wrapper = mountWithContexts(); + wrapper = mountWithContexts( + + ); }); wrapper.update(); diff --git a/awx/ui_next/src/screens/Application/ApplicationDetails/ApplicationDetails.jsx b/awx/ui_next/src/screens/Application/ApplicationDetails/ApplicationDetails.jsx index e6874b65a5..54ab2bdf24 100644 --- a/awx/ui_next/src/screens/Application/ApplicationDetails/ApplicationDetails.jsx +++ b/awx/ui_next/src/screens/Application/ApplicationDetails/ApplicationDetails.jsx @@ -80,6 +80,7 @@ function ApplicationDetails({ application.authorization_grant_type )} /> + ', () => { expect(wrapper.find('Detail[label="Client type"]').prop('value')).toBe( 'Confidential' ); + expect(wrapper.find('Detail[label="Client ID"]').prop('value')).toBe( + 'b1dmj8xzkbFm1ZQ27ygw2ZeE9I0AXqqeL74fiyk4' + ); expect(wrapper.find('Button[aria-label="Edit"]').prop('to')).toBe( '/applications/10/edit' ); diff --git a/awx/ui_next/src/screens/Application/ApplicationEdit/ApplicationEdit.jsx b/awx/ui_next/src/screens/Application/ApplicationEdit/ApplicationEdit.jsx index 18268ba63a..13558bd2a0 100644 --- a/awx/ui_next/src/screens/Application/ApplicationEdit/ApplicationEdit.jsx +++ b/awx/ui_next/src/screens/Application/ApplicationEdit/ApplicationEdit.jsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { useHistory, useParams } from 'react-router-dom'; -import { Card, PageSection } from '@patternfly/react-core'; +import { Card } from '@patternfly/react-core'; import ApplicationForm from '../shared/ApplicationForm'; import { ApplicationsAPI } from '../../../api'; import { CardBody } from '../../../components/Card'; @@ -29,22 +29,18 @@ function ApplicationEdit({ history.push(`/applications/${id}/details`); }; return ( - <> - - - - - - - - + + + + + ); } export default ApplicationEdit; diff --git a/awx/ui_next/src/screens/Application/Applications.jsx b/awx/ui_next/src/screens/Application/Applications.jsx index 1842e5bd89..91b5c9a024 100644 --- a/awx/ui_next/src/screens/Application/Applications.jsx +++ b/awx/ui_next/src/screens/Application/Applications.jsx @@ -2,13 +2,19 @@ import React, { useState, useCallback } from 'react'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { Route, Switch } from 'react-router-dom'; - +import { + ClipboardCopy, + ClipboardCopyVariant, + Modal, +} from '@patternfly/react-core'; import ApplicationsList from './ApplicationsList'; import ApplicationAdd from './ApplicationAdd'; import Application from './Application'; import Breadcrumbs from '../../components/Breadcrumbs'; +import { Detail, DetailList } from '../../components/DetailList'; function Applications({ i18n }) { + const [applicationModalSource, setApplicationModalSource] = useState(null); const [breadcrumbConfig, setBreadcrumbConfig] = useState({ '/applications': i18n._(t`Applications`), '/applications/add': i18n._(t`Create New Application`), @@ -36,7 +42,9 @@ function Applications({ i18n }) { - + setApplicationModalSource(app)} + /> @@ -45,6 +53,48 @@ function Applications({ i18n }) { + {applicationModalSource && ( + setApplicationModalSource(null)} + > + + + {applicationModalSource.client_id && ( + + {applicationModalSource.client_id} + + } + /> + )} + {applicationModalSource.client_secret && ( + + {applicationModalSource.client_secret} + + } + /> + )} + + + )} ); } diff --git a/awx/ui_next/src/screens/Application/Applications.test.jsx b/awx/ui_next/src/screens/Application/Applications.test.jsx index f309a2b60a..bb75e55deb 100644 --- a/awx/ui_next/src/screens/Application/Applications.test.jsx +++ b/awx/ui_next/src/screens/Application/Applications.test.jsx @@ -1,25 +1,48 @@ import React from 'react'; - +import { act } from 'react-dom/test-utils'; +import { createMemoryHistory } from 'history'; import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; import Applications from './Applications'; describe('', () => { - let pageWrapper; - let pageSections; - - beforeEach(() => { - pageWrapper = mountWithContexts(); - pageSections = pageWrapper.find('PageSection'); - }); + let wrapper; afterEach(() => { - pageWrapper.unmount(); + wrapper.unmount(); }); - test('initially renders without crashing', () => { - expect(pageWrapper.length).toBe(1); + test('renders successfully', () => { + wrapper = mountWithContexts(); + const pageSections = wrapper.find('PageSection'); + expect(wrapper.length).toBe(1); expect(pageSections.length).toBe(1); expect(pageSections.first().props().variant).toBe('light'); }); + + test('shows Application information modal after successful creation', async () => { + const history = createMemoryHistory({ + initialEntries: ['/applications/add'], + }); + wrapper = mountWithContexts(, { + context: { router: { history } }, + }); + expect(wrapper.find('Modal[title="Application information"]').length).toBe( + 0 + ); + await act(async () => { + wrapper + .find('ApplicationAdd') + .props() + .onSuccessfulAdd({ + name: 'test', + client_id: 'foobar', + client_secret: 'aaaaaaaaaaaaaaaaaaaaaaaaaa', + }); + }); + wrapper.update(); + expect(wrapper.find('Modal[title="Application information"]').length).toBe( + 1 + ); + }); });