Merge pull request #8776 from nixocio/ui_issue_7708

Show access tab when credential does not belong to an organization

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
softwarefactory-project-zuul[bot]
2021-01-12 18:46:27 +00:00
committed by GitHub
7 changed files with 56 additions and 24 deletions

View File

@@ -144,7 +144,7 @@ class AddResourceRole extends React.Component {
currentStepId, currentStepId,
maxEnabledStep, maxEnabledStep,
} = this.state; } = this.state;
const { onClose, roles, i18n } = this.props; const { onClose, roles, i18n, resource } = this.props;
// Object roles can be user only, so we remove them when // Object roles can be user only, so we remove them when
// showing role choices for team access // showing role choices for team access
@@ -235,18 +235,24 @@ class AddResourceRole extends React.Component {
t`Choose the type of resource that will be receiving new roles. For example, if you'd like to add new roles to a set of users please choose Users and click Next. You'll be able to select the specific resources in the next step.` t`Choose the type of resource that will be receiving new roles. For example, if you'd like to add new roles to a set of users please choose Users and click Next. You'll be able to select the specific resources in the next step.`
)} )}
</div> </div>
<SelectableCard <SelectableCard
isSelected={selectedResource === 'users'} isSelected={selectedResource === 'users'}
label={i18n._(t`Users`)} label={i18n._(t`Users`)}
dataCy="add-role-users" dataCy="add-role-users"
ariaLabel={i18n._(t`Users`)}
onClick={() => this.handleResourceSelect('users')} onClick={() => this.handleResourceSelect('users')}
/> />
<SelectableCard {resource?.type === 'credential' &&
isSelected={selectedResource === 'teams'} !resource?.organization ? null : (
label={i18n._(t`Teams`)} <SelectableCard
dataCy="add-role-teams" isSelected={selectedResource === 'teams'}
onClick={() => this.handleResourceSelect('teams')} label={i18n._(t`Teams`)}
/> dataCy="add-role-teams"
ariaLabel={i18n._(t`Teams`)}
onClick={() => this.handleResourceSelect('teams')}
/>
)}
</div> </div>
), ),
enableNext: selectedResource !== null, enableNext: selectedResource !== null,
@@ -329,10 +335,12 @@ AddResourceRole.propTypes = {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
onSave: PropTypes.func.isRequired, onSave: PropTypes.func.isRequired,
roles: PropTypes.shape(), roles: PropTypes.shape(),
resource: PropTypes.shape(),
}; };
AddResourceRole.defaultProps = { AddResourceRole.defaultProps = {
roles: {}, roles: {},
resource: {},
}; };
export { AddResourceRole as _AddResourceRole }; export { AddResourceRole as _AddResourceRole };

View File

@@ -221,4 +221,22 @@ describe('<_AddResourceRole />', () => {
expect(TeamsAPI.associateRole).toHaveBeenCalledTimes(2); expect(TeamsAPI.associateRole).toHaveBeenCalledTimes(2);
expect(handleSave).toHaveBeenCalled(); expect(handleSave).toHaveBeenCalled();
}); });
test('should not display team as a choice in case credential does not have organization', () => {
const spy = jest.spyOn(_AddResourceRole.prototype, 'handleResourceSelect');
const wrapper = mountWithContexts(
<AddResourceRole
onClose={() => {}}
onSave={() => {}}
roles={roles}
resource={{ type: 'credential', organization: null }}
/>,
{ context: { network: { handleHttpError: () => {} } } }
).find('AddResourceRole');
const selectableCardWrapper = wrapper.find('SelectableCard');
expect(selectableCardWrapper.length).toBe(1);
selectableCardWrapper.first().simulate('click');
expect(spy).toHaveBeenCalledWith('users');
expect(wrapper.state('selectedResource')).toBe('users');
});
}); });

View File

@@ -155,6 +155,7 @@ function ResourceAccessList({ i18n, apiModel, resource }) {
fetchAccessRecords(); fetchAccessRecords();
}} }}
roles={resource.summary_fields.object_roles} roles={resource.summary_fields.object_roles}
resource={resource}
/> />
)} )}
{showDeleteModal && ( {showDeleteModal && (

View File

@@ -31,7 +31,14 @@ const Description = styled.p`
font-size: 14px; font-size: 14px;
`; `;
function SelectableCard({ label, description, onClick, isSelected, dataCy }) { function SelectableCard({
label,
description,
onClick,
isSelected,
dataCy,
ariaLabel,
}) {
return ( return (
<SelectableItem <SelectableItem
onClick={onClick} onClick={onClick}
@@ -40,6 +47,7 @@ function SelectableCard({ label, description, onClick, isSelected, dataCy }) {
tabIndex="0" tabIndex="0"
data-cy={dataCy} data-cy={dataCy}
isSelected={isSelected} isSelected={isSelected}
aria-label={ariaLabel}
> >
<Indicator isSelected={isSelected} /> <Indicator isSelected={isSelected} />
<Contents> <Contents>
@@ -55,12 +63,14 @@ SelectableCard.propTypes = {
description: PropTypes.string, description: PropTypes.string,
onClick: PropTypes.func.isRequired, onClick: PropTypes.func.isRequired,
isSelected: PropTypes.bool, isSelected: PropTypes.bool,
ariaLabel: PropTypes.string,
}; };
SelectableCard.defaultProps = { SelectableCard.defaultProps = {
label: '', label: '',
description: '', description: '',
isSelected: false, isSelected: false,
ariaLabel: '',
}; };
export default SelectableCard; export default SelectableCard;

View File

@@ -56,15 +56,12 @@ function Credential({ i18n, setBreadcrumb }) {
id: 99, id: 99,
}, },
{ name: i18n._(t`Details`), link: `/credentials/${id}/details`, id: 0 }, { name: i18n._(t`Details`), link: `/credentials/${id}/details`, id: 0 },
]; {
if (credential && credential.organization) {
tabsArray.push({
name: i18n._(t`Access`), name: i18n._(t`Access`),
link: `/credentials/${id}/access`, link: `/credentials/${id}/access`,
id: 1, id: 1,
}); },
} ];
let showCardHeader = true; let showCardHeader = true;
@@ -108,14 +105,12 @@ function Credential({ i18n, setBreadcrumb }) {
<Route key="edit" path="/credentials/:id/edit"> <Route key="edit" path="/credentials/:id/edit">
<CredentialEdit credential={credential} /> <CredentialEdit credential={credential} />
</Route>, </Route>,
credential.organization && ( <Route key="access" path="/credentials/:id/access">
<Route key="access" path="/credentials/:id/access"> <ResourceAccessList
<ResourceAccessList resource={credential}
resource={credential} apiModel={CredentialsAPI}
apiModel={CredentialsAPI} />
/> </Route>,
</Route>
),
<Route key="not-found" path="*"> <Route key="not-found" path="*">
{!hasContentLoading && ( {!hasContentLoading && (
<ContentError isNotFound> <ContentError isNotFound>

View File

@@ -31,7 +31,7 @@ describe('<Credential />', () => {
wrapper = mountWithContexts(<Credential setBreadcrumb={() => {}} />); wrapper = mountWithContexts(<Credential setBreadcrumb={() => {}} />);
}); });
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 2); await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 3);
}); });
test('initially renders org-based credential succesfully', async () => { test('initially renders org-based credential succesfully', async () => {

View File

@@ -78,7 +78,7 @@ function CredentialDetail({ i18n, credential }) {
{} {}
), ),
}; };
}, [credentialId, credential_type]), }, [credentialId, credential_type.id]),
{ {
fields: [], fields: [],
managedByTower: true, managedByTower: true,