From 8e0ad2ef6eed99eaaec731a075d24c21b19ce12a Mon Sep 17 00:00:00 2001 From: John Mitchell Date: Tue, 18 Feb 2020 14:40:09 -0500 Subject: [PATCH] add cred access tab and update credentials routing --- .../src/screens/Credential/Credential.jsx | 62 +++++++++++++++---- .../screens/Credential/Credential.test.jsx | 51 ++++++++------- .../src/screens/Credential/Credentials.jsx | 6 +- 3 files changed, 81 insertions(+), 38 deletions(-) diff --git a/awx/ui_next/src/screens/Credential/Credential.jsx b/awx/ui_next/src/screens/Credential/Credential.jsx index 705c305e61..31ede881cc 100644 --- a/awx/ui_next/src/screens/Credential/Credential.jsx +++ b/awx/ui_next/src/screens/Credential/Credential.jsx @@ -6,12 +6,14 @@ import { Switch, useParams, useLocation, + useRouteMatch, Route, Redirect, Link, } from 'react-router-dom'; import { TabbedCardHeader } from '@components/Card'; import CardCloseButton from '@components/CardCloseButton'; +import { ResourceAccessList } from '@components/ResourceAccessList'; import ContentError from '@components/ContentError'; import RoutedTabs from '@components/RoutedTabs'; import CredentialDetail from './CredentialDetail'; @@ -21,7 +23,10 @@ function Credential({ i18n, setBreadcrumb }) { const [credential, setCredential] = useState(null); const [contentError, setContentError] = useState(null); const [hasContentLoading, setHasContentLoading] = useState(true); - const location = useLocation(); + const { pathname } = useLocation(); + const match = useRouteMatch({ + path: '/credentials/:id', + }); const { id } = useParams(); useEffect(() => { @@ -37,18 +42,20 @@ function Credential({ i18n, setBreadcrumb }) { } } fetchData(); - }, [id, setBreadcrumb]); + }, [id, pathname, setBreadcrumb]); const tabsArray = [ { name: i18n._(t`Details`), link: `/credentials/${id}/details`, id: 0 }, - { name: i18n._(t`Access`), link: `/credentials/${id}/access`, id: 1 }, - { - name: i18n._(t`Notifications`), - link: `/credentials/${id}/notifications`, - id: 2, - }, ]; + if (credential && credential.organization) { + tabsArray.push({ + name: i18n._(t`Access`), + link: `/credentials/${id}/access`, + id: 1, + }); + } + let cardHeader = hasContentLoading ? null : ( @@ -56,7 +63,7 @@ function Credential({ i18n, setBreadcrumb }) { ); - if (location.pathname.endsWith('edit') || location.pathname.endsWith('add')) { + if (pathname.endsWith('edit') || pathname.endsWith('add')) { cardHeader = null; } @@ -87,11 +94,40 @@ function Credential({ i18n, setBreadcrumb }) { to="/credentials/:id/details" exact /> - {credential && ( - - - + {credential && [ + } + />, + credential.organization && ( + ( + + )} + /> + ), + + !hasContentLoading && ( + + {match.params.id && ( + + {i18n._(`View Credential Details`)} + )} + + ) + } + />, + ]} ({ + ...jest.requireActual('react-router-dom'), + useRouteMatch: () => ({ + url: '/credentials/2', + params: { id: 2 }, + }), +})); -CredentialsAPI.readDetail.mockResolvedValue({ - data: mockCredentials.results[0], +CredentialsAPI.readDetail.mockResolvedValueOnce({ + data: mockCredential, }); describe('', () => { let wrapper; - beforeEach(async () => { + test('initially renders user-based credential succesfully', async () => { await act(async () => { wrapper = mountWithContexts( {}} />); }); + await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); + await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 1); }); - test('initially renders succesfully', async () => { - expect(wrapper.find('Credential').length).toBe(1); + test('initially renders org-based credential succesfully', async () => { + CredentialsAPI.readDetail.mockResolvedValueOnce({ + data: mockOrgCredential, + }); + + await act(async () => { + wrapper = mountWithContexts( {}} />); + }); + await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); + // org-based credential detail needs access tab + await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 2); }); test('should show content error when user attempts to navigate to erroneous route', async () => { const history = createMemoryHistory({ - initialEntries: ['/credentials/1/foobar'], + initialEntries: ['/credentials/2/foobar'], }); await act(async () => { wrapper = mountWithContexts( {}} />, { @@ -38,8 +57,8 @@ describe('', () => { location: history.location, match: { params: { id: 1 }, - url: '/credentials/1/foobar', - path: '/credentials/1/foobar', + url: '/credentials/2/foobar', + path: '/credentials/2/foobar', }, }, }, @@ -47,19 +66,5 @@ describe('', () => { }); }); await waitForElement(wrapper, 'ContentError', el => el.length === 1); - expect(wrapper.find('ContentError Title').text()).toEqual('Not Found'); - }); - - test('should show content error if api throws an error', async () => { - CredentialsAPI.readDetail.mockImplementationOnce(() => - Promise.reject(new Error()) - ); - await act(async () => { - wrapper = mountWithContexts( {}} />); - }); - await waitForElement(wrapper, 'ContentError', el => el.length === 1); - expect(wrapper.find('ContentError Title').text()).toEqual( - 'Something went wrong...' - ); }); }); diff --git a/awx/ui_next/src/screens/Credential/Credentials.jsx b/awx/ui_next/src/screens/Credential/Credentials.jsx index 6b9db548ee..ce82540615 100644 --- a/awx/ui_next/src/screens/Credential/Credentials.jsx +++ b/awx/ui_next/src/screens/Credential/Credentials.jsx @@ -2,7 +2,7 @@ import React, { useState, useCallback } from 'react'; import { Route, Switch } from 'react-router-dom'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; - +import { Config } from '@contexts/Config'; import Breadcrumbs from '@components/Breadcrumbs'; import Credential from './Credential'; import CredentialAdd from './CredentialAdd'; @@ -24,7 +24,9 @@ function Credentials({ i18n }) { '/credentials': i18n._(t`Credentials`), '/credentials/add': i18n._(t`Create New Credential`), [`/credentials/${credential.id}`]: `${credential.name}`, + [`/credentials/${credential.id}/edit`]: i18n._(t`Edit Details`), [`/credentials/${credential.id}/details`]: i18n._(t`Details`), + [`/credentials/${credential.id}/access`]: i18n._(t`Access`), }); }, [i18n] @@ -35,7 +37,7 @@ function Credentials({ i18n }) { - + {({ me }) => }