mirror of
https://github.com/ansible/awx.git
synced 2026-05-20 15:27:47 -02:30
Update breadcrumb and fetch new hosts when url changes
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { Card, CardHeader, PageSection } from '@patternfly/react-core';
|
import { Card, CardHeader, PageSection } from '@patternfly/react-core';
|
||||||
@@ -16,54 +16,26 @@ import InventorySources from './InventorySources';
|
|||||||
import { InventoriesAPI } from '@api';
|
import { InventoriesAPI } from '@api';
|
||||||
import InventoryEdit from './InventoryEdit';
|
import InventoryEdit from './InventoryEdit';
|
||||||
|
|
||||||
class Inventory extends Component {
|
function Inventory({ history, i18n, location, match, setBreadcrumb }) {
|
||||||
constructor(props) {
|
const [contentError, setContentError] = useState(null);
|
||||||
super(props);
|
const [hasContentLoading, setHasContentLoading] = useState(true);
|
||||||
|
const [inventory, setInventory] = useState(null);
|
||||||
|
|
||||||
this.state = {
|
useEffect(() => {
|
||||||
contentError: null,
|
async function fetchData() {
|
||||||
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 {
|
try {
|
||||||
const { data } = await InventoriesAPI.readDetail(id);
|
const { data } = await InventoriesAPI.readDetail(match.params.id);
|
||||||
setBreadcrumb(data);
|
setBreadcrumb(data);
|
||||||
this.setState({ inventory: data });
|
setInventory(data);
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
this.setState({ contentError: err });
|
setContentError(error);
|
||||||
} finally {
|
} finally {
|
||||||
this.setState({ hasContentLoading: false });
|
setHasContentLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
fetchData();
|
||||||
const { history, i18n, location, match } = this.props;
|
}, [match.params.id, setBreadcrumb]);
|
||||||
const { contentError, hasContentLoading, inventory } = this.state;
|
|
||||||
|
|
||||||
const tabsArray = [
|
const tabsArray = [
|
||||||
{ name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 },
|
{ name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 },
|
||||||
@@ -85,10 +57,7 @@ class Inventory extends Component {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (location.pathname.endsWith('edit') || location.pathname.endsWith('add')) {
|
||||||
location.pathname.endsWith('edit') ||
|
|
||||||
location.pathname.endsWith('add')
|
|
||||||
) {
|
|
||||||
cardHeader = null;
|
cardHeader = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,9 +69,7 @@ class Inventory extends Component {
|
|||||||
{contentError.response.status === 404 && (
|
{contentError.response.status === 404 && (
|
||||||
<span>
|
<span>
|
||||||
{i18n._(`Inventory not found.`)}{' '}
|
{i18n._(`Inventory not found.`)}{' '}
|
||||||
<Link to="/inventories">
|
<Link to="/inventories">{i18n._(`View all Inventories.`)}</Link>
|
||||||
{i18n._(`View all Inventories.`)}
|
|
||||||
</Link>
|
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</ContentError>
|
</ContentError>
|
||||||
@@ -161,7 +128,7 @@ class Inventory extends Component {
|
|||||||
<Route
|
<Route
|
||||||
key="hosts"
|
key="hosts"
|
||||||
path="/inventories/inventory/:id/hosts"
|
path="/inventories/inventory/:id/hosts"
|
||||||
render={() => <InventoryHosts inventory={inventory} />}
|
render={() => <InventoryHosts />}
|
||||||
/>,
|
/>,
|
||||||
<Route
|
<Route
|
||||||
key="sources"
|
key="sources"
|
||||||
@@ -195,7 +162,6 @@ class Inventory extends Component {
|
|||||||
</Card>
|
</Card>
|
||||||
</PageSection>
|
</PageSection>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Inventory as _Inventory };
|
export { Inventory as _Inventory };
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { act } from 'react-dom/test-utils';
|
||||||
import { createMemoryHistory } from 'history';
|
import { createMemoryHistory } from 'history';
|
||||||
import { InventoriesAPI } from '@api';
|
import { InventoriesAPI } from '@api';
|
||||||
import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers';
|
import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers';
|
||||||
@@ -12,28 +13,24 @@ InventoriesAPI.readDetail.mockResolvedValue({
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('<Inventory />', () => {
|
describe('<Inventory />', () => {
|
||||||
test('initially renders succesfully', async done => {
|
let wrapper;
|
||||||
const wrapper = mountWithContexts(
|
|
||||||
|
test('initially renders succesfully', async () => {
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
<Inventory setBreadcrumb={() => {}} match={{ params: { id: 1 } }} />
|
<Inventory setBreadcrumb={() => {}} match={{ params: { id: 1 } }} />
|
||||||
);
|
);
|
||||||
await waitForElement(
|
|
||||||
wrapper,
|
|
||||||
'Inventory',
|
|
||||||
el => el.state('hasContentLoading') === true
|
|
||||||
);
|
|
||||||
await waitForElement(
|
|
||||||
wrapper,
|
|
||||||
'Inventory',
|
|
||||||
el => el.state('hasContentLoading') === false
|
|
||||||
);
|
|
||||||
await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 6);
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||||
|
await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 6);
|
||||||
|
});
|
||||||
|
|
||||||
test('should show content error when user attempts to navigate to erroneous route', async () => {
|
test('should show content error when user attempts to navigate to erroneous route', async () => {
|
||||||
const history = createMemoryHistory({
|
const history = createMemoryHistory({
|
||||||
initialEntries: ['/inventories/inventory/1/foobar'],
|
initialEntries: ['/inventories/inventory/1/foobar'],
|
||||||
});
|
});
|
||||||
const wrapper = mountWithContexts(<Inventory setBreadcrumb={() => {}} />, {
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(<Inventory setBreadcrumb={() => {}} />, {
|
||||||
context: {
|
context: {
|
||||||
router: {
|
router: {
|
||||||
history,
|
history,
|
||||||
@@ -48,6 +45,7 @@ describe('<Inventory />', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
});
|
||||||
await waitForElement(wrapper, 'ContentError', el => el.length === 1);
|
await waitForElement(wrapper, 'ContentError', el => el.length === 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const QS_CONFIG = getQSConfig('host', {
|
|||||||
order_by: 'name',
|
order_by: 'name',
|
||||||
});
|
});
|
||||||
|
|
||||||
function InventoryHosts({ i18n, location, match, inventory }) {
|
function InventoryHosts({ i18n, location, match }) {
|
||||||
const [actions, setActions] = useState(null);
|
const [actions, setActions] = useState(null);
|
||||||
const [contentError, setContentError] = useState(null);
|
const [contentError, setContentError] = useState(null);
|
||||||
const [deletionError, setDeletionError] = useState(null);
|
const [deletionError, setDeletionError] = useState(null);
|
||||||
@@ -47,7 +47,7 @@ function InventoryHosts({ i18n, location, match, inventory }) {
|
|||||||
data: { actions: optionActions },
|
data: { actions: optionActions },
|
||||||
},
|
},
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
fetchHosts(inventory.id, location.search),
|
fetchHosts(match.params.id, location.search),
|
||||||
InventoriesAPI.readOptions(),
|
InventoriesAPI.readOptions(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ function InventoryHosts({ i18n, location, match, inventory }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fetchData();
|
fetchData();
|
||||||
}, [inventory, location]);
|
}, [match.params.id, location]);
|
||||||
|
|
||||||
const handleSelectAll = isSelected => {
|
const handleSelectAll = isSelected => {
|
||||||
setSelected(isSelected ? [...hosts] : []);
|
setSelected(isSelected ? [...hosts] : []);
|
||||||
@@ -88,7 +88,7 @@ function InventoryHosts({ i18n, location, match, inventory }) {
|
|||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
data: { count, results },
|
data: { count, results },
|
||||||
} = await fetchHosts(inventory.id, location.search);
|
} = await fetchHosts(match.params.id, location.search);
|
||||||
|
|
||||||
setHosts(results);
|
setHosts(results);
|
||||||
setHostCount(count);
|
setHostCount(count);
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ describe('<InventoryHosts />', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<InventoryHosts inventory={mockInventory} />);
|
wrapper = mountWithContexts(<InventoryHosts />);
|
||||||
});
|
});
|
||||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user