/* * SonarQube * Copyright (C) 2009-2022 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 { find, without } from 'lodash'; import * as React from 'react'; import { associateProject, dissociateProject, getProfileProjects, ProfileProject } from '../../../api/quality-profiles'; import Modal from '../../../components/controls/Modal'; import SelectList, { SelectListFilter, SelectListSearchParams } from '../../../components/controls/SelectList'; import { translate } from '../../../helpers/l10n'; import { Profile } from '../types'; interface Props { onClose: () => void; profile: Profile; } interface State { needToReload: boolean; lastSearchParams?: SelectListSearchParams; projects: ProfileProject[]; projectsTotalCount?: number; selectedProjects: string[]; } export default class ChangeProjectsForm extends React.PureComponent { mounted = false; constructor(props: Props) { super(props); this.state = { needToReload: false, projects: [], selectedProjects: [] }; } componentDidMount() { this.mounted = true; } componentWillUnmount() { this.mounted = false; } fetchProjects = (searchParams: SelectListSearchParams) => getProfileProjects({ key: this.props.profile.key, p: searchParams.page, ps: searchParams.pageSize, q: searchParams.query !== '' ? searchParams.query : undefined, selected: searchParams.filter }).then(data => { if (this.mounted) { this.setState(prevState => { const more = searchParams.page != null && searchParams.page > 1; const projects = more ? [...prevState.projects, ...data.results] : data.results; const newSeletedProjects = data.results .filter(project => project.selected) .map(project => project.key); const selectedProjects = more ? [...prevState.selectedProjects, ...newSeletedProjects] : newSeletedProjects; return { lastSearchParams: searchParams, needToReload: false, projects, projectsTotalCount: data.paging.total, selectedProjects }; }); } }); handleSelect = (key: string) => associateProject(this.props.profile, key).then(() => { if (this.mounted) { this.setState((state: State) => ({ needToReload: true, selectedProjects: [...state.selectedProjects, key] })); } }); handleUnselect = (key: string) => dissociateProject(this.props.profile, key).then(() => { if (this.mounted) { this.setState((state: State) => ({ needToReload: true, selectedProjects: without(state.selectedProjects, key) })); } }); handleCloseClick = (event: React.SyntheticEvent) => { event.preventDefault(); this.props.onClose(); }; renderElement = (key: string): React.ReactNode => { const project = find(this.state.projects, { key }); return (
{project === undefined ? ( key ) : ( <> {project.name}
{project.key} )}
); }; render() { const header = translate('projects'); return (

{header}

project.key)} elementsTotalCount={this.state.projectsTotalCount} labelAll={translate('quality_gates.projects.all')} labelSelected={translate('quality_gates.projects.with')} labelUnselected={translate('quality_gates.projects.without')} needToReload={ this.state.needToReload && this.state.lastSearchParams && this.state.lastSearchParams.filter !== SelectListFilter.All } onSearch={this.fetchProjects} onSelect={this.handleSelect} onUnselect={this.handleUnselect} renderElement={this.renderElement} selectedElements={this.state.selectedProjects} withPaging={true} />
{translate('close')}
); } }