mirror of
https://github.com/ansible/awx.git
synced 2026-01-10 15:32:07 -03:30
Merge pull request #8738 from AlexSCorey/8532-VaultIdsOnCredChips
Adds vault IDs to Vault credential chips Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
commit
764511f33f
@ -36,6 +36,10 @@ class Jobs extends RelaunchMixin(Base) {
|
||||
return this.http.post(`/api/v2${getBaseURL(type)}${id}/cancel/`);
|
||||
}
|
||||
|
||||
readCredentials(id, type) {
|
||||
return this.http.get(`/api/v2${getBaseURL(type)}${id}/credentials/`);
|
||||
}
|
||||
|
||||
readDetail(id, type) {
|
||||
return this.http.get(`/api/v2${getBaseURL(type)}${id}/`);
|
||||
}
|
||||
|
||||
@ -16,10 +16,17 @@ function CredentialChip({ credential, i18n, i18nHash, ...props }) {
|
||||
type = toTitleCase(credential.kind);
|
||||
}
|
||||
|
||||
const buildCredentialName = () => {
|
||||
if (credential.kind === 'vault' && credential.inputs?.vault_id) {
|
||||
return `${credential.name} | ${credential.inputs.vault_id}`;
|
||||
}
|
||||
return `${credential.name}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<Chip {...props}>
|
||||
<strong>{type}: </strong>
|
||||
{credential.name}
|
||||
{buildCredentialName()}
|
||||
</Chip>
|
||||
);
|
||||
}
|
||||
|
||||
@ -71,6 +71,16 @@ function MultiCredentialsLookup(props) {
|
||||
loadCredentials(params, selectedType.id),
|
||||
CredentialsAPI.readOptions(),
|
||||
]);
|
||||
|
||||
results.map(result => {
|
||||
if (result.kind === 'vault' && result.inputs?.vault_id) {
|
||||
result.label = `${result.name} | ${result.inputs.vault_id}`;
|
||||
return result;
|
||||
}
|
||||
result.label = `${result.name}`;
|
||||
return result;
|
||||
});
|
||||
|
||||
return {
|
||||
credentials: results,
|
||||
credentialsCount: count,
|
||||
@ -108,7 +118,6 @@ function MultiCredentialsLookup(props) {
|
||||
credential={item}
|
||||
/>
|
||||
);
|
||||
|
||||
const isVault = selectedType?.kind === 'vault';
|
||||
|
||||
return (
|
||||
@ -187,6 +196,7 @@ function MultiCredentialsLookup(props) {
|
||||
relatedSearchableKeys={relatedSearchableKeys}
|
||||
multiple={isVault}
|
||||
header={i18n._(t`Credentials`)}
|
||||
displayKey={isVault ? 'label' : 'name'}
|
||||
name="credentials"
|
||||
qsConfig={QS_CONFIG}
|
||||
readOnly={!canDelete}
|
||||
|
||||
@ -87,6 +87,23 @@ describe('<MultiCredentialsLookup />', () => {
|
||||
name: 'Cred 5',
|
||||
url: 'www.google.com',
|
||||
},
|
||||
|
||||
{
|
||||
id: 6,
|
||||
credential_type: 5,
|
||||
kind: 'vault',
|
||||
name: 'Cred 6',
|
||||
url: 'www.google.com',
|
||||
inputs: { vault_id: 'vault ID' },
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
credential_type: 5,
|
||||
kind: 'vault',
|
||||
name: 'Cred 7',
|
||||
url: 'www.google.com',
|
||||
inputs: {},
|
||||
},
|
||||
],
|
||||
count: 3,
|
||||
},
|
||||
@ -196,7 +213,13 @@ describe('<MultiCredentialsLookup />', () => {
|
||||
wrapper.update();
|
||||
expect(CredentialsAPI.read).toHaveBeenCalledTimes(2);
|
||||
expect(wrapper.find('OptionsList').prop('options')).toEqual([
|
||||
{ id: 1, kind: 'cloud', name: 'New Cred', url: 'www.google.com' },
|
||||
{
|
||||
id: 1,
|
||||
kind: 'cloud',
|
||||
name: 'New Cred',
|
||||
url: 'www.google.com',
|
||||
label: 'New Cred',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
@ -268,6 +291,36 @@ describe('<MultiCredentialsLookup />', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test('should properly render vault credential labels', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<MultiCredentialsLookup
|
||||
value={credentials}
|
||||
tooltip="This is credentials look up"
|
||||
onChange={() => {}}
|
||||
onError={() => {}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const searchButton = await waitForElement(
|
||||
wrapper,
|
||||
'Button[aria-label="Search"]'
|
||||
);
|
||||
await act(async () => {
|
||||
searchButton.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
const typeSelect = wrapper.find('AnsibleSelect');
|
||||
act(() => {
|
||||
typeSelect.invoke('onChange')({}, 500);
|
||||
});
|
||||
wrapper.update();
|
||||
const optionsList = wrapper.find('OptionsList');
|
||||
expect(optionsList.prop('multiple')).toEqual(true);
|
||||
expect(wrapper.find('CheckboxListItem[label="Cred 6 | vault ID"]'));
|
||||
expect(wrapper.find('CheckboxListItem[label="Cred 7"]'));
|
||||
});
|
||||
|
||||
test('should allow multiple vault credentials with no vault id', async () => {
|
||||
const onChange = jest.fn();
|
||||
await act(async () => {
|
||||
|
||||
@ -29,10 +29,18 @@ function Job({ i18n, setBreadcrumb }) {
|
||||
const { isLoading, error, request: fetchJob, result } = useRequest(
|
||||
useCallback(async () => {
|
||||
const { data } = await JobsAPI.readDetail(id, type);
|
||||
if (
|
||||
data?.summary_fields?.credentials?.find(cred => cred.kind === 'vault')
|
||||
) {
|
||||
const {
|
||||
data: { results },
|
||||
} = await JobsAPI.readCredentials(data.id, type);
|
||||
|
||||
data.summary_fields.credentials = results;
|
||||
}
|
||||
setBreadcrumb(data);
|
||||
return data;
|
||||
}, [id, type, setBreadcrumb]),
|
||||
null
|
||||
}, [id, type, setBreadcrumb])
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@ -44,6 +44,19 @@ function Project({ i18n, setBreadcrumb }) {
|
||||
role_level: 'notification_admin_role',
|
||||
}),
|
||||
]);
|
||||
|
||||
if (data.summary_fields.credentials) {
|
||||
const params = {
|
||||
page: 1,
|
||||
page_size: 200,
|
||||
order_by: 'name',
|
||||
};
|
||||
const {
|
||||
data: { results },
|
||||
} = await ProjectsAPI.readCredentials(data.id, params);
|
||||
|
||||
data.summary_fields.credentials = results;
|
||||
}
|
||||
return {
|
||||
project: data,
|
||||
isNotifAdmin: notifAdminRes.data.results.length > 0,
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
/* eslint react/no-unused-state: 0 */
|
||||
import React, { useState } from 'react';
|
||||
import { withRouter, Redirect, useHistory } from 'react-router-dom';
|
||||
import { Redirect, useHistory } from 'react-router-dom';
|
||||
import { CardBody } from '../../../components/Card';
|
||||
|
||||
import { JobTemplatesAPI } from '../../../api';
|
||||
import { JobTemplate } from '../../../types';
|
||||
import { getAddedAndRemoved } from '../../../util/lists';
|
||||
import JobTemplateForm from '../shared/JobTemplateForm';
|
||||
|
||||
import ContentLoading from '../../../components/ContentLoading';
|
||||
|
||||
function JobTemplateEdit({ template }) {
|
||||
@ -95,9 +93,7 @@ function JobTemplateEdit({ template }) {
|
||||
return Promise.all([disassociatePromise, associatePromise]);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
history.push(detailsUrl);
|
||||
};
|
||||
const handleCancel = () => history.push(detailsUrl);
|
||||
|
||||
const canEdit = template?.summary_fields?.user_capabilities?.edit;
|
||||
|
||||
@ -122,5 +118,4 @@ function JobTemplateEdit({ template }) {
|
||||
JobTemplateEdit.propTypes = {
|
||||
template: JobTemplate.isRequired,
|
||||
};
|
||||
|
||||
export default withRouter(JobTemplateEdit);
|
||||
export default JobTemplateEdit;
|
||||
|
||||
@ -46,8 +46,21 @@ function Template({ i18n, setBreadcrumb }) {
|
||||
role_level: 'notification_admin_role',
|
||||
}),
|
||||
]);
|
||||
if (actions?.data?.actions?.PUT) {
|
||||
if (data?.webhook_service && data?.related?.webhook_key) {
|
||||
if (data.summary_fields.credentials) {
|
||||
const params = {
|
||||
page: 1,
|
||||
page_size: 200,
|
||||
order_by: 'name',
|
||||
};
|
||||
const {
|
||||
data: { results },
|
||||
} = await JobTemplatesAPI.readCredentials(data.id, params);
|
||||
|
||||
data.summary_fields.credentials = results;
|
||||
}
|
||||
|
||||
if (actions.data.actions.PUT) {
|
||||
if (data.webhook_service && data?.related?.webhook_key) {
|
||||
const {
|
||||
data: { webhook_key },
|
||||
} = await JobTemplatesAPI.readWebhookKey(templateId);
|
||||
@ -142,7 +155,7 @@ function Template({ i18n, setBreadcrumb }) {
|
||||
<PageSection>
|
||||
<Card>
|
||||
<ContentError error={contentError}>
|
||||
{contentError.response.status === 404 && (
|
||||
{contentError.response?.status === 404 && (
|
||||
<span>
|
||||
{i18n._(t`Template not found.`)}{' '}
|
||||
<Link to="/templates">{i18n._(t`View all Templates.`)}</Link>
|
||||
|
||||
@ -28,6 +28,22 @@ describe('<Template />', () => {
|
||||
actions: { PUT: true },
|
||||
},
|
||||
});
|
||||
JobTemplatesAPI.readCredentials.mockResolvedValue({
|
||||
data: {
|
||||
results: [
|
||||
{
|
||||
id: 3,
|
||||
type: 'credential',
|
||||
url: '/api/v2/credentials/3/',
|
||||
name: 'Vault1Id1',
|
||||
inputs: {
|
||||
vault_id: '1',
|
||||
},
|
||||
kind: 'vault',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
OrganizationsAPI.read.mockResolvedValue({
|
||||
data: {
|
||||
count: 1,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user