diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-09-05 11:00:00 +0200 |
---|---|---|
committer | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-09-11 11:28:29 +0200 |
commit | 71fec25c4056c1dcfe75769c2041b1d56a89a2e5 (patch) | |
tree | e640a76709b242652d3cc274a9d0a98f720ae768 /server/sonar-web/src/main/js/apps/projectsManagement/App.tsx | |
parent | 0926670e79d919e0afa3f0a2e11f656bdcd05916 (diff) | |
download | sonarqube-71fec25c4056c1dcfe75769c2041b1d56a89a2e5.tar.gz sonarqube-71fec25c4056c1dcfe75769c2041b1d56a89a2e5.zip |
SONAR-9784 rewrite projects management page
Diffstat (limited to 'server/sonar-web/src/main/js/apps/projectsManagement/App.tsx')
-rw-r--r-- | server/sonar-web/src/main/js/apps/projectsManagement/App.tsx | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/App.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/App.tsx new file mode 100644 index 00000000000..5a860abb5f7 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectsManagement/App.tsx @@ -0,0 +1,246 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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 Helmet from 'react-helmet'; +import { debounce, uniq, without } from 'lodash'; +import Header from './Header'; +import Search from './Search'; +import Projects from './Projects'; +import CreateProjectForm from './CreateProjectForm'; +import ListFooter from '../../components/controls/ListFooter'; +import { PAGE_SIZE, Type, Project } from './utils'; +import { getComponents, getProvisioned, getGhosts } from '../../api/components'; +import { Organization } from '../../app/types'; +import { translate } from '../../helpers/l10n'; + +export interface Props { + hasProvisionPermission?: boolean; + onVisibilityChange: (visibility: string) => void; + organization: Organization; + topLevelQualifiers: string[]; +} + +interface State { + createProjectForm: boolean; + page: number; + projects: Project[]; + qualifiers: string; + query: string; + ready: boolean; + selection: string[]; + total: number; + type: Type; +} + +export default class App extends React.PureComponent<Props, State> { + mounted: boolean; + + constructor(props: Props) { + super(props); + this.state = { + createProjectForm: false, + ready: false, + projects: [], + total: 0, + page: 1, + query: '', + qualifiers: 'TRK', + type: Type.All, + selection: [] + }; + this.requestProjects = debounce(this.requestProjects, 250); + } + + componentDidMount() { + this.mounted = true; + this.requestProjects(); + } + + componentWillUnmount() { + this.mounted = false; + } + + getFilters = () => ({ + organization: this.props.organization.key, + p: this.state.page !== 1 ? this.state.page : undefined, + ps: PAGE_SIZE, + q: this.state.query ? this.state.query : undefined + }); + + requestProjects = () => { + switch (this.state.type) { + case Type.All: + this.requestAllProjects(); + break; + case Type.Provisioned: + this.requestProvisioned(); + break; + case Type.Ghosts: + this.requestGhosts(); + break; + } + }; + + requestGhosts = () => { + const data = this.getFilters(); + getGhosts(data).then(r => { + if (this.mounted) { + let projects: Project[] = r.projects.map((project: any) => ({ + ...project, + id: project.uuid, + qualifier: 'TRK' + })); + if (this.state.page > 1) { + projects = [...this.state.projects, ...projects]; + } + this.setState({ ready: true, projects, selection: [], total: r.total }); + } + }); + }; + + requestProvisioned = () => { + const data = this.getFilters(); + getProvisioned(data).then(r => { + if (this.mounted) { + let projects: Project[] = r.projects.map((project: any) => ({ + ...project, + id: project.uuid, + qualifier: 'TRK' + })); + if (this.state.page > 1) { + projects = [...this.state.projects, ...projects]; + } + this.setState({ ready: true, projects, selection: [], total: r.paging.total }); + } + }); + }; + + requestAllProjects = () => { + const data = this.getFilters(); + Object.assign(data, { qualifiers: this.state.qualifiers }); + getComponents(data).then(r => { + if (this.mounted) { + let projects: Project[] = r.components; + if (this.state.page > 1) { + projects = [...this.state.projects, ...projects]; + } + this.setState({ ready: true, projects, selection: [], total: r.paging.total }); + } + }); + }; + + loadMore = () => { + this.setState({ ready: false, page: this.state.page + 1 }, this.requestProjects); + }; + + onSearch = (query: string) => { + this.setState({ ready: false, page: 1, query, selection: [] }, this.requestProjects); + }; + + onTypeChanged = (newType: Type) => { + this.setState( + { ready: false, page: 1, query: '', type: newType, qualifiers: 'TRK', selection: [] }, + this.requestProjects + ); + }; + + onQualifierChanged = (newQualifier: string) => { + this.setState( + { ready: false, page: 1, query: '', type: Type.All, qualifiers: newQualifier, selection: [] }, + this.requestProjects + ); + }; + + onProjectSelected = (project: string) => { + const newSelection = uniq([...this.state.selection, project]); + this.setState({ selection: newSelection }); + }; + + onProjectDeselected = (project: string) => { + const newSelection = without(this.state.selection, project); + this.setState({ selection: newSelection }); + }; + + onAllSelected = () => { + const newSelection = this.state.projects.map(project => project.key); + this.setState({ selection: newSelection }); + }; + + onAllDeselected = () => { + this.setState({ selection: [] }); + }; + + openCreateProjectForm = () => { + this.setState({ createProjectForm: true }); + }; + + closeCreateProjectForm = () => { + this.setState({ createProjectForm: false }); + }; + + render() { + return ( + <div className="page page-limited" id="projects-management-page"> + <Helmet title={translate('projects_management')} /> + + <Header + hasProvisionPermission={this.props.hasProvisionPermission} + onProjectCreate={this.openCreateProjectForm} + onVisibilityChange={this.props.onVisibilityChange} + organization={this.props.organization} + /> + + <Search + {...this.props} + {...this.state} + onAllSelected={this.onAllSelected} + onAllDeselected={this.onAllDeselected} + onDeleteProjects={this.requestProjects} + onQualifierChanged={this.onQualifierChanged} + onSearch={this.onSearch} + onTypeChanged={this.onTypeChanged} + /> + + <Projects + ready={this.state.ready} + projects={this.state.projects} + selection={this.state.selection} + onProjectSelected={this.onProjectSelected} + onProjectDeselected={this.onProjectDeselected} + organization={this.props.organization} + /> + + <ListFooter + ready={this.state.ready} + count={this.state.projects.length} + total={this.state.total} + loadMore={this.loadMore} + /> + + {this.state.createProjectForm && + <CreateProjectForm + onClose={this.closeCreateProjectForm} + onProjectCreated={this.requestProjects} + organization={this.props.organization} + />} + </div> + ); + } +} |