aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorStas Vilchik <stas-vilchik@users.noreply.github.com>2017-05-29 10:49:12 +0200
committerGitHub <noreply@github.com>2017-05-29 10:49:12 +0200
commitad8afa515b0dddeedd6a37e91c6bcda914d1c309 (patch)
treeea922cb64541274a8e97c3ea6ff9cac6700265a2 /server/sonar-web
parent306a72e5d602fc02085415848b7a40882e52559c (diff)
downloadsonarqube-ad8afa515b0dddeedd6a37e91c6bcda914d1c309.tar.gz
sonarqube-ad8afa515b0dddeedd6a37e91c6bcda914d1c309.zip
rework some modals (#2113)
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js20
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/ShortcutsHelp.js188
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/ShortcutsHelpView.js26
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/templates/nav-shortcuts-help.hbs70
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/ScannerContext.js102
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/Stacktrace.js114
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/TaskActions.js22
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/views/ScannerContextView.hbs17
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/views/ScannerContextView.js46
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/views/StacktraceView.hbs23
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/views/StacktraceView.js49
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/deletion/ConfirmationModal.js48
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/deletion/ConfirmationModalTemplate.hbs14
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/deletion/Form.js91
-rw-r--r--server/sonar-web/src/main/js/apps/settings/licenses/LicenseChangeForm.js75
-rw-r--r--server/sonar-web/src/main/js/apps/settings/licenses/LicenseRow.js8
-rw-r--r--server/sonar-web/src/main/js/apps/settings/licenses/LicenseValueView.hbs16
-rw-r--r--server/sonar-web/src/main/js/apps/settings/licenses/LicenseValueView.js41
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/licenses/actions.js6
19 files changed, 585 insertions, 391 deletions
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js
index 86ed0974c5c..2e2659d7125 100644
--- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js
+++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js
@@ -23,10 +23,12 @@ import GlobalNavBranding from './GlobalNavBranding';
import GlobalNavMenu from './GlobalNavMenu';
import GlobalNavUserContainer from './GlobalNavUserContainer';
import Search from '../../search/Search';
-import ShortcutsHelpView from './ShortcutsHelpView';
+import ShortcutsHelp from './ShortcutsHelp';
import { getCurrentUser, getAppState } from '../../../../store/rootReducer';
class GlobalNav extends React.PureComponent {
+ state = { helpOpen: false };
+
componentDidMount() {
window.addEventListener('keypress', this.onKeyPress);
}
@@ -46,13 +48,15 @@ class GlobalNav extends React.PureComponent {
}
};
- openHelp = e => {
- if (e) {
- e.preventDefault();
- }
- new ShortcutsHelpView().render();
+ handleHelpClick = event => {
+ event.preventDefault();
+ this.openHelp();
};
+ openHelp = () => this.setState({ helpOpen: true });
+
+ closeHelp = () => this.setState({ helpOpen: false });
+
render() {
/* eslint-disable max-len */
return (
@@ -65,7 +69,7 @@ class GlobalNav extends React.PureComponent {
<ul className="nav navbar-nav navbar-right">
<Search {...this.props} />
<li>
- <a className="navbar-help" onClick={this.openHelp} href="#">
+ <a className="navbar-help" onClick={this.handleHelpClick} href="#">
<svg width="16" height="16">
<g transform="matrix(0.0364583,0,0,0.0364583,1,-0.166667)">
<path
@@ -79,6 +83,8 @@ class GlobalNav extends React.PureComponent {
<GlobalNavUserContainer {...this.props} />
</ul>
</div>
+
+ {this.state.helpOpen && <ShortcutsHelp onClose={this.closeHelp} />}
</nav>
);
}
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/ShortcutsHelp.js b/server/sonar-web/src/main/js/app/components/nav/global/ShortcutsHelp.js
new file mode 100644
index 00000000000..273b370f17a
--- /dev/null
+++ b/server/sonar-web/src/main/js/app/components/nav/global/ShortcutsHelp.js
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ */
+// @flow
+import React from 'react';
+import Modal from 'react-modal';
+import { Link } from 'react-router';
+import { translate } from '../../../../helpers/l10n';
+
+type Props = {
+ onClose: () => void
+};
+
+export default class ShortcutsHelp extends React.PureComponent {
+ props: Props;
+
+ handleCloseClick = (event: Event) => {
+ event.preventDefault();
+ this.props.onClose();
+ };
+
+ render() {
+ return (
+ <Modal
+ isOpen={true}
+ contentLabel="shortcuts help"
+ className="modal modal-large"
+ overlayClassName="modal-overlay"
+ onRequestClose={this.props.onClose}>
+
+ <div className="modal-head">
+ <h2>{translate('help')}</h2>
+ </div>
+
+ <div className="modal-body modal-container">
+ <div className="spacer-bottom">
+ <a href="http://www.sonarqube.org">{translate('footer.community')}</a>{' - '}
+ <a href="https://redirect.sonarsource.com/doc/home.html">
+ {translate('footer.documentation')}
+ </a>
+ {' - '}
+ <a href="https://redirect.sonarsource.com/doc/community.html">
+ {translate('footer.support')}
+ </a>
+ {' - '}
+ <a href="https://redirect.sonarsource.com/doc/plugin-library.html">
+ {translate('footer.plugins')}
+ </a>
+ {' - '}
+ <Link to="/web_api" onClick={this.props.onClose}>{translate('footer.web_api')}</Link>
+ {' - '}
+ <Link to="/about" onClick={this.props.onClose}>{translate('footer.about')}</Link>
+ </div>
+
+ <h2 className="spacer-top spacer-bottom">{translate('shortcuts.modal_title')}</h2>
+
+ <div className="columns">
+ <div className="column-half">
+ <div className="spacer-bottom">
+ <h3 className="shortcuts-section-title">{translate('shortcuts.section.global')}</h3>
+ <ul className="shortcuts-list">
+ <li>
+ <span className="shortcut-button spacer-right">s</span>
+ {translate('shortcuts.section.global.search')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">?</span>
+ {translate('shortcuts.section.global.shortcuts')}
+ </li>
+ </ul>
+ </div>
+
+ <h3 className="shortcuts-section-title">{translate('shortcuts.section.rules')}</h3>
+ <ul className="shortcuts-list">
+ <li>
+ <span className="shortcut-button little-spacer-right">↑</span>
+ <span className="shortcut-button spacer-right">↓</span>
+ {translate('shortcuts.section.rules.navigate_between_rules')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">→</span>
+ {translate('shortcuts.section.rules.open_details')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">←</span>
+ {translate('shortcuts.section.rules.return_to_list')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">a</span>
+ {translate('shortcuts.section.rules.activate')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">d</span>
+ {translate('shortcuts.section.rules.deactivate')}
+ </li>
+ </ul>
+ </div>
+
+ <div className="column-half">
+ <h3 className="shortcuts-section-title">{translate('shortcuts.section.issues')}</h3>
+ <ul className="shortcuts-list">
+ <li>
+ <span className="shortcut-button little-spacer-right">↑</span>
+ <span className="shortcut-button spacer-right">↓</span>
+ {translate('shortcuts.section.issues.navigate_between_issues')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">→</span>
+ {translate('shortcuts.section.issues.open_details')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">←</span>
+ {translate('shortcuts.section.issues.return_to_list')}
+ </li>
+ <li>
+ <span className="shortcut-button little-spacer-right">alt</span>
+ <span className="little-spacer-right">+</span>
+ <span className="shortcut-button little-spacer-right">↑</span>
+ <span className="shortcut-button spacer-right">↓</span>
+ {translate('issues.to_navigate_issue_locations')}
+ </li>
+ <li>
+ <span className="shortcut-button little-spacer-right">alt</span>
+ <span className="little-spacer-right">+</span>
+ <span className="shortcut-button little-spacer-right">←</span>
+ <span className="shortcut-button spacer-right">→</span>
+ {translate('issues.to_switch_flows')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">f</span>
+ {translate('shortcuts.section.issue.do_transition')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">a</span>
+ {translate('shortcuts.section.issue.assign')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">m</span>
+ {translate('shortcuts.section.issue.assign_to_me')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">i</span>
+ {translate('shortcuts.section.issue.change_severity')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">c</span>
+ {translate('shortcuts.section.issue.comment')}
+ </li>
+ <li>
+ <span className="shortcut-button little-spacer-right">ctrl</span>
+ <span className="shortcut-button spacer-right">enter</span>
+ {translate('shortcuts.section.issue.submit_comment')}
+ </li>
+ <li>
+ <span className="shortcut-button spacer-right">t</span>
+ {translate('shortcuts.section.issue.change_tags')}
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div className="modal-foot">
+ <a className="js-modal-close" href="#" onClick={this.handleCloseClick}>
+ {translate('close')}
+ </a>
+ </div>
+
+ </Modal>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/ShortcutsHelpView.js b/server/sonar-web/src/main/js/app/components/nav/global/ShortcutsHelpView.js
deleted file mode 100644
index 893e4930ad6..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/global/ShortcutsHelpView.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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 ModalView from '../../../../components/common/modals';
-import ShortcutsHelpTemplate from '../templates/nav-shortcuts-help.hbs';
-
-export default ModalView.extend({
- className: 'modal modal-large',
- template: ShortcutsHelpTemplate
-});
diff --git a/server/sonar-web/src/main/js/app/components/nav/templates/nav-shortcuts-help.hbs b/server/sonar-web/src/main/js/app/components/nav/templates/nav-shortcuts-help.hbs
deleted file mode 100644
index 00f5519d887..00000000000
--- a/server/sonar-web/src/main/js/app/components/nav/templates/nav-shortcuts-help.hbs
+++ /dev/null
@@ -1,70 +0,0 @@
-<div class="modal-head">
- <h2>{{t 'help'}}</h2>
-</div>
-
-<div class="modal-body modal-container">
- <div class="spacer-bottom">
- <a href="http://www.sonarqube.org">Community</a> -
- <a href="https://redirect.sonarsource.com/doc/home.html">Documentation</a> -
- <a href="https://redirect.sonarsource.com/doc/community.html">Get Support</a> -
- <a href="https://redirect.sonarsource.com/doc/plugin-library.html">Plugins</a> -
- <a href="{{link '/web_api'}}">Web API</a> -
- <a href="{{link '/about'}}">About</a>
- </div>
-
- <h2 class="spacer-top spacer-bottom">{{t 'shortcuts.modal_title'}}</h2>
-
- <div class="columns">
- <div class="column-half">
- <div class="spacer-bottom">
- <h3 class="shortcuts-section-title">{{t 'shortcuts.section.global'}}</h3>
- <ul class="shortcuts-list">
- <li><span class="shortcut-button">s</span> &nbsp;&nbsp; {{t 'shortcuts.section.global.search'}}</li>
- <li><span class="shortcut-button">?</span> &nbsp;&nbsp; {{t 'shortcuts.section.global.shortcuts'}}</li>
- </ul>
- </div>
-
- <h3 class="shortcuts-section-title">{{t 'shortcuts.section.rules'}}</h3>
- <ul class="shortcuts-list">
- <li><span class="shortcut-button">&uarr;</span> <span class="shortcut-button">&darr;</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.navigate_between_rules'}}</li>
- <li><span class="shortcut-button">&rarr;</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.open_details'}}</li>
- <li><span class="shortcut-button">&larr;</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.return_to_list'}}</li>
- <li><span class="shortcut-button">a</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.activate'}}</li>
- <li><span class="shortcut-button">d</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.deactivate'}}</li>
- </ul>
- </div>
-
- <div class="column-half">
- <h3 class="shortcuts-section-title">{{t 'shortcuts.section.issues'}}</h3>
- <ul class="shortcuts-list">
- <li><span class="shortcut-button">&uarr;</span> <span class="shortcut-button">&darr;</span> &nbsp;&nbsp; {{t 'shortcuts.section.issues.navigate_between_issues'}}
- </li>
- <li><span class="shortcut-button">&rarr;</span> &nbsp;&nbsp; {{t 'shortcuts.section.issues.open_details'}}</li>
- <li><span class="shortcut-button">&larr;</span> &nbsp;&nbsp; {{t 'shortcuts.section.issues.return_to_list'}}</li>
- <li>
- <span class="shortcut-button">alt</span>
- <span class=>+</span>
- <span class="shortcut-button">↑</span>
- <span class="shortcut-button">↓</span> {{t 'issues.to_navigate_issue_locations'}}
- </li>
- <li>
- <span class="shortcut-button">alt</span>
- <span class=>+</span>
- <span class="shortcut-button">←</span>
- <span class="shortcut-button">→</span> {{t 'issues.to_switch_flows'}}
- </li>
- <li><span class="shortcut-button">f</span> &nbsp;&nbsp; {{t 'shortcuts.section.issue.do_transition'}}</li>
- <li><span class="shortcut-button">a</span> &nbsp;&nbsp; {{t 'shortcuts.section.issue.assign'}}</li>
- <li><span class="shortcut-button">m</span> &nbsp;&nbsp; {{t 'shortcuts.section.issue.assign_to_me'}}</li>
- <li><span class="shortcut-button">i</span> &nbsp;&nbsp; {{t 'shortcuts.section.issue.change_severity'}}</li>
- <li><span class="shortcut-button">c</span> &nbsp;&nbsp; {{t 'shortcuts.section.issue.comment'}}</li>
- <li><span class="shortcut-button">ctrl</span> + <span class="shortcut-button">enter</span> &nbsp;&nbsp; {{t 'shortcuts.section.issue.submit_comment'}}</li>
- <li><span class="shortcut-button">t</span> &nbsp;&nbsp; {{t 'shortcuts.section.issue.change_tags'}}</li>
- </ul>
- </div>
- </div>
-</div>
-
-<div class="modal-foot">
- <a class="js-modal-close" href="#">{{t 'close'}}</a>
-</div> \ No newline at end of file
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/ScannerContext.js b/server/sonar-web/src/main/js/apps/background-tasks/components/ScannerContext.js
new file mode 100644
index 00000000000..f83644560cc
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/ScannerContext.js
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+// @flow
+import React from 'react';
+import Modal from 'react-modal';
+import { getTask } from '../../../api/ce';
+import { translate } from '../../../helpers/l10n';
+
+type Props = {
+ onClose: () => void,
+ task: { componentName: string, id: string, type: string }
+};
+
+type State = {
+ scannerContext: ?string
+};
+
+export default class ScannerContext extends React.PureComponent {
+ mounted: boolean;
+ props: Props;
+ state: State = {
+ scannerContext: null
+ };
+
+ componentDidMount() {
+ this.mounted = true;
+ this.loadScannerContext();
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ loadScannerContext() {
+ getTask(this.props.task.id, ['scannerContext']).then(task => {
+ if (this.mounted) {
+ this.setState({ scannerContext: task.scannerContext });
+ }
+ });
+ }
+
+ handleCloseClick = (event: Event) => {
+ event.preventDefault();
+ this.props.onClose();
+ };
+
+ render() {
+ const { task } = this.props;
+ const { scannerContext } = this.state;
+
+ return (
+ <Modal
+ isOpen={true}
+ contentLabel="scanner context"
+ className="modal modal-large"
+ overlayClassName="modal-overlay"
+ onRequestClose={this.props.onClose}>
+
+ <div className="modal-head">
+ <h2>
+ {translate('background_tasks.scanner_context')}
+ {': '}
+ {task.componentName}
+ {' ['}
+ {translate('background_task.type', task.type)}
+ {']'}
+ </h2>
+ </div>
+
+ <div className="modal-body modal-container">
+ {scannerContext != null
+ ? <pre className="js-task-scanner-context">{scannerContext}</pre>
+ : <i className="spinner" />}
+ </div>
+
+ <div className="modal-foot">
+ <a href="#" className="js-modal-close" onClick={this.handleCloseClick}>
+ {translate('close')}
+ </a>
+ </div>
+
+ </Modal>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Stacktrace.js b/server/sonar-web/src/main/js/apps/background-tasks/components/Stacktrace.js
new file mode 100644
index 00000000000..d6da81e314c
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/Stacktrace.js
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+// @flow
+import React from 'react';
+import Modal from 'react-modal';
+import { getTask } from '../../../api/ce';
+import { translate } from '../../../helpers/l10n';
+
+type Props = {
+ onClose: () => void,
+ task: { componentName: string, errorMessage: string, id: string, type: string }
+};
+
+type State = {
+ loading: boolean,
+ stacktrace: ?string
+};
+
+export default class Stacktrace extends React.PureComponent {
+ mounted: boolean;
+ props: Props;
+ state: State = {
+ loading: true,
+ stacktrace: null
+ };
+
+ componentDidMount() {
+ this.mounted = true;
+ this.loadStacktrace();
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ loadStacktrace() {
+ getTask(this.props.task.id, ['stacktrace']).then(task => {
+ if (this.mounted) {
+ this.setState({ loading: false, stacktrace: task.errorStacktrace });
+ }
+ });
+ }
+
+ handleCloseClick = (event: Event) => {
+ event.preventDefault();
+ this.props.onClose();
+ };
+
+ render() {
+ const { task } = this.props;
+ const { loading, stacktrace } = this.state;
+
+ return (
+ <Modal
+ isOpen={true}
+ contentLabel="stacktrace"
+ className="modal modal-large"
+ overlayClassName="modal-overlay"
+ onRequestClose={this.props.onClose}>
+
+ <div className="modal-head">
+ <h2>
+ {translate('background_tasks.error_stacktrace')}
+ {': '}
+ {task.componentName}
+ {' ['}
+ {translate('background_task.type', task.type)}
+ {']'}
+ </h2>
+ </div>
+
+ <div className="modal-body modal-container">
+ {loading
+ ? <i className="spinner" />
+ : stacktrace
+ ? <div>
+ <h4 className="spacer-bottom">
+ {translate('background_tasks.error_stacktrace')}
+ </h4>
+ <pre className="js-task-stacktrace">{stacktrace}</pre>
+ </div>
+ : <div>
+ <h4 className="spacer-bottom">{translate('background_tasks.error_message')}</h4>
+ <pre className="js-task-error-message">{task.errorMessage}</pre>
+ </div>}
+ </div>
+
+ <div className="modal-foot">
+ <a href="#" className="js-modal-close" onClick={this.handleCloseClick}>
+ {translate('close')}
+ </a>
+ </div>
+
+ </Modal>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskActions.js b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskActions.js
index 1acde211d5f..03b8be8455d 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskActions.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskActions.js
@@ -18,12 +18,17 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import ScannerContextView from '../views/ScannerContextView';
-import StacktraceView from '../views/StacktraceView';
+import ScannerContext from './ScannerContext';
+import Stacktrace from './Stacktrace';
import { STATUSES } from './../constants';
import { translate, translateWithParameters } from '../../../helpers/l10n';
export default class TaskActions extends React.PureComponent {
+ state = {
+ scannerContextOpen: false,
+ stacktraceOpen: false
+ };
+
handleFilterClick(e) {
e.preventDefault();
this.props.onFilterTask(this.props.task);
@@ -36,14 +41,18 @@ export default class TaskActions extends React.PureComponent {
handleShowScannerContextClick(e) {
e.preventDefault();
- new ScannerContextView({ task: this.props.task }).render();
+ this.setState({ scannerContextOpen: true });
}
+ closeScannerContext = () => this.setState({ scannerContextOpen: false });
+
handleShowStacktraceClick(e) {
e.preventDefault();
- new StacktraceView({ task: this.props.task }).render();
+ this.setState({ stacktraceOpen: true });
}
+ closeStacktrace = () => this.setState({ stacktraceOpen: false });
+
render() {
const { component, task } = this.props;
@@ -102,6 +111,11 @@ export default class TaskActions extends React.PureComponent {
</li>}
</ul>
</div>
+
+ {this.state.scannerContextOpen &&
+ <ScannerContext onClose={this.closeScannerContext} task={task} />}
+
+ {this.state.stacktraceOpen && <Stacktrace onClose={this.closeStacktrace} task={task} />}
</td>
);
}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/views/ScannerContextView.hbs b/server/sonar-web/src/main/js/apps/background-tasks/views/ScannerContextView.hbs
deleted file mode 100644
index d1de3da84c7..00000000000
--- a/server/sonar-web/src/main/js/apps/background-tasks/views/ScannerContextView.hbs
+++ /dev/null
@@ -1,17 +0,0 @@
-<form id="deactivate-user-form" autocomplete="off">
- <div class="modal-head">
- <h2>{{t 'background_tasks.scanner_context'}}: {{task.componentName}} [{{t 'background_task.type' task.type}}]</h2>
- </div>
- <div class="modal-body modal-container">
- <div class="js-modal-messages"></div>
-
- {{#if scannerContext}}
- <pre class="js-task-scanner-context">{{scannerContext}}</pre>
- {{else}}
- <i class="spinner"></i>
- {{/if}}
- </div>
- <div class="modal-foot">
- <a href="#" class="js-modal-close">{{t 'close'}}</a>
- </div>
-</form>
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/views/ScannerContextView.js b/server/sonar-web/src/main/js/apps/background-tasks/views/ScannerContextView.js
deleted file mode 100644
index ef35cf57125..00000000000
--- a/server/sonar-web/src/main/js/apps/background-tasks/views/ScannerContextView.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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 Modal from '../../../components/common/modals';
-import Template from './ScannerContextView.hbs';
-import { getTask } from '../../../api/ce';
-
-export default Modal.extend({
- template: Template,
- className: 'modal modal-large',
-
- initialize() {
- this.scannerContext = null;
- this.loadScannerContext();
- },
-
- loadScannerContext() {
- getTask(this.options.task.id, ['scannerContext']).then(task => {
- this.scannerContext = task.scannerContext;
- this.render();
- });
- },
-
- serializeData() {
- return {
- task: this.options.task,
- scannerContext: this.scannerContext
- };
- }
-});
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/views/StacktraceView.hbs b/server/sonar-web/src/main/js/apps/background-tasks/views/StacktraceView.hbs
deleted file mode 100644
index 21ce604acb2..00000000000
--- a/server/sonar-web/src/main/js/apps/background-tasks/views/StacktraceView.hbs
+++ /dev/null
@@ -1,23 +0,0 @@
-<form id="deactivate-user-form" autocomplete="off">
- <div class="modal-head">
- <h2>{{t 'background_tasks.error_stacktrace'}}: {{task.componentName}} [{{t 'background_task.type' task.type}}]</h2>
- </div>
- <div class="modal-body modal-container">
- <div class="js-modal-messages"></div>
-
- {{#if loaded}}
- {{#if stacktrace}}
- <h4 class="spacer-bottom">{{t 'background_tasks.error_stacktrace'}}</h4>
- <pre class="js-task-stacktrace">{{stacktrace}}</pre>
- {{else}}
- <h4 class="spacer-bottom">{{t 'background_tasks.error_message'}}</h4>
- <pre class="js-task-error-message">{{task.errorMessage}}</pre>
- {{/if}}
- {{else}}
- <i class="spinner"></i>
- {{/if}}
- </div>
- <div class="modal-foot">
- <a href="#" class="js-modal-close">{{t 'close'}}</a>
- </div>
-</form>
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/views/StacktraceView.js b/server/sonar-web/src/main/js/apps/background-tasks/views/StacktraceView.js
deleted file mode 100644
index 866d9a487eb..00000000000
--- a/server/sonar-web/src/main/js/apps/background-tasks/views/StacktraceView.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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 Modal from '../../../components/common/modals';
-import Template from './StacktraceView.hbs';
-import { getTask } from '../../../api/ce';
-
-export default Modal.extend({
- template: Template,
- className: 'modal modal-large',
-
- initialize() {
- this.loaded = false;
- this.stacktrace = null;
- this.loadStacktrace();
- },
-
- loadStacktrace() {
- getTask(this.options.task.id, ['stacktrace']).then(task => {
- this.loaded = true;
- this.stacktrace = task.errorStacktrace;
- this.render();
- });
- },
-
- serializeData() {
- return {
- task: this.options.task,
- stacktrace: this.stacktrace,
- loaded: this.loaded
- };
- }
-});
diff --git a/server/sonar-web/src/main/js/apps/project-admin/deletion/ConfirmationModal.js b/server/sonar-web/src/main/js/apps/project-admin/deletion/ConfirmationModal.js
deleted file mode 100644
index 273850ea38b..00000000000
--- a/server/sonar-web/src/main/js/apps/project-admin/deletion/ConfirmationModal.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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 ModalForm from '../../../components/common/modal-form';
-import Template from './ConfirmationModalTemplate.hbs';
-import { deleteProject } from '../../../api/components';
-
-export default ModalForm.extend({
- template: Template,
-
- onFormSubmit() {
- ModalForm.prototype.onFormSubmit.apply(this, arguments);
- this.disableForm();
- this.showSpinner();
-
- deleteProject(this.options.project.key)
- .then(() => {
- this.trigger('done');
- })
- .catch(function(e) {
- e.response.json().then(r => {
- this.hideSpinner();
- this.showErrors(r.errors, r.warnings);
- this.enableForm();
- });
- });
- },
-
- serializeData() {
- return { project: this.options.project };
- }
-});
diff --git a/server/sonar-web/src/main/js/apps/project-admin/deletion/ConfirmationModalTemplate.hbs b/server/sonar-web/src/main/js/apps/project-admin/deletion/ConfirmationModalTemplate.hbs
deleted file mode 100644
index 749e408d5bc..00000000000
--- a/server/sonar-web/src/main/js/apps/project-admin/deletion/ConfirmationModalTemplate.hbs
+++ /dev/null
@@ -1,14 +0,0 @@
-<form id="deactivate-user-form" autocomplete="off">
- <div class="modal-head">
- <h2>{{t 'qualifiers.delete.TRK'}}</h2>
- </div>
- <div class="modal-body">
- <div class="js-modal-messages"></div>
- {{tp 'project_deletion.delete_resource_confirmation' project.name}}
- </div>
- <div class="modal-foot">
- <i class="js-modal-spinner spinner spacer-right hidden"></i>
- <button id="delete-project-confirm" class="button-red">{{t 'delete'}}</button>
- <a href="#" class="js-modal-close">{{t 'cancel'}}</a>
- </div>
-</form>
diff --git a/server/sonar-web/src/main/js/apps/project-admin/deletion/Form.js b/server/sonar-web/src/main/js/apps/project-admin/deletion/Form.js
index 1a848accaee..ac8ca55598b 100644
--- a/server/sonar-web/src/main/js/apps/project-admin/deletion/Form.js
+++ b/server/sonar-web/src/main/js/apps/project-admin/deletion/Form.js
@@ -18,30 +18,97 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import ConfirmationModal from './ConfirmationModal';
-import { translate } from '../../../helpers/l10n';
+import Modal from 'react-modal';
+import { deleteProject } from '../../../api/components';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
export default class Form extends React.PureComponent {
static propTypes = {
component: React.PropTypes.object.isRequired
};
- handleDelete(e) {
- e.preventDefault();
- new ConfirmationModal({ project: this.props.component })
- .on('done', () => {
- window.location = window.baseUrl + '/';
- })
- .render();
+ static contextTypes = {
+ router: React.PropTypes.object
+ };
+
+ state = { loading: false, modalOpen: false };
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
}
+ handleDeleteClick = event => {
+ event.preventDefault();
+ this.setState({ modalOpen: true });
+ };
+
+ closeModal = () => this.setState({ modalOpen: false });
+
+ stopLoading = () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ };
+
+ handleSubmit = event => {
+ event.preventDefault();
+ this.setState({ loading: true });
+ deleteProject(this.props.component.key)
+ .then(() => this.context.router.replace('/'))
+ .catch(this.stopLoading);
+ };
+
+ handleCloseClick = (event: Event) => {
+ event.preventDefault();
+ this.closeModal();
+ };
+
render() {
+ const { component } = this.props;
+
return (
- <form onSubmit={this.handleDelete.bind(this)}>
- <button id="delete-project" className="button-red">
+ <div>
+ <button id="delete-project" className="button-red" onClick={this.handleDeleteClick}>
{translate('delete')}
</button>
- </form>
+
+ {this.state.modalOpen &&
+ <Modal
+ isOpen={true}
+ contentLabel="project deletion"
+ className="modal"
+ overlayClassName="modal-overlay"
+ onRequestClose={this.closeModal}>
+ <form onSubmit={this.handleSubmit}>
+ <div className="modal-head">
+ <h2>{translate('qualifiers.delete.TRK')}</h2>
+ </div>
+ <div className="modal-body">
+ <div className="js-modal-messages" />
+ {translateWithParameters(
+ 'project_deletion.delete_resource_confirmation',
+ component.name
+ )}
+ </div>
+ <div className="modal-foot">
+ {this.state.loading && <i className="js-modal-spinner spinner spacer-right" />}
+ <button
+ id="delete-project-confirm"
+ className="button-red"
+ disabled={this.state.loading}>
+ {translate('delete')}
+ </button>
+ <a href="#" className="js-modal-close" onClick={this.handleCloseClick}>
+ {translate('cancel')}
+ </a>
+ </div>
+ </form>
+ </Modal>}
+ </div>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseChangeForm.js b/server/sonar-web/src/main/js/apps/settings/licenses/LicenseChangeForm.js
index e3e443e51b6..ff068c49d98 100644
--- a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseChangeForm.js
+++ b/server/sonar-web/src/main/js/apps/settings/licenses/LicenseChangeForm.js
@@ -18,8 +18,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import LicenseValueView from './LicenseValueView';
-import { translate } from '../../../helpers/l10n';
+import Modal from 'react-modal';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
export default class LicenseChangeForm extends React.PureComponent {
static propTypes = {
@@ -27,23 +27,80 @@ export default class LicenseChangeForm extends React.PureComponent {
onChange: React.PropTypes.func.isRequired
};
+ state = {
+ loading: false,
+ modalOpen: false
+ };
+
onClick(e) {
e.preventDefault();
e.target.blur();
+ this.setState({ modalOpen: true });
+ }
- const { license, onChange } = this.props;
+ closeModal = () => this.setState({ modalOpen: false });
- new LicenseValueView({
- productName: license.name || license.key,
- value: license.value,
- onChange
- }).render();
- }
+ handleSubmit = event => {
+ event.preventDefault();
+ if (this.textarea) {
+ const { value } = this.textarea;
+ this.setState({ loading: true });
+ this.props
+ .onChange(value)
+ .then(
+ () => this.setState({ loading: false, modalOpen: false }),
+ () => this.setState({ loading: false })
+ );
+ }
+ };
+
+ handleCancelClick = event => {
+ event.preventDefault();
+ this.closeModal();
+ };
render() {
+ const { license } = this.props;
+ const productName = license.name || license.key;
+
return (
<button className="js-change" onClick={e => this.onClick(e)}>
{translate('update_verb')}
+
+ {this.state.modalOpen &&
+ <Modal
+ isOpen={true}
+ contentLabel="license update"
+ className="modal"
+ overlayClassName="modal-overlay"
+ onRequestClose={this.closeModal}>
+ <form onSubmit={this.handleSubmit}>
+ <div className="modal-head">
+ <h2>{translateWithParameters('licenses.update_license_for_x', productName)}</h2>
+ </div>
+ <div className="modal-body">
+ <label htmlFor="license-input">{translate('licenses.license_input_label')}</label>
+ <textarea
+ autoFocus={true}
+ className="width-100 spacer-top"
+ ref={node => (this.textarea = node)}
+ rows="7"
+ id="license-input"
+ defaultValue={license.value}
+ />
+ <div className="spacer-top note">{translate('licenses.license_input_note')}</div>
+ </div>
+ <div className="modal-foot">
+ {this.state.loading && <i className="js-modal-spinner spinner spacer-right" />}
+ <button className="js-modal-submit" disabled={this.state.loading}>
+ {translate('save')}
+ </button>
+ <a href="#" className="js-modal-close" onClick={this.handleCancelClick}>
+ {translate('cancel')}
+ </a>
+ </div>
+ </form>
+ </Modal>}
</button>
);
}
diff --git a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRow.js b/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRow.js
index 94f12ae7720..9a5a332ac20 100644
--- a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRow.js
+++ b/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRow.js
@@ -28,11 +28,7 @@ export default class LicenseRow extends React.PureComponent {
setLicense: React.PropTypes.func.isRequired
};
- handleSet(value) {
- return this.props.setLicense(this.props.license.key, value).catch(() => {
- /* do nothing */
- });
- }
+ handleSet = value => this.props.setLicense(this.props.license.key, value);
render() {
const { license } = this.props;
@@ -59,7 +55,7 @@ export default class LicenseRow extends React.PureComponent {
</div>
</td>
<td className="text-right">
- <LicenseChangeForm license={license} onChange={value => this.handleSet(value)} />
+ <LicenseChangeForm license={license} onChange={this.handleSet} />
</td>
</tr>
);
diff --git a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseValueView.hbs b/server/sonar-web/src/main/js/apps/settings/licenses/LicenseValueView.hbs
deleted file mode 100644
index c4aab7ea6f7..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseValueView.hbs
+++ /dev/null
@@ -1,16 +0,0 @@
-<form>
- <div class="modal-head">
- <h2>{{tp 'licenses.update_license_for_x' productName}}</h2>
- </div>
- <div class="modal-body">
- <div class="js-modal-messages"></div>
- <label for="license-input">{{t 'licenses.license_input_label'}}</label>
- <textarea class="width-100 spacer-top" rows="7" id="license-input">{{value}}</textarea>
- <div class="spacer-top note">{{t 'licenses.license_input_note'}}</div>
- </div>
- <div class="modal-foot">
- <i class="js-modal-spinner spinner spacer-right hidden"></i>
- <button class="js-modal-submit">{{t 'save'}}</button>
- <a href="#" class="js-modal-close">{{t 'cancel'}}</a>
- </div>
-</form>
diff --git a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseValueView.js b/server/sonar-web/src/main/js/apps/settings/licenses/LicenseValueView.js
deleted file mode 100644
index 22b4e3a155b..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseValueView.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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 ModalForm from '../../../components/common/modal-form';
-import Template from './LicenseValueView.hbs';
-
-export default ModalForm.extend({
- template: Template,
-
- onFormSubmit() {
- ModalForm.prototype.onFormSubmit.apply(this, arguments);
- this.disableForm();
- this.showSpinner();
-
- const value = this.$('textarea').val();
- this.options.onChange(value).then(() => this.destroy());
- },
-
- serializeData() {
- return {
- productName: this.options.productName,
- value: this.options.value
- };
- }
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/store/licenses/actions.js b/server/sonar-web/src/main/js/apps/settings/store/licenses/actions.js
index c24cae2d6d2..9ef043c73c7 100644
--- a/server/sonar-web/src/main/js/apps/settings/store/licenses/actions.js
+++ b/server/sonar-web/src/main/js/apps/settings/store/licenses/actions.js
@@ -56,7 +56,7 @@ export const setLicense = (key, value) => dispatch => {
const request = value ? licenses.setLicense(key, value) : licenses.resetLicense(key);
return request
- .then(() => {
+ .then(() =>
licenses.getLicenses().then(licenses => {
dispatch(receiveLicenses(licenses));
if (isLicenseFromListInvalid(licenses, key)) {
@@ -64,7 +64,7 @@ export const setLicense = (key, value) => dispatch => {
} else {
dispatch(addGlobalSuccessMessage(translate('licenses.success_message')));
}
- });
- })
+ })
+ )
.catch(handleError(dispatch));
};