aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src
diff options
context:
space:
mode:
authorStas Vilchik <vilchiks@gmail.com>2017-02-01 19:05:48 +0100
committerStas Vilchik <stas-vilchik@users.noreply.github.com>2017-02-07 11:07:02 +0100
commitab71ca77ca97a03b503f65449132c007ae32f269 (patch)
tree4dab2ed1a99a152c6b55975a617abf4f9d3e3b73 /server/sonar-web/src
parentea7785d32257e0500a020e1650d02e8b69069a86 (diff)
downloadsonarqube-ab71ca77ca97a03b503f65449132c007ae32f269.tar.gz
sonarqube-ab71ca77ca97a03b503f65449132c007ae32f269.zip
SONAR-8659 Create organization's projects management page
Diffstat (limited to 'server/sonar-web/src')
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js12
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjectsManagement.js43
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js12
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap9
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/routes.js2
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/views/ApplyTemplateView.js13
-rw-r--r--server/sonar-web/src/main/js/apps/projects-admin/AppContainer.js7
-rw-r--r--server/sonar-web/src/main/js/apps/projects-admin/create-view.js7
-rw-r--r--server/sonar-web/src/main/js/apps/projects-admin/header.js6
-rw-r--r--server/sonar-web/src/main/js/apps/projects-admin/main.js18
-rw-r--r--server/sonar-web/src/main/js/apps/projects-admin/projects.js8
-rw-r--r--server/sonar-web/src/main/js/apps/projects-admin/views/BulkApplyTemplateView.js14
12 files changed, 126 insertions, 25 deletions
diff --git a/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js b/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js
index 64d431e88e3..8181ccd9379 100644
--- a/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js
+++ b/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js
@@ -155,11 +155,13 @@ class SettingsNav extends React.Component {
{translate('sidebar.projects')} <i className="icon-dropdown"/>
</a>
<ul className="dropdown-menu">
- <li>
- <IndexLink to="/projects_admin" activeClassName="active">
- Management
- </IndexLink>
- </li>
+ {!this.props.customOrganizations && (
+ <li>
+ <IndexLink to="/projects_admin" activeClassName="active">
+ Management
+ </IndexLink>
+ </li>
+ )}
<li>
<IndexLink to="/background_tasks" activeClassName="active">
{translate('background_tasks.page')}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjectsManagement.js b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjectsManagement.js
new file mode 100644
index 00000000000..5cfdcbf949e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjectsManagement.js
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+// @flow
+import React from 'react';
+import { connect } from 'react-redux';
+import AppContainer from '../../projects-admin/AppContainer';
+import { getOrganizationByKey } from '../../../store/rootReducer';
+import type { Organization } from '../../../store/organizations/duck';
+
+class OrganizationProjectsManagement extends React.Component {
+ props: {
+ organization: Organization
+ };
+
+ render () {
+ return (
+ <AppContainer organization={this.props.organization}/>
+ );
+ }
+}
+
+const mapStateToProps = (state, ownProps) => ({
+ organization: getOrganizationByKey(state, ownProps.params.organizationKey)
+});
+
+export default connect(mapStateToProps)(OrganizationProjectsManagement);
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js
index 6b585676a77..b0a213f3cdb 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js
@@ -28,7 +28,8 @@ const ADMIN_PATHS = [
'groups',
'delete',
'permissions',
- 'permission_templates'
+ 'permission_templates',
+ 'projects_management'
];
export default class OrganizationNavigation extends React.Component {
@@ -73,6 +74,11 @@ export default class OrganizationNavigation extends React.Component {
</Link>
</li>
<li>
+ <Link to={`/organizations/${organization.key}/projects_management`} activeClassName="active">
+ {translate('projects_management')}
+ </Link>
+ </li>
+ <li>
<Link to={`/organizations/${organization.key}/edit`} activeClassName="active">
{translate('edit')}
</Link>
@@ -90,7 +96,9 @@ export default class OrganizationNavigation extends React.Component {
render () {
const { organization, location } = this.props;
- const isHomeActive = location.pathname.startsWith(`organizations/${organization.key}/projects`);
+ const isHomeActive =
+ location.pathname === `organizations/${organization.key}/projects` ||
+ location.pathname === `organizations/${organization.key}/projects/favorite`;
return (
<nav className="navbar navbar-context page-container" id="context-navigation">
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap
index e781526e320..62d369ad119 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap
@@ -80,6 +80,15 @@ exports[`test admin 1`] = `
activeClassName="active"
onlyActiveOnIndex={false}
style={Object {}}
+ to="/organizations/foo/projects_management">
+ projects_management
+ </Link>
+ </li>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
to="/organizations/foo/edit">
edit
</Link>
diff --git a/server/sonar-web/src/main/js/apps/organizations/routes.js b/server/sonar-web/src/main/js/apps/organizations/routes.js
index 3885eb9ddf7..8057ebe2320 100644
--- a/server/sonar-web/src/main/js/apps/organizations/routes.js
+++ b/server/sonar-web/src/main/js/apps/organizations/routes.js
@@ -27,6 +27,7 @@ import OrganizationEdit from './components/OrganizationEdit';
import OrganizationGroups from './components/OrganizationGroups';
import OrganizationPermissions from './components/OrganizationPermissions';
import OrganizationPermissionTemplates from './components/OrganizationPermissionTemplates';
+import OrganizationProjectsManagement from './components/OrganizationProjectsManagement';
import OrganizationDelete from './components/OrganizationDelete';
export default (
@@ -40,6 +41,7 @@ export default (
<Route path="groups" component={OrganizationGroups}/>
<Route path="permissions" component={OrganizationPermissions}/>
<Route path="permission_templates" component={OrganizationPermissionTemplates}/>
+ <Route path="projects_management" component={OrganizationProjectsManagement}/>
</Route>
</Route>
);
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/views/ApplyTemplateView.js b/server/sonar-web/src/main/js/apps/permissions/project/views/ApplyTemplateView.js
index a22e93f8740..487fb2c3822 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/views/ApplyTemplateView.js
+++ b/server/sonar-web/src/main/js/apps/permissions/project/views/ApplyTemplateView.js
@@ -33,7 +33,10 @@ export default ModalForm.extend({
},
loadPermissionTemplates () {
- return getPermissionTemplates(this.options.project.organization).then(r => {
+ const request = this.options.organization ?
+ getPermissionTemplates(this.options.organization.key) :
+ getPermissionTemplates();
+ return request.then(r => {
this.permissionTemplates = r.permissionTemplates;
this.render();
});
@@ -52,10 +55,14 @@ export default ModalForm.extend({
const permissionTemplate = this.$('#project-permissions-template').val();
this.disableForm();
- applyTemplateToProject({
+ const data = {
projectKey: this.options.project.key,
templateId: permissionTemplate
- }).then(() => {
+ };
+ if (this.options.organization) {
+ data.organization = this.options.organization.key;
+ }
+ applyTemplateToProject(data).then(() => {
this.trigger('done');
this.done = true;
this.render();
diff --git a/server/sonar-web/src/main/js/apps/projects-admin/AppContainer.js b/server/sonar-web/src/main/js/apps/projects-admin/AppContainer.js
index ebf5317536f..6f3e5c141a1 100644
--- a/server/sonar-web/src/main/js/apps/projects-admin/AppContainer.js
+++ b/server/sonar-web/src/main/js/apps/projects-admin/AppContainer.js
@@ -25,12 +25,15 @@ import { getRootQualifiers } from '../../store/appState/duck';
class AppContainer extends React.Component {
render () {
- const hasProvisionPermission = this.props.user.permissions.global.indexOf('provisioning') !== -1;
+ const hasProvisionPermission = this.props.organization ?
+ this.props.organization.canProvisionProjects :
+ this.props.user.permissions.global.indexOf('provisioning') !== -1;
return (
<Main
hasProvisionPermission={hasProvisionPermission}
- topLevelQualifiers={this.props.rootQualifiers}/>
+ topLevelQualifiers={this.props.rootQualifiers}
+ organization={this.props.organization}/>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/projects-admin/create-view.js b/server/sonar-web/src/main/js/apps/projects-admin/create-view.js
index 3f1662349bc..553182105e9 100644
--- a/server/sonar-web/src/main/js/apps/projects-admin/create-view.js
+++ b/server/sonar-web/src/main/js/apps/projects-admin/create-view.js
@@ -45,6 +45,9 @@ export default ModalForm.extend({
branch: this.$('#create-project-branch').val(),
key: this.$('#create-project-key').val()
};
+ if (this.options.organization) {
+ data.organization = this.options.organization.key;
+ }
this.disableForm();
return createProject(data)
.then(project => {
@@ -57,9 +60,7 @@ export default ModalForm.extend({
})
.catch(error => {
this.enableForm();
- if (error.response.status === 400) {
- error.response.json().then(obj => this.showErrors([{ msg: obj.err_msg }]));
- }
+ error.response.json().then(r => this.showErrors(r.errors, r.warnings));
});
},
diff --git a/server/sonar-web/src/main/js/apps/projects-admin/header.js b/server/sonar-web/src/main/js/apps/projects-admin/header.js
index 1d4200e3aa5..68e964de07a 100644
--- a/server/sonar-web/src/main/js/apps/projects-admin/header.js
+++ b/server/sonar-web/src/main/js/apps/projects-admin/header.js
@@ -28,7 +28,8 @@ export default class Header extends React.Component {
createProject () {
new CreateView({
- refresh: this.props.refresh
+ refresh: this.props.refresh,
+ organization: this.props.organization
}).render();
}
@@ -37,7 +38,8 @@ export default class Header extends React.Component {
total: this.props.total,
selection: this.props.selection,
query: this.props.query,
- qualifier: this.props.qualifier
+ qualifier: this.props.qualifier,
+ organization: this.props.organization
}).render();
}
diff --git a/server/sonar-web/src/main/js/apps/projects-admin/main.js b/server/sonar-web/src/main/js/apps/projects-admin/main.js
index 749e4b7bcb1..3bef593f74d 100644
--- a/server/sonar-web/src/main/js/apps/projects-admin/main.js
+++ b/server/sonar-web/src/main/js/apps/projects-admin/main.js
@@ -30,7 +30,8 @@ import ListFooter from '../../components/controls/ListFooter';
export default React.createClass({
propTypes: {
- hasProvisionPermission: React.PropTypes.bool.isRequired
+ hasProvisionPermission: React.PropTypes.bool.isRequired,
+ organization: React.PropTypes.object
},
getInitialState () {
@@ -62,6 +63,9 @@ export default React.createClass({
if (this.state.query) {
filters.q = this.state.query;
}
+ if (this.props.organization) {
+ filters.organization = this.props.organization.key;
+ }
return filters;
},
@@ -182,7 +186,11 @@ export default React.createClass({
deleteProjects () {
this.setState({ ready: false });
const ids = this.state.selection.join(',');
- deleteComponents({ ids }).then(() => {
+ const data = { ids };
+ if (this.props.organization) {
+ Object.assign(data, { organization: this.props.organization.key });
+ }
+ deleteComponents(data).then(() => {
this.setState({ page: 1, selection: [] }, this.requestProjects);
});
},
@@ -196,7 +204,8 @@ export default React.createClass({
total={this.state.total}
query={this.state.query}
qualifier={this.state.qualifiers}
- refresh={this.requestProjects}/>
+ refresh={this.requestProjects}
+ organization={this.props.organization}/>
<Search {...this.props} {...this.state}
onSearch={this.onSearch}
@@ -212,7 +221,8 @@ export default React.createClass({
refresh={this.requestProjects}
selection={this.state.selection}
onProjectSelected={this.onProjectSelected}
- onProjectDeselected={this.onProjectDeselected}/>
+ onProjectDeselected={this.onProjectDeselected}
+ organization={this.props.organization}/>
<ListFooter
ready={this.state.ready}
diff --git a/server/sonar-web/src/main/js/apps/projects-admin/projects.js b/server/sonar-web/src/main/js/apps/projects-admin/projects.js
index d6b002248a4..e2bd4690713 100644
--- a/server/sonar-web/src/main/js/apps/projects-admin/projects.js
+++ b/server/sonar-web/src/main/js/apps/projects-admin/projects.js
@@ -29,7 +29,8 @@ import { translate } from '../../helpers/l10n';
export default class Projects extends React.Component {
static propTypes = {
projects: React.PropTypes.array.isRequired,
- selection: React.PropTypes.array.isRequired
+ selection: React.PropTypes.array.isRequired,
+ organization: React.PropTypes.object
};
componentWillMount () {
@@ -47,7 +48,10 @@ export default class Projects extends React.Component {
onApplyTemplateClick (project, e) {
e.preventDefault();
e.target.blur();
- new ApplyTemplateView({ project }).render();
+ new ApplyTemplateView({
+ project,
+ organization: this.props.organization
+ }).render();
}
isProjectSelected (project) {
diff --git a/server/sonar-web/src/main/js/apps/projects-admin/views/BulkApplyTemplateView.js b/server/sonar-web/src/main/js/apps/projects-admin/views/BulkApplyTemplateView.js
index c2f216edf35..3dc188ff1e1 100644
--- a/server/sonar-web/src/main/js/apps/projects-admin/views/BulkApplyTemplateView.js
+++ b/server/sonar-web/src/main/js/apps/projects-admin/views/BulkApplyTemplateView.js
@@ -34,7 +34,10 @@ export default ModalForm.extend({
},
loadPermissionTemplates () {
- return getPermissionTemplates().then(r => {
+ const request = this.options.organization ?
+ getPermissionTemplates(this.options.organization.key) :
+ getPermissionTemplates();
+ return request.then(r => {
this.permissionTemplates = r.permissionTemplates;
this.render();
});
@@ -59,6 +62,10 @@ export default ModalForm.extend({
data.qualifier = this.options.qualifier;
}
+ if (this.options.organization) {
+ data.organization = this.options.organization.key;
+ }
+
return bulkApplyTemplate(data);
},
@@ -68,6 +75,9 @@ export default ModalForm.extend({
selection.forEach(projectId => {
const data = { templateId: permissionTemplate, projectId };
+ if (this.options.organization) {
+ data.organization = this.options.organization.key;
+ }
lastRequest = lastRequest.then(() => applyTemplateToProject(data));
});
@@ -88,7 +98,7 @@ export default ModalForm.extend({
this.trigger('done');
this.done = true;
this.render();
- }).catch(function (e) {
+ }).catch(e => {
e.response.json().then(r => {
this.showErrors(r.errors, r.warnings);
this.enableForm();