diff --git a/awx/ui_next/src/screens/Organization/OrganizationDetail/OrganizationDetail.jsx b/awx/ui_next/src/screens/Organization/OrganizationDetail/OrganizationDetail.jsx
index 8895b26094..6811431627 100644
--- a/awx/ui_next/src/screens/Organization/OrganizationDetail/OrganizationDetail.jsx
+++ b/awx/ui_next/src/screens/Organization/OrganizationDetail/OrganizationDetail.jsx
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
-import { Link, useRouteMatch } from 'react-router-dom';
+import { Link, useHistory, useRouteMatch } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { Button } from '@patternfly/react-core';
@@ -7,8 +7,11 @@ import { OrganizationsAPI } from '@api';
import { DetailList, Detail, UserDateDetail } from '@components/DetailList';
import { CardBody, CardActionsRow } from '@components/Card';
import { ChipGroup, Chip } from '@components/Chip';
+import AlertModal from '@components/AlertModal';
import ContentError from '@components/ContentError';
import ContentLoading from '@components/ContentLoading';
+import DeleteButton from '@components/DeleteButton';
+import ErrorDetail from '@components/ErrorDetail';
function OrganizationDetail({ i18n, organization }) {
const {
@@ -24,8 +27,10 @@ function OrganizationDetail({ i18n, organization }) {
summary_fields,
} = organization;
const [contentError, setContentError] = useState(null);
+ const [deletionError, setDeletionError] = useState(null);
const [hasContentLoading, setHasContentLoading] = useState(true);
const [instanceGroups, setInstanceGroups] = useState([]);
+ const history = useHistory();
useEffect(() => {
(async () => {
@@ -44,6 +49,17 @@ function OrganizationDetail({ i18n, organization }) {
})();
}, [id]);
+ const handleDelete = async () => {
+ setHasContentLoading(true);
+ try {
+ await OrganizationsAPI.destroy(id);
+ history.push(`/organizations`);
+ } catch (error) {
+ setDeletionError(error);
+ }
+ setHasContentLoading(false);
+ };
+
if (hasContentLoading) {
return ;
}
@@ -94,11 +110,37 @@ function OrganizationDetail({ i18n, organization }) {
{summary_fields.user_capabilities.edit && (
-
+ {/* Update delete modal to show dependencies https://github.com/ansible/awx/issues/5546 */}
+ {deletionError && (
+ setDeletionError(null)}
+ >
+ {i18n._(t`Failed to delete organization.`)}
+
+
+ )}
);
}
diff --git a/awx/ui_next/src/screens/Organization/OrganizationDetail/OrganizationDetail.test.jsx b/awx/ui_next/src/screens/Organization/OrganizationDetail/OrganizationDetail.test.jsx
index b3593fd952..39448e2434 100644
--- a/awx/ui_next/src/screens/Organization/OrganizationDetail/OrganizationDetail.test.jsx
+++ b/awx/ui_next/src/screens/Organization/OrganizationDetail/OrganizationDetail.test.jsx
@@ -19,6 +19,7 @@ describe('', () => {
summary_fields: {
user_capabilities: {
edit: true,
+ delete: true,
},
},
};
@@ -98,7 +99,7 @@ describe('', () => {
});
const editButton = await waitForElement(
wrapper,
- 'OrganizationDetail Button'
+ 'OrganizationDetail Button[aria-label="Edit"]'
);
expect(editButton.text()).toEqual('Edit');
expect(editButton.prop('to')).toBe('/organizations/undefined/edit');
@@ -115,6 +116,74 @@ describe('', () => {
);
});
await waitForElement(wrapper, 'OrganizationDetail');
- expect(wrapper.find('OrganizationDetail Button').length).toBe(0);
+ expect(
+ wrapper.find('OrganizationDetail Button[aria-label="Edit"]').length
+ ).toBe(0);
+ });
+
+ test('expected api calls are made for delete', async () => {
+ OrganizationsAPI.readInstanceGroups.mockResolvedValue({ data: {} });
+
+ let wrapper;
+ await act(async () => {
+ wrapper = mountWithContexts(
+
+ );
+ });
+ await waitForElement(
+ wrapper,
+ 'OrganizationDetail Button[aria-label="Delete"]'
+ );
+ await act(async () => {
+ wrapper.find('DeleteButton').invoke('onConfirm')();
+ });
+ expect(OrganizationsAPI.destroy).toHaveBeenCalledTimes(1);
+ });
+
+ test('should show content error for failed instance group fetch', async () => {
+ OrganizationsAPI.readInstanceGroups.mockImplementationOnce(() =>
+ Promise.reject(new Error())
+ );
+
+ let wrapper;
+ await act(async () => {
+ wrapper = mountWithContexts(
+
+ );
+ });
+ await waitForElement(wrapper, 'ContentError', el => el.length === 1);
+ });
+
+ test('Error dialog shown for failed deletion', async () => {
+ OrganizationsAPI.destroy.mockImplementationOnce(() =>
+ Promise.reject(new Error())
+ );
+
+ let wrapper;
+ await act(async () => {
+ wrapper = mountWithContexts(
+
+ );
+ });
+ await waitForElement(
+ wrapper,
+ 'OrganizationDetail Button[aria-label="Delete"]'
+ );
+ await act(async () => {
+ wrapper.find('DeleteButton').invoke('onConfirm')();
+ });
+ await waitForElement(
+ wrapper,
+ 'Modal[title="Error!"]',
+ el => el.length === 1
+ );
+ await act(async () => {
+ wrapper.find('Modal[title="Error!"]').invoke('onClose')();
+ });
+ await waitForElement(
+ wrapper,
+ 'Modal[title="Error!"]',
+ el => el.length === 0
+ );
});
});