diff --git a/awx/ui_next/src/screens/Inventory/Inventory.jsx b/awx/ui_next/src/screens/Inventory/Inventory.jsx index 54b5ac2298..5352b949a4 100644 --- a/awx/ui_next/src/screens/Inventory/Inventory.jsx +++ b/awx/ui_next/src/screens/Inventory/Inventory.jsx @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React, { useEffect, useState } from 'react'; import { t } from '@lingui/macro'; import { withI18n } from '@lingui/react'; import { Card, CardHeader, PageSection } from '@patternfly/react-core'; @@ -16,186 +16,152 @@ import InventorySources from './InventorySources'; import { InventoriesAPI } from '@api'; import InventoryEdit from './InventoryEdit'; -class Inventory extends Component { - constructor(props) { - super(props); +function Inventory({ history, i18n, location, match, setBreadcrumb }) { + const [contentError, setContentError] = useState(null); + const [hasContentLoading, setHasContentLoading] = useState(true); + const [inventory, setInventory] = useState(null); - this.state = { - contentError: null, - hasContentLoading: true, - inventory: null, - }; - this.loadInventory = this.loadInventory.bind(this); - } - - async componentDidMount() { - await this.loadInventory(); - } - - async componentDidUpdate(prevProps) { - const { location, match } = this.props; - const url = `/inventories/inventory/${match.params.id}/`; - - if ( - prevProps.location.pathname.startsWith(url) && - prevProps.location !== location && - location.pathname === `${url}details` - ) { - await this.loadInventory(); - } - } - - async loadInventory() { - const { setBreadcrumb, match } = this.props; - const { id } = match.params; - - this.setState({ contentError: null, hasContentLoading: true }); - try { - const { data } = await InventoriesAPI.readDetail(id); - setBreadcrumb(data); - this.setState({ inventory: data }); - } catch (err) { - this.setState({ contentError: err }); - } finally { - this.setState({ hasContentLoading: false }); - } - } - - render() { - const { history, i18n, location, match } = this.props; - const { contentError, hasContentLoading, inventory } = this.state; - - const tabsArray = [ - { name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 }, - { name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 }, - { name: i18n._(t`Groups`), link: `${match.url}/groups`, id: 2 }, - { name: i18n._(t`Hosts`), link: `${match.url}/hosts`, id: 3 }, - { name: i18n._(t`Sources`), link: `${match.url}/sources`, id: 4 }, - { - name: i18n._(t`Completed Jobs`), - link: `${match.url}/completed_jobs`, - id: 5, - }, - ]; - - let cardHeader = hasContentLoading ? null : ( - - - - - ); - - if ( - location.pathname.endsWith('edit') || - location.pathname.endsWith('add') - ) { - cardHeader = null; + useEffect(() => { + async function fetchData() { + try { + const { data } = await InventoriesAPI.readDetail(match.params.id); + setBreadcrumb(data); + setInventory(data); + } catch (error) { + setContentError(error); + } finally { + setHasContentLoading(false); + } } - if (!hasContentLoading && contentError) { - return ( - - - - {contentError.response.status === 404 && ( - - {i18n._(`Inventory not found.`)}{' '} - - {i18n._(`View all Inventories.`)} - - - )} - - - - ); - } + fetchData(); + }, [match.params.id, setBreadcrumb]); + const tabsArray = [ + { name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 }, + { name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 }, + { name: i18n._(t`Groups`), link: `${match.url}/groups`, id: 2 }, + { name: i18n._(t`Hosts`), link: `${match.url}/hosts`, id: 3 }, + { name: i18n._(t`Sources`), link: `${match.url}/sources`, id: 4 }, + { + name: i18n._(t`Completed Jobs`), + link: `${match.url}/completed_jobs`, + id: 5, + }, + ]; + + let cardHeader = hasContentLoading ? null : ( + + + + + ); + + if (location.pathname.endsWith('edit') || location.pathname.endsWith('add')) { + cardHeader = null; + } + + if (!hasContentLoading && contentError) { return ( - {cardHeader} - - - {inventory && [ - ( - - )} - />, - } - />, - } - />, - ( - - )} - />, - } - />, - } - />, - } - />, - } - />, - - !hasContentLoading && ( - - {match.params.id && ( - - {i18n._(`View Inventory Details`)} - - )} - - ) - } - />, - ]} - + + {contentError.response.status === 404 && ( + + {i18n._(`Inventory not found.`)}{' '} + {i18n._(`View all Inventories.`)} + + )} + ); } + + return ( + + + {cardHeader} + + + {inventory && [ + ( + + )} + />, + } + />, + } + />, + ( + + )} + />, + } + />, + } + />, + } + />, + } + />, + + !hasContentLoading && ( + + {match.params.id && ( + + {i18n._(`View Inventory Details`)} + + )} + + ) + } + />, + ]} + + + + ); } export { Inventory as _Inventory }; diff --git a/awx/ui_next/src/screens/Inventory/Inventory.test.jsx b/awx/ui_next/src/screens/Inventory/Inventory.test.jsx index cff57dfc11..f242b01a7d 100644 --- a/awx/ui_next/src/screens/Inventory/Inventory.test.jsx +++ b/awx/ui_next/src/screens/Inventory/Inventory.test.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { act } from 'react-dom/test-utils'; import { createMemoryHistory } from 'history'; import { InventoriesAPI } from '@api'; import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers'; @@ -12,41 +13,38 @@ InventoriesAPI.readDetail.mockResolvedValue({ }); describe('', () => { - test('initially renders succesfully', async done => { - const wrapper = mountWithContexts( - {}} match={{ params: { id: 1 } }} /> - ); - await waitForElement( - wrapper, - 'Inventory', - el => el.state('hasContentLoading') === true - ); - await waitForElement( - wrapper, - 'Inventory', - el => el.state('hasContentLoading') === false - ); + let wrapper; + + test('initially renders succesfully', async () => { + await act(async () => { + wrapper = mountWithContexts( + {}} match={{ params: { id: 1 } }} /> + ); + }); + await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 6); - done(); }); + test('should show content error when user attempts to navigate to erroneous route', async () => { const history = createMemoryHistory({ initialEntries: ['/inventories/inventory/1/foobar'], }); - const wrapper = mountWithContexts( {}} />, { - context: { - router: { - history, - route: { - location: history.location, - match: { - params: { id: 1 }, - url: '/inventories/inventory/1/foobar', - path: '/inventories/inventory/1/foobar', + await act(async () => { + wrapper = mountWithContexts( {}} />, { + context: { + router: { + history, + route: { + location: history.location, + match: { + params: { id: 1 }, + url: '/inventories/inventory/1/foobar', + path: '/inventories/inventory/1/foobar', + }, }, }, }, - }, + }); }); await waitForElement(wrapper, 'ContentError', el => el.length === 1); }); diff --git a/awx/ui_next/src/screens/Inventory/InventoryHosts/InventoryHosts.jsx b/awx/ui_next/src/screens/Inventory/InventoryHosts/InventoryHosts.jsx index f35d87ae1c..921b78a7a5 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryHosts/InventoryHosts.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryHosts/InventoryHosts.jsx @@ -20,7 +20,7 @@ const QS_CONFIG = getQSConfig('host', { order_by: 'name', }); -function InventoryHosts({ i18n, location, match, inventory }) { +function InventoryHosts({ i18n, location, match }) { const [actions, setActions] = useState(null); const [contentError, setContentError] = useState(null); const [deletionError, setDeletionError] = useState(null); @@ -47,7 +47,7 @@ function InventoryHosts({ i18n, location, match, inventory }) { data: { actions: optionActions }, }, ] = await Promise.all([ - fetchHosts(inventory.id, location.search), + fetchHosts(match.params.id, location.search), InventoriesAPI.readOptions(), ]); @@ -62,7 +62,7 @@ function InventoryHosts({ i18n, location, match, inventory }) { } fetchData(); - }, [inventory, location]); + }, [match.params.id, location]); const handleSelectAll = isSelected => { setSelected(isSelected ? [...hosts] : []); @@ -88,7 +88,7 @@ function InventoryHosts({ i18n, location, match, inventory }) { try { const { data: { count, results }, - } = await fetchHosts(inventory.id, location.search); + } = await fetchHosts(match.params.id, location.search); setHosts(results); setHostCount(count); diff --git a/awx/ui_next/src/screens/Inventory/InventoryHosts/InventoryHosts.test.jsx b/awx/ui_next/src/screens/Inventory/InventoryHosts/InventoryHosts.test.jsx index 59e339722d..715413c81b 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryHosts/InventoryHosts.test.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryHosts/InventoryHosts.test.jsx @@ -81,7 +81,7 @@ describe('', () => { }, }); await act(async () => { - wrapper = mountWithContexts(); + wrapper = mountWithContexts(); }); await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); });