diff --git a/awx/ui_next/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.jsx b/awx/ui_next/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.jsx
index cdf8490ec4..0697750773 100644
--- a/awx/ui_next/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.jsx
+++ b/awx/ui_next/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.jsx
@@ -67,7 +67,7 @@ function InventoryGroupHostList({ i18n }) {
const {
isLoading: isDisassociateLoading,
deleteItems: disassociateHosts,
- deletionError: disassociateError,
+ deletionError: disassociateErr,
} = useDeleteItems(
useCallback(async () => {
return Promise.all(
@@ -96,7 +96,7 @@ function InventoryGroupHostList({ i18n }) {
[groupId, inventoryId]
);
- const { request: handleAssociate, error: associateError } = useRequest(
+ const { request: handleAssociate, error: associateErr } = useRequest(
useCallback(
async hostsToAssociate => {
await Promise.all(
@@ -110,9 +110,14 @@ function InventoryGroupHostList({ i18n }) {
)
);
- const { error, dismissError } = useDismissableError(
- associateError || disassociateError
- );
+ const {
+ error: associateError,
+ dismissError: dismissAssociateError,
+ } = useDismissableError(associateErr);
+ const {
+ error: disassociateError,
+ dismissError: dismissDisassociateError,
+ } = useDismissableError(disassociateErr);
const canAdd =
actions && Object.prototype.hasOwnProperty.call(actions, 'POST');
@@ -211,17 +216,26 @@ function InventoryGroupHostList({ i18n }) {
title={i18n._(t`Select Hosts`)}
/>
)}
- {error && (
+ {associateError && (
- {associateError
- ? i18n._(t`Failed to associate.`)
- : i18n._(t`Failed to disassociate one or more hosts.`)}
-
+ {i18n._(t`Failed to associate.`)}
+
+
+ )}
+ {disassociateError && (
+
+ {i18n._(t`Failed to disassociate one or more hosts.`)}
+
)}
>
diff --git a/awx/ui_next/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.test.jsx b/awx/ui_next/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.test.jsx
index 06b4d823e0..04d6a8a46c 100644
--- a/awx/ui_next/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.test.jsx
+++ b/awx/ui_next/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.test.jsx
@@ -148,6 +148,9 @@ describe('', () => {
});
wrapper.update();
expect(wrapper.find('AlertModal ErrorDetail').length).toBe(1);
+ expect(wrapper.find('AlertModal ModalBoxBody').text()).toEqual(
+ expect.stringContaining('Failed to disassociate one or more hosts.')
+ );
});
test('should show associate host modal when adding an existing host', () => {
@@ -195,6 +198,39 @@ describe('', () => {
expect(GroupsAPI.associateHost).toHaveBeenCalledTimes(1);
});
+ test('should show error modal for failed host association', async () => {
+ GroupsAPI.associateHost.mockRejectedValue(new Error());
+ InventoriesAPI.readHosts.mockResolvedValue({
+ data: {
+ count: 1,
+ results: [{ id: 123, name: 'foo', url: '/api/v2/hosts/123/' }],
+ },
+ });
+ wrapper
+ .find('DropdownToggle button[aria-label="add host"]')
+ .simulate('click');
+ await act(async () => {
+ wrapper
+ .find('DropdownItem[aria-label="add existing host"]')
+ .simulate('click');
+ });
+ await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
+ await act(async () => {
+ wrapper
+ .find('CheckboxListItem')
+ .first()
+ .invoke('onSelect')();
+ });
+ await act(async () => {
+ wrapper.find('button[aria-label="Save"]').simulate('click');
+ });
+ wrapper.update();
+ expect(wrapper.find('AlertModal ErrorDetail').length).toBe(1);
+ expect(wrapper.find('AlertModal ModalBoxBody').text()).toEqual(
+ expect.stringContaining('Failed to associate.')
+ );
+ });
+
test('should navigate to host add form when adding a new host', async () => {
GroupsAPI.readAllHosts.mockResolvedValue({
data: { ...mockHosts },