@@ -31,6 +31,7 @@ import { Organization } from '../../app/types'; | |||
import { translate } from '../../helpers/l10n'; | |||
export interface Props { | |||
currentUser: { login: string }; | |||
hasProvisionPermission?: boolean; | |||
onVisibilityChange: (visibility: string) => void; | |||
organization: Organization; | |||
@@ -191,6 +192,7 @@ export default class App extends React.PureComponent<Props, State> { | |||
/> | |||
<Projects | |||
currentUser={this.props.currentUser} | |||
ready={this.state.ready} | |||
projects={this.state.projects} | |||
selection={this.state.selection} |
@@ -22,7 +22,7 @@ import { connect } from 'react-redux'; | |||
import App from './App'; | |||
import { Organization } from '../../app/types'; | |||
import { onFail } from '../../store/rootActions'; | |||
import { getAppState, getOrganizationByKey } from '../../store/rootReducer'; | |||
import { getAppState, getOrganizationByKey, getCurrentUser } from '../../store/rootReducer'; | |||
import { receiveOrganizations } from '../../store/organizations/duck'; | |||
import { changeProjectVisibility } from '../../api/organizations'; | |||
import { fetchOrganization } from '../../apps/organizations/actions'; | |||
@@ -32,6 +32,7 @@ interface Props { | |||
defaultOrganization: string; | |||
qualifiers: string[]; | |||
}; | |||
currentUser: { login: string }; | |||
fetchOrganization: (organization: string) => void; | |||
onVisibilityChange: (organization: Organization, visibility: string) => void; | |||
onRequestFail: (error: any) => void; | |||
@@ -64,6 +65,7 @@ class AppContainer extends React.PureComponent<Props> { | |||
return ( | |||
<App | |||
currentUser={this.props.currentUser} | |||
hasProvisionPermission={organization.canProvisionProjects} | |||
onVisibilityChange={this.handleVisibilityChange} | |||
organization={organization} | |||
@@ -75,6 +77,7 @@ class AppContainer extends React.PureComponent<Props> { | |||
const mapStateToProps = (state: any, ownProps: Props) => ({ | |||
appState: getAppState(state), | |||
currentUser: getCurrentUser(state), | |||
organization: | |||
ownProps.organization || getOrganizationByKey(state, getAppState(state).defaultOrganization) | |||
}); |
@@ -19,17 +19,17 @@ | |||
*/ | |||
import * as React from 'react'; | |||
import { Link } from 'react-router'; | |||
import ProjectRowActions from './ProjectRowActions'; | |||
import { Project } from './utils'; | |||
import { Visibility } from '../../app/types'; | |||
import PrivateBadge from '../../components/common/PrivateBadge'; | |||
import Checkbox from '../../components/controls/Checkbox'; | |||
import QualifierIcon from '../../components/shared/QualifierIcon'; | |||
import { translate } from '../../helpers/l10n'; | |||
import { getComponentPermissionsUrl } from '../../helpers/urls'; | |||
import DateTooltipFormatter from '../../components/intl/DateTooltipFormatter'; | |||
interface Props { | |||
onApplyTemplateClick: (project: Project) => void; | |||
currentUser: { login: string }; | |||
onApplyTemplate: (project: Project) => void; | |||
onProjectCheck: (project: Project, checked: boolean) => void; | |||
project: Project; | |||
selected: boolean; | |||
@@ -40,12 +40,6 @@ export default class ProjectRow extends React.PureComponent<Props> { | |||
this.props.onProjectCheck(this.props.project, checked); | |||
}; | |||
handleApplyTemplateClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => { | |||
event.preventDefault(); | |||
event.currentTarget.blur(); | |||
this.props.onApplyTemplateClick(this.props.project); | |||
}; | |||
render() { | |||
const { project, selected } = this.props; | |||
@@ -82,23 +76,11 @@ export default class ProjectRow extends React.PureComponent<Props> { | |||
</td> | |||
<td className="thin nowrap"> | |||
<div className="dropdown"> | |||
<button className="dropdown-toggle" data-toggle="dropdown"> | |||
{translate('actions')} <i className="icon-dropdown" /> | |||
</button> | |||
<ul className="dropdown-menu dropdown-menu-right"> | |||
<li> | |||
<Link to={getComponentPermissionsUrl(project.key)}> | |||
{translate('edit_permissions')} | |||
</Link> | |||
</li> | |||
<li> | |||
<a className="js-apply-template" href="#" onClick={this.handleApplyTemplateClick}> | |||
{translate('projects_role.apply_template')} | |||
</a> | |||
</li> | |||
</ul> | |||
</div> | |||
<ProjectRowActions | |||
currentUser={this.props.currentUser} | |||
onApplyTemplate={this.props.onApplyTemplate} | |||
project={project} | |||
/> | |||
</td> | |||
</tr> | |||
); |
@@ -0,0 +1,153 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { Link } from 'react-router'; | |||
import RestoreAccessModal from './RestoreAccessModal'; | |||
import { Project } from './utils'; | |||
import { getComponentShow } from '../../api/components'; | |||
import { getComponentNavigation } from '../../api/nav'; | |||
import { translate } from '../../helpers/l10n'; | |||
import { getComponentPermissionsUrl } from '../../helpers/urls'; | |||
export interface Props { | |||
currentUser: { login: string }; | |||
onApplyTemplate: (project: Project) => void; | |||
project: Project; | |||
} | |||
interface State { | |||
hasAccess?: boolean; | |||
loading: boolean; | |||
restoreAccessModal: boolean; | |||
} | |||
export default class ProjectRowActions extends React.PureComponent<Props, State> { | |||
mounted: boolean; | |||
state: State = { loading: false, restoreAccessModal: false }; | |||
componentDidMount() { | |||
this.mounted = true; | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
fetchPermissions = () => { | |||
this.setState({ loading: false }); | |||
// call `getComponentNavigation` to check if user has the "Administer" permission | |||
// call `getComponentShow` to check if user has the "Browse" permission | |||
Promise.all([ | |||
getComponentNavigation(this.props.project.key), | |||
getComponentShow(this.props.project.key) | |||
]).then( | |||
([navResponse]) => { | |||
if (this.mounted) { | |||
const hasAccess = Boolean( | |||
navResponse.configuration && navResponse.configuration.showPermissions | |||
); | |||
this.setState({ hasAccess, loading: false }); | |||
} | |||
}, | |||
() => { | |||
if (this.mounted) { | |||
this.setState({ hasAccess: false, loading: false }); | |||
} | |||
} | |||
); | |||
}; | |||
handleDropdownClick = () => { | |||
if (this.state.hasAccess === undefined && !this.state.loading) { | |||
this.fetchPermissions(); | |||
} | |||
}; | |||
handleApplyTemplateClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => { | |||
event.preventDefault(); | |||
event.currentTarget.blur(); | |||
this.props.onApplyTemplate(this.props.project); | |||
}; | |||
handleRestoreAccessClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => { | |||
event.preventDefault(); | |||
event.currentTarget.blur(); | |||
this.setState({ restoreAccessModal: true }); | |||
}; | |||
handleRestoreAccessClose = () => this.setState({ restoreAccessModal: false }); | |||
handleRestoreAccessDone = () => { | |||
this.setState({ hasAccess: true, restoreAccessModal: false }); | |||
}; | |||
render() { | |||
const { hasAccess, loading } = this.state; | |||
return ( | |||
<div className="dropdown"> | |||
<button | |||
className="dropdown-toggle" | |||
data-toggle="dropdown" | |||
onClick={this.handleDropdownClick}> | |||
{translate('actions')} <i className="icon-dropdown" /> | |||
</button> | |||
{loading ? ( | |||
<div className="dropdown-menu dropdown-menu-right"> | |||
<i className="spinner spacer-left" /> | |||
</div> | |||
) : ( | |||
<ul className="dropdown-menu dropdown-menu-right"> | |||
{hasAccess === true && ( | |||
<li> | |||
<Link to={getComponentPermissionsUrl(this.props.project.key)}> | |||
{translate('edit_permissions')} | |||
</Link> | |||
</li> | |||
)} | |||
{hasAccess === false && ( | |||
<li> | |||
<a className="js-restore-access" href="#" onClick={this.handleRestoreAccessClick}> | |||
{translate('global_permissions.restore_access')} | |||
</a> | |||
</li> | |||
)} | |||
<li> | |||
<a className="js-apply-template" href="#" onClick={this.handleApplyTemplateClick}> | |||
{translate('projects_role.apply_template')} | |||
</a> | |||
</li> | |||
</ul> | |||
)} | |||
{this.state.restoreAccessModal && ( | |||
<RestoreAccessModal | |||
currentUser={this.props.currentUser} | |||
onClose={this.handleRestoreAccessClose} | |||
onRestoreAccess={this.handleRestoreAccessDone} | |||
project={this.props.project} | |||
/> | |||
)} | |||
</div> | |||
); | |||
} | |||
} |
@@ -23,8 +23,10 @@ import ProjectRow from './ProjectRow'; | |||
import { Project } from './utils'; | |||
import ApplyTemplateView from '../permissions/project/views/ApplyTemplateView'; | |||
import { Organization } from '../../app/types'; | |||
import { translate } from '../../helpers/l10n'; | |||
interface Props { | |||
currentUser: { login: string }; | |||
onProjectDeselected: (project: string) => void; | |||
onProjectSelected: (project: string) => void; | |||
organization: Organization; | |||
@@ -42,7 +44,7 @@ export default class Projects extends React.PureComponent<Props> { | |||
} | |||
}; | |||
onApplyTemplateClick = (project: Project) => { | |||
handleApplyTemplate = (project: Project) => { | |||
new ApplyTemplateView({ project, organization: this.props.organization }).render(); | |||
}; | |||
@@ -54,18 +56,19 @@ export default class Projects extends React.PureComponent<Props> { | |||
<thead> | |||
<tr> | |||
<th /> | |||
<th>Name</th> | |||
<th>{translate('name')}</th> | |||
<th /> | |||
<th>Key</th> | |||
<th className="thin nowrap text-right">Last Analysis</th> | |||
<th>{translate('key')}</th> | |||
<th className="thin nowrap text-right">{translate('last_analysis')}</th> | |||
<th /> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{this.props.projects.map(project => ( | |||
<ProjectRow | |||
currentUser={this.props.currentUser} | |||
key={project.key} | |||
onApplyTemplateClick={this.onApplyTemplateClick} | |||
onApplyTemplate={this.handleApplyTemplate} | |||
onProjectCheck={this.onProjectCheck} | |||
project={project} | |||
selected={this.props.selection.includes(project.key)} |
@@ -0,0 +1,113 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import Modal from 'react-modal'; | |||
import { Project } from './utils'; | |||
import { grantPermissionToUser } from '../../api/permissions'; | |||
import { translate } from '../../helpers/l10n'; | |||
import { FormattedMessage } from 'react-intl'; | |||
interface Props { | |||
currentUser: { login: string }; | |||
onClose: () => void; | |||
onRestoreAccess: () => void; | |||
project: Project; | |||
} | |||
interface State { | |||
loading: boolean; | |||
} | |||
export default class BulkApplyTemplateModal extends React.PureComponent<Props, State> { | |||
mounted: boolean; | |||
state: State = { loading: false }; | |||
componentDidMount() { | |||
this.mounted = true; | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => { | |||
event.preventDefault(); | |||
this.props.onClose(); | |||
}; | |||
handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => { | |||
event.preventDefault(); | |||
this.setState({ loading: true }); | |||
Promise.all([this.grantPermission('user'), this.grantPermission('admin')]).then( | |||
this.props.onRestoreAccess, | |||
() => { | |||
if (this.mounted) { | |||
this.setState({ loading: false }); | |||
} | |||
} | |||
); | |||
}; | |||
grantPermission = (permission: string) => | |||
grantPermissionToUser( | |||
this.props.project.key, | |||
this.props.currentUser.login, | |||
permission, | |||
this.props.project.organization | |||
); | |||
render() { | |||
const header = translate('global_permissions.restore_access'); | |||
return ( | |||
<Modal | |||
isOpen={true} | |||
contentLabel={header} | |||
className="modal" | |||
overlayClassName="modal-overlay" | |||
onRequestClose={this.props.onClose}> | |||
<header className="modal-head"> | |||
<h2>{header}</h2> | |||
</header> | |||
<form onSubmit={this.handleFormSubmit}> | |||
<div className="modal-body"> | |||
<FormattedMessage | |||
defaultMessage={translate('global_permissions.restore_access.message')} | |||
id="global_permissions.restore_access.message" | |||
values={{ | |||
browse: <strong>{translate('projects_role.user')}</strong>, | |||
administer: <strong>{translate('projects_role.admin')}</strong> | |||
}} | |||
/> | |||
</div> | |||
<footer className="modal-foot"> | |||
{this.state.loading && <i className="spinner spacer-right" />} | |||
<button disabled={this.state.loading}>{translate('restore')}</button> | |||
<a className="js-modal-close" href="#" onClick={this.handleCancelClick}> | |||
{translate('cancel')} | |||
</a> | |||
</footer> | |||
</form> | |||
</Modal> | |||
); | |||
} | |||
} |
@@ -138,6 +138,7 @@ it('changes default project visibility', () => { | |||
function mountRender(props?: { [P in keyof Props]?: Props[P] }) { | |||
return mount( | |||
<App | |||
currentUser={{ login: 'foo' }} | |||
hasProvisionPermission={true} | |||
onVisibilityChange={jest.fn()} | |||
organization={organization} |
@@ -21,7 +21,6 @@ import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import ProjectRow from '../ProjectRow'; | |||
import { Visibility } from '../../../app/types'; | |||
import { click } from '../../../helpers/testUtils'; | |||
const project = { | |||
key: 'project', | |||
@@ -44,17 +43,11 @@ it('checks project', () => { | |||
expect(onProjectCheck).toBeCalledWith(project, false); | |||
}); | |||
it('applies permission template', () => { | |||
const onApplyTemplateClick = jest.fn(); | |||
const wrapper = shallowRender({ onApplyTemplateClick }); | |||
click(wrapper.find('.js-apply-template')); | |||
expect(onApplyTemplateClick).toBeCalledWith(project); | |||
}); | |||
function shallowRender(props?: any) { | |||
return shallow( | |||
<ProjectRow | |||
onApplyTemplateClick={jest.fn()} | |||
currentUser={{ login: 'foo' }} | |||
onApplyTemplate={jest.fn()} | |||
onProjectCheck={jest.fn()} | |||
project={project} | |||
selected={true} |
@@ -0,0 +1,75 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import ProjectRowActions, { Props } from '../ProjectRowActions'; | |||
import { Visibility } from '../../../app/types'; | |||
import { click } from '../../../helpers/testUtils'; | |||
jest.mock('../../../api/components', () => ({ | |||
getComponentShow: jest.fn(() => Promise.reject(undefined)) | |||
})); | |||
jest.mock('../../../api/nav', () => ({ | |||
getComponentNavigation: jest.fn(() => Promise.resolve()) | |||
})); | |||
const project = { | |||
id: '', | |||
key: 'project', | |||
name: 'Project', | |||
organization: 'org', | |||
qualifier: 'TRK', | |||
visibility: Visibility.Private | |||
}; | |||
it('restores access', async () => { | |||
const wrapper = shallowRender(); | |||
expect(wrapper).toMatchSnapshot(); | |||
click(wrapper.find('.dropdown-toggle')); | |||
await new Promise(setImmediate); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
click(wrapper.find('.js-restore-access')); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
it('applies permission template', () => { | |||
const onApplyTemplate = jest.fn(); | |||
const wrapper = shallowRender({ onApplyTemplate }); | |||
click(wrapper.find('.js-apply-template')); | |||
expect(onApplyTemplate).toBeCalledWith(project); | |||
}); | |||
function shallowRender(props: Partial<Props> = {}) { | |||
const wrapper = shallow( | |||
<ProjectRowActions | |||
currentUser={{ login: 'admin' }} | |||
onApplyTemplate={jest.fn()} | |||
project={project} | |||
{...props} | |||
/> | |||
); | |||
(wrapper.instance() as ProjectRowActions).mounted = true; | |||
return wrapper; | |||
} |
@@ -59,13 +59,14 @@ it('opens modal to apply permission template', () => { | |||
wrapper | |||
.find('ProjectRow') | |||
.first() | |||
.prop<Function>('onApplyTemplateClick')(projects[0]); | |||
.prop<Function>('onApplyTemplate')(projects[0]); | |||
expect(ApplyTemplateView).toBeCalledWith({ organization, project: projects[0] }); | |||
}); | |||
function shallowRender(props?: any) { | |||
return shallow( | |||
<Projects | |||
currentUser={{ login: 'foo' }} | |||
onProjectDeselected={jest.fn()} | |||
onProjectSelected={jest.fn()} | |||
organization={organization} |
@@ -64,49 +64,22 @@ exports[`renders 1`] = ` | |||
<td | |||
className="thin nowrap" | |||
> | |||
<div | |||
className="dropdown" | |||
> | |||
<button | |||
className="dropdown-toggle" | |||
data-toggle="dropdown" | |||
> | |||
actions | |||
<i | |||
className="icon-dropdown" | |||
/> | |||
</button> | |||
<ul | |||
className="dropdown-menu dropdown-menu-right" | |||
> | |||
<li> | |||
<Link | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to={ | |||
Object { | |||
"pathname": "/project_roles", | |||
"query": Object { | |||
"id": "project", | |||
}, | |||
} | |||
} | |||
> | |||
edit_permissions | |||
</Link> | |||
</li> | |||
<li> | |||
<a | |||
className="js-apply-template" | |||
href="#" | |||
onClick={[Function]} | |||
> | |||
projects_role.apply_template | |||
</a> | |||
</li> | |||
</ul> | |||
</div> | |||
<ProjectRowActions | |||
currentUser={ | |||
Object { | |||
"login": "foo", | |||
} | |||
} | |||
onApplyTemplate={[Function]} | |||
project={ | |||
Object { | |||
"key": "project", | |||
"name": "Project", | |||
"qualifier": "TRK", | |||
"visibility": "private", | |||
} | |||
} | |||
/> | |||
</td> | |||
</tr> | |||
`; | |||
@@ -173,49 +146,23 @@ exports[`renders 2`] = ` | |||
<td | |||
className="thin nowrap" | |||
> | |||
<div | |||
className="dropdown" | |||
> | |||
<button | |||
className="dropdown-toggle" | |||
data-toggle="dropdown" | |||
> | |||
actions | |||
<i | |||
className="icon-dropdown" | |||
/> | |||
</button> | |||
<ul | |||
className="dropdown-menu dropdown-menu-right" | |||
> | |||
<li> | |||
<Link | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to={ | |||
Object { | |||
"pathname": "/project_roles", | |||
"query": Object { | |||
"id": "project", | |||
}, | |||
} | |||
} | |||
> | |||
edit_permissions | |||
</Link> | |||
</li> | |||
<li> | |||
<a | |||
className="js-apply-template" | |||
href="#" | |||
onClick={[Function]} | |||
> | |||
projects_role.apply_template | |||
</a> | |||
</li> | |||
</ul> | |||
</div> | |||
<ProjectRowActions | |||
currentUser={ | |||
Object { | |||
"login": "foo", | |||
} | |||
} | |||
onApplyTemplate={[Function]} | |||
project={ | |||
Object { | |||
"key": "project", | |||
"lastAnalysisDate": "2017-04-08T00:00:00.000Z", | |||
"name": "Project", | |||
"qualifier": "TRK", | |||
"visibility": "private", | |||
} | |||
} | |||
/> | |||
</td> | |||
</tr> | |||
`; |
@@ -0,0 +1,131 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`restores access 1`] = ` | |||
<div | |||
className="dropdown" | |||
> | |||
<button | |||
className="dropdown-toggle" | |||
data-toggle="dropdown" | |||
onClick={[Function]} | |||
> | |||
actions | |||
<i | |||
className="icon-dropdown" | |||
/> | |||
</button> | |||
<ul | |||
className="dropdown-menu dropdown-menu-right" | |||
> | |||
<li> | |||
<a | |||
className="js-apply-template" | |||
href="#" | |||
onClick={[Function]} | |||
> | |||
projects_role.apply_template | |||
</a> | |||
</li> | |||
</ul> | |||
</div> | |||
`; | |||
exports[`restores access 2`] = ` | |||
<div | |||
className="dropdown" | |||
> | |||
<button | |||
className="dropdown-toggle" | |||
data-toggle="dropdown" | |||
onClick={[Function]} | |||
> | |||
actions | |||
<i | |||
className="icon-dropdown" | |||
/> | |||
</button> | |||
<ul | |||
className="dropdown-menu dropdown-menu-right" | |||
> | |||
<li> | |||
<a | |||
className="js-restore-access" | |||
href="#" | |||
onClick={[Function]} | |||
> | |||
global_permissions.restore_access | |||
</a> | |||
</li> | |||
<li> | |||
<a | |||
className="js-apply-template" | |||
href="#" | |||
onClick={[Function]} | |||
> | |||
projects_role.apply_template | |||
</a> | |||
</li> | |||
</ul> | |||
</div> | |||
`; | |||
exports[`restores access 3`] = ` | |||
<div | |||
className="dropdown" | |||
> | |||
<button | |||
className="dropdown-toggle" | |||
data-toggle="dropdown" | |||
onClick={[Function]} | |||
> | |||
actions | |||
<i | |||
className="icon-dropdown" | |||
/> | |||
</button> | |||
<ul | |||
className="dropdown-menu dropdown-menu-right" | |||
> | |||
<li> | |||
<a | |||
className="js-restore-access" | |||
href="#" | |||
onClick={[Function]} | |||
> | |||
global_permissions.restore_access | |||
</a> | |||
</li> | |||
<li> | |||
<a | |||
className="js-apply-template" | |||
href="#" | |||
onClick={[Function]} | |||
> | |||
projects_role.apply_template | |||
</a> | |||
</li> | |||
</ul> | |||
<BulkApplyTemplateModal | |||
currentUser={ | |||
Object { | |||
"login": "admin", | |||
} | |||
} | |||
onClose={[Function]} | |||
onRestoreAccess={[Function]} | |||
project={ | |||
Object { | |||
"id": "", | |||
"key": "project", | |||
"name": "Project", | |||
"organization": "org", | |||
"qualifier": "TRK", | |||
"visibility": "private", | |||
} | |||
} | |||
/> | |||
</div> | |||
`; |
@@ -9,23 +9,28 @@ exports[`renders list of projects 1`] = ` | |||
<tr> | |||
<th /> | |||
<th> | |||
Name | |||
name | |||
</th> | |||
<th /> | |||
<th> | |||
Key | |||
key | |||
</th> | |||
<th | |||
className="thin nowrap text-right" | |||
> | |||
Last Analysis | |||
last_analysis | |||
</th> | |||
<th /> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<ProjectRow | |||
onApplyTemplateClick={[Function]} | |||
currentUser={ | |||
Object { | |||
"login": "foo", | |||
} | |||
} | |||
onApplyTemplate={[Function]} | |||
onProjectCheck={[Function]} | |||
project={ | |||
Object { | |||
@@ -38,7 +43,12 @@ exports[`renders list of projects 1`] = ` | |||
selected={true} | |||
/> | |||
<ProjectRow | |||
onApplyTemplateClick={[Function]} | |||
currentUser={ | |||
Object { | |||
"login": "foo", | |||
} | |||
} | |||
onApplyTemplate={[Function]} | |||
onProjectCheck={[Function]} | |||
project={ | |||
Object { |
@@ -76,6 +76,7 @@ issues=Issues | |||
inheritance=Inheritance | |||
key=Key | |||
language=Language | |||
last_analysis=Last Analysis | |||
learn_more=Learn More | |||
library=Library | |||
line_number=Line Number | |||
@@ -1891,6 +1892,8 @@ global_permissions.scan.desc=Ability to get all settings required to perform an | |||
global_permissions.provisioning=Create Projects | |||
global_permissions.provisioning.desc=Ability to initialize a project so its settings can be configured before the first analysis. | |||
global_permissions.filter_by_x_permission=Filter by "{0}" permission | |||
global_permissions.restore_access=Restore Access | |||
global_permissions.restore_access.message=You will receive {browse} and {administer} permissions on the project. Do you want to continue? | |||