From: Stas Vilchik Date: Fri, 16 Nov 2018 15:41:05 +0000 (+0100) Subject: SONAR-11477 Drop UI for updating module keys (#958) X-Git-Tag: 7.6~111 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=a0acec09a79485117ab9c8e3c67a8446224d5de9;p=sonarqube.git SONAR-11477 Drop UI for updating module keys (#958) --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkUpdateKeyAction.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkUpdateKeyAction.java index 60cf61f77f7..bd60c532c11 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkUpdateKeyAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkUpdateKeyAction.java @@ -92,6 +92,7 @@ public class BulkUpdateKeyAction implements ProjectsWsAction { PARAM_DRY_RUN, PARAM_PROJECT, PARAM_FROM, PARAM_TO, PARAM_PROJECT_ID, PARAM_PROJECT) + .setDeprecatedSince("7.6") .setSince("6.1") .setPost(true) .setResponseExample(getClass().getResource("bulk_update_key-example.json")) diff --git a/server/sonar-web/src/main/js/api/components.ts b/server/sonar-web/src/main/js/api/components.ts index efbeedbaa52..60317a41e39 100644 --- a/server/sonar-web/src/main/js/api/components.ts +++ b/server/sonar-web/src/main/js/api/components.ts @@ -222,27 +222,8 @@ export function searchComponents(data?: { return getJSON('/api/components/search', data); } -/** - * Change component's key - */ -export function changeKey(from: string, to: string): Promise { - const url = '/api/projects/update_key'; - const data = { from, to }; - return post(url, data); -} - -/** - * Bulk change component's key - */ -export function bulkChangeKey( - project: string, - from: string, - to: string, - dryRun: boolean = false -): Promise { - const url = '/api/projects/bulk_update_key'; - const data = { project, from, to, dryRun }; - return postJSON(url, data); +export function changeKey(data: { from: string; to: string }) { + return post('/api/projects/update_key', data).catch(throwGlobalError); } export interface SuggestionsResponse { diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx index 781120376f3..dca733a3587 100644 --- a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx +++ b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx @@ -268,7 +268,7 @@ export default function startReactApp( /> import('../../apps/project-admin/key/Key'))} + component={lazyLoad(() => import('../../apps/projectKey/Key'))} /> diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdate.js b/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdate.js deleted file mode 100644 index 59ceb9da3b1..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdate.js +++ /dev/null @@ -1,148 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import BulkUpdateForm from './BulkUpdateForm'; -import BulkUpdateResults from './BulkUpdateResults'; -import { reloadUpdateKeyPage } from './utils'; -import { translate, translateWithParameters } from '../../../helpers/l10n'; -import { bulkChangeKey } from '../../../api/components'; -import { parseError } from '../../../helpers/request'; -import { - addGlobalErrorMessage, - addGlobalSuccessMessage, - closeAllGlobalMessages -} from '../../../store/globalMessages'; -import RecentHistory from '../../../app/components/RecentHistory'; - -class BulkUpdate extends React.PureComponent { - static propTypes = { - component: PropTypes.object.isRequired, - addGlobalErrorMessage: PropTypes.func.isRequired, - addGlobalSuccessMessage: PropTypes.func.isRequired, - closeAllGlobalMessages: PropTypes.func.isRequired - }; - - state = { - updating: false, - updated: false, - newComponentKey: null - }; - - handleSubmit(replace, by) { - this.loadResults(replace, by); - } - - handleConfirm() { - this.setState({ updating: true }); - - const { component } = this.props; - const { replace, by } = this.state; - - bulkChangeKey(component.key, replace, by) - .then(r => { - const result = r.keys.find(result => result.key === component.key); - const newComponentKey = result != null ? result.newKey : component.key; - - if (newComponentKey !== component.key) { - RecentHistory.remove(component.key); - } - - this.props.addGlobalSuccessMessage(translate('update_key.key_updated.reload')); - this.setState({ updating: false }); - reloadUpdateKeyPage(newComponentKey); - }) - .catch(e => { - this.setState({ updating: false }); - parseError(e).then(message => this.props.addGlobalErrorMessage(message)); - }); - } - - loadResults(replace, by) { - const { component } = this.props; - bulkChangeKey(component.key, replace, by, true) - .then(r => { - this.setState({ results: r.keys, replace, by }); - this.props.closeAllGlobalMessages(); - }) - .catch(e => { - this.setState({ results: null }); - parseError(e).then(message => this.props.addGlobalErrorMessage(message)); - }); - } - - renderUpdating() { - return ( -
- -
- ); - } - - render() { - const { component } = this.props; - const { updating, updated } = this.state; - const { results, replace, by } = this.state; - - if (updating) { - return this.renderUpdating(); - } - - if (updated) { - return this.renderUpdated(); - } - - return ( -
-
-
{translate('update_key.bulk_change_description')}
-
- {translateWithParameters( - 'update_key.current_key_for_project_x_is_x', - component.name, - component.key - )} -
-
- - - - {results != null && ( - - )} -
- ); - } -} - -export default connect( - null, - { - addGlobalErrorMessage, - addGlobalSuccessMessage, - closeAllGlobalMessages - } -)(BulkUpdate); diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdateForm.js b/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdateForm.js deleted file mode 100644 index 07814359462..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdateForm.js +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 React from 'react'; -import PropTypes from 'prop-types'; -import { translate } from '../../../helpers/l10n'; -import { SubmitButton } from '../../../components/ui/buttons'; - -export default class BulkUpdateForm extends React.PureComponent { - static propTypes = { - onSubmit: PropTypes.func.isRequired - }; - - handleSubmit = e => { - e.preventDefault(); - - const replace = this.refs.replace.value; - const by = this.refs.by.value; - - this.props.onSubmit(replace, by); - }; - - render() { - return ( -
-
- - -
- -
- - - - {translate('update_key.see_results')} - -
-
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdateResults.js b/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdateResults.js deleted file mode 100644 index a51599ae9d6..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdateResults.js +++ /dev/null @@ -1,94 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 React from 'react'; -import PropTypes from 'prop-types'; -import { some } from 'lodash'; -import { translateWithParameters, translate } from '../../../helpers/l10n'; -import { Button } from '../../../components/ui/buttons'; - -export default class BulkUpdateResults extends React.PureComponent { - static propTypes = { - results: PropTypes.array.isRequired, - onConfirm: PropTypes.func.isRequired - }; - - render() { - const { results, replace, by } = this.props; - const isEmpty = results.length === 0; - const hasDuplications = some(results, r => r.duplicate); - const canUpdate = !isEmpty && !hasDuplications; - - return ( -
- {isEmpty && ( -
- {translateWithParameters('update_key.no_key_to_update', replace)} -
- )} - - {hasDuplications && ( -
- {translateWithParameters('update_key.cant_update_because_duplicate_keys', replace, by)} -
- )} - - {canUpdate && ( -
- {translate('update_key.keys_will_be_updated_as_follows')} -
- )} - - {!isEmpty && ( - - - - - - - - - {results.map(result => ( - - - - - ))} - -
{translate('update_key.old_key')}{translate('update_key.new_key')}
{result.key} - {result.duplicate && ( - - {translate('update_key.duplicate_key')} - - )} - {result.newKey} -
- )} - -
- {canUpdate && ( - - )} -
-
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/FineGrainedUpdate.js b/server/sonar-web/src/main/js/apps/project-admin/key/FineGrainedUpdate.js deleted file mode 100644 index 43e17ebfded..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/key/FineGrainedUpdate.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 React from 'react'; -import UpdateKeyForm from './UpdateKeyForm'; -import QualifierIcon from '../../../components/icons-components/QualifierIcon'; - -export default function FineGrainedUpdate(props) { - const { component, modules } = props; - const components = [component, ...modules]; - - return ( -
- - - {components.map(component => ( - - - - - ))} - -
- {component.name} - - -
-
- ); -} diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/Header.js b/server/sonar-web/src/main/js/apps/project-admin/key/Header.js deleted file mode 100644 index 6c14beda91b..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/key/Header.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 React from 'react'; -import { translate } from '../../../helpers/l10n'; - -export default function Header() { - return ( -
-

{translate('update_key.page')}

-
{translate('update_key.page.description')}
-
- ); -} diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/Key.js b/server/sonar-web/src/main/js/apps/project-admin/key/Key.js deleted file mode 100644 index ee2791f3ded..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/key/Key.js +++ /dev/null @@ -1,156 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 React from 'react'; -import PropTypes from 'prop-types'; -import Helmet from 'react-helmet'; -import { connect } from 'react-redux'; -import Header from './Header'; -import UpdateForm from './UpdateForm'; -import BulkUpdate from './BulkUpdate'; -import FineGrainedUpdate from './FineGrainedUpdate'; -import { reloadUpdateKeyPage } from './utils'; -import { changeKey, fetchProjectModules } from '../store/actions'; -import { translate } from '../../../helpers/l10n'; -import { - addGlobalErrorMessage, - addGlobalSuccessMessage, - closeAllGlobalMessages -} from '../../../store/globalMessages'; -import RecentHistory from '../../../app/components/RecentHistory'; -import { getProjectAdminProjectModules } from '../../../store/rootReducer'; - -class Key extends React.PureComponent { - static propTypes = { - component: PropTypes.object, - fetchProjectModules: PropTypes.func.isRequired, - changeKey: PropTypes.func.isRequired, - addGlobalErrorMessage: PropTypes.func.isRequired, - addGlobalSuccessMessage: PropTypes.func.isRequired, - closeAllGlobalMessages: PropTypes.func.isRequired - }; - - state = { - tab: 'bulk' - }; - - componentDidMount() { - this.props.fetchProjectModules(this.props.component.key); - } - - handleChangeKey = (key, newKey) => { - return this.props.changeKey(key, newKey).then(() => { - if (key === this.props.component.key) { - this.props.addGlobalSuccessMessage(translate('update_key.key_updated.reload')); - RecentHistory.remove(key); - reloadUpdateKeyPage(newKey); - } else { - this.props.addGlobalSuccessMessage(translate('update_key.key_updated')); - } - }); - }; - - handleChangeTab = event => { - event.preventDefault(); - event.currentTarget.blur(); - const { tab } = event.currentTarget.dataset; - this.setState({ tab }); - this.props.closeAllGlobalMessages(); - }; - - render() { - const { component, modules } = this.props; - - const noModules = modules != null && modules.length === 0; - const hasModules = modules != null && modules.length > 0; - - const { tab } = this.state; - - return ( -
- -
- - {modules == null && } - - {noModules && ( -
- -
- )} - - {hasModules && ( -
- - - {tab === 'bulk' && } - - {tab === 'fine' && ( - - )} -
- )} -
- ); - } -} - -const mapStateToProps = (state, ownProps) => ({ - modules: getProjectAdminProjectModules(state, ownProps.location.query.id) -}); - -export default connect( - mapStateToProps, - { - fetchProjectModules, - changeKey, - addGlobalErrorMessage, - addGlobalSuccessMessage, - closeAllGlobalMessages - } -)(Key); diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/UpdateForm.tsx b/server/sonar-web/src/main/js/apps/project-admin/key/UpdateForm.tsx deleted file mode 100644 index 1ece13fef36..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/key/UpdateForm.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 UpdateKeyConfirm from './UpdateKeyConfirm'; -import { Button, SubmitButton } from '../../../components/ui/buttons'; -import { translate } from '../../../helpers/l10n'; - -interface Props { - component: { key: string; name: string }; - onKeyChange: (oldKey: string, newKey: string) => Promise; -} - -interface State { - newKey?: string; -} - -export default class UpdateForm extends React.PureComponent { - state: State = {}; - - handleChange = (event: React.ChangeEvent) => { - const newKey = event.currentTarget.value; - this.setState({ newKey }); - }; - - handleReset = () => { - this.setState({ newKey: undefined }); - }; - - render() { - const { component } = this.props; - const { newKey } = this.state; - const value = newKey != null ? newKey : component.key; - const hasChanged = value !== component.key; - - return ( - - {({ onFormSubmit }) => ( -
- - -
- - {translate('update_verb')} - - - -
-
- )} -
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/UpdateKeyConfirm.tsx b/server/sonar-web/src/main/js/apps/project-admin/key/UpdateKeyConfirm.tsx deleted file mode 100644 index 8796aac4386..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/key/UpdateKeyConfirm.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 ConfirmButton, { ChildrenProps } from '../../../components/controls/ConfirmButton'; -import { translate, translateWithParameters } from '../../../helpers/l10n'; - -interface Props { - children: (props: ChildrenProps) => React.ReactNode; - component: { key: string; name: string }; - newKey: string | undefined; - onConfirm: (oldKey: string, newKey: string) => Promise; -} - -export default class UpdateKeyConfirm extends React.PureComponent { - handleConfirm = () => { - return this.props.newKey - ? this.props.onConfirm(this.props.component.key, this.props.newKey) - : Promise.reject(undefined); - }; - - render() { - const { children, component, newKey } = this.props; - - return ( - - {translateWithParameters('update_key.are_you_sure_to_change_key', component.name)} -
- {translate('update_key.old_key')} - {': '} - {component.key} -
-
- {translate('update_key.new_key')} - {': '} - {newKey} -
- - } - modalHeader={translate('update_key.page')} - onConfirm={this.handleConfirm}> - {children} -
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/UpdateKeyForm.tsx b/server/sonar-web/src/main/js/apps/project-admin/key/UpdateKeyForm.tsx deleted file mode 100644 index 6d8a023ec03..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/key/UpdateKeyForm.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 UpdateKeyConfirm from './UpdateKeyConfirm'; -import { Button } from '../../../components/ui/buttons'; -import { translate } from '../../../helpers/l10n'; - -interface Props { - component: { key: string; name: string }; - onKeyChange: (oldKey: string, newKey: string) => Promise; -} - -interface State { - newKey?: string; -} - -export default class UpdateKeyForm extends React.PureComponent { - state: State = {}; - - handleInputChange = (event: React.ChangeEvent) => { - const newKey = event.currentTarget.value; - this.setState({ newKey }); - }; - - handleResetClick = () => { - this.setState({ newKey: undefined }); - }; - - render() { - const { component } = this.props; - const { newKey } = this.state; - const value = newKey !== undefined ? newKey : component.key; - const hasChanged = newKey !== undefined && newKey !== component.key; - - return ( -
- - - - {({ onClick }) => ( - - )} - - - -
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/project-admin/key/utils.js b/server/sonar-web/src/main/js/apps/project-admin/key/utils.js deleted file mode 100644 index 0a30626afa5..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/key/utils.js +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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. - */ -export const reloadUpdateKeyPage = componentKey => { - setTimeout(() => { - window.location = window.baseUrl + '/project/key?id=' + encodeURIComponent(componentKey); - }, 3000); -}; diff --git a/server/sonar-web/src/main/js/apps/project-admin/store/actions.js b/server/sonar-web/src/main/js/apps/project-admin/store/actions.js deleted file mode 100644 index cdb042caee9..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/store/actions.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 { getTree, changeKey as changeKeyApi } from '../../../api/components'; -import throwGlobalError from '../../../app/utils/throwGlobalError'; - -export const RECEIVE_PROJECT_MODULES = 'projectAdmin/RECEIVE_PROJECT_MODULES'; -const receiveProjectModules = (projectKey, modules) => ({ - type: RECEIVE_PROJECT_MODULES, - projectKey, - modules -}); - -export const fetchProjectModules = projectKey => dispatch => { - getTree({ component: projectKey, qualifiers: 'BRC', s: 'name', ps: 500 }).then( - r => { - dispatch(receiveProjectModules(projectKey, r.components)); - }, - () => {} - ); -}; - -export const CHANGE_KEY = 'projectAdmin/CHANGE_KEY'; -const changeKeyAction = (key, newKey) => ({ - type: CHANGE_KEY, - key, - newKey -}); - -export const changeKey = (key, newKey) => dispatch => { - return changeKeyApi(key, newKey).then( - () => dispatch(changeKeyAction(key, newKey)), - throwGlobalError - ); -}; diff --git a/server/sonar-web/src/main/js/apps/project-admin/store/components.js b/server/sonar-web/src/main/js/apps/project-admin/store/components.js deleted file mode 100644 index d8e238365db..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/store/components.js +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 { keyBy, omit } from 'lodash'; -import { RECEIVE_PROJECT_MODULES, CHANGE_KEY } from './actions'; - -const components = (state = {}, action = {}) => { - if (action.type === RECEIVE_PROJECT_MODULES) { - const newComponentsByKey = keyBy(action.modules, 'key'); - return { ...state, ...newComponentsByKey }; - } - - if (action.type === CHANGE_KEY) { - const oldComponent = state[action.key]; - if (oldComponent != null) { - const newComponent = { ...oldComponent, key: action.newKey }; - return { - ...omit(state, action.key), - [action.newKey]: newComponent - }; - } - } - - return state; -}; - -export default components; - -export const getComponentByKey = (state, key) => state[key]; diff --git a/server/sonar-web/src/main/js/apps/project-admin/store/modulesByProject.js b/server/sonar-web/src/main/js/apps/project-admin/store/modulesByProject.js deleted file mode 100644 index 9b5014be2d1..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/store/modulesByProject.js +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 { RECEIVE_PROJECT_MODULES, CHANGE_KEY } from './actions'; - -const modulesByProject = (state = {}, action = {}) => { - if (action.type === RECEIVE_PROJECT_MODULES) { - const moduleKeys = action.modules.map(module => module.key); - return { ...state, [action.projectKey]: moduleKeys }; - } - - if (action.type === CHANGE_KEY) { - const newState = {}; - Object.keys(state).forEach(projectKey => { - const moduleKeys = state[projectKey]; - const changedKeyIndex = moduleKeys.indexOf(action.key); - if (changedKeyIndex !== -1) { - const newModuleKeys = [...moduleKeys]; - newModuleKeys.splice(changedKeyIndex, 1, action.newKey); - newState[projectKey] = newModuleKeys; - } else { - newState[projectKey] = moduleKeys; - } - }); - return newState; - } - - return state; -}; - -export default modulesByProject; - -export const getProjectModules = (state, projectKey) => state[projectKey]; diff --git a/server/sonar-web/src/main/js/apps/project-admin/store/rootReducer.js b/server/sonar-web/src/main/js/apps/project-admin/store/rootReducer.js deleted file mode 100644 index 6bff2faed22..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/store/rootReducer.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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 { combineReducers } from 'redux'; -import components, { getComponentByKey as nextGetComponentByKey } from './components'; -import modulesByProject, { getProjectModules as nextGetProjectModules } from './modulesByProject'; - -const rootReducer = combineReducers({ - components, - modulesByProject -}); - -export default rootReducer; - -export const getComponentByKey = (state, componentKey) => - nextGetComponentByKey(state.components, componentKey); - -export const getProjectModules = (state, projectKey) => { - const moduleKeys = nextGetProjectModules(state.modulesByProject, projectKey); - if (moduleKeys == null) { - return null; - } - return moduleKeys.map(moduleKey => getComponentByKey(state, moduleKey)); -}; diff --git a/server/sonar-web/src/main/js/apps/projectKey/Key.tsx b/server/sonar-web/src/main/js/apps/projectKey/Key.tsx new file mode 100644 index 00000000000..38454a5bc00 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectKey/Key.tsx @@ -0,0 +1,55 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 { withRouter, WithRouterProps } from 'react-router'; +import UpdateForm from './UpdateForm'; +import { changeKey } from '../../api/components'; +import RecentHistory from '../../app/components/RecentHistory'; +import { translate } from '../../helpers/l10n'; + +interface Props { + component: Pick; +} + +export class Key extends React.PureComponent { + handleChangeKey = (newKey: string) => { + return changeKey({ from: this.props.component.key, to: newKey }).then(() => { + RecentHistory.remove(this.props.component.key); + this.props.router.replace({ pathname: '/project/key', query: { id: newKey } }); + }); + }; + + render() { + const { component } = this.props; + return ( +
+ +
+

{translate('update_key.page')}

+
{translate('update_key.page.description')}
+
+ +
+ ); + } +} + +export default withRouter(Key); diff --git a/server/sonar-web/src/main/js/apps/projectKey/UpdateForm.tsx b/server/sonar-web/src/main/js/apps/projectKey/UpdateForm.tsx new file mode 100644 index 00000000000..39dbe961d25 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectKey/UpdateForm.tsx @@ -0,0 +1,104 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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 { Button, SubmitButton } from '../../components/ui/buttons'; +import { translate, translateWithParameters } from '../../helpers/l10n'; +import ConfirmButton from '../../components/controls/ConfirmButton'; + +interface Props { + component: Pick; + onKeyChange: (newKey: string) => Promise; +} + +interface State { + newKey?: string; +} + +export default class UpdateForm extends React.PureComponent { + state: State = {}; + + handleChange = (event: React.ChangeEvent) => { + const newKey = event.currentTarget.value; + this.setState({ newKey }); + }; + + handleReset = () => { + this.setState({ newKey: undefined }); + }; + + render() { + const { component } = this.props; + const { newKey } = this.state; + const value = newKey != null ? newKey : component.key; + const hasChanged = value !== component.key; + + return ( + + {translateWithParameters('update_key.are_you_sure_to_change_key', component.name)} +
+ {translate('update_key.old_key')} + {': '} + {component.key} +
+
+ {translate('update_key.new_key')} + {': '} + {newKey} +
+ + } + modalHeader={translate('update_key.page')} + onConfirm={this.props.onKeyChange}> + {({ onFormSubmit }) => ( +
+ + +
+ + {translate('update_verb')} + + + +
+
+ )} +
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projectKey/__tests__/Key-test.tsx b/server/sonar-web/src/main/js/apps/projectKey/__tests__/Key-test.tsx new file mode 100644 index 00000000000..57c8aa569b4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectKey/__tests__/Key-test.tsx @@ -0,0 +1,42 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 { shallow } from 'enzyme'; +import { WithRouterProps } from 'react-router'; +import { Key } from '../Key'; +import { changeKey } from '../../../api/components'; + +jest.mock('../../../api/components', () => ({ + changeKey: jest.fn().mockResolvedValue(undefined) +})); + +it('should render and change key', async () => { + const withRouterProps = { router: { replace: jest.fn() } as any } as WithRouterProps; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + + wrapper.find('UpdateForm').prop('onKeyChange')('bar'); + await new Promise(setImmediate); + expect(changeKey).toBeCalledWith({ from: 'foo', to: 'bar' }); + expect(withRouterProps.router.replace).toBeCalledWith({ + pathname: '/project/key', + query: { id: 'bar' } + }); +}); diff --git a/server/sonar-web/src/main/js/apps/projectKey/__tests__/UpdateForm-test.tsx b/server/sonar-web/src/main/js/apps/projectKey/__tests__/UpdateForm-test.tsx new file mode 100644 index 00000000000..457575b7abf --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectKey/__tests__/UpdateForm-test.tsx @@ -0,0 +1,41 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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 { shallow, ShallowWrapper } from 'enzyme'; +import UpdateForm from '../UpdateForm'; +import { change, click } from '../../../helpers/testUtils'; + +it('should render', () => { + const wrapper = shallow( + + ); + expect(getInner(wrapper)).toMatchSnapshot(); + + change(getInner(wrapper).find('input'), 'bar'); + expect(getInner(wrapper)).toMatchSnapshot(); + + click(getInner(wrapper).find('Button')); + expect(getInner(wrapper)).toMatchSnapshot(); +}); + +function getInner(wrapper: ShallowWrapper) { + // TODO find a better way to do this + return wrapper.dive().dive(); +} diff --git a/server/sonar-web/src/main/js/apps/projectKey/__tests__/__snapshots__/Key-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectKey/__tests__/__snapshots__/Key-test.tsx.snap new file mode 100644 index 00000000000..da5365e6d5c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectKey/__tests__/__snapshots__/Key-test.tsx.snap @@ -0,0 +1,37 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render and change key 1`] = ` +
+ +
+

+ update_key.page +

+
+ update_key.page.description +
+
+ +
+`; diff --git a/server/sonar-web/src/main/js/apps/projectKey/__tests__/__snapshots__/UpdateForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectKey/__tests__/__snapshots__/UpdateForm-test.tsx.snap new file mode 100644 index 00000000000..0a009777e05 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectKey/__tests__/__snapshots__/UpdateForm-test.tsx.snap @@ -0,0 +1,112 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render 1`] = ` + +
+ +
+ + update_verb + + +
+
+
+`; + +exports[`should render 2`] = ` + +
+ +
+ + update_verb + + +
+
+
+`; + +exports[`should render 3`] = ` + +
+ +
+ + update_verb + + +
+
+
+`; diff --git a/server/sonar-web/src/main/js/components/SelectList/SelectListListContainer.tsx b/server/sonar-web/src/main/js/components/SelectList/SelectListListContainer.tsx index 96d969a33f7..829bee3f284 100644 --- a/server/sonar-web/src/main/js/components/SelectList/SelectListListContainer.tsx +++ b/server/sonar-web/src/main/js/components/SelectList/SelectListListContainer.tsx @@ -91,7 +91,7 @@ export default class SelectListListContainer extends React.PureComponent 0 && elements.length !== selectedElements.length}> - {translate('update_key.bulk_update')} + {translate('bulk_change')} diff --git a/server/sonar-web/src/main/js/store/rootReducer.ts b/server/sonar-web/src/main/js/store/rootReducer.ts index fa3890586fc..e4286c79a99 100644 --- a/server/sonar-web/src/main/js/store/rootReducer.ts +++ b/server/sonar-web/src/main/js/store/rootReducer.ts @@ -24,7 +24,6 @@ import languages, * as fromLanguages from './languages'; import metrics, * as fromMetrics from './metrics'; import organizations, * as fromOrganizations from './organizations'; import users, * as fromUsers from './users'; -import projectAdminApp, * as fromProjectAdminApp from '../apps/project-admin/store/rootReducer'; import settingsApp, * as fromSettingsApp from '../apps/settings/store/rootReducer'; export type Store = { @@ -36,7 +35,6 @@ export type Store = { users: fromUsers.State; // apps - projectAdminApp: any; settingsApp: any; }; @@ -49,7 +47,6 @@ export default combineReducers({ users, // apps - projectAdminApp, settingsApp }); @@ -128,7 +125,3 @@ export function isSettingsAppLoading(state: Store, key: string) { export function getSettingsAppValidationMessage(state: Store, key: string) { return fromSettingsApp.getValidationMessage(state.settingsApp, key); } - -export function getProjectAdminProjectModules(state: Store, projectKey: string) { - return fromProjectAdminApp.getProjectModules(state.projectAdminApp, projectKey); -} diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index ef551894203..dd4cb444f2d 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -514,7 +514,7 @@ project_quality_profiles.page.description=Choose which profile is associated wit project_quality_gate.page=Quality Gate project_quality_gate.page.description=Choose which quality gate is associated with this project. update_key.page=Update Key -update_key.page.description=Edit the keys of a project and/or its modules. Key changes must be made here BEFORE analyzing the project with the new keys, otherwise the analysis will simply create another project with the new key, rather than updating the existing project. +update_key.page.description=Edit the key of a project. Key changes must be made here BEFORE analyzing the project with the new keys, otherwise the analysis will simply create another project with the new key, rather than updating the existing project. deletion.page=Deletion project_deletion.page.description=Delete this project. The operation cannot be undone. portfolio_deletion.page.description=This portfolio and its sub-portfolios will be deleted. If this portfolio is referenced by other entities, it will be removed from them. Independent entities referenced by this portfolio, such as projects and other top-level portfolios will not be deleted. This operation cannot be undone. @@ -1075,27 +1075,12 @@ project_activity.custom_metric.covered_lines=Covered Lines #------------------------------------------------------------------------------ # -# PROJECT / MODULE "UPDATE KEY" PAGE +# PROJECT "UPDATE KEY" PAGE # #------------------------------------------------------------------------------ -update_key.bulk_update=Bulk Update -update_key.fine_grained_key_update=Fine-grained Update update_key.old_key=Old Key update_key.new_key=New Key -update_key.key_updated=The key has successfully been updated for all required resources. -update_key.key_updated.reload=The key has successfully been updated for all required resources. This page will be reloaded shortly. -update_key.bulk_change_description=The bulk update allows to replace a part of the current key(s) by another string on the current project and all its submodules - if applicable. -update_key.current_key_for_project_x_is_x=The key of the "{0}" project is currently "{1}". -update_key.replace=Replace -update_key.by=By -update_key.replace_example=org.myCompany -update_key.by_example=com.myNewCompany -update_key.cant_update_because_duplicate_keys=The replacement of "{0}" by "{1}" is impossible as it would result in duplicate keys (in red below): -update_key.keys_will_be_updated_as_follows=The resources will be updated as follows: -update_key.duplicate_key=Duplicate Key -update_key.no_key_to_update=No key contains the string to replace ("{0}"). -update_key.are_you_sure_to_change_key=Are you sure you want to change key of "{0}", as well as all its modules and resources? -update_key.see_results=See Results +update_key.are_you_sure_to_change_key=Are you sure you want to change key of "{0}"? #------------------------------------------------------------------------------