diff --git a/awx/ui/src/components/DisassociateButton/DisassociateButton.js b/awx/ui/src/components/DisassociateButton/DisassociateButton.js
index e2b3275b8d..9e6a4e81c6 100644
--- a/awx/ui/src/components/DisassociateButton/DisassociateButton.js
+++ b/awx/ui/src/components/DisassociateButton/DisassociateButton.js
@@ -33,18 +33,30 @@ function DisassociateButton({
}
}, [isKebabified, isOpen, onKebabModalChange]);
- function cannotDisassociate(item) {
+ function cannotDisassociateAllOthers(item) {
return !item.summary_fields?.user_capabilities?.delete;
}
+ function cannotDisassociateInstances(item) {
+ return item.node_type === 'control';
+ }
+
+ const cannotDisassociate = itemsToDisassociate.some(
+ (i) => i.type === 'instance'
+ )
+ ? cannotDisassociateInstances
+ : cannotDisassociateAllOthers;
function renderTooltip() {
if (verifyCannotDisassociate) {
const itemsUnableToDisassociate = itemsToDisassociate
.filter(cannotDisassociate)
- .map((item) => item.name)
+ .map((item) => item.name ?? item.hostname)
.join(', ');
-
- if (itemsToDisassociate.some(cannotDisassociate)) {
+ if (
+ cannotDisassociate
+ ? itemsToDisassociate.some(cannotDisassociateInstances)
+ : itemsToDisassociate.some(cannotDisassociateAllOthers)
+ ) {
return (
{t`You do not have permission to disassociate the following: ${itemsUnableToDisassociate}`}
@@ -79,12 +91,17 @@ function DisassociateButton({
aria-label={t`disassociate`}
isDisabled={isDisabled}
component="button"
+ ouiaId="disassociate-tooltip"
onClick={() => setIsOpen(true)}
>
{t`Disassociate`}
) : (
-
+
', () => {
);
expect(wrapper.find('button[disabled]')).toHaveLength(1);
});
+
+ test('should disable button for control instance', () => {
+ const wrapper = mountWithContexts(
+
{}}
+ itemsToDelete={[
+ {
+ id: 1,
+ hostname: 'awx',
+ node_type: 'control',
+ },
+ ]}
+ />
+ );
+ expect(wrapper.find('button[disabled]')).toHaveLength(1);
+ });
});
});
diff --git a/awx/ui/src/screens/InstanceGroup/InstanceDetails/InstanceDetails.js b/awx/ui/src/screens/InstanceGroup/InstanceDetails/InstanceDetails.js
index ac149f22b0..f99a008f33 100644
--- a/awx/ui/src/screens/InstanceGroup/InstanceDetails/InstanceDetails.js
+++ b/awx/ui/src/screens/InstanceGroup/InstanceDetails/InstanceDetails.js
@@ -273,13 +273,15 @@ function InstanceDetails({ setBreadcrumb, instanceGroup }) {
{t`Health Check`}
-
+ {me.is_superuser && instance.node_type !== 'control' && (
+
+ )}
', () => {
);
});
await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0);
- expect(
- wrapper.find("Button[ouiaId='disassociate-button']").prop('isDisabled')
- ).toBe(true);
+ expect(wrapper.find("Button[ouiaId='disassociate-button']")).toHaveLength(
+ 0
+ );
expect(
wrapper.find("Button[ouiaId='health-check-button']").prop('isDisabled')
).toBe(true);
@@ -412,7 +412,7 @@ describe('', () => {
},
});
jest.spyOn(ConfigContext, 'useConfig').mockImplementation(() => ({
- me: { is_system_auditor: true },
+ me: { is_superuser: true },
}));
await act(async () => {
wrapper = mountWithContexts(
@@ -463,7 +463,7 @@ describe('', () => {
},
});
jest.spyOn(ConfigContext, 'useConfig').mockImplementation(() => ({
- me: { is_system_auditor: true },
+ me: { is_superuser: true },
}));
await act(async () => {
wrapper = mountWithContexts(
@@ -474,6 +474,7 @@ describe('', () => {
);
});
await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0);
+
await act(async () =>
wrapper.find('Button[ouiaId="disassociate-button"]').prop('onClick')()
);
diff --git a/awx/ui/src/screens/InstanceGroup/Instances/InstanceList.js b/awx/ui/src/screens/InstanceGroup/Instances/InstanceList.js
index bf7b8d5f10..3d2f3bac93 100644
--- a/awx/ui/src/screens/InstanceGroup/Instances/InstanceList.js
+++ b/awx/ui/src/screens/InstanceGroup/Instances/InstanceList.js
@@ -207,12 +207,12 @@ function InstanceList() {
]
: []),
s.node_type === 'control'
+ )}
key="disassociate"
onDisassociate={handleDisassociate}
- itemsToDisassociate={selected.filter(
- (s) => s.node_type !== 'control'
- )}
+ itemsToDisassociate={selected}
modalTitle={t`Disassociate instance from instance group?`}
/>,
', () => {
wrapper.update();
expect(wrapper.find('AlertModal')).toHaveLength(1);
});
+
+ test('should disable disassociate button', async () => {
+ expect(
+ wrapper.find('Button[ouiaId="disassociate-button"]').prop('isDisabled')
+ ).toBe(true);
+ await act(async () =>
+ wrapper.find('DataListToolbar').prop('onSelectAll')(instances)
+ );
+
+ wrapper.update();
+ expect(
+ wrapper.find('Button[ouiaId="disassociate-button"]').prop('isDisabled')
+ ).toBe(true);
+ await act(async () =>
+ wrapper
+ .find('Tr#instance-row-1')
+ .find('SelectColumn[aria-label="Select row 0"]')
+ .prop('onSelect')(false)
+ );
+
+ wrapper.update();
+ expect(
+ wrapper.find('Button[ouiaId="disassociate-button"]').prop('isDisabled')
+ ).toBe(false);
+ });
});
diff --git a/awx/ui/src/screens/InstanceGroup/Instances/InstanceListItem.js b/awx/ui/src/screens/InstanceGroup/Instances/InstanceListItem.js
index e666e68ab0..8f43814db4 100644
--- a/awx/ui/src/screens/InstanceGroup/Instances/InstanceListItem.js
+++ b/awx/ui/src/screens/InstanceGroup/Instances/InstanceListItem.js
@@ -121,9 +121,8 @@ function InstanceListItem({
|
diff --git a/awx/ui/src/screens/InstanceGroup/Instances/InstanceListItem.test.js b/awx/ui/src/screens/InstanceGroup/Instances/InstanceListItem.test.js
index a549923d0c..77c7a92797 100644
--- a/awx/ui/src/screens/InstanceGroup/Instances/InstanceListItem.test.js
+++ b/awx/ui/src/screens/InstanceGroup/Instances/InstanceListItem.test.js
@@ -201,24 +201,6 @@ describe('', () => {
expect(wrapper.find('Td').at(1).prop('select').onSelect).toEqual(onSelect);
});
- test('should disable checkbox', async () => {
- const onSelect = jest.fn();
- await act(async () => {
- wrapper = mountWithContexts(
-
- );
- });
- expect(wrapper.find('Td').at(1).prop('select').disable).toEqual(true);
- });
-
test('should display instance toggle', () => {
expect(wrapper.find('InstanceToggle').length).toBe(1);
});