mirror of
https://github.com/ansible/awx.git
synced 2026-01-12 02:19:58 -03:30
Merge pull request #8659 from mabashian/7989-group-action-buttons
Hide edit/delete buttons on group details view for users that don't have permissions Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
commit
170e64070b
@ -17,7 +17,7 @@ import InventoryGroupsDeleteModal from '../shared/InventoryGroupsDeleteModal';
|
||||
|
||||
function InventoryGroupDetail({ i18n, inventoryGroup }) {
|
||||
const {
|
||||
summary_fields: { created_by, modified_by },
|
||||
summary_fields: { created_by, modified_by, user_capabilities },
|
||||
created,
|
||||
modified,
|
||||
name,
|
||||
@ -54,24 +54,28 @@ function InventoryGroupDetail({ i18n, inventoryGroup }) {
|
||||
/>
|
||||
</DetailList>
|
||||
<CardActionsRow>
|
||||
<Button
|
||||
variant="primary"
|
||||
aria-label={i18n._(t`Edit`)}
|
||||
onClick={() =>
|
||||
history.push(
|
||||
`/inventories/inventory/${params.id}/groups/${params.groupId}/edit`
|
||||
)
|
||||
}
|
||||
>
|
||||
{i18n._(t`Edit`)}
|
||||
</Button>
|
||||
<InventoryGroupsDeleteModal
|
||||
groups={[inventoryGroup]}
|
||||
isDisabled={false}
|
||||
onAfterDelete={() =>
|
||||
history.push(`/inventories/inventory/${params.id}/groups`)
|
||||
}
|
||||
/>
|
||||
{user_capabilities?.edit && (
|
||||
<Button
|
||||
variant="primary"
|
||||
aria-label={i18n._(t`Edit`)}
|
||||
onClick={() =>
|
||||
history.push(
|
||||
`/inventories/inventory/${params.id}/groups/${params.groupId}/edit`
|
||||
)
|
||||
}
|
||||
>
|
||||
{i18n._(t`Edit`)}
|
||||
</Button>
|
||||
)}
|
||||
{user_capabilities?.delete && (
|
||||
<InventoryGroupsDeleteModal
|
||||
groups={[inventoryGroup]}
|
||||
isDisabled={false}
|
||||
onAfterDelete={() =>
|
||||
history.push(`/inventories/inventory/${params.id}/groups`)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</CardActionsRow>
|
||||
{error && (
|
||||
<AlertModal
|
||||
|
||||
@ -27,77 +27,130 @@ const inventoryGroup = {
|
||||
username: 'Bond',
|
||||
id: 14,
|
||||
},
|
||||
user_capabilities: {
|
||||
delete: true,
|
||||
edit: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('<InventoryGroupDetail />', () => {
|
||||
let wrapper;
|
||||
let history;
|
||||
beforeEach(async () => {
|
||||
await act(async () => {
|
||||
history = createMemoryHistory({
|
||||
initialEntries: ['/inventories/inventory/1/groups/1/details'],
|
||||
});
|
||||
wrapper = mountWithContexts(
|
||||
<Route path="/inventories/inventory/:id/groups/:groupId">
|
||||
<InventoryGroupDetail inventoryGroup={inventoryGroup} />
|
||||
</Route>,
|
||||
{
|
||||
context: {
|
||||
router: {
|
||||
history,
|
||||
route: {
|
||||
location: history.location,
|
||||
match: { params: { id: 1 } },
|
||||
|
||||
describe('User has full permissions', () => {
|
||||
beforeEach(async () => {
|
||||
await act(async () => {
|
||||
history = createMemoryHistory({
|
||||
initialEntries: ['/inventories/inventory/1/groups/1/details'],
|
||||
});
|
||||
wrapper = mountWithContexts(
|
||||
<Route path="/inventories/inventory/:id/groups/:groupId">
|
||||
<InventoryGroupDetail inventoryGroup={inventoryGroup} />
|
||||
</Route>,
|
||||
{
|
||||
context: {
|
||||
router: {
|
||||
history,
|
||||
route: {
|
||||
location: history.location,
|
||||
match: { params: { id: 1 } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
});
|
||||
});
|
||||
afterEach(() => {
|
||||
wrapper.unmount();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
test('InventoryGroupDetail renders successfully', () => {
|
||||
expect(wrapper.length).toBe(1);
|
||||
});
|
||||
|
||||
test('should open delete modal and then call api to delete the group', async () => {
|
||||
await act(async () => {
|
||||
wrapper.find('button[aria-label="Delete"]').simulate('click');
|
||||
});
|
||||
await waitForElement(wrapper, 'Modal', el => el.length === 1);
|
||||
expect(wrapper.find('Modal').length).toBe(1);
|
||||
await act(async () => {
|
||||
wrapper.find('Radio[id="radio-delete"]').invoke('onChange')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(
|
||||
wrapper.find('Button[aria-label="Confirm Delete"]').prop('isDisabled')
|
||||
).toBe(false);
|
||||
await act(() =>
|
||||
wrapper.find('Button[aria-label="Confirm Delete"]').prop('onClick')()
|
||||
);
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
expect(GroupsAPI.destroy).toBeCalledWith(1);
|
||||
});
|
||||
|
||||
test('should navigate user to edit form on edit button click', async () => {
|
||||
wrapper.find('button[aria-label="Edit"]').simulate('click');
|
||||
expect(history.location.pathname).toEqual(
|
||||
'/inventories/inventory/1/groups/1/edit'
|
||||
);
|
||||
});
|
||||
|
||||
test('details should render with the proper values and action buttons shown', () => {
|
||||
expect(wrapper.find('Detail[label="Name"]').prop('value')).toBe('Foo');
|
||||
expect(wrapper.find('Detail[label="Description"]').prop('value')).toBe(
|
||||
'Bar'
|
||||
);
|
||||
expect(wrapper.find('Detail[label="Created"]').length).toBe(1);
|
||||
expect(wrapper.find('Detail[label="Last Modified"]').length).toBe(1);
|
||||
expect(wrapper.find('VariablesDetail').prop('value')).toBe('bizz: buzz');
|
||||
|
||||
expect(wrapper.find('button[aria-label="Edit"]').length).toBe(1);
|
||||
expect(wrapper.find('button[aria-label="Delete"]').length).toBe(1);
|
||||
});
|
||||
});
|
||||
afterEach(() => {
|
||||
wrapper.unmount();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
test('InventoryGroupDetail renders successfully', () => {
|
||||
expect(wrapper.length).toBe(1);
|
||||
});
|
||||
|
||||
test('should open delete modal and then call api to delete the group', async () => {
|
||||
await act(async () => {
|
||||
wrapper.find('button[aria-label="Delete"]').simulate('click');
|
||||
describe('User has read-only permissions', () => {
|
||||
test('should hide edit/delete buttons', async () => {
|
||||
const readOnlyGroup = {
|
||||
...inventoryGroup,
|
||||
summary_fields: {
|
||||
...inventoryGroup.summary_fields,
|
||||
user_capabilities: {
|
||||
delete: false,
|
||||
edit: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await act(async () => {
|
||||
history = createMemoryHistory({
|
||||
initialEntries: ['/inventories/inventory/1/groups/1/details'],
|
||||
});
|
||||
wrapper = mountWithContexts(
|
||||
<Route path="/inventories/inventory/:id/groups/:groupId">
|
||||
<InventoryGroupDetail inventoryGroup={readOnlyGroup} />
|
||||
</Route>,
|
||||
{
|
||||
context: {
|
||||
router: {
|
||||
history,
|
||||
route: {
|
||||
location: history.location,
|
||||
match: { params: { id: 1 } },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
});
|
||||
|
||||
expect(wrapper.find('button[aria-label="Edit"]').length).toBe(0);
|
||||
expect(wrapper.find('button[aria-label="Delete"]').length).toBe(0);
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
await waitForElement(wrapper, 'Modal', el => el.length === 1);
|
||||
expect(wrapper.find('Modal').length).toBe(1);
|
||||
await act(async () => {
|
||||
wrapper.find('Radio[id="radio-delete"]').invoke('onChange')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(
|
||||
wrapper.find('Button[aria-label="Confirm Delete"]').prop('isDisabled')
|
||||
).toBe(false);
|
||||
await act(() =>
|
||||
wrapper.find('Button[aria-label="Confirm Delete"]').prop('onClick')()
|
||||
);
|
||||
expect(GroupsAPI.destroy).toBeCalledWith(1);
|
||||
});
|
||||
|
||||
test('should navigate user to edit form on edit button click', async () => {
|
||||
wrapper.find('button[aria-label="Edit"]').simulate('click');
|
||||
expect(history.location.pathname).toEqual(
|
||||
'/inventories/inventory/1/groups/1/edit'
|
||||
);
|
||||
});
|
||||
|
||||
test('details should render with the proper values', () => {
|
||||
expect(wrapper.find('Detail[label="Name"]').prop('value')).toBe('Foo');
|
||||
expect(wrapper.find('Detail[label="Description"]').prop('value')).toBe(
|
||||
'Bar'
|
||||
);
|
||||
expect(wrapper.find('Detail[label="Created"]').length).toBe(1);
|
||||
expect(wrapper.find('Detail[label="Last Modified"]').length).toBe(1);
|
||||
expect(wrapper.find('VariablesDetail').prop('value')).toBe('bizz: buzz');
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user