mirror of
https://github.com/ansible/awx.git
synced 2026-02-27 07:56:06 -03:30
Add Credential List and unit tests
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card, CardBody, PageSection } from '@patternfly/react-core';
|
||||||
|
|
||||||
|
function CredentialAdd() {
|
||||||
|
return (
|
||||||
|
<PageSection>
|
||||||
|
<Card>
|
||||||
|
<CardBody>Coming soon :)</CardBody>
|
||||||
|
</Card>
|
||||||
|
</PageSection>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CredentialAdd;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from './CredentialAdd';
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import { withI18n } from '@lingui/react';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
|
import { CredentialsAPI, CredentialTypesAPI } from '@api';
|
||||||
|
import { Card, PageSection } from '@patternfly/react-core';
|
||||||
|
import AlertModal from '@components/AlertModal';
|
||||||
|
import ErrorDetail from '@components/ErrorDetail';
|
||||||
|
import DataListToolbar from '@components/DataListToolbar';
|
||||||
|
import PaginatedDataList, {
|
||||||
|
ToolbarAddButton,
|
||||||
|
ToolbarDeleteButton,
|
||||||
|
} from '@components/PaginatedDataList';
|
||||||
|
import { getQSConfig, parseQueryString } from '@util/qs';
|
||||||
|
import { CredentialListItem } from '.';
|
||||||
|
|
||||||
|
const QS_CONFIG = getQSConfig('project', {
|
||||||
|
page: 1,
|
||||||
|
page_size: 20,
|
||||||
|
order_by: 'name',
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchCredentialTypes = async credentials => {
|
||||||
|
const typeIds = Array.from(
|
||||||
|
credentials.reduce((accumulator, credential) => {
|
||||||
|
accumulator.add(credential.credential_type);
|
||||||
|
return accumulator;
|
||||||
|
}, new Set())
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { results },
|
||||||
|
} = await CredentialTypesAPI.read({
|
||||||
|
or__id: typeIds,
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
const assignCredentialKinds = (credentials, credentialTypes) => {
|
||||||
|
const typesById = credentialTypes.reduce((accumulator, type) => {
|
||||||
|
accumulator[type.id] = type.name;
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
credentials.forEach(credential => {
|
||||||
|
credential.kind = typesById[credential.credential_type];
|
||||||
|
});
|
||||||
|
|
||||||
|
return credentials;
|
||||||
|
};
|
||||||
|
|
||||||
|
function CredentialList({ i18n }) {
|
||||||
|
const [actions, setActions] = useState(null);
|
||||||
|
const [contentError, setContentError] = useState(null);
|
||||||
|
const [credentialCount, setCredentialCount] = useState(0);
|
||||||
|
const [credentials, setCredentials] = useState([]);
|
||||||
|
const [deletionError, setDeletionError] = useState(null);
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [selected, setSelected] = useState([]);
|
||||||
|
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchData() {
|
||||||
|
const params = parseQueryString(QS_CONFIG, location.search);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [
|
||||||
|
{
|
||||||
|
data: { count, results },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: { actions: optionActions },
|
||||||
|
},
|
||||||
|
] = await Promise.all([
|
||||||
|
CredentialsAPI.read(params),
|
||||||
|
CredentialsAPI.readOptions(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const credentialTypes = await fetchCredentialTypes(results);
|
||||||
|
|
||||||
|
setCredentials(assignCredentialKinds(results, credentialTypes));
|
||||||
|
setCredentialCount(count);
|
||||||
|
setActions(optionActions);
|
||||||
|
} catch (error) {
|
||||||
|
setContentError(error);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData();
|
||||||
|
}, [location]);
|
||||||
|
|
||||||
|
const handleSelectAll = isSelected => {
|
||||||
|
setSelected(isSelected ? [...credentials] : []);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelect = row => {
|
||||||
|
if (selected.some(s => s.id === row.id)) {
|
||||||
|
setSelected(selected.filter(s => s.id !== row.id));
|
||||||
|
} else {
|
||||||
|
setSelected(selected.concat(row));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = async () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Promise.all(
|
||||||
|
selected.map(credential => CredentialsAPI.destroy(credential.id))
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
setDeletionError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = parseQueryString(QS_CONFIG, location.search);
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
data: { count, results },
|
||||||
|
} = await CredentialsAPI.read(params);
|
||||||
|
|
||||||
|
const credentialTypes = await fetchCredentialTypes(results);
|
||||||
|
|
||||||
|
setCredentials(assignCredentialKinds(results, credentialTypes));
|
||||||
|
setCredentialCount(count);
|
||||||
|
} catch (error) {
|
||||||
|
setContentError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const canAdd =
|
||||||
|
actions && Object.prototype.hasOwnProperty.call(actions, 'POST');
|
||||||
|
const isAllSelected =
|
||||||
|
selected.length > 0 && selected.length === credentials.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageSection>
|
||||||
|
<Card>
|
||||||
|
<PaginatedDataList
|
||||||
|
contentError={contentError}
|
||||||
|
hasContentLoading={isLoading}
|
||||||
|
items={credentials}
|
||||||
|
itemCount={credentialCount}
|
||||||
|
qsConfig={QS_CONFIG}
|
||||||
|
renderItem={item => (
|
||||||
|
<CredentialListItem
|
||||||
|
key={item.id}
|
||||||
|
credential={item}
|
||||||
|
detailUrl={`/credentials/${item.id}/details`}
|
||||||
|
isSelected={selected.some(row => row.id === item.id)}
|
||||||
|
onSelect={() => handleSelect(item)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
renderToolbar={props => (
|
||||||
|
<DataListToolbar
|
||||||
|
{...props}
|
||||||
|
showSelectAll
|
||||||
|
isAllSelected={isAllSelected}
|
||||||
|
onSelectAll={handleSelectAll}
|
||||||
|
qsConfig={QS_CONFIG}
|
||||||
|
additionalControls={[
|
||||||
|
<ToolbarDeleteButton
|
||||||
|
key="delete"
|
||||||
|
onDelete={handleDelete}
|
||||||
|
itemsToDelete={selected}
|
||||||
|
pluralizedItemName={i18n._(t`Credentials`)}
|
||||||
|
/>,
|
||||||
|
canAdd && (
|
||||||
|
<ToolbarAddButton key="add" linkTo="/credentials/add" />
|
||||||
|
),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
<AlertModal
|
||||||
|
isOpen={deletionError}
|
||||||
|
variant="danger"
|
||||||
|
title={i18n._(t`Error!`)}
|
||||||
|
onClose={() => setDeletionError(null)}
|
||||||
|
>
|
||||||
|
{i18n._(t`Failed to delete one or more credentials.`)}
|
||||||
|
<ErrorDetail error={deletionError} />
|
||||||
|
</AlertModal>
|
||||||
|
</PageSection>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withI18n()(CredentialList);
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { act } from 'react-dom/test-utils';
|
||||||
|
import { CredentialsAPI, CredentialTypesAPI } from '@api';
|
||||||
|
import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers';
|
||||||
|
import { CredentialList } from '.';
|
||||||
|
import { mockCredentials, mockCredentialTypes } from '../shared';
|
||||||
|
|
||||||
|
jest.mock('@api');
|
||||||
|
|
||||||
|
describe('<CredentialList />', () => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
CredentialsAPI.read.mockResolvedValueOnce({ data: mockCredentials });
|
||||||
|
CredentialTypesAPI.read.mockResolvedValueOnce({
|
||||||
|
data: mockCredentialTypes,
|
||||||
|
});
|
||||||
|
CredentialsAPI.readOptions.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
actions: {
|
||||||
|
GET: {},
|
||||||
|
POST: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(<CredentialList />);
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('initially renders successfully', () => {
|
||||||
|
expect(wrapper.find('CredentialList').length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should fetch credentials from api and render the in the list', () => {
|
||||||
|
expect(CredentialsAPI.read).toHaveBeenCalled();
|
||||||
|
expect(wrapper.find('CredentialListItem').length).toBe(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show content error if credentials are not successfully fetched from api', async () => {
|
||||||
|
CredentialsAPI.readOptions.mockImplementationOnce(() =>
|
||||||
|
Promise.reject(new Error())
|
||||||
|
);
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(<CredentialList />);
|
||||||
|
});
|
||||||
|
await waitForElement(wrapper, 'ContentError', el => el.length === 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should check and uncheck the row item', async () => {
|
||||||
|
expect(
|
||||||
|
wrapper.find('PFDataListCheck[id="select-credential-1"]').props().checked
|
||||||
|
).toBe(false);
|
||||||
|
await act(async () => {
|
||||||
|
wrapper
|
||||||
|
.find('PFDataListCheck[id="select-credential-1"]')
|
||||||
|
.invoke('onChange')(true);
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
expect(
|
||||||
|
wrapper.find('PFDataListCheck[id="select-credential-1"]').props().checked
|
||||||
|
).toBe(true);
|
||||||
|
await act(async () => {
|
||||||
|
wrapper
|
||||||
|
.find('PFDataListCheck[id="select-credential-1"]')
|
||||||
|
.invoke('onChange')(false);
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
expect(
|
||||||
|
wrapper.find('PFDataListCheck[id="select-credential-1"]').props().checked
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should check all row items when select all is checked', async () => {
|
||||||
|
wrapper.find('PFDataListCheck').forEach(el => {
|
||||||
|
expect(el.props().checked).toBe(false);
|
||||||
|
});
|
||||||
|
await act(async () => {
|
||||||
|
wrapper.find('Checkbox#select-all').invoke('onChange')(true);
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
wrapper.find('PFDataListCheck').forEach(el => {
|
||||||
|
expect(el.props().checked).toBe(true);
|
||||||
|
});
|
||||||
|
await act(async () => {
|
||||||
|
wrapper.find('Checkbox#select-all').invoke('onChange')(false);
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
wrapper.find('PFDataListCheck').forEach(el => {
|
||||||
|
expect(el.props().checked).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call api delete credentials for each selected credential', async () => {
|
||||||
|
CredentialsAPI.read.mockResolvedValueOnce({ data: mockCredentials });
|
||||||
|
CredentialTypesAPI.read.mockResolvedValueOnce({
|
||||||
|
data: mockCredentialTypes,
|
||||||
|
});
|
||||||
|
CredentialsAPI.destroy = jest.fn();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
wrapper
|
||||||
|
.find('PFDataListCheck[id="select-credential-3"]')
|
||||||
|
.invoke('onChange')();
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
await act(async () => {
|
||||||
|
wrapper.find('ToolbarDeleteButton').invoke('onDelete')();
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
expect(CredentialsAPI.destroy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show error modal when credential is not successfully deleted from api', async () => {
|
||||||
|
CredentialsAPI.destroy.mockImplementationOnce(() =>
|
||||||
|
Promise.reject(new Error())
|
||||||
|
);
|
||||||
|
await act(async () => {
|
||||||
|
wrapper
|
||||||
|
.find('PFDataListCheck[id="select-credential-2"]')
|
||||||
|
.invoke('onChange')();
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
await act(async () => {
|
||||||
|
wrapper.find('ToolbarDeleteButton').invoke('onDelete')();
|
||||||
|
});
|
||||||
|
await waitForElement(
|
||||||
|
wrapper,
|
||||||
|
'Modal',
|
||||||
|
el => el.props().isOpen === true && el.props().title === 'Error!'
|
||||||
|
);
|
||||||
|
await act(async () => {
|
||||||
|
wrapper.find('ModalBoxCloseButton').invoke('onClose')();
|
||||||
|
});
|
||||||
|
await waitForElement(wrapper, 'Modal', el => el.props().isOpen === false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { string, bool, func } from 'prop-types';
|
||||||
|
import { withI18n } from '@lingui/react';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import {
|
||||||
|
DataListItem,
|
||||||
|
DataListItemRow,
|
||||||
|
DataListItemCells as _DataListItemCells,
|
||||||
|
Tooltip,
|
||||||
|
} from '@patternfly/react-core';
|
||||||
|
import { PencilAltIcon } from '@patternfly/react-icons';
|
||||||
|
|
||||||
|
import ActionButtonCell from '@components/ActionButtonCell';
|
||||||
|
import DataListCell from '@components/DataListCell';
|
||||||
|
import DataListCheck from '@components/DataListCheck';
|
||||||
|
import ListActionButton from '@components/ListActionButton';
|
||||||
|
import VerticalSeparator from '@components/VerticalSeparator';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { Credential } from '@types';
|
||||||
|
|
||||||
|
const DataListItemCells = styled(_DataListItemCells)`
|
||||||
|
${DataListCell}:first-child {
|
||||||
|
flex-grow: 2;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
function CredentialListItem({
|
||||||
|
credential,
|
||||||
|
detailUrl,
|
||||||
|
isSelected,
|
||||||
|
onSelect,
|
||||||
|
i18n,
|
||||||
|
}) {
|
||||||
|
const labelId = `check-action-${credential.id}`;
|
||||||
|
const canEdit = credential.summary_fields.user_capabilities.edit;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DataListItem key={credential.id} aria-labelledby={labelId}>
|
||||||
|
<DataListItemRow>
|
||||||
|
<DataListCheck
|
||||||
|
id={`select-credential-${credential.id}`}
|
||||||
|
checked={isSelected}
|
||||||
|
onChange={onSelect}
|
||||||
|
aria-labelledby={labelId}
|
||||||
|
/>
|
||||||
|
<DataListItemCells
|
||||||
|
dataListCells={[
|
||||||
|
<DataListCell key="name">
|
||||||
|
<VerticalSeparator />
|
||||||
|
<Link to={`${detailUrl}`}>
|
||||||
|
<b>{credential.name}</b>
|
||||||
|
</Link>
|
||||||
|
</DataListCell>,
|
||||||
|
<DataListCell key="type">{credential.kind}</DataListCell>,
|
||||||
|
<ActionButtonCell lastcolumn="true" key="action">
|
||||||
|
{canEdit && (
|
||||||
|
<Tooltip content={i18n._(t`Edit Credential`)} position="top">
|
||||||
|
<ListActionButton
|
||||||
|
variant="plain"
|
||||||
|
component={Link}
|
||||||
|
to={`/credentials/${credential.id}/edit`}
|
||||||
|
>
|
||||||
|
<PencilAltIcon />
|
||||||
|
</ListActionButton>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</ActionButtonCell>,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</DataListItemRow>
|
||||||
|
</DataListItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
CredentialListItem.propTypes = {
|
||||||
|
detailUrl: string.isRequired,
|
||||||
|
credential: Credential.isRequired,
|
||||||
|
isSelected: bool.isRequired,
|
||||||
|
onSelect: func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withI18n()(CredentialListItem);
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
||||||
|
import { CredentialListItem } from '.';
|
||||||
|
import { mockCredentials } from '../shared';
|
||||||
|
|
||||||
|
describe('<CredentialListItem />', () => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('edit button shown to users with edit capabilities', () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<CredentialListItem
|
||||||
|
credential={mockCredentials.results[0]}
|
||||||
|
detailUrl="/foo/bar"
|
||||||
|
isSelected={false}
|
||||||
|
onSelect={() => {}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(wrapper.find('PencilAltIcon').exists()).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('edit button hidden from users without edit capabilities', () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<CredentialListItem
|
||||||
|
credential={mockCredentials.results[1]}
|
||||||
|
detailUrl="/foo/bar"
|
||||||
|
isSelected={false}
|
||||||
|
onSelect={() => {}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(wrapper.find('PencilAltIcon').exists()).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export { default as CredentialList } from './CredentialList';
|
||||||
|
export { default as CredentialListItem } from './CredentialListItem';
|
||||||
@@ -1,26 +1,27 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React from 'react';
|
||||||
|
import { Route, Switch } from 'react-router-dom';
|
||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import {
|
|
||||||
PageSection,
|
|
||||||
PageSectionVariants,
|
|
||||||
Title,
|
|
||||||
} from '@patternfly/react-core';
|
|
||||||
|
|
||||||
class Credentials extends Component {
|
import Breadcrumbs from '@components/Breadcrumbs/Breadcrumbs';
|
||||||
render() {
|
import { CredentialList } from './CredentialList';
|
||||||
const { i18n } = this.props;
|
import CredentialAdd from './CredentialAdd';
|
||||||
const { light } = PageSectionVariants;
|
|
||||||
|
|
||||||
return (
|
function Credentials({ i18n }) {
|
||||||
<Fragment>
|
const breadcrumbConfig = {
|
||||||
<PageSection variant={light} className="pf-m-condensed">
|
'/credentials': i18n._(t`Credentials`),
|
||||||
<Title size="2xl">{i18n._(t`Credentials`)}</Title>
|
'/credentials/add': i18n._(t`Create New Credential`),
|
||||||
</PageSection>
|
};
|
||||||
<PageSection />
|
|
||||||
</Fragment>
|
return (
|
||||||
);
|
<>
|
||||||
}
|
<Breadcrumbs breadcrumbConfig={breadcrumbConfig} />
|
||||||
|
<Switch>
|
||||||
|
<Route path="/credentials/add" render={() => <CredentialAdd />} />
|
||||||
|
<Route path="/credentials" render={() => <CredentialList />} />
|
||||||
|
</Switch>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withI18n()(Credentials);
|
export default withI18n()(Credentials);
|
||||||
|
|||||||
@@ -1,29 +1,58 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
||||||
|
import { createMemoryHistory } from 'history';
|
||||||
import Credentials from './Credentials';
|
import Credentials from './Credentials';
|
||||||
|
|
||||||
describe('<Credentials />', () => {
|
describe('<Credentials />', () => {
|
||||||
let pageWrapper;
|
let wrapper;
|
||||||
let pageSections;
|
|
||||||
let title;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
pageWrapper = mountWithContexts(<Credentials />);
|
|
||||||
pageSections = pageWrapper.find('PageSection');
|
|
||||||
title = pageWrapper.find('Title');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
pageWrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('initially renders without crashing', () => {
|
test('initially renders succesfully', () => {
|
||||||
expect(pageWrapper.length).toBe(1);
|
wrapper = mountWithContexts(<Credentials />);
|
||||||
expect(pageSections.length).toBe(2);
|
});
|
||||||
expect(title.length).toBe(1);
|
|
||||||
expect(title.props().size).toBe('2xl');
|
test('should display credential list breadcrumb heading', () => {
|
||||||
expect(pageSections.first().props().variant).toBe('light');
|
const history = createMemoryHistory({
|
||||||
|
initialEntries: ['/credentials'],
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper = mountWithContexts(<Credentials />, {
|
||||||
|
context: {
|
||||||
|
router: {
|
||||||
|
history,
|
||||||
|
route: {
|
||||||
|
location: history.location,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.find('Crumb').length).toBe(1);
|
||||||
|
expect(wrapper.find('BreadcrumbHeading').text()).toBe('Credentials');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should display create new credential breadcrumb heading', () => {
|
||||||
|
const history = createMemoryHistory({
|
||||||
|
initialEntries: ['/credentials/add'],
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper = mountWithContexts(<Credentials />, {
|
||||||
|
context: {
|
||||||
|
router: {
|
||||||
|
history,
|
||||||
|
route: {
|
||||||
|
location: history.location,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.find('Crumb').length).toBe(2);
|
||||||
|
expect(wrapper.find('BreadcrumbHeading').text()).toBe(
|
||||||
|
'Create New Credential'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
{
|
||||||
|
"count": 3,
|
||||||
|
"next": null,
|
||||||
|
"previous": null,
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"type": "credential_type",
|
||||||
|
"url": "/api/v2/credential_types/1/",
|
||||||
|
"related": {
|
||||||
|
"credentials": "/api/v2/credential_types/1/credentials/",
|
||||||
|
"activity_stream": "/api/v2/credential_types/1/activity_stream/"
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"user_capabilities": {
|
||||||
|
"edit": false,
|
||||||
|
"delete": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"created": "2019-12-16T21:01:03.430100Z",
|
||||||
|
"modified": "2019-12-16T21:01:24.834078Z",
|
||||||
|
"name": "Machine",
|
||||||
|
"description": "",
|
||||||
|
"kind": "ssh",
|
||||||
|
"namespace": "ssh",
|
||||||
|
"managed_by_tower": true,
|
||||||
|
"inputs": {
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"id": "username",
|
||||||
|
"label": "Username",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "password",
|
||||||
|
"label": "Password",
|
||||||
|
"type": "string",
|
||||||
|
"secret": true,
|
||||||
|
"ask_at_runtime": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ssh_key_data",
|
||||||
|
"label": "SSH Private Key",
|
||||||
|
"type": "string",
|
||||||
|
"format": "ssh_private_key",
|
||||||
|
"secret": true,
|
||||||
|
"multiline": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ssh_public_key_data",
|
||||||
|
"label": "Signed SSH Certificate",
|
||||||
|
"type": "string",
|
||||||
|
"multiline": true,
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ssh_key_unlock",
|
||||||
|
"label": "Private Key Passphrase",
|
||||||
|
"type": "string",
|
||||||
|
"secret": true,
|
||||||
|
"ask_at_runtime": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "become_method",
|
||||||
|
"label": "Privilege Escalation Method",
|
||||||
|
"type": "string",
|
||||||
|
"help_text": "Specify a method for \"become\" operations. This is equivalent to specifying the --become-method Ansible parameter."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "become_username",
|
||||||
|
"label": "Privilege Escalation Username",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "become_password",
|
||||||
|
"label": "Privilege Escalation Password",
|
||||||
|
"type": "string",
|
||||||
|
"secret": true,
|
||||||
|
"ask_at_runtime": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"injectors": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"type": "credential_type",
|
||||||
|
"url": "/api/v2/credential_types/2/",
|
||||||
|
"related": {
|
||||||
|
"credentials": "/api/v2/credential_types/2/credentials/",
|
||||||
|
"activity_stream": "/api/v2/credential_types/2/activity_stream/"
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"user_capabilities": {
|
||||||
|
"edit": false,
|
||||||
|
"delete": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"created": "2019-12-16T21:01:03.443889Z",
|
||||||
|
"modified": "2019-12-16T21:01:24.844433Z",
|
||||||
|
"name": "Source Control",
|
||||||
|
"description": "",
|
||||||
|
"kind": "scm",
|
||||||
|
"namespace": "scm",
|
||||||
|
"managed_by_tower": true,
|
||||||
|
"inputs": {
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"id": "username",
|
||||||
|
"label": "Username",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "password",
|
||||||
|
"label": "Password",
|
||||||
|
"type": "string",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ssh_key_data",
|
||||||
|
"label": "SCM Private Key",
|
||||||
|
"type": "string",
|
||||||
|
"format": "ssh_private_key",
|
||||||
|
"secret": true,
|
||||||
|
"multiline": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ssh_key_unlock",
|
||||||
|
"label": "Private Key Passphrase",
|
||||||
|
"type": "string",
|
||||||
|
"secret": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"injectors": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"type": "credential_type",
|
||||||
|
"url": "/api/v2/credential_types/3/",
|
||||||
|
"related": {
|
||||||
|
"created_by": "/api/v2/users/1/",
|
||||||
|
"modified_by": "/api/v2/users/1/",
|
||||||
|
"credentials": "/api/v2/credential_types/3/credentials/",
|
||||||
|
"activity_stream": "/api/v2/credential_types/3/activity_stream/"
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"created_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"modified_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"user_capabilities": {
|
||||||
|
"edit": true,
|
||||||
|
"delete": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"created": "2019-12-17T16:11:57.723478Z",
|
||||||
|
"modified": "2019-12-17T16:12:01.582942Z",
|
||||||
|
"name": "Bar",
|
||||||
|
"description": "",
|
||||||
|
"kind": "cloud",
|
||||||
|
"namespace": null,
|
||||||
|
"managed_by_tower": false,
|
||||||
|
"inputs": {},
|
||||||
|
"injectors": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
366
awx/ui_next/src/screens/Credential/shared/data.credentials.json
Normal file
366
awx/ui_next/src/screens/Credential/shared/data.credentials.json
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
{
|
||||||
|
"count": 5,
|
||||||
|
"next": "/api/v2/credentials/",
|
||||||
|
"previous": null,
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"type": "credential",
|
||||||
|
"url": "/api/v2/credentials/1/",
|
||||||
|
"related": {
|
||||||
|
"created_by": "/api/v2/users/1/",
|
||||||
|
"modified_by": "/api/v2/users/1/",
|
||||||
|
"activity_stream": "/api/v2/credentials/1/activity_stream/",
|
||||||
|
"access_list": "/api/v2/credentials/1/access_list/",
|
||||||
|
"object_roles": "/api/v2/credentials/1/object_roles/",
|
||||||
|
"owner_users": "/api/v2/credentials/1/owner_users/",
|
||||||
|
"owner_teams": "/api/v2/credentials/1/owner_teams/",
|
||||||
|
"copy": "/api/v2/credentials/1/copy/",
|
||||||
|
"input_sources": "/api/v2/credentials/1/input_sources/",
|
||||||
|
"credential_type": "/api/v2/credential_types/23/",
|
||||||
|
"user": "/api/v2/users/7/"
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"created_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"modified_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"object_roles": {
|
||||||
|
"admin_role": {
|
||||||
|
"description": "Can manage all aspects of the credential",
|
||||||
|
"name": "Admin",
|
||||||
|
"id": 284
|
||||||
|
},
|
||||||
|
"use_role": {
|
||||||
|
"description": "Can use the credential in a job template",
|
||||||
|
"name": "Use",
|
||||||
|
"id": 285
|
||||||
|
},
|
||||||
|
"read_role": {
|
||||||
|
"description": "May view settings for the credential",
|
||||||
|
"name": "Read",
|
||||||
|
"id": 286
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_capabilities": {
|
||||||
|
"edit": true,
|
||||||
|
"delete": true,
|
||||||
|
"copy": true,
|
||||||
|
"use": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"created": "2019-12-17T16:12:25.258897Z",
|
||||||
|
"modified": "2019-12-17T16:12:25.258920Z",
|
||||||
|
"name": "Foo",
|
||||||
|
"organization": null,
|
||||||
|
"credential_type": 1,
|
||||||
|
"kind": null,
|
||||||
|
"cloud": true,
|
||||||
|
"kubernetes": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"type": "credential",
|
||||||
|
"url": "/api/v2/credentials/2/",
|
||||||
|
"related": {
|
||||||
|
"created_by": "/api/v2/users/8/",
|
||||||
|
"modified_by": "/api/v2/users/12/",
|
||||||
|
"activity_stream": "/api/v2/credentials/2/activity_stream/",
|
||||||
|
"access_list": "/api/v2/credentials/2/access_list/",
|
||||||
|
"object_roles": "/api/v2/credentials/2/object_roles/",
|
||||||
|
"owner_users": "/api/v2/credentials/2/owner_users/",
|
||||||
|
"owner_teams": "/api/v2/credentials/2/owner_teams/",
|
||||||
|
"copy": "/api/v2/credentials/2/copy/",
|
||||||
|
"input_sources": "/api/v2/credentials/2/input_sources/",
|
||||||
|
"credential_type": "/api/v2/credential_types/1/",
|
||||||
|
"user": "/api/v2/users/7/"
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"created_by": {
|
||||||
|
"id": 8,
|
||||||
|
"username": "user-2",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"modified_by": {
|
||||||
|
"id": 12,
|
||||||
|
"username": "user-6",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"object_roles": {
|
||||||
|
"admin_role": {
|
||||||
|
"description": "Can manage all aspects of the credential",
|
||||||
|
"name": "Admin",
|
||||||
|
"id": 81
|
||||||
|
},
|
||||||
|
"use_role": {
|
||||||
|
"description": "Can use the credential in a job template",
|
||||||
|
"name": "Use",
|
||||||
|
"id": 82
|
||||||
|
},
|
||||||
|
"read_role": {
|
||||||
|
"description": "May view settings for the credential",
|
||||||
|
"name": "Read",
|
||||||
|
"id": 83
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_capabilities": {
|
||||||
|
"edit": false,
|
||||||
|
"delete": false,
|
||||||
|
"copy": false,
|
||||||
|
"use": false
|
||||||
|
},
|
||||||
|
"owners": [
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"type": "user",
|
||||||
|
"name": "user-1",
|
||||||
|
"description": " ",
|
||||||
|
"url": "/api/v2/users/7/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"created": "2019-12-16T21:04:40.896097Z",
|
||||||
|
"modified": "2019-12-16T21:04:40.896121Z",
|
||||||
|
"name": "Bar",
|
||||||
|
"description": "",
|
||||||
|
"organization": null,
|
||||||
|
"credential_type": 1,
|
||||||
|
"inputs": {},
|
||||||
|
"kind": "ssh",
|
||||||
|
"cloud": false,
|
||||||
|
"kubernetes": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"type": "credential",
|
||||||
|
"url": "/api/v2/credentials/3/",
|
||||||
|
"related": {
|
||||||
|
"created_by": "/api/v2/users/9/",
|
||||||
|
"modified_by": "/api/v2/users/13/",
|
||||||
|
"activity_stream": "/api/v2/credentials/3/activity_stream/",
|
||||||
|
"access_list": "/api/v2/credentials/3/access_list/",
|
||||||
|
"object_roles": "/api/v2/credentials/3/object_roles/",
|
||||||
|
"owner_users": "/api/v2/credentials/3/owner_users/",
|
||||||
|
"owner_teams": "/api/v2/credentials/3/owner_teams/",
|
||||||
|
"copy": "/api/v2/credentials/3/copy/",
|
||||||
|
"input_sources": "/api/v2/credentials/3/input_sources/",
|
||||||
|
"credential_type": "/api/v2/credential_types/1/",
|
||||||
|
"user": "/api/v2/users/8/"
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"created_by": {
|
||||||
|
"id": 9,
|
||||||
|
"username": "user-3",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"modified_by": {
|
||||||
|
"id": 13,
|
||||||
|
"username": "user-7",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"object_roles": {
|
||||||
|
"admin_role": {
|
||||||
|
"description": "Can manage all aspects of the credential",
|
||||||
|
"name": "Admin",
|
||||||
|
"id": 84
|
||||||
|
},
|
||||||
|
"use_role": {
|
||||||
|
"description": "Can use the credential in a job template",
|
||||||
|
"name": "Use",
|
||||||
|
"id": 85
|
||||||
|
},
|
||||||
|
"read_role": {
|
||||||
|
"description": "May view settings for the credential",
|
||||||
|
"name": "Read",
|
||||||
|
"id": 86
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_capabilities": {
|
||||||
|
"edit": true,
|
||||||
|
"delete": true,
|
||||||
|
"copy": true,
|
||||||
|
"use": true
|
||||||
|
},
|
||||||
|
"owners": [
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"type": "user",
|
||||||
|
"name": "user-2",
|
||||||
|
"description": " ",
|
||||||
|
"url": "/api/v2/users/8/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"created": "2019-12-16T21:04:40.955954Z",
|
||||||
|
"modified": "2019-12-16T21:04:40.955976Z",
|
||||||
|
"name": "Baz",
|
||||||
|
"description": "",
|
||||||
|
"organization": null,
|
||||||
|
"credential_type": 1,
|
||||||
|
"inputs": {},
|
||||||
|
"kind": "ssh",
|
||||||
|
"cloud": false,
|
||||||
|
"kubernetes": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"type": "credential",
|
||||||
|
"url": "/api/v2/credentials/4/",
|
||||||
|
"related": {
|
||||||
|
"created_by": "/api/v2/users/1/",
|
||||||
|
"modified_by": "/api/v2/users/1/",
|
||||||
|
"activity_stream": "/api/v2/credentials/4/activity_stream/",
|
||||||
|
"access_list": "/api/v2/credentials/4/access_list/",
|
||||||
|
"object_roles": "/api/v2/credentials/4/object_roles/",
|
||||||
|
"owner_users": "/api/v2/credentials/4/owner_users/",
|
||||||
|
"owner_teams": "/api/v2/credentials/4/owner_teams/",
|
||||||
|
"copy": "/api/v2/credentials/4/copy/",
|
||||||
|
"input_sources": "/api/v2/credentials/4/input_sources/",
|
||||||
|
"credential_type": "/api/v2/credential_types/25/",
|
||||||
|
"user": "/api/v2/users/1/"
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"created_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"modified_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"object_roles": {
|
||||||
|
"admin_role": {
|
||||||
|
"description": "Can manage all aspects of the credential",
|
||||||
|
"name": "Admin",
|
||||||
|
"id": 318
|
||||||
|
},
|
||||||
|
"use_role": {
|
||||||
|
"description": "Can use the credential in a job template",
|
||||||
|
"name": "Use",
|
||||||
|
"id": 319
|
||||||
|
},
|
||||||
|
"read_role": {
|
||||||
|
"description": "May view settings for the credential",
|
||||||
|
"name": "Read",
|
||||||
|
"id": 320
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_capabilities": {
|
||||||
|
"edit": true,
|
||||||
|
"delete": true,
|
||||||
|
"copy": true,
|
||||||
|
"use": true
|
||||||
|
},
|
||||||
|
"owners": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"type": "user",
|
||||||
|
"name": "admin",
|
||||||
|
"description": " ",
|
||||||
|
"url": "/api/v2/users/1/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"created": "2019-12-18T16:31:09.772005Z",
|
||||||
|
"modified": "2019-12-18T16:31:09.832666Z",
|
||||||
|
"name": "FooBar",
|
||||||
|
"description": "",
|
||||||
|
"organization": null,
|
||||||
|
"credential_type": 2,
|
||||||
|
"inputs": {},
|
||||||
|
"kind": null,
|
||||||
|
"cloud": true,
|
||||||
|
"kubernetes": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"type": "credential",
|
||||||
|
"url": "/api/v2/credentials/5/",
|
||||||
|
"related": {
|
||||||
|
"created_by": "/api/v2/users/1/",
|
||||||
|
"modified_by": "/api/v2/users/1/",
|
||||||
|
"activity_stream": "/api/v2/credentials/5/activity_stream/",
|
||||||
|
"access_list": "/api/v2/credentials/5/access_list/",
|
||||||
|
"object_roles": "/api/v2/credentials/5/object_roles/",
|
||||||
|
"owner_users": "/api/v2/credentials/5/owner_users/",
|
||||||
|
"owner_teams": "/api/v2/credentials/5/owner_teams/",
|
||||||
|
"copy": "/api/v2/credentials/5/copy/",
|
||||||
|
"input_sources": "/api/v2/credentials/5/input_sources/",
|
||||||
|
"credential_type": "/api/v2/credential_types/25/",
|
||||||
|
"user": "/api/v2/users/1/"
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"created_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"modified_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"object_roles": {
|
||||||
|
"admin_role": {
|
||||||
|
"description": "Can manage all aspects of the credential",
|
||||||
|
"name": "Admin",
|
||||||
|
"id": 290
|
||||||
|
},
|
||||||
|
"use_role": {
|
||||||
|
"description": "Can use the credential in a job template",
|
||||||
|
"name": "Use",
|
||||||
|
"id": 291
|
||||||
|
},
|
||||||
|
"read_role": {
|
||||||
|
"description": "May view settings for the credential",
|
||||||
|
"name": "Read",
|
||||||
|
"id": 292
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_capabilities": {
|
||||||
|
"edit": true,
|
||||||
|
"delete": true,
|
||||||
|
"copy": true,
|
||||||
|
"use": true
|
||||||
|
},
|
||||||
|
"owners": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"type": "user",
|
||||||
|
"name": "admin",
|
||||||
|
"description": " ",
|
||||||
|
"url": "/api/v2/users/1/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"created": "2019-12-17T16:12:44.923123Z",
|
||||||
|
"modified": "2019-12-17T16:12:44.923151Z",
|
||||||
|
"name": "Qux",
|
||||||
|
"description": "",
|
||||||
|
"organization": null,
|
||||||
|
"credential_type": 3,
|
||||||
|
"inputs": {},
|
||||||
|
"kind": null,
|
||||||
|
"cloud": true,
|
||||||
|
"kubernetes": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
2
awx/ui_next/src/screens/Credential/shared/index.js
Normal file
2
awx/ui_next/src/screens/Credential/shared/index.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export { default as mockCredentials } from './data.credentials.json';
|
||||||
|
export { default as mockCredentialTypes } from './data.credential_types.json';
|
||||||
@@ -50,7 +50,7 @@ class HostListItem extends React.Component {
|
|||||||
/>
|
/>
|
||||||
<DataListItemCells
|
<DataListItemCells
|
||||||
dataListCells={[
|
dataListCells={[
|
||||||
<DataListCell key="divider">
|
<DataListCell key="name">
|
||||||
<VerticalSeparator />
|
<VerticalSeparator />
|
||||||
<Link to={`${detailUrl}`}>
|
<Link to={`${detailUrl}`}>
|
||||||
<b>{host.name}</b>
|
<b>{host.name}</b>
|
||||||
|
|||||||
Reference in New Issue
Block a user