From 3d8cdcbf8558e40385f481272045056d5435a3e6 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Mon, 17 Oct 2016 11:37:50 +0200 Subject: move /projects to /projects/admin --- .../config/webpack/webpack.config.base.js | 2 +- .../apps/projects-admin/__tests__/projects-test.js | 46 +++++ .../src/main/js/apps/projects-admin/app.js | 33 +++ .../src/main/js/apps/projects-admin/constants.js | 28 +++ .../src/main/js/apps/projects-admin/create-view.js | 72 +++++++ .../src/main/js/apps/projects-admin/delete-view.js | 32 +++ .../src/main/js/apps/projects-admin/form-view.js | 39 ++++ .../src/main/js/apps/projects-admin/header.js | 83 ++++++++ .../src/main/js/apps/projects-admin/main.js | 227 +++++++++++++++++++++ .../src/main/js/apps/projects-admin/projects.js | 117 +++++++++++ .../src/main/js/apps/projects-admin/search.js | 159 +++++++++++++++ .../templates/BulkApplyTemplateTemplate.hbs | 68 ++++++ .../templates/projects-create-form.hbs | 41 ++++ .../projects-admin/templates/projects-delete.hbs | 13 ++ .../projects-admin/views/BulkApplyTemplateView.js | 108 ++++++++++ .../js/apps/projects/__tests__/projects-test.js | 46 ----- server/sonar-web/src/main/js/apps/projects/app.js | 33 --- .../src/main/js/apps/projects/constants.js | 28 --- .../src/main/js/apps/projects/create-view.js | 72 ------- .../src/main/js/apps/projects/delete-view.js | 32 --- .../src/main/js/apps/projects/form-view.js | 39 ---- .../sonar-web/src/main/js/apps/projects/header.js | 83 -------- server/sonar-web/src/main/js/apps/projects/main.js | 227 --------------------- .../src/main/js/apps/projects/projects.js | 117 ----------- .../sonar-web/src/main/js/apps/projects/search.js | 159 --------------- .../templates/BulkApplyTemplateTemplate.hbs | 68 ------ .../projects/templates/projects-create-form.hbs | 41 ---- .../js/apps/projects/templates/projects-delete.hbs | 13 -- .../apps/projects/views/BulkApplyTemplateView.js | 108 ---------- .../src/main/js/main/nav/settings/settings-nav.js | 4 +- .../app/controllers/projects_admin_controller.rb | 30 +++ .../WEB-INF/app/controllers/projects_controller.rb | 30 --- .../WEB-INF/app/views/projects/index.html.erb | 3 - .../app/views/projects_admin/index.html.erb | 3 + 34 files changed, 1102 insertions(+), 1102 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/__tests__/projects-test.js create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/app.js create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/constants.js create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/create-view.js create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/delete-view.js create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/form-view.js create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/header.js create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/main.js create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/projects.js create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/search.js create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/templates/BulkApplyTemplateTemplate.hbs create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/templates/projects-create-form.hbs create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/templates/projects-delete.hbs create mode 100644 server/sonar-web/src/main/js/apps/projects-admin/views/BulkApplyTemplateView.js delete mode 100644 server/sonar-web/src/main/js/apps/projects/__tests__/projects-test.js delete mode 100644 server/sonar-web/src/main/js/apps/projects/app.js delete mode 100644 server/sonar-web/src/main/js/apps/projects/constants.js delete mode 100644 server/sonar-web/src/main/js/apps/projects/create-view.js delete mode 100644 server/sonar-web/src/main/js/apps/projects/delete-view.js delete mode 100644 server/sonar-web/src/main/js/apps/projects/form-view.js delete mode 100644 server/sonar-web/src/main/js/apps/projects/header.js delete mode 100644 server/sonar-web/src/main/js/apps/projects/main.js delete mode 100644 server/sonar-web/src/main/js/apps/projects/projects.js delete mode 100644 server/sonar-web/src/main/js/apps/projects/search.js delete mode 100644 server/sonar-web/src/main/js/apps/projects/templates/BulkApplyTemplateTemplate.hbs delete mode 100644 server/sonar-web/src/main/js/apps/projects/templates/projects-create-form.hbs delete mode 100644 server/sonar-web/src/main/js/apps/projects/templates/projects-delete.hbs delete mode 100644 server/sonar-web/src/main/js/apps/projects/views/BulkApplyTemplateView.js create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/app/controllers/projects_admin_controller.rb delete mode 100644 server/sonar-web/src/main/webapp/WEB-INF/app/controllers/projects_controller.rb delete mode 100644 server/sonar-web/src/main/webapp/WEB-INF/app/views/projects/index.html.erb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/app/views/projects_admin/index.html.erb (limited to 'server/sonar-web') diff --git a/server/sonar-web/config/webpack/webpack.config.base.js b/server/sonar-web/config/webpack/webpack.config.base.js index 245c6ba7ca4..de369bbcb09 100644 --- a/server/sonar-web/config/webpack/webpack.config.base.js +++ b/server/sonar-web/config/webpack/webpack.config.base.js @@ -43,7 +43,7 @@ module.exports = { 'permission-templates': './src/main/js/apps/permission-templates/app.js', 'project-admin': './src/main/js/apps/project-admin/app.js', 'project-permissions': './src/main/js/apps/permissions/project/app.js', - 'projects': './src/main/js/apps/projects/app.js', + 'projects-admin': './src/main/js/apps/projects-admin/app.js', 'quality-gates': './src/main/js/apps/quality-gates/app.js', 'quality-profiles': './src/main/js/apps/quality-profiles/app.js', 'settings': './src/main/js/apps/settings/app.js', diff --git a/server/sonar-web/src/main/js/apps/projects-admin/__tests__/projects-test.js b/server/sonar-web/src/main/js/apps/projects-admin/__tests__/projects-test.js new file mode 100644 index 00000000000..85abb704b2b --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/__tests__/projects-test.js @@ -0,0 +1,46 @@ +/* + * 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 React from 'react'; +import { shallow } from 'enzyme'; +import Projects from '../projects'; +import Checkbox from '../../../components/controls/Checkbox'; + +it('should render list of projects with no selection', () => { + const projects = [ + { id: '1', key: 'a', name: 'A', qualifier: 'TRK' }, + { id: '2', key: 'b', name: 'B', qualifier: 'TRK' } + ]; + + const result = shallow(); + expect(result.find('tr').length).toBe(2); + expect(result.find(Checkbox).filterWhere(n => n.prop('checked')).length).toBe(0); +}); + +it('should render list of projects with one selected', () => { + const projects = [ + { id: '1', key: 'a', name: 'A', qualifier: 'TRK' }, + { id: '2', key: 'b', name: 'B', qualifier: 'TRK' } + ]; + const selection = ['1']; + + const result = shallow(); + expect(result.find('tr').length).toBe(2); + expect(result.find(Checkbox).filterWhere(n => n.prop('checked')).length).toBe(1); +}); diff --git a/server/sonar-web/src/main/js/apps/projects-admin/app.js b/server/sonar-web/src/main/js/apps/projects-admin/app.js new file mode 100644 index 00000000000..7c68d2c4b6e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/app.js @@ -0,0 +1,33 @@ +/* + * 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 React from 'react'; +import ReactDOM from 'react-dom'; +import Main from './main'; +import { getCurrentUser } from '../../api/users'; + +window.sonarqube.appStarted.then(options => { + getCurrentUser().then(user => { + const el = document.querySelector(options.el); + const hasProvisionPermission = user.permissions.global.indexOf('provisioning') !== -1; + const topLevelQualifiers = options.rootQualifiers; + ReactDOM.render(
, el); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/projects-admin/constants.js b/server/sonar-web/src/main/js/apps/projects-admin/constants.js new file mode 100644 index 00000000000..59a57a281e6 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/constants.js @@ -0,0 +1,28 @@ +/* + * 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. + */ +export const PAGE_SIZE = 50; + +export const QUALIFIERS_ORDER = ['TRK', 'VW', 'DEV']; + +export const TYPE = { + ALL: 'ALL', + PROVISIONED: 'PROVISIONED', + GHOSTS: 'GHOSTS' +}; 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 new file mode 100644 index 00000000000..3f1662349bc --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/create-view.js @@ -0,0 +1,72 @@ +/* + * 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 ModalForm from '../../components/common/modal-form'; +import { createProject } from '../../api/components'; +import Template from './templates/projects-create-form.hbs'; + +export default ModalForm.extend({ + template: Template, + + onRender () { + ModalForm.prototype.onRender.apply(this, arguments); + this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); + }, + + onDestroy () { + ModalForm.prototype.onDestroy.apply(this, arguments); + this.$('[data-toggle="tooltip"]').tooltip('destroy'); + }, + + onFormSubmit () { + ModalForm.prototype.onFormSubmit.apply(this, arguments); + this.sendRequest(); + }, + + sendRequest () { + const data = { + name: this.$('#create-project-name').val(), + branch: this.$('#create-project-branch').val(), + key: this.$('#create-project-key').val() + }; + this.disableForm(); + return createProject(data) + .then(project => { + if (this.options.refresh) { + this.options.refresh(); + } + this.enableForm(); + this.createdProject = project; + this.render(); + }) + .catch(error => { + this.enableForm(); + if (error.response.status === 400) { + error.response.json().then(obj => this.showErrors([{ msg: obj.err_msg }])); + } + }); + }, + + serializeData () { + return { + ...ModalForm.prototype.serializeData.apply(this, arguments), + createdProject: this.createdProject + }; + } +}); diff --git a/server/sonar-web/src/main/js/apps/projects-admin/delete-view.js b/server/sonar-web/src/main/js/apps/projects-admin/delete-view.js new file mode 100644 index 00000000000..7d7ee00be62 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/delete-view.js @@ -0,0 +1,32 @@ +/* + * 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 ModalForm from '../../components/common/modal-form'; +import Template from './templates/projects-delete.hbs'; + +export default ModalForm.extend({ + template: Template, + + onFormSubmit () { + ModalForm.prototype.onFormSubmit.apply(this, arguments); + this.options.deleteProjects(); + this.destroy(); + } +}); + diff --git a/server/sonar-web/src/main/js/apps/projects-admin/form-view.js b/server/sonar-web/src/main/js/apps/projects-admin/form-view.js new file mode 100644 index 00000000000..7b96a150358 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/form-view.js @@ -0,0 +1,39 @@ +/* + * 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 ModalForm from '../../components/common/modal-form'; + +export default ModalForm.extend({ + + onRender () { + ModalForm.prototype.onRender.apply(this, arguments); + this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); + }, + + onDestroy () { + ModalForm.prototype.onDestroy.apply(this, arguments); + this.$('[data-toggle="tooltip"]').tooltip('destroy'); + }, + + onFormSubmit () { + ModalForm.prototype.onFormSubmit.apply(this, arguments); + this.sendRequest(); + } + +}); 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 new file mode 100644 index 00000000000..1d4200e3aa5 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/header.js @@ -0,0 +1,83 @@ +/* + * 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 React from 'react'; +import CreateView from './create-view'; +import BulkApplyTemplateView from './views/BulkApplyTemplateView'; + +export default class Header extends React.Component { + static propTypes = { + hasProvisionPermission: React.PropTypes.bool.isRequired + }; + + createProject () { + new CreateView({ + refresh: this.props.refresh + }).render(); + } + + bulkApplyTemplate () { + new BulkApplyTemplateView({ + total: this.props.total, + selection: this.props.selection, + query: this.props.query, + qualifier: this.props.qualifier + }).render(); + } + + renderCreateButton () { + if (!this.props.hasProvisionPermission) { + return null; + } + return ( +
  • + +
  • + ); + } + + renderBulkApplyTemplateButton () { + return ( +
  • + +
  • + ); + } + + render () { + return ( +
    +

    Projects Management

    +
    +
      + {this.renderCreateButton()} + {this.renderBulkApplyTemplateButton()} +
    +
    +

    Use this page to delete multiple projects at once, or to provision projects + if you would like to configure them before the first analysis. Note that once a project is provisioned, you + have access to perform all project configurations on it.

    +
    + ); + } +} 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 new file mode 100644 index 00000000000..c3a240b19db --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/main.js @@ -0,0 +1,227 @@ +/* + * 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 _ from 'underscore'; +import React from 'react'; +import Header from './header'; +import Search from './search'; +import Projects from './projects'; +import { PAGE_SIZE, TYPE } from './constants'; +import { + getComponents, + getProvisioned, + getGhosts, + deleteComponents +} from '../../api/components'; +import ListFooter from '../../components/controls/ListFooter'; + +export default React.createClass({ + propTypes: { + hasProvisionPermission: React.PropTypes.bool.isRequired, + topLevelQualifiers: React.PropTypes.array.isRequired + }, + + getInitialState() { + return { + ready: false, + projects: [], + total: 0, + page: 1, + query: '', + qualifiers: 'TRK', + type: TYPE.ALL, + selection: [] + }; + }, + + componentWillMount () { + this.requestProjects = _.debounce(this.requestProjects, 250); + }, + + componentDidMount() { + this.requestProjects(); + }, + + getFilters() { + const filters = { ps: PAGE_SIZE }; + if (this.state.page !== 1) { + filters.p = this.state.page; + } + if (this.state.query) { + filters.q = this.state.query; + } + return filters; + }, + + requestProjects() { + switch (this.state.type) { + case TYPE.ALL: + this.requestAllProjects(); + break; + case TYPE.PROVISIONED: + this.requestProvisioned(); + break; + case TYPE.GHOSTS: + this.requestGhosts(); + break; + default: + + // should never happen + } + }, + + requestGhosts() { + const data = this.getFilters(); + getGhosts(data).then(r => { + let projects = r.projects.map(project => { + return _.extend(project, { id: project.uuid, qualifier: 'TRK' }); + }); + if (this.state.page > 1) { + projects = [].concat(this.state.projects, projects); + } + this.setState({ ready: true, projects, total: r.total }); + }); + }, + + requestProvisioned() { + const data = this.getFilters(); + getProvisioned(data).then(r => { + let projects = r.projects.map(project => { + return _.extend(project, { id: project.uuid, qualifier: 'TRK' }); + }); + if (this.state.page > 1) { + projects = [].concat(this.state.projects, projects); + } + this.setState({ ready: true, projects, total: r.total }); + }); + }, + + requestAllProjects() { + const data = this.getFilters(); + data.qualifiers = this.state.qualifiers; + getComponents(data).then(r => { + let projects = r.components; + if (this.state.page > 1) { + projects = [].concat(this.state.projects, projects); + } + this.setState({ ready: true, projects, total: r.paging.total }); + }); + }, + + loadMore() { + this.setState({ ready: false, page: this.state.page + 1 }, + this.requestProjects); + }, + + onSearch(query) { + this.setState({ + ready: false, + page: 1, + query, + selection: [] + }, this.requestProjects); + }, + + onTypeChanged(newType) { + this.setState({ + ready: false, + page: 1, + query: '', + type: newType, + qualifiers: 'TRK', + selection: [] + }, this.requestProjects); + }, + + onQualifierChanged(newQualifier) { + this.setState({ + ready: false, + page: 1, + query: '', + type: TYPE.ALL, + qualifiers: newQualifier, + selection: [] + }, this.requestProjects); + }, + + onProjectSelected(project) { + const newSelection = _.uniq([].concat(this.state.selection, project.id)); + this.setState({ selection: newSelection }); + }, + + onProjectDeselected(project) { + const newSelection = _.without(this.state.selection, project.id); + this.setState({ selection: newSelection }); + }, + + onAllSelected() { + const newSelection = this.state.projects.map(project => { + return project.id; + }); + this.setState({ selection: newSelection }); + }, + + onAllDeselected() { + this.setState({ selection: [] }); + }, + + deleteProjects() { + this.setState({ ready: false }); + const ids = this.state.selection.join(','); + deleteComponents({ ids }).then(() => { + this.setState({ page: 1, selection: [] }, this.requestProjects); + }); + }, + + render() { + return ( +
    +
    + + + + + + +
    + ); + } +}); 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 new file mode 100644 index 00000000000..140471de317 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/projects.js @@ -0,0 +1,117 @@ +/* + * 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 classNames from 'classnames'; +import React from 'react'; +import { + getComponentUrl, + getComponentPermissionsUrl +} from '../../helpers/urls'; +import ApplyTemplateView from '../permissions/project/views/ApplyTemplateView'; +import Checkbox from '../../components/controls/Checkbox'; +import QualifierIcon from '../../components/shared/qualifier-icon'; +import { translate } from '../../helpers/l10n'; + +export default class Projects extends React.Component { + static propTypes = { + projects: React.PropTypes.array.isRequired, + selection: React.PropTypes.array.isRequired, + refresh: React.PropTypes.func.isRequired + }; + + componentWillMount () { + this.renderProject = this.renderProject.bind(this); + } + + onProjectCheck (project, checked) { + if (checked) { + this.props.onProjectSelected(project); + } else { + this.props.onProjectDeselected(project); + } + } + + onApplyTemplateClick (project, e) { + e.preventDefault(); + e.target.blur(); + new ApplyTemplateView({ project }).render(); + } + + isProjectSelected (project) { + return this.props.selection.indexOf(project.id) !== -1; + } + + renderProject (project) { + const permissionsUrl = getComponentPermissionsUrl(project.key); + + return ( + + + + + + + + {' '} + {project.name} + + + + {project.key} + + + + + + ); + } + + render () { + const className = classNames('data', 'zebra', + { 'new-loading': !this.props.ready } + ); + + return ( + + {this.props.projects.map(this.renderProject)} +
    + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projects-admin/search.js b/server/sonar-web/src/main/js/apps/projects-admin/search.js new file mode 100644 index 00000000000..24817c916f9 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/search.js @@ -0,0 +1,159 @@ +/* + * 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 _ from 'underscore'; +import React from 'react'; +import { TYPE, QUALIFIERS_ORDER } from './constants'; +import DeleteView from './delete-view'; +import RadioToggle from '../../components/controls/RadioToggle'; +import Checkbox from '../../components/controls/Checkbox'; +import { translate } from '../../helpers/l10n'; + +export default React.createClass({ + propTypes: { + onSearch: React.PropTypes.func.isRequired + }, + + onSubmit(e) { + e.preventDefault(); + this.search(); + }, + + search() { + const q = this.refs.input.value; + this.props.onSearch(q); + }, + + getTypeOptions() { + return [ + { value: TYPE.ALL, label: 'All' }, + { value: TYPE.PROVISIONED, label: 'Provisioned' }, + { value: TYPE.GHOSTS, label: 'Ghosts' } + ]; + }, + + getQualifierOptions() { + const options = this.props.topLevelQualifiers.map(q => { + return { value: q, label: translate('qualifiers', q) }; + }); + return _.sortBy(options, option => { + return QUALIFIERS_ORDER.indexOf(option.value); + }); + }, + + renderCheckbox() { + const isAllChecked = this.props.projects.length > 0 && + this.props.selection.length === this.props.projects.length; + const thirdState = this.props.projects.length > 0 && + this.props.selection.length > 0 && + this.props.selection.length < this.props.projects.length; + const checked = isAllChecked || thirdState; + return ( + + ); + }, + + renderSpinner() { + return ; + }, + + onCheck(checked) { + if (checked) { + this.props.onAllSelected(); + } else { + this.props.onAllDeselected(); + } + }, + + renderGhostsDescription () { + if (this.props.type !== TYPE.GHOSTS || !this.props.ready) { + return null; + } + return
    {translate('bulk_deletion.ghosts.description')}
    ; + }, + + deleteProjects() { + new DeleteView({ + deleteProjects: this.props.deleteProjects + }).render(); + }, + + renderQualifierFilter() { + const options = this.getQualifierOptions(); + if (options.length < 2) { + return null; + } + return ( + + + + ); + }, + + render() { + const isSomethingSelected = this.props.projects.length > 0 && this.props.selection.length > 0; + return ( +
    + + + + + {this.renderQualifierFilter()} + + + + + +
    + {this.props.ready ? this.renderCheckbox() : this.renderSpinner()} + + + +
    + + +
    +
    + +
    + {this.renderGhostsDescription()} +
    + ); + } +}); diff --git a/server/sonar-web/src/main/js/apps/projects-admin/templates/BulkApplyTemplateTemplate.hbs b/server/sonar-web/src/main/js/apps/projects-admin/templates/BulkApplyTemplateTemplate.hbs new file mode 100644 index 00000000000..b4933eb193c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/templates/BulkApplyTemplateTemplate.hbs @@ -0,0 +1,68 @@ +
    + + + + + +
    diff --git a/server/sonar-web/src/main/js/apps/projects-admin/templates/projects-create-form.hbs b/server/sonar-web/src/main/js/apps/projects-admin/templates/projects-create-form.hbs new file mode 100644 index 00000000000..f94b5461f8f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/templates/projects-create-form.hbs @@ -0,0 +1,41 @@ +
    + + + +
    diff --git a/server/sonar-web/src/main/js/apps/projects-admin/templates/projects-delete.hbs b/server/sonar-web/src/main/js/apps/projects-admin/templates/projects-delete.hbs new file mode 100644 index 00000000000..2ab69b28f72 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/templates/projects-delete.hbs @@ -0,0 +1,13 @@ +
    + + + +
    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 new file mode 100644 index 00000000000..d2fc1aba72e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects-admin/views/BulkApplyTemplateView.js @@ -0,0 +1,108 @@ +/* + * 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 ModalForm from '../../../components/common/modal-form'; +import { + applyTemplateToProject, + bulkApplyTemplate, + getPermissionTemplates +} from '../../../api/permissions'; +import Template from '../templates/BulkApplyTemplateTemplate.hbs'; + +export default ModalForm.extend({ + template: Template, + + initialize () { + this.loadPermissionTemplates(); + this.done = false; + }, + + loadPermissionTemplates () { + return getPermissionTemplates().then(r => { + this.permissionTemplates = r.permissionTemplates; + this.render(); + }); + }, + + onRender () { + ModalForm.prototype.onRender.apply(this, arguments); + this.$('#project-permissions-template').select2({ + width: '250px', + minimumResultsForSearch: 20 + }); + }, + + bulkApplyToAll (permissionTemplate) { + const data = { templateId: permissionTemplate }; + + if (this.options.query) { + data.q = this.options.query; + } + + if (this.options.qualifier) { + data.qualifier = this.options.qualifier; + } + + return bulkApplyTemplate(data); + }, + + bulkApplyToSelected(permissionTemplate) { + const { selection } = this.options; + let lastRequest = Promise.resolve(); + + selection.forEach(projectId => { + const data = { templateId: permissionTemplate, projectId }; + lastRequest = lastRequest.then(() => applyTemplateToProject(data)); + }); + + return lastRequest; + }, + + onFormSubmit () { + ModalForm.prototype.onFormSubmit.apply(this, arguments); + const permissionTemplate = this.$('#project-permissions-template').val(); + const applyTo = this.$('[name="apply-to"]:checked').val(); + this.disableForm(); + + const request = applyTo === 'all' ? + this.bulkApplyToAll(permissionTemplate) : + this.bulkApplyToSelected(permissionTemplate); + + request.then(() => { + this.trigger('done'); + this.done = true; + this.render(); + }).catch(function (e) { + e.response.json().then(r => { + this.showErrors(r.errors, r.warnings); + this.enableForm(); + }); + }); + }, + + serializeData () { + return { + permissionTemplates: this.permissionTemplates, + selection: this.options.selection, + selectionTotal: this.options.selection.length, + total: this.options.total, + done: this.done + }; + } +}); diff --git a/server/sonar-web/src/main/js/apps/projects/__tests__/projects-test.js b/server/sonar-web/src/main/js/apps/projects/__tests__/projects-test.js deleted file mode 100644 index 85abb704b2b..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/__tests__/projects-test.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 React from 'react'; -import { shallow } from 'enzyme'; -import Projects from '../projects'; -import Checkbox from '../../../components/controls/Checkbox'; - -it('should render list of projects with no selection', () => { - const projects = [ - { id: '1', key: 'a', name: 'A', qualifier: 'TRK' }, - { id: '2', key: 'b', name: 'B', qualifier: 'TRK' } - ]; - - const result = shallow(); - expect(result.find('tr').length).toBe(2); - expect(result.find(Checkbox).filterWhere(n => n.prop('checked')).length).toBe(0); -}); - -it('should render list of projects with one selected', () => { - const projects = [ - { id: '1', key: 'a', name: 'A', qualifier: 'TRK' }, - { id: '2', key: 'b', name: 'B', qualifier: 'TRK' } - ]; - const selection = ['1']; - - const result = shallow(); - expect(result.find('tr').length).toBe(2); - expect(result.find(Checkbox).filterWhere(n => n.prop('checked')).length).toBe(1); -}); diff --git a/server/sonar-web/src/main/js/apps/projects/app.js b/server/sonar-web/src/main/js/apps/projects/app.js deleted file mode 100644 index 7c68d2c4b6e..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/app.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 React from 'react'; -import ReactDOM from 'react-dom'; -import Main from './main'; -import { getCurrentUser } from '../../api/users'; - -window.sonarqube.appStarted.then(options => { - getCurrentUser().then(user => { - const el = document.querySelector(options.el); - const hasProvisionPermission = user.permissions.global.indexOf('provisioning') !== -1; - const topLevelQualifiers = options.rootQualifiers; - ReactDOM.render(
    , el); - }); -}); diff --git a/server/sonar-web/src/main/js/apps/projects/constants.js b/server/sonar-web/src/main/js/apps/projects/constants.js deleted file mode 100644 index 59a57a281e6..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/constants.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ -export const PAGE_SIZE = 50; - -export const QUALIFIERS_ORDER = ['TRK', 'VW', 'DEV']; - -export const TYPE = { - ALL: 'ALL', - PROVISIONED: 'PROVISIONED', - GHOSTS: 'GHOSTS' -}; diff --git a/server/sonar-web/src/main/js/apps/projects/create-view.js b/server/sonar-web/src/main/js/apps/projects/create-view.js deleted file mode 100644 index 3f1662349bc..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/create-view.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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 ModalForm from '../../components/common/modal-form'; -import { createProject } from '../../api/components'; -import Template from './templates/projects-create-form.hbs'; - -export default ModalForm.extend({ - template: Template, - - onRender () { - ModalForm.prototype.onRender.apply(this, arguments); - this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); - }, - - onDestroy () { - ModalForm.prototype.onDestroy.apply(this, arguments); - this.$('[data-toggle="tooltip"]').tooltip('destroy'); - }, - - onFormSubmit () { - ModalForm.prototype.onFormSubmit.apply(this, arguments); - this.sendRequest(); - }, - - sendRequest () { - const data = { - name: this.$('#create-project-name').val(), - branch: this.$('#create-project-branch').val(), - key: this.$('#create-project-key').val() - }; - this.disableForm(); - return createProject(data) - .then(project => { - if (this.options.refresh) { - this.options.refresh(); - } - this.enableForm(); - this.createdProject = project; - this.render(); - }) - .catch(error => { - this.enableForm(); - if (error.response.status === 400) { - error.response.json().then(obj => this.showErrors([{ msg: obj.err_msg }])); - } - }); - }, - - serializeData () { - return { - ...ModalForm.prototype.serializeData.apply(this, arguments), - createdProject: this.createdProject - }; - } -}); diff --git a/server/sonar-web/src/main/js/apps/projects/delete-view.js b/server/sonar-web/src/main/js/apps/projects/delete-view.js deleted file mode 100644 index 7d7ee00be62..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/delete-view.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 ModalForm from '../../components/common/modal-form'; -import Template from './templates/projects-delete.hbs'; - -export default ModalForm.extend({ - template: Template, - - onFormSubmit () { - ModalForm.prototype.onFormSubmit.apply(this, arguments); - this.options.deleteProjects(); - this.destroy(); - } -}); - diff --git a/server/sonar-web/src/main/js/apps/projects/form-view.js b/server/sonar-web/src/main/js/apps/projects/form-view.js deleted file mode 100644 index 7b96a150358..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/form-view.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 ModalForm from '../../components/common/modal-form'; - -export default ModalForm.extend({ - - onRender () { - ModalForm.prototype.onRender.apply(this, arguments); - this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' }); - }, - - onDestroy () { - ModalForm.prototype.onDestroy.apply(this, arguments); - this.$('[data-toggle="tooltip"]').tooltip('destroy'); - }, - - onFormSubmit () { - ModalForm.prototype.onFormSubmit.apply(this, arguments); - this.sendRequest(); - } - -}); diff --git a/server/sonar-web/src/main/js/apps/projects/header.js b/server/sonar-web/src/main/js/apps/projects/header.js deleted file mode 100644 index 1d4200e3aa5..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/header.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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 React from 'react'; -import CreateView from './create-view'; -import BulkApplyTemplateView from './views/BulkApplyTemplateView'; - -export default class Header extends React.Component { - static propTypes = { - hasProvisionPermission: React.PropTypes.bool.isRequired - }; - - createProject () { - new CreateView({ - refresh: this.props.refresh - }).render(); - } - - bulkApplyTemplate () { - new BulkApplyTemplateView({ - total: this.props.total, - selection: this.props.selection, - query: this.props.query, - qualifier: this.props.qualifier - }).render(); - } - - renderCreateButton () { - if (!this.props.hasProvisionPermission) { - return null; - } - return ( -
  • - -
  • - ); - } - - renderBulkApplyTemplateButton () { - return ( -
  • - -
  • - ); - } - - render () { - return ( -
    -

    Projects Management

    -
    -
      - {this.renderCreateButton()} - {this.renderBulkApplyTemplateButton()} -
    -
    -

    Use this page to delete multiple projects at once, or to provision projects - if you would like to configure them before the first analysis. Note that once a project is provisioned, you - have access to perform all project configurations on it.

    -
    - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/projects/main.js b/server/sonar-web/src/main/js/apps/projects/main.js deleted file mode 100644 index c3a240b19db..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/main.js +++ /dev/null @@ -1,227 +0,0 @@ -/* - * 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 _ from 'underscore'; -import React from 'react'; -import Header from './header'; -import Search from './search'; -import Projects from './projects'; -import { PAGE_SIZE, TYPE } from './constants'; -import { - getComponents, - getProvisioned, - getGhosts, - deleteComponents -} from '../../api/components'; -import ListFooter from '../../components/controls/ListFooter'; - -export default React.createClass({ - propTypes: { - hasProvisionPermission: React.PropTypes.bool.isRequired, - topLevelQualifiers: React.PropTypes.array.isRequired - }, - - getInitialState() { - return { - ready: false, - projects: [], - total: 0, - page: 1, - query: '', - qualifiers: 'TRK', - type: TYPE.ALL, - selection: [] - }; - }, - - componentWillMount () { - this.requestProjects = _.debounce(this.requestProjects, 250); - }, - - componentDidMount() { - this.requestProjects(); - }, - - getFilters() { - const filters = { ps: PAGE_SIZE }; - if (this.state.page !== 1) { - filters.p = this.state.page; - } - if (this.state.query) { - filters.q = this.state.query; - } - return filters; - }, - - requestProjects() { - switch (this.state.type) { - case TYPE.ALL: - this.requestAllProjects(); - break; - case TYPE.PROVISIONED: - this.requestProvisioned(); - break; - case TYPE.GHOSTS: - this.requestGhosts(); - break; - default: - - // should never happen - } - }, - - requestGhosts() { - const data = this.getFilters(); - getGhosts(data).then(r => { - let projects = r.projects.map(project => { - return _.extend(project, { id: project.uuid, qualifier: 'TRK' }); - }); - if (this.state.page > 1) { - projects = [].concat(this.state.projects, projects); - } - this.setState({ ready: true, projects, total: r.total }); - }); - }, - - requestProvisioned() { - const data = this.getFilters(); - getProvisioned(data).then(r => { - let projects = r.projects.map(project => { - return _.extend(project, { id: project.uuid, qualifier: 'TRK' }); - }); - if (this.state.page > 1) { - projects = [].concat(this.state.projects, projects); - } - this.setState({ ready: true, projects, total: r.total }); - }); - }, - - requestAllProjects() { - const data = this.getFilters(); - data.qualifiers = this.state.qualifiers; - getComponents(data).then(r => { - let projects = r.components; - if (this.state.page > 1) { - projects = [].concat(this.state.projects, projects); - } - this.setState({ ready: true, projects, total: r.paging.total }); - }); - }, - - loadMore() { - this.setState({ ready: false, page: this.state.page + 1 }, - this.requestProjects); - }, - - onSearch(query) { - this.setState({ - ready: false, - page: 1, - query, - selection: [] - }, this.requestProjects); - }, - - onTypeChanged(newType) { - this.setState({ - ready: false, - page: 1, - query: '', - type: newType, - qualifiers: 'TRK', - selection: [] - }, this.requestProjects); - }, - - onQualifierChanged(newQualifier) { - this.setState({ - ready: false, - page: 1, - query: '', - type: TYPE.ALL, - qualifiers: newQualifier, - selection: [] - }, this.requestProjects); - }, - - onProjectSelected(project) { - const newSelection = _.uniq([].concat(this.state.selection, project.id)); - this.setState({ selection: newSelection }); - }, - - onProjectDeselected(project) { - const newSelection = _.without(this.state.selection, project.id); - this.setState({ selection: newSelection }); - }, - - onAllSelected() { - const newSelection = this.state.projects.map(project => { - return project.id; - }); - this.setState({ selection: newSelection }); - }, - - onAllDeselected() { - this.setState({ selection: [] }); - }, - - deleteProjects() { - this.setState({ ready: false }); - const ids = this.state.selection.join(','); - deleteComponents({ ids }).then(() => { - this.setState({ page: 1, selection: [] }, this.requestProjects); - }); - }, - - render() { - return ( -
    -
    - - - - - - -
    - ); - } -}); diff --git a/server/sonar-web/src/main/js/apps/projects/projects.js b/server/sonar-web/src/main/js/apps/projects/projects.js deleted file mode 100644 index 140471de317..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/projects.js +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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 classNames from 'classnames'; -import React from 'react'; -import { - getComponentUrl, - getComponentPermissionsUrl -} from '../../helpers/urls'; -import ApplyTemplateView from '../permissions/project/views/ApplyTemplateView'; -import Checkbox from '../../components/controls/Checkbox'; -import QualifierIcon from '../../components/shared/qualifier-icon'; -import { translate } from '../../helpers/l10n'; - -export default class Projects extends React.Component { - static propTypes = { - projects: React.PropTypes.array.isRequired, - selection: React.PropTypes.array.isRequired, - refresh: React.PropTypes.func.isRequired - }; - - componentWillMount () { - this.renderProject = this.renderProject.bind(this); - } - - onProjectCheck (project, checked) { - if (checked) { - this.props.onProjectSelected(project); - } else { - this.props.onProjectDeselected(project); - } - } - - onApplyTemplateClick (project, e) { - e.preventDefault(); - e.target.blur(); - new ApplyTemplateView({ project }).render(); - } - - isProjectSelected (project) { - return this.props.selection.indexOf(project.id) !== -1; - } - - renderProject (project) { - const permissionsUrl = getComponentPermissionsUrl(project.key); - - return ( - - - - - - - - {' '} - {project.name} - - - - {project.key} - - - - - - ); - } - - render () { - const className = classNames('data', 'zebra', - { 'new-loading': !this.props.ready } - ); - - return ( - - {this.props.projects.map(this.renderProject)} -
    - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/projects/search.js b/server/sonar-web/src/main/js/apps/projects/search.js deleted file mode 100644 index 24817c916f9..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/search.js +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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 _ from 'underscore'; -import React from 'react'; -import { TYPE, QUALIFIERS_ORDER } from './constants'; -import DeleteView from './delete-view'; -import RadioToggle from '../../components/controls/RadioToggle'; -import Checkbox from '../../components/controls/Checkbox'; -import { translate } from '../../helpers/l10n'; - -export default React.createClass({ - propTypes: { - onSearch: React.PropTypes.func.isRequired - }, - - onSubmit(e) { - e.preventDefault(); - this.search(); - }, - - search() { - const q = this.refs.input.value; - this.props.onSearch(q); - }, - - getTypeOptions() { - return [ - { value: TYPE.ALL, label: 'All' }, - { value: TYPE.PROVISIONED, label: 'Provisioned' }, - { value: TYPE.GHOSTS, label: 'Ghosts' } - ]; - }, - - getQualifierOptions() { - const options = this.props.topLevelQualifiers.map(q => { - return { value: q, label: translate('qualifiers', q) }; - }); - return _.sortBy(options, option => { - return QUALIFIERS_ORDER.indexOf(option.value); - }); - }, - - renderCheckbox() { - const isAllChecked = this.props.projects.length > 0 && - this.props.selection.length === this.props.projects.length; - const thirdState = this.props.projects.length > 0 && - this.props.selection.length > 0 && - this.props.selection.length < this.props.projects.length; - const checked = isAllChecked || thirdState; - return ( - - ); - }, - - renderSpinner() { - return ; - }, - - onCheck(checked) { - if (checked) { - this.props.onAllSelected(); - } else { - this.props.onAllDeselected(); - } - }, - - renderGhostsDescription () { - if (this.props.type !== TYPE.GHOSTS || !this.props.ready) { - return null; - } - return
    {translate('bulk_deletion.ghosts.description')}
    ; - }, - - deleteProjects() { - new DeleteView({ - deleteProjects: this.props.deleteProjects - }).render(); - }, - - renderQualifierFilter() { - const options = this.getQualifierOptions(); - if (options.length < 2) { - return null; - } - return ( - - - - ); - }, - - render() { - const isSomethingSelected = this.props.projects.length > 0 && this.props.selection.length > 0; - return ( -
    - - - - - {this.renderQualifierFilter()} - - - - - -
    - {this.props.ready ? this.renderCheckbox() : this.renderSpinner()} - - - -
    - - -
    -
    - -
    - {this.renderGhostsDescription()} -
    - ); - } -}); diff --git a/server/sonar-web/src/main/js/apps/projects/templates/BulkApplyTemplateTemplate.hbs b/server/sonar-web/src/main/js/apps/projects/templates/BulkApplyTemplateTemplate.hbs deleted file mode 100644 index b4933eb193c..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/templates/BulkApplyTemplateTemplate.hbs +++ /dev/null @@ -1,68 +0,0 @@ -
    - - - - - -
    diff --git a/server/sonar-web/src/main/js/apps/projects/templates/projects-create-form.hbs b/server/sonar-web/src/main/js/apps/projects/templates/projects-create-form.hbs deleted file mode 100644 index f94b5461f8f..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/templates/projects-create-form.hbs +++ /dev/null @@ -1,41 +0,0 @@ -
    - - - -
    diff --git a/server/sonar-web/src/main/js/apps/projects/templates/projects-delete.hbs b/server/sonar-web/src/main/js/apps/projects/templates/projects-delete.hbs deleted file mode 100644 index 2ab69b28f72..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/templates/projects-delete.hbs +++ /dev/null @@ -1,13 +0,0 @@ -
    - - - -
    diff --git a/server/sonar-web/src/main/js/apps/projects/views/BulkApplyTemplateView.js b/server/sonar-web/src/main/js/apps/projects/views/BulkApplyTemplateView.js deleted file mode 100644 index d2fc1aba72e..00000000000 --- a/server/sonar-web/src/main/js/apps/projects/views/BulkApplyTemplateView.js +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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 ModalForm from '../../../components/common/modal-form'; -import { - applyTemplateToProject, - bulkApplyTemplate, - getPermissionTemplates -} from '../../../api/permissions'; -import Template from '../templates/BulkApplyTemplateTemplate.hbs'; - -export default ModalForm.extend({ - template: Template, - - initialize () { - this.loadPermissionTemplates(); - this.done = false; - }, - - loadPermissionTemplates () { - return getPermissionTemplates().then(r => { - this.permissionTemplates = r.permissionTemplates; - this.render(); - }); - }, - - onRender () { - ModalForm.prototype.onRender.apply(this, arguments); - this.$('#project-permissions-template').select2({ - width: '250px', - minimumResultsForSearch: 20 - }); - }, - - bulkApplyToAll (permissionTemplate) { - const data = { templateId: permissionTemplate }; - - if (this.options.query) { - data.q = this.options.query; - } - - if (this.options.qualifier) { - data.qualifier = this.options.qualifier; - } - - return bulkApplyTemplate(data); - }, - - bulkApplyToSelected(permissionTemplate) { - const { selection } = this.options; - let lastRequest = Promise.resolve(); - - selection.forEach(projectId => { - const data = { templateId: permissionTemplate, projectId }; - lastRequest = lastRequest.then(() => applyTemplateToProject(data)); - }); - - return lastRequest; - }, - - onFormSubmit () { - ModalForm.prototype.onFormSubmit.apply(this, arguments); - const permissionTemplate = this.$('#project-permissions-template').val(); - const applyTo = this.$('[name="apply-to"]:checked').val(); - this.disableForm(); - - const request = applyTo === 'all' ? - this.bulkApplyToAll(permissionTemplate) : - this.bulkApplyToSelected(permissionTemplate); - - request.then(() => { - this.trigger('done'); - this.done = true; - this.render(); - }).catch(function (e) { - e.response.json().then(r => { - this.showErrors(r.errors, r.warnings); - this.enableForm(); - }); - }); - }, - - serializeData () { - return { - permissionTemplates: this.permissionTemplates, - selection: this.options.selection, - selectionTotal: this.options.selection.length, - total: this.options.total, - done: this.done - }; - } -}); diff --git a/server/sonar-web/src/main/js/main/nav/settings/settings-nav.js b/server/sonar-web/src/main/js/main/nav/settings/settings-nav.js index afad572d0e8..35313c30300 100644 --- a/server/sonar-web/src/main/js/main/nav/settings/settings-nav.js +++ b/server/sonar-web/src/main/js/main/nav/settings/settings-nav.js @@ -41,7 +41,7 @@ export default React.createClass({ }, isProjectsActive() { - const urls = ['/projects', '/background_tasks']; + const urls = ['/projects_admin', '/background_tasks']; return this.isSomethingActive(urls); }, @@ -109,7 +109,7 @@ export default React.createClass({
      - {this.renderLink('/projects', 'Management')} + {this.renderLink('/projects_admin', 'Management')} {this.renderLink('/background_tasks', translate('background_tasks.page'))}
    diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/projects_admin_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/projects_admin_controller.rb new file mode 100644 index 00000000000..09ad7385d78 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/projects_admin_controller.rb @@ -0,0 +1,30 @@ +# +# SonarQube, open source software quality management tool. +# Copyright (C) 2008-2014 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube 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. +# +# SonarQube 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. +# +class ProjectsAdminController < ApplicationController + + before_filter :admin_required + + SECTION=Navigation::SECTION_CONFIGURATION + + def index + + end + +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/projects_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/projects_controller.rb deleted file mode 100644 index 6661201822c..00000000000 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/projects_controller.rb +++ /dev/null @@ -1,30 +0,0 @@ -# -# SonarQube, open source software quality management tool. -# Copyright (C) 2008-2014 SonarSource -# mailto:contact AT sonarsource DOT com -# -# SonarQube 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. -# -# SonarQube 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. -# -class ProjectsController < ApplicationController - - before_filter :admin_required - - SECTION=Navigation::SECTION_CONFIGURATION - - def index - - end - -end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects/index.html.erb deleted file mode 100644 index e9c8ffd9ad8..00000000000 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects/index.html.erb +++ /dev/null @@ -1,3 +0,0 @@ -<% content_for :extra_script do %> - -<% end %> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects_admin/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects_admin/index.html.erb new file mode 100644 index 00000000000..3c6e21dbbd1 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/projects_admin/index.html.erb @@ -0,0 +1,3 @@ +<% content_for :extra_script do %> + +<% end %> -- cgit v1.2.3