mirror of
https://github.com/ansible/awx.git
synced 2026-03-10 22:19:28 -02:30
Merge pull request #5129 from mabashian/resource-access-tabs
Configures access tabs for job template, project, inventory and smart inventory details
Reviewed-by: Michael Abashian
https://github.com/mabashian
This commit is contained in:
@@ -4,6 +4,12 @@ class Inventories extends Base {
|
|||||||
constructor(http) {
|
constructor(http) {
|
||||||
super(http);
|
super(http);
|
||||||
this.baseUrl = '/api/v2/inventories/';
|
this.baseUrl = '/api/v2/inventories/';
|
||||||
|
|
||||||
|
this.readAccessList = this.readAccessList.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
readAccessList(id, params) {
|
||||||
|
return this.http.get(`${this.baseUrl}${id}/access_list/`, { params });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class JobTemplates extends InstanceGroupsMixin(NotificationsMixin(Base)) {
|
|||||||
this.associateLabel = this.associateLabel.bind(this);
|
this.associateLabel = this.associateLabel.bind(this);
|
||||||
this.disassociateLabel = this.disassociateLabel.bind(this);
|
this.disassociateLabel = this.disassociateLabel.bind(this);
|
||||||
this.readCredentials = this.readCredentials.bind(this);
|
this.readCredentials = this.readCredentials.bind(this);
|
||||||
|
this.readAccessList = this.readAccessList.bind(this);
|
||||||
this.generateLabel = this.generateLabel.bind(this);
|
this.generateLabel = this.generateLabel.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +58,10 @@ class JobTemplates extends InstanceGroupsMixin(NotificationsMixin(Base)) {
|
|||||||
disassociate: true,
|
disassociate: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readAccessList(id, params) {
|
||||||
|
return this.http.get(`${this.baseUrl}${id}/access_list/`, { params });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default JobTemplates;
|
export default JobTemplates;
|
||||||
|
|||||||
@@ -7,11 +7,16 @@ class Projects extends LaunchUpdateMixin(NotificationsMixin(Base)) {
|
|||||||
super(http);
|
super(http);
|
||||||
this.baseUrl = '/api/v2/projects/';
|
this.baseUrl = '/api/v2/projects/';
|
||||||
|
|
||||||
|
this.readAccessList = this.readAccessList.bind(this);
|
||||||
this.readPlaybooks = this.readPlaybooks.bind(this);
|
this.readPlaybooks = this.readPlaybooks.bind(this);
|
||||||
this.readSync = this.readSync.bind(this);
|
this.readSync = this.readSync.bind(this);
|
||||||
this.sync = this.sync.bind(this);
|
this.sync = this.sync.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readAccessList(id, params) {
|
||||||
|
return this.http.get(`${this.baseUrl}${id}/access_list/`, { params });
|
||||||
|
}
|
||||||
|
|
||||||
readPlaybooks(id) {
|
readPlaybooks(id) {
|
||||||
return this.http.get(`${this.baseUrl}${id}/playbooks/`);
|
return this.http.get(`${this.baseUrl}${id}/playbooks/`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class DeleteRoleConfirmationModal extends React.Component {
|
|||||||
<Button
|
<Button
|
||||||
key="delete"
|
key="delete"
|
||||||
variant="danger"
|
variant="danger"
|
||||||
aria-label="Confirm delete"
|
aria-label={i18n._(t`Confirm delete`)}
|
||||||
onClick={onConfirm}
|
onClick={onConfirm}
|
||||||
>
|
>
|
||||||
{i18n._(t`Delete`)}
|
{i18n._(t`Delete`)}
|
||||||
@@ -57,11 +57,7 @@ class DeleteRoleConfirmationModal extends React.Component {
|
|||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
{i18n._(
|
{i18n._(
|
||||||
t`If you ${(
|
t`If you only want to remove access for this particular user, please remove them from the team.`
|
||||||
<b>
|
|
||||||
<i>only</i>
|
|
||||||
</b>
|
|
||||||
)} want to remove access for this particular user, please remove them from the team.`
|
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
) : (
|
) : (
|
||||||
@@ -3,7 +3,7 @@ import { withRouter } 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 { OrganizationsAPI, TeamsAPI, UsersAPI } from '@api';
|
import { TeamsAPI, UsersAPI } from '@api';
|
||||||
import AddResourceRole from '@components/AddRole/AddResourceRole';
|
import AddResourceRole from '@components/AddRole/AddResourceRole';
|
||||||
import AlertModal from '@components/AlertModal';
|
import AlertModal from '@components/AlertModal';
|
||||||
import DataListToolbar from '@components/DataListToolbar';
|
import DataListToolbar from '@components/DataListToolbar';
|
||||||
@@ -11,10 +11,9 @@ import PaginatedDataList, {
|
|||||||
ToolbarAddButton,
|
ToolbarAddButton,
|
||||||
} from '@components/PaginatedDataList';
|
} from '@components/PaginatedDataList';
|
||||||
import { getQSConfig, encodeQueryString, parseQueryString } from '@util/qs';
|
import { getQSConfig, encodeQueryString, parseQueryString } from '@util/qs';
|
||||||
import { Organization } from '@types';
|
|
||||||
|
|
||||||
import DeleteRoleConfirmationModal from './DeleteRoleConfirmationModal';
|
import DeleteRoleConfirmationModal from './DeleteRoleConfirmationModal';
|
||||||
import OrganizationAccessItem from './OrganizationAccessItem';
|
import ResourceAccessListItem from './ResourceAccessListItem';
|
||||||
|
|
||||||
const QS_CONFIG = getQSConfig('access', {
|
const QS_CONFIG = getQSConfig('access', {
|
||||||
page: 1,
|
page: 1,
|
||||||
@@ -22,11 +21,7 @@ const QS_CONFIG = getQSConfig('access', {
|
|||||||
order_by: 'first_name',
|
order_by: 'first_name',
|
||||||
});
|
});
|
||||||
|
|
||||||
class OrganizationAccess extends React.Component {
|
class ResourceAccessList extends React.Component {
|
||||||
static propTypes = {
|
|
||||||
organization: Organization.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -65,14 +60,14 @@ class OrganizationAccess extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async loadAccessList() {
|
async loadAccessList() {
|
||||||
const { organization, location } = this.props;
|
const { apiModel, resource, location } = this.props;
|
||||||
const params = parseQueryString(QS_CONFIG, location.search);
|
const params = parseQueryString(QS_CONFIG, location.search);
|
||||||
|
|
||||||
this.setState({ contentError: null, hasContentLoading: true });
|
this.setState({ contentError: null, hasContentLoading: true });
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
data: { results: accessRecords = [], count: itemCount = 0 },
|
data: { results: accessRecords = [], count: itemCount = 0 },
|
||||||
} = await OrganizationsAPI.readAccessList(organization.id, params);
|
} = await apiModel.readAccessList(resource.id, params);
|
||||||
this.setState({ itemCount, accessRecords });
|
this.setState({ itemCount, accessRecords });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.setState({ contentError: err });
|
this.setState({ contentError: err });
|
||||||
@@ -143,7 +138,7 @@ class OrganizationAccess extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { organization, i18n } = this.props;
|
const { resource, i18n } = this.props;
|
||||||
const {
|
const {
|
||||||
accessRecords,
|
accessRecords,
|
||||||
contentError,
|
contentError,
|
||||||
@@ -154,7 +149,7 @@ class OrganizationAccess extends React.Component {
|
|||||||
itemCount,
|
itemCount,
|
||||||
isAddModalOpen,
|
isAddModalOpen,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const canEdit = organization.summary_fields.user_capabilities.edit;
|
const canEdit = resource.summary_fields.user_capabilities.edit;
|
||||||
const isDeleteModalOpen =
|
const isDeleteModalOpen =
|
||||||
!hasContentLoading && !hasDeletionError && deletionRole;
|
!hasContentLoading && !hasDeletionError && deletionRole;
|
||||||
|
|
||||||
@@ -204,7 +199,7 @@ class OrganizationAccess extends React.Component {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
renderItem={accessRecord => (
|
renderItem={accessRecord => (
|
||||||
<OrganizationAccessItem
|
<ResourceAccessListItem
|
||||||
key={accessRecord.id}
|
key={accessRecord.id}
|
||||||
accessRecord={accessRecord}
|
accessRecord={accessRecord}
|
||||||
onRoleDelete={this.handleDeleteOpen}
|
onRoleDelete={this.handleDeleteOpen}
|
||||||
@@ -215,7 +210,7 @@ class OrganizationAccess extends React.Component {
|
|||||||
<AddResourceRole
|
<AddResourceRole
|
||||||
onClose={this.handleAddClose}
|
onClose={this.handleAddClose}
|
||||||
onSave={this.handleAddSuccess}
|
onSave={this.handleAddSuccess}
|
||||||
roles={organization.summary_fields.object_roles}
|
roles={resource.summary_fields.object_roles}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isDeleteModalOpen && (
|
{isDeleteModalOpen && (
|
||||||
@@ -239,5 +234,5 @@ class OrganizationAccess extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { OrganizationAccess as _OrganizationAccess };
|
export { ResourceAccessList as _ResourceAccessList };
|
||||||
export default withI18n()(withRouter(OrganizationAccess));
|
export default withI18n()(withRouter(ResourceAccessList));
|
||||||
@@ -5,11 +5,11 @@ import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers';
|
|||||||
|
|
||||||
import { OrganizationsAPI, TeamsAPI, UsersAPI } from '@api';
|
import { OrganizationsAPI, TeamsAPI, UsersAPI } from '@api';
|
||||||
|
|
||||||
import OrganizationAccess from './OrganizationAccess';
|
import ResourceAccessList from './ResourceAccessList';
|
||||||
|
|
||||||
jest.mock('@api');
|
jest.mock('@api');
|
||||||
|
|
||||||
describe('<OrganizationAccess />', () => {
|
describe('<ResourceAccessList />', () => {
|
||||||
const organization = {
|
const organization = {
|
||||||
id: 1,
|
id: 1,
|
||||||
name: 'Default',
|
name: 'Default',
|
||||||
@@ -83,33 +83,33 @@ describe('<OrganizationAccess />', () => {
|
|||||||
|
|
||||||
test('initially renders succesfully', () => {
|
test('initially renders succesfully', () => {
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<OrganizationAccess organization={organization} />
|
<ResourceAccessList resource={organization} apiModel={OrganizationsAPI} />
|
||||||
);
|
);
|
||||||
expect(wrapper.find('PaginatedDataList')).toHaveLength(1);
|
expect(wrapper.find('PaginatedDataList')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should fetch and display access records on mount', async done => {
|
test('should fetch and display access records on mount', async done => {
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<OrganizationAccess organization={organization} />
|
<ResourceAccessList resource={organization} apiModel={OrganizationsAPI} />
|
||||||
);
|
);
|
||||||
await waitForElement(
|
await waitForElement(
|
||||||
wrapper,
|
wrapper,
|
||||||
'OrganizationAccessItem',
|
'ResourceAccessListItem',
|
||||||
el => el.length === 2
|
el => el.length === 2
|
||||||
);
|
);
|
||||||
expect(wrapper.find('PaginatedDataList').prop('items')).toEqual(
|
expect(wrapper.find('PaginatedDataList').prop('items')).toEqual(
|
||||||
data.results
|
data.results
|
||||||
);
|
);
|
||||||
expect(wrapper.find('OrganizationAccess').state('hasContentLoading')).toBe(
|
expect(wrapper.find('ResourceAccessList').state('hasContentLoading')).toBe(
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
expect(wrapper.find('OrganizationAccess').state('contentError')).toBe(null);
|
expect(wrapper.find('ResourceAccessList').state('contentError')).toBe(null);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should open confirmation dialog when deleting role', async done => {
|
test('should open confirmation dialog when deleting role', async done => {
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<OrganizationAccess organization={organization} />
|
<ResourceAccessList resource={organization} apiModel={OrganizationsAPI} />
|
||||||
);
|
);
|
||||||
await sleep(0);
|
await sleep(0);
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
@@ -118,7 +118,7 @@ describe('<OrganizationAccess />', () => {
|
|||||||
button.prop('onClick')();
|
button.prop('onClick')();
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|
||||||
const component = wrapper.find('OrganizationAccess');
|
const component = wrapper.find('ResourceAccessList');
|
||||||
expect(component.state('deletionRole')).toEqual(
|
expect(component.state('deletionRole')).toEqual(
|
||||||
data.results[0].summary_fields.direct_access[0].role
|
data.results[0].summary_fields.direct_access[0].role
|
||||||
);
|
);
|
||||||
@@ -129,7 +129,7 @@ describe('<OrganizationAccess />', () => {
|
|||||||
|
|
||||||
it('should close dialog when cancel button clicked', async done => {
|
it('should close dialog when cancel button clicked', async done => {
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<OrganizationAccess organization={organization} />
|
<ResourceAccessList resource={organization} apiModel={OrganizationsAPI} />
|
||||||
);
|
);
|
||||||
await sleep(0);
|
await sleep(0);
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
@@ -138,7 +138,7 @@ describe('<OrganizationAccess />', () => {
|
|||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|
||||||
wrapper.find('DeleteRoleConfirmationModal').prop('onCancel')();
|
wrapper.find('DeleteRoleConfirmationModal').prop('onCancel')();
|
||||||
const component = wrapper.find('OrganizationAccess');
|
const component = wrapper.find('ResourceAccessList');
|
||||||
expect(component.state('deletionRole')).toBeNull();
|
expect(component.state('deletionRole')).toBeNull();
|
||||||
expect(component.state('deletionRecord')).toBeNull();
|
expect(component.state('deletionRecord')).toBeNull();
|
||||||
expect(TeamsAPI.disassociateRole).not.toHaveBeenCalled();
|
expect(TeamsAPI.disassociateRole).not.toHaveBeenCalled();
|
||||||
@@ -148,7 +148,7 @@ describe('<OrganizationAccess />', () => {
|
|||||||
|
|
||||||
it('should delete user role', async done => {
|
it('should delete user role', async done => {
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<OrganizationAccess organization={organization} />
|
<ResourceAccessList resource={organization} apiModel={OrganizationsAPI} />
|
||||||
);
|
);
|
||||||
const button = await waitForElement(
|
const button = await waitForElement(
|
||||||
wrapper,
|
wrapper,
|
||||||
@@ -170,7 +170,7 @@ describe('<OrganizationAccess />', () => {
|
|||||||
|
|
||||||
await sleep(0);
|
await sleep(0);
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
const component = wrapper.find('OrganizationAccess');
|
const component = wrapper.find('ResourceAccessList');
|
||||||
expect(component.state('deletionRole')).toBeNull();
|
expect(component.state('deletionRole')).toBeNull();
|
||||||
expect(component.state('deletionRecord')).toBeNull();
|
expect(component.state('deletionRecord')).toBeNull();
|
||||||
expect(TeamsAPI.disassociateRole).not.toHaveBeenCalled();
|
expect(TeamsAPI.disassociateRole).not.toHaveBeenCalled();
|
||||||
@@ -181,7 +181,7 @@ describe('<OrganizationAccess />', () => {
|
|||||||
|
|
||||||
it('should delete team role', async done => {
|
it('should delete team role', async done => {
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<OrganizationAccess organization={organization} />
|
<ResourceAccessList resource={organization} apiModel={OrganizationsAPI} />
|
||||||
);
|
);
|
||||||
const button = await waitForElement(
|
const button = await waitForElement(
|
||||||
wrapper,
|
wrapper,
|
||||||
@@ -203,7 +203,7 @@ describe('<OrganizationAccess />', () => {
|
|||||||
|
|
||||||
await sleep(0);
|
await sleep(0);
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
const component = wrapper.find('OrganizationAccess');
|
const component = wrapper.find('ResourceAccessList');
|
||||||
expect(component.state('deletionRole')).toBeNull();
|
expect(component.state('deletionRole')).toBeNull();
|
||||||
expect(component.state('deletionRecord')).toBeNull();
|
expect(component.state('deletionRecord')).toBeNull();
|
||||||
expect(TeamsAPI.disassociateRole).toHaveBeenCalledWith(5, 3);
|
expect(TeamsAPI.disassociateRole).toHaveBeenCalledWith(5, 3);
|
||||||
@@ -22,7 +22,7 @@ const DataListItemCells = styled(PFDataListItemCells)`
|
|||||||
align-items: start;
|
align-items: start;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
class OrganizationAccessItem extends React.Component {
|
class ResourceAccessListItem extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
accessRecord: AccessRecord.isRequired,
|
accessRecord: AccessRecord.isRequired,
|
||||||
onRoleDelete: func.isRequired,
|
onRoleDelete: func.isRequired,
|
||||||
@@ -132,4 +132,4 @@ class OrganizationAccessItem extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withI18n()(OrganizationAccessItem);
|
export default withI18n()(ResourceAccessListItem);
|
||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
|
|
||||||
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
||||||
|
|
||||||
import OrganizationAccessItem from './OrganizationAccessItem';
|
import ResourceAccessListItem from './ResourceAccessListItem';
|
||||||
|
|
||||||
const accessRecord = {
|
const accessRecord = {
|
||||||
id: 2,
|
id: 2,
|
||||||
@@ -28,14 +28,14 @@ const accessRecord = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('<OrganizationAccessItem />', () => {
|
describe('<ResourceAccessListItem />', () => {
|
||||||
test('initially renders succesfully', () => {
|
test('initially renders succesfully', () => {
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<OrganizationAccessItem
|
<ResourceAccessListItem
|
||||||
accessRecord={accessRecord}
|
accessRecord={accessRecord}
|
||||||
onRoleDelete={() => {}}
|
onRoleDelete={() => {}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
expect(wrapper.find('OrganizationAccessItem')).toMatchSnapshot();
|
expect(wrapper.find('ResourceAccessListItem')).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -110,7 +110,7 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
|
|||||||
Are you sure you want to remove {0} access from {1}? Doing so affects all members of the team.
|
Are you sure you want to remove {0} access from {1}? Doing so affects all members of the team.
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
If you {0} want to remove access for this particular user, please remove them from the team.
|
If you only want to remove access for this particular user, please remove them from the team.
|
||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class="at-c-alertModal__icon"
|
class="at-c-alertModal__icon"
|
||||||
@@ -211,7 +211,7 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
|
|||||||
Are you sure you want to remove {0} access from {1}? Doing so affects all members of the team.
|
Are you sure you want to remove {0} access from {1}? Doing so affects all members of the team.
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
If you {0} want to remove access for this particular user, please remove them from the team.
|
If you only want to remove access for this particular user, please remove them from the team.
|
||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class="at-c-alertModal__icon"
|
class="at-c-alertModal__icon"
|
||||||
@@ -422,7 +422,7 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
|
|||||||
Are you sure you want to remove {0} access from {1}? Doing so affects all members of the team.
|
Are you sure you want to remove {0} access from {1}? Doing so affects all members of the team.
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
If you {0} want to remove access for this particular user, please remove them from the team.
|
If you only want to remove access for this particular user, please remove them from the team.
|
||||||
<ExclamationCircleIcon
|
<ExclamationCircleIcon
|
||||||
className="at-c-alertModal__icon"
|
className="at-c-alertModal__icon"
|
||||||
color="currentColor"
|
color="currentColor"
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`<OrganizationAccessItem /> initially renders succesfully 1`] = `
|
exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||||
<OrganizationAccessItem
|
<ResourceAccessListItem
|
||||||
accessRecord={
|
accessRecord={
|
||||||
Object {
|
Object {
|
||||||
"first_name": "jane",
|
"first_name": "jane",
|
||||||
@@ -47,7 +47,7 @@ exports[`<OrganizationAccessItem /> initially renders succesfully 1`] = `
|
|||||||
<div
|
<div
|
||||||
className="pf-c-data-list__item-row"
|
className="pf-c-data-list__item-row"
|
||||||
>
|
>
|
||||||
<OrganizationAccessItem__DataListItemCells
|
<ResourceAccessListItem__DataListItemCells
|
||||||
dataListCells={
|
dataListCells={
|
||||||
Array [
|
Array [
|
||||||
<DataListCell>
|
<DataListCell>
|
||||||
@@ -157,17 +157,17 @@ exports[`<OrganizationAccessItem /> initially renders succesfully 1`] = `
|
|||||||
"$$typeof": Symbol(react.forward_ref),
|
"$$typeof": Symbol(react.forward_ref),
|
||||||
"attrs": Array [],
|
"attrs": Array [],
|
||||||
"componentStyle": ComponentStyle {
|
"componentStyle": ComponentStyle {
|
||||||
"componentId": "OrganizationAccessItem__DataListItemCells-sc-1b9e0ad-0",
|
"componentId": "ResourceAccessListItem__DataListItemCells-a3r9sq-0",
|
||||||
"isStatic": true,
|
"isStatic": true,
|
||||||
"lastClassName": "QeteT",
|
"lastClassName": "WzRoT",
|
||||||
"rules": Array [
|
"rules": Array [
|
||||||
"align-items:start;",
|
"align-items:start;",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"displayName": "OrganizationAccessItem__DataListItemCells",
|
"displayName": "ResourceAccessListItem__DataListItemCells",
|
||||||
"foldedComponentIds": Array [],
|
"foldedComponentIds": Array [],
|
||||||
"render": [Function],
|
"render": [Function],
|
||||||
"styledComponentId": "OrganizationAccessItem__DataListItemCells-sc-1b9e0ad-0",
|
"styledComponentId": "ResourceAccessListItem__DataListItemCells-a3r9sq-0",
|
||||||
"target": [Function],
|
"target": [Function],
|
||||||
"toString": [Function],
|
"toString": [Function],
|
||||||
"warnTooManyClasses": [Function],
|
"warnTooManyClasses": [Function],
|
||||||
@@ -178,7 +178,7 @@ exports[`<OrganizationAccessItem /> initially renders succesfully 1`] = `
|
|||||||
rowid="access-list-item"
|
rowid="access-list-item"
|
||||||
>
|
>
|
||||||
<DataListItemCells
|
<DataListItemCells
|
||||||
className="OrganizationAccessItem__DataListItemCells-sc-1b9e0ad-0 QeteT"
|
className="ResourceAccessListItem__DataListItemCells-a3r9sq-0 WzRoT"
|
||||||
dataListCells={
|
dataListCells={
|
||||||
Array [
|
Array [
|
||||||
<DataListCell>
|
<DataListCell>
|
||||||
@@ -232,7 +232,7 @@ exports[`<OrganizationAccessItem /> initially renders succesfully 1`] = `
|
|||||||
rowid="access-list-item"
|
rowid="access-list-item"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="pf-c-data-list__item-content OrganizationAccessItem__DataListItemCells-sc-1b9e0ad-0 QeteT"
|
className="pf-c-data-list__item-content ResourceAccessListItem__DataListItemCells-a3r9sq-0 WzRoT"
|
||||||
>
|
>
|
||||||
<DataListCell
|
<DataListCell
|
||||||
key="name"
|
key="name"
|
||||||
@@ -887,10 +887,10 @@ exports[`<OrganizationAccessItem /> initially renders succesfully 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</DataListItemCells>
|
</DataListItemCells>
|
||||||
</StyledComponent>
|
</StyledComponent>
|
||||||
</OrganizationAccessItem__DataListItemCells>
|
</ResourceAccessListItem__DataListItemCells>
|
||||||
</div>
|
</div>
|
||||||
</DataListItemRow>
|
</DataListItemRow>
|
||||||
</li>
|
</li>
|
||||||
</DataListItem>
|
</DataListItem>
|
||||||
</OrganizationAccessItem>
|
</ResourceAccessListItem>
|
||||||
`;
|
`;
|
||||||
5
awx/ui_next/src/components/ResourceAccessList/index.js
Normal file
5
awx/ui_next/src/components/ResourceAccessList/index.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export { default as ResourceAccessList } from './ResourceAccessList';
|
||||||
|
export { default as ResourceAccessListItem } from './ResourceAccessListItem';
|
||||||
|
export {
|
||||||
|
default as DeleteRoleConfirmationModal,
|
||||||
|
} from './DeleteRoleConfirmationModal';
|
||||||
@@ -6,12 +6,12 @@ import { Switch, Route, Redirect, withRouter, Link } from 'react-router-dom';
|
|||||||
import CardCloseButton from '@components/CardCloseButton';
|
import CardCloseButton from '@components/CardCloseButton';
|
||||||
import ContentError from '@components/ContentError';
|
import ContentError from '@components/ContentError';
|
||||||
import RoutedTabs from '@components/RoutedTabs';
|
import RoutedTabs from '@components/RoutedTabs';
|
||||||
|
import { ResourceAccessList } from '@components/ResourceAccessList';
|
||||||
import InventoryDetail from './InventoryDetail';
|
import InventoryDetail from './InventoryDetail';
|
||||||
import InventoryAccess from './InventoryAccess';
|
|
||||||
import InventoryHosts from './InventoryHosts';
|
import InventoryHosts from './InventoryHosts';
|
||||||
import InventoryGroups from './InventoryGroups';
|
import InventoryGroups from './InventoryGroups';
|
||||||
import InventorySources from './InventorySources';
|
|
||||||
import InventoryCompletedJobs from './InventoryCompletedJobs';
|
import InventoryCompletedJobs from './InventoryCompletedJobs';
|
||||||
|
import InventorySources from './InventorySources';
|
||||||
import { InventoriesAPI } from '@api';
|
import { InventoriesAPI } from '@api';
|
||||||
import InventoryEdit from './InventoryEdit';
|
import InventoryEdit from './InventoryEdit';
|
||||||
|
|
||||||
@@ -137,7 +137,12 @@ class Inventory extends Component {
|
|||||||
<Route
|
<Route
|
||||||
key="access"
|
key="access"
|
||||||
path="/inventories/inventory/:id/access"
|
path="/inventories/inventory/:id/access"
|
||||||
render={() => <InventoryAccess inventory={inventory} />}
|
render={() => (
|
||||||
|
<ResourceAccessList
|
||||||
|
resource={inventory}
|
||||||
|
apiModel={InventoriesAPI}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>,
|
/>,
|
||||||
<Route
|
<Route
|
||||||
key="groups"
|
key="groups"
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import { CardBody } from '@patternfly/react-core';
|
|
||||||
|
|
||||||
class InventoryAccess extends Component {
|
|
||||||
render() {
|
|
||||||
return <CardBody>Coming soon :)</CardBody>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default InventoryAccess;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { default } from './InventoryAccess';
|
|
||||||
@@ -6,8 +6,8 @@ import { Switch, Route, Redirect, withRouter, Link } from 'react-router-dom';
|
|||||||
import CardCloseButton from '@components/CardCloseButton';
|
import CardCloseButton from '@components/CardCloseButton';
|
||||||
import ContentError from '@components/ContentError';
|
import ContentError from '@components/ContentError';
|
||||||
import RoutedTabs from '@components/RoutedTabs';
|
import RoutedTabs from '@components/RoutedTabs';
|
||||||
|
import { ResourceAccessList } from '@components/ResourceAccessList';
|
||||||
import SmartInventoryDetail from './SmartInventoryDetail';
|
import SmartInventoryDetail from './SmartInventoryDetail';
|
||||||
import SmartInventoryAccess from './SmartInventoryAccess';
|
|
||||||
import SmartInventoryHosts from './SmartInventoryHosts';
|
import SmartInventoryHosts from './SmartInventoryHosts';
|
||||||
import SmartInventoryCompletedJobs from './SmartInventoryCompletedJobs';
|
import SmartInventoryCompletedJobs from './SmartInventoryCompletedJobs';
|
||||||
import { InventoriesAPI } from '@api';
|
import { InventoriesAPI } from '@api';
|
||||||
@@ -132,7 +132,12 @@ class SmartInventory extends Component {
|
|||||||
<Route
|
<Route
|
||||||
key="access"
|
key="access"
|
||||||
path="/inventories/smart_inventory/:id/access"
|
path="/inventories/smart_inventory/:id/access"
|
||||||
render={() => <SmartInventoryAccess inventory={inventory} />}
|
render={() => (
|
||||||
|
<ResourceAccessList
|
||||||
|
resource={inventory}
|
||||||
|
apiModel={InventoriesAPI}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>,
|
/>,
|
||||||
<Route
|
<Route
|
||||||
key="hosts"
|
key="hosts"
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import { CardBody } from '@patternfly/react-core';
|
|
||||||
|
|
||||||
class SmartInventoryAccess extends Component {
|
|
||||||
render() {
|
|
||||||
return <CardBody>Coming soon :)</CardBody>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SmartInventoryAccess;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { default } from './SmartInventoryAccess';
|
|
||||||
@@ -12,7 +12,7 @@ import CardCloseButton from '@components/CardCloseButton';
|
|||||||
import RoutedTabs from '@components/RoutedTabs';
|
import RoutedTabs from '@components/RoutedTabs';
|
||||||
import ContentError from '@components/ContentError';
|
import ContentError from '@components/ContentError';
|
||||||
import NotificationList from '@components/NotificationList/NotificationList';
|
import NotificationList from '@components/NotificationList/NotificationList';
|
||||||
import { OrganizationAccess } from './OrganizationAccess';
|
import { ResourceAccessList } from '@components/ResourceAccessList';
|
||||||
import OrganizationDetail from './OrganizationDetail';
|
import OrganizationDetail from './OrganizationDetail';
|
||||||
import OrganizationEdit from './OrganizationEdit';
|
import OrganizationEdit from './OrganizationEdit';
|
||||||
import OrganizationTeams from './OrganizationTeams';
|
import OrganizationTeams from './OrganizationTeams';
|
||||||
@@ -216,7 +216,10 @@ class Organization extends Component {
|
|||||||
<Route
|
<Route
|
||||||
path="/organizations/:id/access"
|
path="/organizations/:id/access"
|
||||||
render={() => (
|
render={() => (
|
||||||
<OrganizationAccess organization={organization} />
|
<ResourceAccessList
|
||||||
|
resource={organization}
|
||||||
|
apiModel={OrganizationsAPI}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
export { default as OrganizationAccess } from './OrganizationAccess';
|
|
||||||
export { default as OrganizationAccessItem } from './OrganizationAccessItem';
|
|
||||||
export {
|
|
||||||
default as DeleteRoleConfirmationModal,
|
|
||||||
} from './DeleteRoleConfirmationModal';
|
|
||||||
@@ -12,7 +12,7 @@ import CardCloseButton from '@components/CardCloseButton';
|
|||||||
import RoutedTabs from '@components/RoutedTabs';
|
import RoutedTabs from '@components/RoutedTabs';
|
||||||
import ContentError from '@components/ContentError';
|
import ContentError from '@components/ContentError';
|
||||||
import NotificationList from '@components/NotificationList';
|
import NotificationList from '@components/NotificationList';
|
||||||
import ProjectAccess from './ProjectAccess';
|
import { ResourceAccessList } from '@components/ResourceAccessList';
|
||||||
import ProjectDetail from './ProjectDetail';
|
import ProjectDetail from './ProjectDetail';
|
||||||
import ProjectEdit from './ProjectEdit';
|
import ProjectEdit from './ProjectEdit';
|
||||||
import ProjectJobTemplates from './ProjectJobTemplates';
|
import ProjectJobTemplates from './ProjectJobTemplates';
|
||||||
@@ -222,7 +222,12 @@ class Project extends Component {
|
|||||||
{project && (
|
{project && (
|
||||||
<Route
|
<Route
|
||||||
path="/projects/:id/access"
|
path="/projects/:id/access"
|
||||||
render={() => <ProjectAccess project={project} />}
|
render={() => (
|
||||||
|
<ResourceAccessList
|
||||||
|
resource={project}
|
||||||
|
apiModel={ProjectsAPI}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{canSeeNotificationsTab && (
|
{canSeeNotificationsTab && (
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import { CardBody } from '@patternfly/react-core';
|
|
||||||
|
|
||||||
class ProjectAccess extends Component {
|
|
||||||
render() {
|
|
||||||
return <CardBody>Coming soon :)</CardBody>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ProjectAccess;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { default } from './ProjectAccess';
|
|
||||||
@@ -7,6 +7,7 @@ import CardCloseButton from '@components/CardCloseButton';
|
|||||||
import ContentError from '@components/ContentError';
|
import ContentError from '@components/ContentError';
|
||||||
import NotificationList from '@components/NotificationList';
|
import NotificationList from '@components/NotificationList';
|
||||||
import RoutedTabs from '@components/RoutedTabs';
|
import RoutedTabs from '@components/RoutedTabs';
|
||||||
|
import { ResourceAccessList } from '@components/ResourceAccessList';
|
||||||
import JobTemplateDetail from './JobTemplateDetail';
|
import JobTemplateDetail from './JobTemplateDetail';
|
||||||
import { JobTemplatesAPI, OrganizationsAPI } from '@api';
|
import { JobTemplatesAPI, OrganizationsAPI } from '@api';
|
||||||
import JobTemplateEdit from './JobTemplateEdit';
|
import JobTemplateEdit from './JobTemplateEdit';
|
||||||
@@ -90,7 +91,7 @@ class Template extends Component {
|
|||||||
|
|
||||||
const tabsArray = [
|
const tabsArray = [
|
||||||
{ name: i18n._(t`Details`), link: `${match.url}/details` },
|
{ name: i18n._(t`Details`), link: `${match.url}/details` },
|
||||||
{ name: i18n._(t`Access`), link: '/home' },
|
{ name: i18n._(t`Access`), link: `${match.url}/access` },
|
||||||
];
|
];
|
||||||
|
|
||||||
if (canSeeNotificationsTab) {
|
if (canSeeNotificationsTab) {
|
||||||
@@ -177,6 +178,18 @@ class Template extends Component {
|
|||||||
render={() => <JobTemplateEdit template={template} />}
|
render={() => <JobTemplateEdit template={template} />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{template && (
|
||||||
|
<Route
|
||||||
|
key="access"
|
||||||
|
path="/templates/:templateType/:id/access"
|
||||||
|
render={() => (
|
||||||
|
<ResourceAccessList
|
||||||
|
resource={template}
|
||||||
|
apiModel={JobTemplatesAPI}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{canSeeNotificationsTab && (
|
{canSeeNotificationsTab && (
|
||||||
<Route
|
<Route
|
||||||
path="/templates/:templateType/:id/notifications"
|
path="/templates/:templateType/:id/notifications"
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class Templates extends Component {
|
|||||||
[`/templates/${template.type}/${template.id}/notifications`]: i18n._(
|
[`/templates/${template.type}/${template.id}/notifications`]: i18n._(
|
||||||
t`Notifications`
|
t`Notifications`
|
||||||
),
|
),
|
||||||
|
[`/templates/${template.type}/${template.id}/access`]: i18n._(t`Access`),
|
||||||
};
|
};
|
||||||
this.setState({ breadcrumbConfig });
|
this.setState({ breadcrumbConfig });
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user