aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps
diff options
context:
space:
mode:
authorStas Vilchik <vilchiks@gmail.com>2016-11-21 10:03:40 +0100
committerStas Vilchik <vilchiks@gmail.com>2016-11-28 13:39:04 +0100
commit3a34147be1e725f71b8e102ba53b1f5b9bd10b13 (patch)
tree16ab51c591f124cf0e34a7005361392493a6ebc5 /server/sonar-web/src/main/js/apps
parentbd96be1c6c971381952dff396e0e10ae9233a6b7 (diff)
downloadsonarqube-3a34147be1e725f71b8e102ba53b1f5b9bd10b13.tar.gz
sonarqube-3a34147be1e725f71b8e102ba53b1f5b9bd10b13.zip
step towards a single-entry-point js app (#1362)
Diffstat (limited to 'server/sonar-web/src/main/js/apps')
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js5
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/routes.js26
-rw-r--r--server/sonar-web/src/main/js/apps/code/app.js44
-rw-r--r--server/sonar-web/src/main/js/apps/code/components/ComponentName.js6
-rw-r--r--server/sonar-web/src/main/js/apps/code/components/Search.js2
-rw-r--r--server/sonar-web/src/main/js/apps/code/routes.js (renamed from server/sonar-web/src/main/js/apps/markdown/markdown-help-view.js)12
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/app.js99
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js (renamed from server/sonar-web/src/main/js/apps/overview/app.js)18
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/init.js94
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/routes.js26
-rw-r--r--server/sonar-web/src/main/js/apps/component-issues/components/ComponentIssuesAppContainer.js31
-rw-r--r--server/sonar-web/src/main/js/apps/component-issues/init.js (renamed from server/sonar-web/src/main/js/apps/component-issues/app.js)12
-rw-r--r--server/sonar-web/src/main/js/apps/component-issues/routes.js26
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/app.js81
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/app/App.js1
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/app/AppContainer.js9
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/app/actions.js9
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/app/reducer.js4
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/MeasureBubbleChartContainer.js6
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetails.js4
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsContainer.js21
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/details/actions.js9
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListViewContainer.js31
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureDrilldown.js33
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeViewContainer.js48
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/details/history/MeasureHistoryContainer.js6
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemapContainer.js6
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresContainer.js12
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasuresContainer.js12
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/home/Home.js4
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/home/HomeContainer.js12
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/home/MeasuresList.js2
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/home/actions.js8
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/routes.js49
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/store/configureStore.js41
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/store/listViewActions.js11
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/store/rootReducer.js116
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/store/statusActions.js4
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/store/treeViewActions.js21
-rw-r--r--server/sonar-web/src/main/js/apps/custom-measures/components/CustomMeasuresAppContainer.js39
-rw-r--r--server/sonar-web/src/main/js/apps/custom-measures/init.js (renamed from server/sonar-web/src/main/js/apps/custom-measures/app.js)16
-rw-r--r--server/sonar-web/src/main/js/apps/custom-measures/routes.js26
-rw-r--r--server/sonar-web/src/main/js/apps/groups/components/GroupsAppContainer.js31
-rw-r--r--server/sonar-web/src/main/js/apps/groups/init.js (renamed from server/sonar-web/src/main/js/apps/groups/app.js)14
-rw-r--r--server/sonar-web/src/main/js/apps/groups/routes.js26
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/IssuesAppContainer.js31
-rw-r--r--server/sonar-web/src/main/js/apps/issues/init.js (renamed from server/sonar-web/src/main/js/apps/issues/app.js)14
-rw-r--r--server/sonar-web/src/main/js/apps/issues/routes.js26
-rw-r--r--server/sonar-web/src/main/js/apps/maintenance/components/MaintenanceAppContainer.js31
-rw-r--r--server/sonar-web/src/main/js/apps/maintenance/components/SetupAppContainer.js (renamed from server/sonar-web/src/main/js/apps/markdown/app.js)20
-rw-r--r--server/sonar-web/src/main/js/apps/maintenance/init.js (renamed from server/sonar-web/src/main/js/apps/maintenance/app.js)8
-rw-r--r--server/sonar-web/src/main/js/apps/maintenance/routes.js31
-rw-r--r--server/sonar-web/src/main/js/apps/markdown/templates/markdown-help.hbs100
-rw-r--r--server/sonar-web/src/main/js/apps/metrics/components/MetricsAppContainer.js31
-rw-r--r--server/sonar-web/src/main/js/apps/metrics/init.js (renamed from server/sonar-web/src/main/js/apps/metrics/app.js)14
-rw-r--r--server/sonar-web/src/main/js/apps/metrics/routes.js26
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/AppContainer.js (renamed from server/sonar-web/src/main/js/apps/permissions/global/app.js)36
-rw-r--r--server/sonar-web/src/main/js/apps/overview/routes.js28
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/ActionsCell.js2
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/AppContainer.js41
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/NameCell.js2
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/TemplateHeader.js2
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/routes.js26
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.js40
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/global/components/PageHeader.js4
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/global/store/actions.js49
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/components/AllHoldersList.js40
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/components/App.js10
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.js4
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/store/actions.js49
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/routes.js31
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.js4
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/store/actions.js13
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/store/error.js21
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/store/filter.js4
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/store/groups/byName.js7
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/store/groups/names.js4
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/store/loading.js6
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/store/query.js6
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/store/selectedPermission.js4
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/store/users/byLogin.js7
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/shared/store/users/logins.js4
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/app.js66
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/components/GlobalMessagesContainer.js4
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/deletion/Deletion.js6
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/key/BulkUpdate.js2
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/key/Key.js6
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/links/Links.js4
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/quality-gate/QualityGate.js6
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/quality-profiles/QualityProfiles.js6
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/routes.js (renamed from server/sonar-web/src/main/js/apps/projects-admin/app.js)25
-rw-r--r--server/sonar-web/src/main/js/apps/project-admin/store/actions.js26
-rw-r--r--server/sonar-web/src/main/js/apps/projects-admin/AppContainer.js (renamed from server/sonar-web/src/main/js/apps/background-tasks/app.js)46
-rw-r--r--server/sonar-web/src/main/js/apps/projects-admin/routes.js26
-rw-r--r--server/sonar-web/src/main/js/apps/projects/routes.js2
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/routes.js2
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/routes.js2
-rw-r--r--server/sonar-web/src/main/js/apps/settings/app.js56
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js4
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/App.js4
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/AppContainer.js40
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.js4
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/Definition.js12
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/GlobalMessagesContainer.js4
-rw-r--r--server/sonar-web/src/main/js/apps/settings/encryption/EncryptionAppContainer.js4
-rw-r--r--server/sonar-web/src/main/js/apps/settings/licenses/LicenseRowContainer.js4
-rw-r--r--server/sonar-web/src/main/js/apps/settings/licenses/LicensesListContainer.js4
-rw-r--r--server/sonar-web/src/main/js/apps/settings/routes.js (renamed from server/sonar-web/src/main/js/apps/permission-templates/app.js)35
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/actions.js6
-rw-r--r--server/sonar-web/src/main/js/apps/system/routes.js (renamed from server/sonar-web/src/main/js/apps/system/app.js)11
-rw-r--r--server/sonar-web/src/main/js/apps/update-center/components/UpdateCenterAppContainer.js31
-rw-r--r--server/sonar-web/src/main/js/apps/update-center/init.js (renamed from server/sonar-web/src/main/js/apps/update-center/app.js)17
-rw-r--r--server/sonar-web/src/main/js/apps/update-center/routes.js (renamed from server/sonar-web/src/main/js/apps/permissions/project/app.js)23
-rw-r--r--server/sonar-web/src/main/js/apps/users/components/UsersAppContainer.js31
-rw-r--r--server/sonar-web/src/main/js/apps/users/init.js (renamed from server/sonar-web/src/main/js/apps/users/app.js)15
-rw-r--r--server/sonar-web/src/main/js/apps/users/routes.js26
-rw-r--r--server/sonar-web/src/main/js/apps/web-api/app.js41
-rw-r--r--server/sonar-web/src/main/js/apps/web-api/components/Action.js2
-rw-r--r--server/sonar-web/src/main/js/apps/web-api/components/Menu.js2
-rw-r--r--server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js11
-rw-r--r--server/sonar-web/src/main/js/apps/web-api/routes.js27
122 files changed, 1557 insertions, 981 deletions
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js b/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js
index 5beee99c9af..0fa65014b61 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js
@@ -21,7 +21,6 @@
import React from 'react';
import shallowCompare from 'react-addons-shallow-compare';
import debounce from 'lodash/debounce';
-import { PropTypes as RouterPropTypes } from 'react-router';
import { DEFAULT_FILTERS, DEBOUNCE_DELAY, STATUSES, CURRENTS } from './../constants';
import Header from './Header';
@@ -41,7 +40,7 @@ export default class BackgroundTasksApp extends React.Component {
static propTypes = {
component: React.PropTypes.object,
- location: RouterPropTypes.location.isRequired
+ location: React.PropTypes.object
};
state: any = {
@@ -136,7 +135,7 @@ export default class BackgroundTasksApp extends React.Component {
});
this.context.router.push({
- pathname: '/',
+ pathname: this.props.location.pathname,
query: nextQuery
});
}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/routes.js b/server/sonar-web/src/main/js/apps/background-tasks/routes.js
new file mode 100644
index 00000000000..5bbcd616795
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/background-tasks/routes.js
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import BackgroundTasksApp from './components/BackgroundTasksApp';
+
+export default (
+ <IndexRoute component={BackgroundTasksApp}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/code/app.js b/server/sonar-web/src/main/js/apps/code/app.js
deleted file mode 100644
index fc13bb30a31..00000000000
--- a/server/sonar-web/src/main/js/apps/code/app.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { render } from 'react-dom';
-import { Router, Route, Redirect, useRouterHistory } from 'react-router';
-import { createHistory } from 'history';
-
-import App from './components/App';
-
-window.sonarqube.appStarted.then(options => {
- const el = document.querySelector(options.el);
-
- const history = useRouterHistory(createHistory)({
- basename: window.baseUrl + '/code'
- });
-
- const AppWithComponent = (props) => {
- return <App {...props} component={options.component}/>;
- };
-
- render((
- <Router history={history}>
- <Redirect from="/index" to="/"/>
- <Route path="/" component={AppWithComponent}/>
- </Router>
- ), el);
-});
diff --git a/server/sonar-web/src/main/js/apps/code/components/ComponentName.js b/server/sonar-web/src/main/js/apps/code/components/ComponentName.js
index cfe56f47381..ae166bbaa02 100644
--- a/server/sonar-web/src/main/js/apps/code/components/ComponentName.js
+++ b/server/sonar-web/src/main/js/apps/code/components/ComponentName.js
@@ -48,7 +48,7 @@ function mostCommitPrefix (strings) {
return prefix.substr(0, prefix.length - lastPrefixPart.length);
}
-const Component = ({ component, rootComponent, previous, canBrowse }) => {
+const ComponentName = ({ component, rootComponent, previous, canBrowse }) => {
const areBothDirs = component.qualifier === 'DIR' && previous && previous.qualifier === 'DIR';
const prefix = areBothDirs ? mostCommitPrefix([component.name + '/', previous.name + '/']) : '';
const name = prefix ? (
@@ -75,7 +75,7 @@ const Component = ({ component, rootComponent, previous, canBrowse }) => {
Object.assign(query, { selected: component.key });
}
inner = (
- <Link to={{ pathname: '/', query }} className="link-with-icon">
+ <Link to={{ pathname: '/code', query }} className="link-with-icon">
<QualifierIcon qualifier={component.qualifier}/>
{' '}
<span>{name}</span>
@@ -99,4 +99,4 @@ const Component = ({ component, rootComponent, previous, canBrowse }) => {
);
};
-export default Component;
+export default ComponentName;
diff --git a/server/sonar-web/src/main/js/apps/code/components/Search.js b/server/sonar-web/src/main/js/apps/code/components/Search.js
index d54f727e5f3..659b397074c 100644
--- a/server/sonar-web/src/main/js/apps/code/components/Search.js
+++ b/server/sonar-web/src/main/js/apps/code/components/Search.js
@@ -103,7 +103,7 @@ export default class Search extends React.Component {
window.location = getComponentUrl(selected.refKey);
} else {
this.context.router.push({
- pathname: '/',
+ pathname: '/code',
query: {
id: component.key,
selected: selected.key
diff --git a/server/sonar-web/src/main/js/apps/markdown/markdown-help-view.js b/server/sonar-web/src/main/js/apps/code/routes.js
index 95235579e99..882c1b76882 100644
--- a/server/sonar-web/src/main/js/apps/markdown/markdown-help-view.js
+++ b/server/sonar-web/src/main/js/apps/code/routes.js
@@ -17,10 +17,10 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import Marionette from 'backbone.marionette';
-import Template from './templates/markdown-help.hbs';
-
-export default Marionette.ItemView.extend({
- template: Template
-});
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import App from './components/App';
+export default (
+ <IndexRoute component={App}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/app.js b/server/sonar-web/src/main/js/apps/coding-rules/app.js
deleted file mode 100644
index ea4adc1cf3f..00000000000
--- a/server/sonar-web/src/main/js/apps/coding-rules/app.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import $ from 'jquery';
-import _ from 'underscore';
-import Backbone from 'backbone';
-import Marionette from 'backbone.marionette';
-import State from './models/state';
-import Layout from './layout';
-import Rules from './models/rules';
-import Facets from '../../components/navigator/models/facets';
-import Controller from './controller';
-import Router from '../../components/navigator/router';
-import WorkspaceListView from './workspace-list-view';
-import WorkspaceHeaderView from './workspace-header-view';
-import FacetsView from './facets-view';
-import FiltersView from './filters-view';
-
-const App = new Marionette.Application();
-const init = function () {
- const options = window.sonarqube;
-
- this.layout = new Layout({ el: options.el });
- this.layout.render();
- $('#footer').addClass('search-navigator-footer');
-
- this.state = new State();
- this.list = new Rules();
- this.facets = new Facets();
-
- this.controller = new Controller({ app: this });
-
- this.workspaceListView = new WorkspaceListView({
- app: this,
- collection: this.list
- });
- this.layout.workspaceListRegion.show(this.workspaceListView);
- this.workspaceListView.bindScrollEvents();
-
- this.workspaceHeaderView = new WorkspaceHeaderView({
- app: this,
- collection: this.list
- });
- this.layout.workspaceHeaderRegion.show(this.workspaceHeaderView);
-
- this.facetsView = new FacetsView({
- app: this,
- collection: this.facets
- });
- this.layout.facetsRegion.show(this.facetsView);
-
- this.filtersView = new FiltersView({
- app: this
- });
- this.layout.filtersRegion.show(this.filtersView);
-
- key.setScope('list');
- this.router = new Router({
- app: this
- });
- Backbone.history.start();
-};
-
-const appXHR = $.get(window.baseUrl + '/api/rules/app').done(function (r) {
- App.canWrite = r.canWrite;
- App.qualityProfiles = _.sortBy(r.qualityprofiles, ['name', 'lang']);
- App.languages = _.extend(r.languages, {
- none: 'None'
- });
- _.map(App.qualityProfiles, function (profile) {
- profile.language = App.languages[profile.lang];
- });
- App.repositories = r.repositories;
- App.statuses = r.statuses;
-});
-
-App.on('start', function (options) {
- appXHR.done(function () {
- init.call(App, options);
- });
-});
-
-window.sonarqube.appStarted.then(options => App.start(options));
diff --git a/server/sonar-web/src/main/js/apps/overview/app.js b/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js
index 5d8ad1b4a17..97491378c7f 100644
--- a/server/sonar-web/src/main/js/apps/overview/app.js
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js
@@ -18,14 +18,14 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import { render } from 'react-dom';
+import init from '../init';
-import App from './components/App';
+export default class CodingRulesAppContainer extends React.Component {
+ componentDidMount () {
+ init(this.refs.container);
+ }
-window.sonarqube.appStarted.then(options => {
- const el = document.querySelector(options.el);
- const component = { ...options.component, ...window.sonarqube.overview.component };
- render((
- <App component={component}/>
- ), el);
-});
+ render () {
+ return <div ref="container"/>;
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/init.js b/server/sonar-web/src/main/js/apps/coding-rules/init.js
new file mode 100644
index 00000000000..aa7c9644ede
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/coding-rules/init.js
@@ -0,0 +1,94 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import $ from 'jquery';
+import _ from 'underscore';
+import Backbone from 'backbone';
+import Marionette from 'backbone.marionette';
+import State from './models/state';
+import Layout from './layout';
+import Rules from './models/rules';
+import Facets from '../../components/navigator/models/facets';
+import Controller from './controller';
+import Router from '../../components/navigator/router';
+import WorkspaceListView from './workspace-list-view';
+import WorkspaceHeaderView from './workspace-header-view';
+import FacetsView from './facets-view';
+import FiltersView from './filters-view';
+
+const App = new Marionette.Application();
+
+App.on('start', function (el) {
+ $.get(window.baseUrl + '/api/rules/app').done(function (r) {
+ App.canWrite = r.canWrite;
+ App.qualityProfiles = _.sortBy(r.qualityprofiles, ['name', 'lang']);
+ App.languages = _.extend(r.languages, {
+ none: 'None'
+ });
+ _.map(App.qualityProfiles, function (profile) {
+ profile.language = App.languages[profile.lang];
+ });
+ App.repositories = r.repositories;
+ App.statuses = r.statuses;
+ }).done(() => {
+ this.layout = new Layout({ el });
+ this.layout.render();
+ $('#footer').addClass('search-navigator-footer');
+
+ this.state = new State();
+ this.list = new Rules();
+ this.facets = new Facets();
+
+ this.controller = new Controller({ app: this });
+
+ this.workspaceListView = new WorkspaceListView({
+ app: this,
+ collection: this.list
+ });
+ this.layout.workspaceListRegion.show(this.workspaceListView);
+ this.workspaceListView.bindScrollEvents();
+
+ this.workspaceHeaderView = new WorkspaceHeaderView({
+ app: this,
+ collection: this.list
+ });
+ this.layout.workspaceHeaderRegion.show(this.workspaceHeaderView);
+
+ this.facetsView = new FacetsView({
+ app: this,
+ collection: this.facets
+ });
+ this.layout.facetsRegion.show(this.facetsView);
+
+ this.filtersView = new FiltersView({
+ app: this
+ });
+ this.layout.filtersRegion.show(this.filtersView);
+
+ key.setScope('list');
+ this.router = new Router({
+ app: this
+ });
+ Backbone.history.start();
+ });
+});
+
+export default function (el) {
+ App.start(el);
+}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/routes.js b/server/sonar-web/src/main/js/apps/coding-rules/routes.js
new file mode 100644
index 00000000000..9688c9e7819
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/coding-rules/routes.js
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import CodingRulesAppContainer from './components/CodingRulesAppContainer';
+
+export default (
+ <IndexRoute component={CodingRulesAppContainer}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/component-issues/components/ComponentIssuesAppContainer.js b/server/sonar-web/src/main/js/apps/component-issues/components/ComponentIssuesAppContainer.js
new file mode 100644
index 00000000000..430ba7b0e79
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/component-issues/components/ComponentIssuesAppContainer.js
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import init from '../init';
+
+export default class ComponentIssuesAppContainer extends React.Component {
+ componentDidMount () {
+ init(this.refs.container);
+ }
+
+ render () {
+ return <div ref="container"/>;
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/component-issues/app.js b/server/sonar-web/src/main/js/apps/component-issues/init.js
index 7397e84eed9..95269406d71 100644
--- a/server/sonar-web/src/main/js/apps/component-issues/app.js
+++ b/server/sonar-web/src/main/js/apps/component-issues/init.js
@@ -33,7 +33,7 @@ import FacetsView from './../issues/facets-view';
import HeaderView from './../issues/HeaderView';
const App = new Marionette.Application();
-const init = function () {
+const init = function (el) {
const options = window.sonarqube;
this.config = options.config;
@@ -49,7 +49,7 @@ const init = function () {
this.list = new Issues();
this.facets = new Facets();
- this.layout = new Layout({ app: this, el: options.el });
+ this.layout = new Layout({ app: this, el });
this.layout.render();
$('#footer').addClass('search-navigator-footer');
@@ -109,8 +109,10 @@ App.updateContextFacets = function () {
});
};
-App.on('start', function (options) {
- init.call(App, options);
+App.on('start', function (el) {
+ init.call(App, el);
});
-window.sonarqube.appStarted.then(options => App.start(options));
+export default function (el) {
+ App.start(el);
+}
diff --git a/server/sonar-web/src/main/js/apps/component-issues/routes.js b/server/sonar-web/src/main/js/apps/component-issues/routes.js
new file mode 100644
index 00000000000..e07322509f2
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/component-issues/routes.js
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import ComponentIssuesAppContainer from './components/ComponentIssuesAppContainer';
+
+export default (
+ <IndexRoute component={ComponentIssuesAppContainer}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/app.js b/server/sonar-web/src/main/js/apps/component-measures/app.js
deleted file mode 100644
index 230a10f092a..00000000000
--- a/server/sonar-web/src/main/js/apps/component-measures/app.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { render } from 'react-dom';
-import { Router, Route, IndexRoute, Redirect, IndexRedirect, useRouterHistory } from 'react-router';
-import { createHistory } from 'history';
-import { Provider } from 'react-redux';
-
-import AppContainer from './app/AppContainer';
-import HomeContainer from './home/HomeContainer';
-import AllMeasuresContainer from './home/AllMeasuresContainer';
-import DomainMeasuresContainer from './home/DomainMeasuresContainer';
-import MeasureDetailsContainer from './details/MeasureDetailsContainer';
-import ListViewContainer from './details/drilldown/ListViewContainer';
-import TreeViewContainer from './details/drilldown/TreeViewContainer';
-import MeasureHistoryContainer from './details/history/MeasureHistoryContainer';
-import MeasureTreemapContainer from './details/treemap/MeasureTreemapContainer';
-
-import configureStore from './store/configureStore';
-
-import { checkHistoryExistence } from './hooks';
-
-import './styles.css';
-
-window.sonarqube.appStarted.then(options => {
- const el = document.querySelector(options.el);
-
- const history = useRouterHistory(createHistory)({
- basename: window.baseUrl + '/component_measures'
- });
-
- const store = configureStore({
- app: { component: options.component }
- });
-
- const handleRouteUpdate = () => {
- window.scrollTo(0, 0);
- };
-
- render((
- <Provider store={store}>
- <Router history={history} onUpdate={handleRouteUpdate}>
- <Redirect from="/index" to="/"/>
-
- <Route path="/" component={AppContainer}>
- <Route component={HomeContainer}>
- <IndexRoute component={AllMeasuresContainer}/>
- <Route path="domain/:domainName" component={DomainMeasuresContainer}/>
- </Route>
-
- <Route path="metric/:metricKey" component={MeasureDetailsContainer}>
- <IndexRedirect to="list"/>
- <Route path="list" component={ListViewContainer}/>
- <Route path="tree" component={TreeViewContainer}/>
- <Route path="history" component={MeasureHistoryContainer} onEnter={checkHistoryExistence}/>
- <Route path="treemap" component={MeasureTreemapContainer}/>
- </Route>
- </Route>
-
- <Redirect from="*" to="/"/>
- </Router>
- </Provider>
- ), el);
-});
diff --git a/server/sonar-web/src/main/js/apps/component-measures/app/App.js b/server/sonar-web/src/main/js/apps/component-measures/app/App.js
index fa23544cd91..75fa2d320a4 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/app/App.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/app/App.js
@@ -23,6 +23,7 @@ import Spinner from './../components/Spinner';
export default class App extends React.Component {
componentDidMount () {
+ this.props.setComponent(this.props.component);
this.props.fetchMetrics();
}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/app/AppContainer.js b/server/sonar-web/src/main/js/apps/component-measures/app/AppContainer.js
index 2bd53a0ab19..c3e9e632d10 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/app/AppContainer.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/app/AppContainer.js
@@ -18,19 +18,20 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-
import App from './App';
-import { fetchMetrics } from './actions';
+import { fetchMetrics, setComponent } from './actions';
+import { getMeasuresAppAllMetrics } from '../../../app/store/rootReducer';
const mapStateToProps = state => {
return {
- metrics: state.app.metrics
+ metrics: getMeasuresAppAllMetrics(state)
};
};
const mapDispatchToProps = dispatch => {
return {
- fetchMetrics: () => dispatch(fetchMetrics())
+ fetchMetrics: () => dispatch(fetchMetrics()),
+ setComponent: component => dispatch(setComponent(component))
};
};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/app/actions.js b/server/sonar-web/src/main/js/apps/component-measures/app/actions.js
index 85f74ffa9a4..92e80e68fc1 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/app/actions.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/app/actions.js
@@ -23,8 +23,9 @@ import { getMetrics } from '../../../api/metrics';
* Actions
*/
-export const DISPLAY_HOME = 'app/DISPLAY_HOME';
-export const RECEIVE_METRICS = 'app/RECEIVE_METRICS';
+export const DISPLAY_HOME = 'measuresApp/app/DISPLAY_HOME';
+export const RECEIVE_METRICS = 'measuresApp/app/RECEIVE_METRICS';
+export const SET_COMPONENT = 'measuresApp/app/SET_COMPONENT';
/*
* Action Creators
@@ -38,6 +39,10 @@ function receiveMetrics (metrics) {
return { type: RECEIVE_METRICS, metrics };
}
+export function setComponent (component) {
+ return { type: SET_COMPONENT, component };
+}
+
/*
* Workflow
*/
diff --git a/server/sonar-web/src/main/js/apps/component-measures/app/reducer.js b/server/sonar-web/src/main/js/apps/component-measures/app/reducer.js
index 2484e2d0563..0df67b1d78f 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/app/reducer.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/app/reducer.js
@@ -17,7 +17,7 @@
* 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_METRICS } from './actions';
+import { RECEIVE_METRICS, SET_COMPONENT } from './actions';
const initialState = {
metrics: undefined
@@ -27,6 +27,8 @@ export default function appReducer (state = initialState, action = {}) {
switch (action.type) {
case RECEIVE_METRICS:
return { ...state, metrics: action.metrics };
+ case SET_COMPONENT:
+ return { ...state, component: action.component };
default:
return state;
}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/MeasureBubbleChartContainer.js b/server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/MeasureBubbleChartContainer.js
index f219bfe01cc..029cee95b55 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/MeasureBubbleChartContainer.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/bubbleChart/MeasureBubbleChartContainer.js
@@ -18,13 +18,13 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-
import MeasureBubbleChart from './BubbleChart';
+import { getMeasuresAppAllMetrics, getMeasuresAppComponent } from '../../../../app/store/rootReducer';
const mapStateToProps = state => {
return {
- component: state.app.component,
- metrics: state.app.metrics
+ component: getMeasuresAppComponent(state),
+ metrics: getMeasuresAppAllMetrics(state)
};
};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetails.js b/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetails.js
index 35d400d3e4c..125b9c72897 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetails.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetails.js
@@ -71,7 +71,7 @@ export default class MeasureDetails extends React.Component {
<section id="component-measures-details" className="page page-container page-limited">
<div className="note">
<IndexLink
- to={{ pathname: '/', query: { id: component.key } }}
+ to={{ pathname: '/component_measures', query: { id: component.key } }}
id="component-measures-back-to-all-measures"
className="text-muted">
{translate('component_measures.all_measures')}
@@ -80,7 +80,7 @@ export default class MeasureDetails extends React.Component {
<span>
{' / '}
<Link
- to={{ pathname: `domain/${metric.domain}`, query: { id: component.key } }}
+ to={{ pathname: `/component_measures/domain/${metric.domain}`, query: { id: component.key } }}
className="text-muted">
{translateWithParameters('component_measures.domain_measures', metric.domain)}
</Link>
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsContainer.js b/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsContainer.js
index b0d87963394..055ce5225e3 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsContainer.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/details/MeasureDetailsContainer.js
@@ -18,18 +18,25 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-
import MeasureDetails from './MeasureDetails';
import { fetchMeasure } from './actions';
+import {
+ getMeasuresAppAllMetrics,
+ getMeasuresAppDetailsMetric,
+ getMeasuresAppDetailsMeasure,
+ getMeasuresAppDetailsSecondaryMeasure,
+ getMeasuresAppDetailsPeriods
+ , getMeasuresAppComponent
+} from '../../../app/store/rootReducer';
const mapStateToProps = state => {
return {
- component: state.app.component,
- metrics: state.app.metrics,
- metric: state.details.metric,
- measure: state.details.measure,
- secondaryMeasure: state.details.secondaryMeasure,
- periods: state.details.periods
+ component: getMeasuresAppComponent(state),
+ metrics: getMeasuresAppAllMetrics(state),
+ metric: getMeasuresAppDetailsMetric(state),
+ measure: getMeasuresAppDetailsMeasure(state),
+ secondaryMeasure: getMeasuresAppDetailsSecondaryMeasure(state),
+ periods: getMeasuresAppDetailsPeriods(state)
};
};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/actions.js b/server/sonar-web/src/main/js/apps/component-measures/details/actions.js
index 7f24fce6112..608c7e2b97c 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/details/actions.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/details/actions.js
@@ -19,13 +19,14 @@
*/
import { getMeasuresAndMeta } from '../../../api/measures';
import { enhanceWithLeak } from '../utils';
+import { getMeasuresAppComponent, getMeasuresAppAllMetrics } from '../../../app/store/rootReducer';
/*
* Actions
*/
-export const REQUEST_MEASURE = 'details/REQUEST_MEASURE';
-export const RECEIVE_MEASURE = 'details/RECEIVE_MEASURE';
+export const REQUEST_MEASURE = 'measuresApp/details/REQUEST_MEASURE';
+export const RECEIVE_MEASURE = 'measuresApp/details/RECEIVE_MEASURE';
/*
* Action Creators
@@ -45,7 +46,9 @@ function receiveMeasure (measure, secondaryMeasure, periods) {
export function fetchMeasure (metricKey, periodIndex = 1) {
return (dispatch, getState) => {
- const { component, metrics } = getState().app;
+ const state = getState();
+ const component = getMeasuresAppComponent(state);
+ const metrics = getMeasuresAppAllMetrics(state);
const metricsToRequest = [metricKey];
if (metricKey === 'ncloc') {
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListViewContainer.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListViewContainer.js
index c96c5586383..d982d7aef88 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListViewContainer.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/ListViewContainer.js
@@ -18,24 +18,29 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-import pick from '../../../../../../../node_modules/lodash/pick';
-
import ListView from './ListView';
import { fetchList, fetchMore, selectComponent, selectNext, selectPrevious } from '../../store/listViewActions';
+import {
+ getMeasuresAppListComponents,
+ getMeasuresAppListSelected,
+ getMeasuresAppListTotal,
+ getMeasuresAppListPageIndex,
+ getMeasuresAppAllMetrics,
+ getMeasuresAppDetailsMetric,
+ isMeasuresAppFetching
+ , getMeasuresAppComponent
+} from '../../../../app/store/rootReducer';
const mapStateToProps = state => {
- const drilldown = pick(state.list, [
- 'components',
- 'selected',
- 'total',
- 'pageIndex'
- ]);
return {
- ...drilldown,
- component: state.app.component,
- metrics: state.app.metrics,
- metric: state.details.metric,
- fetching: state.status.fetching
+ components: getMeasuresAppListComponents(state),
+ selected: getMeasuresAppListSelected(state),
+ total: getMeasuresAppListTotal(state),
+ pageIndex: getMeasuresAppListPageIndex(state),
+ component: getMeasuresAppComponent(state),
+ metrics: getMeasuresAppAllMetrics(state),
+ metric: getMeasuresAppDetailsMetric(state),
+ fetching: isMeasuresAppFetching(state)
};
};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureDrilldown.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureDrilldown.js
index f41d19f8411..cc7e06546ed 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureDrilldown.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/MeasureDrilldown.js
@@ -39,20 +39,20 @@ export default class MeasureDrilldown extends React.Component {
<div className="measure-details-drilldown">
<ul className="measure-details-drilldown-mode">
{component.qualifier !== 'DEV' && (
- <li>
- <Link
- activeClassName="active"
- to={{ pathname: `metric/${metric.key}/list`, query: { id: component.key } }}>
- <IconList/>
- {translate('component_measures.tab.list')}
- </Link>
- </li>
+ <li>
+ <Link
+ activeClassName="active"
+ to={{ pathname: `/component_measures/metric/${metric.key}/list`, query: { id: component.key } }}>
+ <IconList/>
+ {translate('component_measures.tab.list')}
+ </Link>
+ </li>
)}
<li>
<Link
activeClassName="active"
- to={{ pathname: `metric/${metric.key}/tree`, query: { id: component.key } }}>
+ to={{ pathname: `/component_measures/metric/${metric.key}/tree`, query: { id: component.key } }}>
<IconTree/>
{translate('component_measures.tab.tree')}
</Link>
@@ -62,7 +62,10 @@ export default class MeasureDrilldown extends React.Component {
<li>
<Link
activeClassName="active"
- to={{ pathname: `metric/${metric.key}/bubbles`, query: { id: component.key } }}>
+ to={{
+ pathname: `/component_measures/metric/${metric.key}/bubbles`,
+ query: { id: component.key }
+ }}>
<IconBubbles/>
{translate('component_measures.tab.bubbles')}
</Link>
@@ -73,7 +76,10 @@ export default class MeasureDrilldown extends React.Component {
<li>
<Link
activeClassName="active"
- to={{ pathname: `metric/${metric.key}/treemap`, query: { id: component.key } }}>
+ to={{
+ pathname: `/component_measures/metric/${metric.key}/treemap`,
+ query: { id: component.key }
+ }}>
<IconTreemap/>
{translate('component_measures.tab.treemap')}
</Link>
@@ -84,7 +90,10 @@ export default class MeasureDrilldown extends React.Component {
<li>
<Link
activeClassName="active"
- to={{ pathname: `metric/${metric.key}/history`, query: { id: component.key } }}>
+ to={{
+ pathname: `/component_measures/metric/${metric.key}/history`,
+ query: { id: component.key }
+ }}>
<IconHistory/>
{translate('component_measures.tab.history')}
</Link>
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeViewContainer.js b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeViewContainer.js
index 4900542ad24..114b9ef08e2 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeViewContainer.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/details/drilldown/TreeViewContainer.js
@@ -18,33 +18,39 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-import pick from '../../../../../../../node_modules/lodash/pick';
-
import TreeView from './TreeView';
import {
- start,
- drilldown,
- useBreadcrumbs,
- fetchMore,
- selectComponent,
- selectNext,
- selectPrevious
+ start,
+ drilldown,
+ useBreadcrumbs,
+ fetchMore,
+ selectComponent,
+ selectNext,
+ selectPrevious
} from '../../store/treeViewActions';
+import {
+ getMeasuresAppTreeComponents,
+ getMeasuresAppTreeBreadcrumbs,
+ getMeasuresAppTreeSelected,
+ getMeasuresAppTreeTotal,
+ getMeasuresAppTreePageIndex,
+ getMeasuresAppAllMetrics,
+ getMeasuresAppDetailsMetric,
+ isMeasuresAppFetching
+ , getMeasuresAppComponent
+} from '../../../../app/store/rootReducer';
const mapStateToProps = state => {
- const drilldown = pick(state.tree, [
- 'components',
- 'breadcrumbs',
- 'selected',
- 'total',
- 'pageIndex'
- ]);
return {
- ...drilldown,
- component: state.app.component,
- metrics: state.app.metrics,
- metric: state.details.metric,
- fetching: state.status.fetching
+ components: getMeasuresAppTreeComponents(state),
+ breadcrumbs: getMeasuresAppTreeBreadcrumbs(state),
+ selected: getMeasuresAppTreeSelected(state),
+ total: getMeasuresAppTreeTotal(state),
+ pageIndex: getMeasuresAppTreePageIndex(state),
+ component: getMeasuresAppComponent(state),
+ metrics: getMeasuresAppAllMetrics(state),
+ metric: getMeasuresAppDetailsMetric(state),
+ fetching: isMeasuresAppFetching(state)
};
};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/history/MeasureHistoryContainer.js b/server/sonar-web/src/main/js/apps/component-measures/details/history/MeasureHistoryContainer.js
index bfe7decf1a3..b70189eedb5 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/details/history/MeasureHistoryContainer.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/details/history/MeasureHistoryContainer.js
@@ -18,13 +18,13 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-
import MeasureHistory from './MeasureHistory';
+import { getMeasuresAppDetailsMetric, getMeasuresAppComponent } from '../../../../app/store/rootReducer';
const mapStateToProps = state => {
return {
- component: state.app.component,
- metric: state.details.metric
+ component: getMeasuresAppComponent(state),
+ metric: getMeasuresAppDetailsMetric(state)
};
};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemapContainer.js b/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemapContainer.js
index 978a2a522e2..e24858b82e3 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemapContainer.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemapContainer.js
@@ -18,13 +18,13 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-
import MeasureTreemap from './MeasureTreemap';
+import { getMeasuresAppDetailsMetric, getMeasuresAppComponent } from '../../../../app/store/rootReducer';
const mapStateToProps = state => {
return {
- component: state.app.component,
- metric: state.details.metric
+ component: getMeasuresAppComponent(state),
+ metric: getMeasuresAppDetailsMetric(state)
};
};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresContainer.js b/server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresContainer.js
index 00bb948b70b..d02d06bfcc3 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresContainer.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/home/AllMeasuresContainer.js
@@ -18,14 +18,18 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-
import AllMeasures from './AllMeasures';
+import {
+ getMeasuresAppHomeDomains,
+ getMeasuresAppHomePeriods,
+ getMeasuresAppComponent
+} from '../../../app/store/rootReducer';
const mapStateToProps = state => {
return {
- component: state.app.component,
- domains: state.home.domains,
- periods: state.home.periods
+ component: getMeasuresAppComponent(state),
+ domains: getMeasuresAppHomeDomains(state),
+ periods: getMeasuresAppHomePeriods(state)
};
};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasuresContainer.js b/server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasuresContainer.js
index f71d24c0368..53094eb9bc7 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasuresContainer.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/home/DomainMeasuresContainer.js
@@ -18,14 +18,18 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-
import DomainMeasures from './DomainMeasures';
+import {
+ getMeasuresAppHomeDomains,
+ getMeasuresAppHomePeriods,
+ getMeasuresAppComponent
+} from '../../../app/store/rootReducer';
const mapStateToProps = state => {
return {
- component: state.app.component,
- domains: state.home.domains,
- periods: state.home.periods
+ component: getMeasuresAppComponent(state),
+ domains: getMeasuresAppHomeDomains(state),
+ periods: getMeasuresAppHomePeriods(state)
};
};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/Home.js b/server/sonar-web/src/main/js/apps/component-measures/home/Home.js
index 84b8dabece3..6b1faf5402f 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/home/Home.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/home/Home.js
@@ -51,7 +51,7 @@ export default class Home extends React.Component {
<ul>
<li>
<IndexLink
- to={{ pathname: '/', query: { id: component.key } }}
+ to={{ pathname: '/component_measures', query: { id: component.key } }}
activeClassName="active">
{translate('all')}
</IndexLink>
@@ -59,7 +59,7 @@ export default class Home extends React.Component {
{domains.map(domain => (
<li key={domain.name}>
<Link
- to={{ pathname: `domain/${domain.name}`, query: { id: component.key } }}
+ to={{ pathname: `/component_measures/domain/${domain.name}`, query: { id: component.key } }}
activeClassName="active">
{getLocalizedMetricDomain(domain.name)}
</Link>
diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/HomeContainer.js b/server/sonar-web/src/main/js/apps/component-measures/home/HomeContainer.js
index a5473ec3dba..58e3285c181 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/home/HomeContainer.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/home/HomeContainer.js
@@ -18,16 +18,20 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-
import Home from './Home';
import { fetchMeasures } from './actions';
import { displayHome } from '../app/actions';
+import {
+ getMeasuresAppHomeDomains,
+ getMeasuresAppHomePeriods,
+ getMeasuresAppComponent
+} from '../../../app/store/rootReducer';
const mapStateToProps = state => {
return {
- component: state.app.component,
- domains: state.home.domains,
- periods: state.home.periods
+ component: getMeasuresAppComponent(state),
+ domains: getMeasuresAppHomeDomains(state),
+ periods: getMeasuresAppHomePeriods(state)
};
};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/MeasuresList.js b/server/sonar-web/src/main/js/apps/component-measures/home/MeasuresList.js
index 95a0ac857a8..42d3f46e94f 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/home/MeasuresList.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/home/MeasuresList.js
@@ -30,7 +30,7 @@ const MeasuresList = ({ measures, component, className = 'domain-measures' }) =>
<li
key={measure.metric.key}
id={`measure-${measure.metric.key}`}>
- <Link to={{ pathname: `metric/${measure.metric.key}`, query: { id: component.key } }}>
+ <Link to={{ pathname: `/component_measures/metric/${measure.metric.key}`, query: { id: component.key } }}>
<div className="domain-measures-name">
<span id={`measure-${measure.metric.key}-name`}>
{getLocalizedMetricName(measure.metric)}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/home/actions.js b/server/sonar-web/src/main/js/apps/component-measures/home/actions.js
index 31a9309c900..006d4680523 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/home/actions.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/home/actions.js
@@ -21,8 +21,9 @@ import { startFetching, stopFetching } from '../store/statusActions';
import { getMeasuresAndMeta } from '../../../api/measures';
import { getLeakPeriod } from '../../../helpers/periods';
import { getLeakValue } from '../utils';
+import { getMeasuresAppComponent, getMeasuresAppAllMetrics } from '../../../app/store/rootReducer';
-export const RECEIVE_MEASURES = 'home/RECEIVE_MEASURES';
+export const RECEIVE_MEASURES = 'measuresApp/home/RECEIVE_MEASURES';
export function receiveMeasures (measures, periods) {
return { type: RECEIVE_MEASURES, measures, periods };
@@ -39,7 +40,10 @@ export function fetchMeasures () {
return (dispatch, getState) => {
dispatch(startFetching());
- const { component, metrics } = getState().app;
+ const state = getState();
+ const component = getMeasuresAppComponent(state);
+ const metrics = getMeasuresAppAllMetrics(state);
+
const metricKeys = metrics
.filter(metric => !metric.hidden)
.filter(metric => metric.type !== 'DATA' && metric.type !== 'DISTRIB')
diff --git a/server/sonar-web/src/main/js/apps/component-measures/routes.js b/server/sonar-web/src/main/js/apps/component-measures/routes.js
new file mode 100644
index 00000000000..e2e24f96034
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/component-measures/routes.js
@@ -0,0 +1,49 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { Route, IndexRoute, IndexRedirect } from 'react-router';
+import AppContainer from './app/AppContainer';
+import HomeContainer from './home/HomeContainer';
+import AllMeasuresContainer from './home/AllMeasuresContainer';
+import DomainMeasuresContainer from './home/DomainMeasuresContainer';
+import MeasureDetailsContainer from './details/MeasureDetailsContainer';
+import ListViewContainer from './details/drilldown/ListViewContainer';
+import TreeViewContainer from './details/drilldown/TreeViewContainer';
+import MeasureHistoryContainer from './details/history/MeasureHistoryContainer';
+import MeasureTreemapContainer from './details/treemap/MeasureTreemapContainer';
+import { checkHistoryExistence } from './hooks';
+import './styles.css';
+
+export default (
+ <Route component={AppContainer}>
+ <Route component={HomeContainer}>
+ <IndexRoute component={AllMeasuresContainer}/>
+ <Route path="domain/:domainName" component={DomainMeasuresContainer}/>
+ </Route>
+
+ <Route path="metric/:metricKey" component={MeasureDetailsContainer}>
+ <IndexRedirect to="list"/>
+ <Route path="list" component={ListViewContainer}/>
+ <Route path="tree" component={TreeViewContainer}/>
+ <Route path="history" component={MeasureHistoryContainer} onEnter={checkHistoryExistence}/>
+ <Route path="treemap" component={MeasureTreemapContainer}/>
+ </Route>
+ </Route>
+);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/configureStore.js b/server/sonar-web/src/main/js/apps/component-measures/store/configureStore.js
deleted file mode 100644
index 07d55655531..00000000000
--- a/server/sonar-web/src/main/js/apps/component-measures/store/configureStore.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { combineReducers } from 'redux';
-
-import appReducer from './../app/reducer';
-import statusReducer from './statusReducer';
-import homeReducer from '../home/reducer';
-import detailsReducer from '../details/reducer';
-import listViewReducer from './listViewReducer';
-import treeViewReducer from './treeViewReducer';
-import configureStore from '../../../components/store/configureStore';
-
-export default function customConfigureStore (initialState) {
- const rootReducer = combineReducers({
- app: appReducer,
- home: homeReducer,
- details: detailsReducer,
- list: listViewReducer,
- tree: treeViewReducer,
- status: statusReducer
- });
-
- return configureStore(rootReducer, initialState);
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/listViewActions.js b/server/sonar-web/src/main/js/apps/component-measures/store/listViewActions.js
index 8e61e53dd0a..1f48656bfb8 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/store/listViewActions.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/store/listViewActions.js
@@ -21,8 +21,9 @@ import { getComponentTree } from '../../../api/components';
import { enhanceWithMeasure } from '../utils';
import { startFetching, stopFetching } from './statusActions';
import complementary from '../config/complementary';
+import { getMeasuresAppList } from '../../../app/store/rootReducer';
-export const UPDATE_STORE = 'drilldown/list/UPDATE_STORE';
+export const UPDATE_STORE = 'measuresApp/drilldown/list/UPDATE_STORE';
function updateStore (state) {
return { type: UPDATE_STORE, state };
@@ -77,7 +78,7 @@ function fetchLeaves (baseComponent, metric, pageIndex = 1, periodIndex = 1) {
*/
export function fetchList (baseComponent, metric, periodIndex = 1) {
return (dispatch, getState) => {
- const { list } = getState();
+ const list = getMeasuresAppList(getState());
if (list.baseComponent === baseComponent && list.metric === metric) {
return Promise.resolve();
}
@@ -96,7 +97,7 @@ export function fetchList (baseComponent, metric, periodIndex = 1) {
export function fetchMore (periodIndex) {
return (dispatch, getState) => {
- const { baseComponent, metric, pageIndex, components } = getState().list;
+ const { baseComponent, metric, pageIndex, components } = getMeasuresAppList(getState());
dispatch(startFetching());
return fetchLeaves(baseComponent, metric, pageIndex + 1, periodIndex).then(r => {
const nextComponents = [...components, ...r.components];
@@ -121,7 +122,7 @@ export function selectComponent (component) {
*/
export function selectNext () {
return (dispatch, getState) => {
- const { components, selected } = getState().list;
+ const { components, selected } = getMeasuresAppList(getState());
const selectedIndex = components.indexOf(selected);
if (selectedIndex < components.length - 1) {
const nextSelected = components[selectedIndex + 1];
@@ -135,7 +136,7 @@ export function selectNext () {
*/
export function selectPrevious () {
return (dispatch, getState) => {
- const { components, selected } = getState().list;
+ const { components, selected } = getMeasuresAppList(getState());
const selectedIndex = components.indexOf(selected);
if (selectedIndex > 0) {
const nextSelected = components[selectedIndex - 1];
diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/rootReducer.js b/server/sonar-web/src/main/js/apps/component-measures/store/rootReducer.js
new file mode 100644
index 00000000000..f57fef25a4a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/component-measures/store/rootReducer.js
@@ -0,0 +1,116 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { combineReducers } from 'redux';
+
+import appReducer from './../app/reducer';
+import statusReducer from './statusReducer';
+import homeReducer from '../home/reducer';
+import detailsReducer from '../details/reducer';
+import listViewReducer from './listViewReducer';
+import treeViewReducer from './treeViewReducer';
+
+export default combineReducers({
+ app: appReducer,
+ home: homeReducer,
+ details: detailsReducer,
+ list: listViewReducer,
+ tree: treeViewReducer,
+ status: statusReducer
+});
+
+export const getComponent = state => (
+ state.app.component
+);
+
+export const getAllMetrics = state => (
+ state.app.metrics
+);
+
+export const getDetailsMetric = state => (
+ state.details.metric
+);
+
+export const getDetailsMeasure = state => (
+ state.details.measure
+);
+
+export const getDetailsSecondaryMeasure = state => (
+ state.details.secondaryMeasure
+);
+
+export const getDetailsPeriods = state => (
+ state.details.periods
+);
+
+export const isFetching = state => (
+ state.status.fetching
+);
+
+export const getList = state => (
+ state.list
+);
+
+export const getListComponents = state => (
+ state.list.components
+);
+
+export const getListSelected = state => (
+ state.list.selected
+);
+
+export const getListTotal = state => (
+ state.list.total
+);
+
+export const getListPageIndex = state => (
+ state.list.pageIndex
+);
+
+export const getTree = state => (
+ state.tree
+);
+
+export const getTreeComponents = state => (
+ state.tree.components
+);
+
+export const getTreeBreadcrumbs = state => (
+ state.tree.breadcrumbs
+);
+
+export const getTreeSelected = state => (
+ state.tree.selected
+);
+
+export const getTreeTotal = state => (
+ state.tree.total
+);
+
+export const getTreePageIndex = state => (
+ state.tree.pageIndex
+);
+
+export const getHomeDomains = state => (
+ state.home.domains
+);
+
+export const getHomePeriods = state => (
+ state.home.periods
+);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/statusActions.js b/server/sonar-web/src/main/js/apps/component-measures/store/statusActions.js
index 5755ad5ff55..83eb605cb7c 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/store/statusActions.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/store/statusActions.js
@@ -17,8 +17,8 @@
* 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 START_FETCHING = 'status/START_FETCHING';
-export const STOP_FETCHING = 'status/STOP_FETCHING';
+export const START_FETCHING = 'measuresApp/status/START_FETCHING';
+export const STOP_FETCHING = 'measuresApp/status/STOP_FETCHING';
export function startFetching () {
return { type: START_FETCHING };
diff --git a/server/sonar-web/src/main/js/apps/component-measures/store/treeViewActions.js b/server/sonar-web/src/main/js/apps/component-measures/store/treeViewActions.js
index 49cc3ff504d..81d2896c9d8 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/store/treeViewActions.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/store/treeViewActions.js
@@ -23,13 +23,14 @@ import { getComponentTree } from '../../../api/components';
import { enhanceWithMeasure } from '../utils';
import { startFetching, stopFetching } from './statusActions';
import complementary from '../config/complementary';
+import { getMeasuresAppTree } from '../../../app/store/rootReducer';
/*
* Actions
*/
-export const UPDATE_STORE = 'drilldown/tree/UPDATE_STORE';
-export const INIT = 'drilldown/tree/INIT';
+export const UPDATE_STORE = 'measuresApp/drilldown/tree/UPDATE_STORE';
+export const INIT = 'measuresApp/drilldown/tree/INIT';
/*
* Action Creators
@@ -115,7 +116,7 @@ function fetchComponents (rootComponent, baseComponent, metric, pageIndex = 1, p
*/
function fetchList (baseComponent) {
return (dispatch, getState) => {
- const { metric, periodIndex, rootComponent } = getState().tree;
+ const { metric, periodIndex, rootComponent } = getMeasuresAppTree(getState());
dispatch(startFetching());
return fetchComponents(rootComponent, baseComponent, metric, 1, periodIndex).then(r => {
@@ -139,7 +140,7 @@ function fetchList (baseComponent) {
*/
export function start (rootComponent, metric, periodIndex = 1) {
return (dispatch, getState) => {
- const { tree } = getState();
+ const tree = getMeasuresAppTree(getState());
if (rootComponent === tree.rootComponent && metric === tree.metric) {
return Promise.resolve();
}
@@ -155,7 +156,7 @@ export function start (rootComponent, metric, periodIndex = 1) {
*/
export function drilldown (component) {
return (dispatch, getState) => {
- const { metric, rootComponent, breadcrumbs, periodIndex } = getState().tree;
+ const { metric, rootComponent, breadcrumbs, periodIndex } = getMeasuresAppTree(getState());
dispatch(startFetching());
return fetchComponents(rootComponent, component, metric, 1, periodIndex).then(r => {
dispatch(updateStore({
@@ -174,7 +175,7 @@ export function drilldown (component) {
*/
export function useBreadcrumbs (component) {
return (dispatch, getState) => {
- const { metric, rootComponent, breadcrumbs, periodIndex } = getState().tree;
+ const { metric, rootComponent, breadcrumbs, periodIndex } = getMeasuresAppTree(getState());
const index = breadcrumbs.indexOf(component);
dispatch(startFetching());
return fetchComponents(rootComponent, component, metric, 1, periodIndex).then(r => {
@@ -190,7 +191,7 @@ export function useBreadcrumbs (component) {
export function fetchMore () {
return (dispatch, getState) => {
- const { rootComponent, baseComponent, metric, pageIndex, components, periodIndex } = getState().tree;
+ const { rootComponent, baseComponent, metric, pageIndex, components, periodIndex } = getMeasuresAppTree(getState());
dispatch(startFetching());
return fetchComponents(rootComponent, baseComponent, metric, pageIndex + 1, periodIndex).then(r => {
const nextComponents = [...components, ...r.components];
@@ -206,7 +207,7 @@ export function fetchMore () {
*/
export function selectComponent (component) {
return (dispatch, getState) => {
- const { breadcrumbs } = getState().tree;
+ const { breadcrumbs } = getMeasuresAppTree(getState());
const nextBreadcrumbs = [...breadcrumbs, component];
dispatch(updateStore({
selected: component,
@@ -220,7 +221,7 @@ export function selectComponent (component) {
*/
export function selectNext () {
return (dispatch, getState) => {
- const { components, selected, breadcrumbs } = getState().tree;
+ const { components, selected, breadcrumbs } = getMeasuresAppTree(getState());
const selectedIndex = components.indexOf(selected);
if (selectedIndex < components.length - 1) {
const nextSelected = components[selectedIndex + 1];
@@ -238,7 +239,7 @@ export function selectNext () {
*/
export function selectPrevious () {
return (dispatch, getState) => {
- const { components, selected, breadcrumbs } = getState().tree;
+ const { components, selected, breadcrumbs } = getMeasuresAppTree(getState());
const selectedIndex = components.indexOf(selected);
if (selectedIndex > 0) {
const nextSelected = components[selectedIndex - 1];
diff --git a/server/sonar-web/src/main/js/apps/custom-measures/components/CustomMeasuresAppContainer.js b/server/sonar-web/src/main/js/apps/custom-measures/components/CustomMeasuresAppContainer.js
new file mode 100644
index 00000000000..a88477e394a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/custom-measures/components/CustomMeasuresAppContainer.js
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import init from '../init';
+
+export default class CustomMeasuresAppContainer extends React.Component {
+ componentDidMount () {
+ if (this.props.component) {
+ init(this.refs.container, this.props.component);
+ }
+ }
+
+ componentDidUpdate () {
+ if (this.props.component) {
+ init(this.refs.container, this.props.component);
+ }
+ }
+
+ render () {
+ return <div ref="container"/>;
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/custom-measures/app.js b/server/sonar-web/src/main/js/apps/custom-measures/init.js
index 531584e81d4..caf512737a0 100644
--- a/server/sonar-web/src/main/js/apps/custom-measures/app.js
+++ b/server/sonar-web/src/main/js/apps/custom-measures/init.js
@@ -25,22 +25,20 @@ import ListView from './list-view';
import ListFooterView from './list-footer-view';
const App = new Marionette.Application();
-const init = function (options) {
+const init = function (el, component) {
// Layout
- this.layout = new Layout({
- el: options.el
- });
+ this.layout = new Layout({ el });
this.layout.render();
// Collection
this.customMeasures = new CustomMeasures({
- projectId: options.component.id
+ projectId: component.id
});
// Header View
this.headerView = new HeaderView({
collection: this.customMeasures,
- projectId: options.component.id
+ projectId: component.id
});
this.layout.headerRegion.show(this.headerView);
@@ -61,8 +59,10 @@ const init = function (options) {
};
App.on('start', function (options) {
- init.call(App, options);
+ init.call(App, options.el, options.component);
});
-window.sonarqube.appStarted.then(options => App.start(options));
+export default function (el, component) {
+ App.start({ el, component });
+}
diff --git a/server/sonar-web/src/main/js/apps/custom-measures/routes.js b/server/sonar-web/src/main/js/apps/custom-measures/routes.js
new file mode 100644
index 00000000000..09b916d711d
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/custom-measures/routes.js
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import CustomMeasuresAppContainer from './components/CustomMeasuresAppContainer';
+
+export default (
+ <IndexRoute component={CustomMeasuresAppContainer}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/groups/components/GroupsAppContainer.js b/server/sonar-web/src/main/js/apps/groups/components/GroupsAppContainer.js
new file mode 100644
index 00000000000..55cbb49127e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/components/GroupsAppContainer.js
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import init from '../init';
+
+export default class GroupsAppContainer extends React.Component {
+ componentDidMount () {
+ init(this.refs.container);
+ }
+
+ render () {
+ return <div ref="container"/>;
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/groups/app.js b/server/sonar-web/src/main/js/apps/groups/init.js
index c9d8562646f..4ec6a7e95e6 100644
--- a/server/sonar-web/src/main/js/apps/groups/app.js
+++ b/server/sonar-web/src/main/js/apps/groups/init.js
@@ -26,11 +26,9 @@ import ListView from './list-view';
import ListFooterView from './list-footer-view';
const App = new Marionette.Application();
-const init = function () {
- const options = window.sonarqube;
-
+const init = function (el) {
// Layout
- this.layout = new Layout({ el: options.el });
+ this.layout = new Layout({ el });
this.layout.render();
// Collection
@@ -56,9 +54,11 @@ const init = function () {
this.groups.fetch();
};
-App.on('start', function () {
- init.call(App);
+App.on('start', function (el) {
+ init.call(App, el);
});
-window.sonarqube.appStarted.then(options => App.start(options));
+export default function (el) {
+ App.start(el);
+}
diff --git a/server/sonar-web/src/main/js/apps/groups/routes.js b/server/sonar-web/src/main/js/apps/groups/routes.js
new file mode 100644
index 00000000000..08981267c79
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/routes.js
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import GroupsAppContainer from './components/GroupsAppContainer';
+
+export default (
+ <IndexRoute component={GroupsAppContainer}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/issues/components/IssuesAppContainer.js b/server/sonar-web/src/main/js/apps/issues/components/IssuesAppContainer.js
new file mode 100644
index 00000000000..33820285418
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/issues/components/IssuesAppContainer.js
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import init from '../init';
+
+export default class IssuesAppContainer extends React.Component {
+ componentDidMount () {
+ init(this.refs.container);
+ }
+
+ render () {
+ return <div ref="container"/>;
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/issues/app.js b/server/sonar-web/src/main/js/apps/issues/init.js
index 4623b55988f..2ac5041b6ef 100644
--- a/server/sonar-web/src/main/js/apps/issues/app.js
+++ b/server/sonar-web/src/main/js/apps/issues/init.js
@@ -32,14 +32,12 @@ import FacetsView from './facets-view';
import HeaderView from './HeaderView';
const App = new Marionette.Application();
-const init = function () {
- const options = window.sonarqube;
-
+const init = function (el) {
this.state = new State({ canBulkChange: !!window.SS.user });
this.list = new Issues();
this.facets = new Facets();
- this.layout = new Layout({ app: this, el: options.el });
+ this.layout = new Layout({ app: this, el });
this.layout.render();
$('#footer').addClass('search-navigator-footer');
@@ -74,9 +72,11 @@ const init = function () {
Backbone.history.start();
};
-App.on('start', function () {
- init.call(App);
+App.on('start', function (el) {
+ init.call(App, el);
});
-window.sonarqube.appStarted.then(options => App.start(options));
+export default function (el) {
+ App.start(el);
+}
diff --git a/server/sonar-web/src/main/js/apps/issues/routes.js b/server/sonar-web/src/main/js/apps/issues/routes.js
new file mode 100644
index 00000000000..a05f0ec92d2
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/issues/routes.js
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import IssuesAppContainer from './components/IssuesAppContainer';
+
+export default (
+ <IndexRoute component={IssuesAppContainer}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/MaintenanceAppContainer.js b/server/sonar-web/src/main/js/apps/maintenance/components/MaintenanceAppContainer.js
new file mode 100644
index 00000000000..1419251f259
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/maintenance/components/MaintenanceAppContainer.js
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import init from '../init';
+
+export default class MaintenanceAppContainer extends React.Component {
+ componentDidMount () {
+ init(this.refs.container, false);
+ }
+
+ render () {
+ return <div ref="container"/>;
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/markdown/app.js b/server/sonar-web/src/main/js/apps/maintenance/components/SetupAppContainer.js
index e6b264a6885..4fb0c472b00 100644
--- a/server/sonar-web/src/main/js/apps/markdown/app.js
+++ b/server/sonar-web/src/main/js/apps/maintenance/components/SetupAppContainer.js
@@ -17,15 +17,15 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import Marionette from 'backbone.marionette';
-import MarkdownView from './markdown-help-view';
+import React from 'react';
+import init from '../init';
-const App = new Marionette.Application();
-
-App.on('start', function () {
- const options = window.sonarqube;
- new MarkdownView({ el: options.el }).render();
-});
-
-window.sonarqube.appStarted.then(options => App.start(options));
+export default class SetupAppContainer extends React.Component {
+ componentDidMount () {
+ init(this.refs.container, true);
+ }
+ render () {
+ return <div ref="container"/>;
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/maintenance/app.js b/server/sonar-web/src/main/js/apps/maintenance/init.js
index 6ed1c7dbce0..3b812525570 100644
--- a/server/sonar-web/src/main/js/apps/maintenance/app.js
+++ b/server/sonar-web/src/main/js/apps/maintenance/init.js
@@ -24,9 +24,7 @@ import MainView from './main-view';
const App = new Marionette.Application();
-App.on('start', function () {
- const options = window.sonarqube;
-
+App.on('start', function (options) {
const viewOptions = _.extend(options, {
model: new Backbone.Model()
});
@@ -34,5 +32,7 @@ App.on('start', function () {
mainView.render().refresh();
});
-App.start();
+export default function (el, setup) {
+ App.start({ el, setup });
+}
diff --git a/server/sonar-web/src/main/js/apps/maintenance/routes.js b/server/sonar-web/src/main/js/apps/maintenance/routes.js
new file mode 100644
index 00000000000..259894f544c
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/maintenance/routes.js
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import MaintenanceAppContainer from './components/MaintenanceAppContainer';
+import SetupAppContainer from './components/SetupAppContainer';
+
+export const maintenanceRoutes = (
+ <IndexRoute component={MaintenanceAppContainer}/>
+);
+
+export const setupRoutes = (
+ <IndexRoute component={SetupAppContainer}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/markdown/templates/markdown-help.hbs b/server/sonar-web/src/main/js/apps/markdown/templates/markdown-help.hbs
deleted file mode 100644
index dbcabaf2227..00000000000
--- a/server/sonar-web/src/main/js/apps/markdown/templates/markdown-help.hbs
+++ /dev/null
@@ -1,100 +0,0 @@
-<h2 class="spacer-bottom">Markdown Syntax</h2>
-<table class="width-100 data zebra">
- <thead>
- <tr>
- <th>Write:</th>
- <th>To display:</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>*this text is bold*</td>
- <td class="markdown"><strong>this text is bold</strong></td>
- </tr>
- <tr>
- <td>http://sonarqube.org</td>
- <td class="markdown"><a href="http://sonarqube.org">http://sonarqube.org</a></td>
- </tr>
- <tr>
- <td class="text-top">
- [SonarQubeâ„¢ Home Page](http://www.sonarqube.org)
- </td>
- <td class="markdown text-top">
- <a href="http://www.sonarqube.org" target="_blank">SonarQubeâ„¢ Home Page</a>
- </td>
- </tr>
- <tr>
- <td class="text-top">* first item<br>
- * second item
- </td>
- <td class="markdown">
- <ul>
- <li>first item</li>
- <li>second item</li>
- </ul>
- </td>
- </tr>
- <tr>
- <td class="text-top">1. first item<br>
- 1. second item
- </td>
- <td class="markdown text-top">
- <ol>
- <li>first item</li>
- <li>second item</li>
- </ol>
- </td>
- </tr>
- <tr>
- <td class="text-top">
- = Heading Level 1<br>
- == Heading Level 2<br>
- === Heading Level 3<br>
- ==== Heading Level 4<br>
- ===== Heading Level 5<br>
- ====== Heading Level 6<br>
- <td class="markdown text-top">
- <h1>Heading Level 1</h1>
- <h2>Heading Level 2</h2>
- <h3>Heading Level 3</h3>
- <h4>Heading Level 4</h4>
- <h5>Heading Level 5</h5>
- <h6>Heading Level 6</h6>
- </td>
- </tr>
- <tr>
- <td class="text-top">``Lists#newArrayList()``</td>
- <td class="markdown text-top"><code>Lists#newArrayList()</code></td>
- </tr>
- <tr>
- <td class="text-top">
- ``<br>
- // code on multiple lines<br>
- public void foo() {<br>
- &nbsp;&nbsp;// do some logic here<br>
- }<br>
- ``
- </td>
- <td class="markdown text-top">
-<pre>
- // code on multiple lines
- public void foo() {
- // do some logic here
- }
-</pre>
- </td>
- </tr>
- <tr>
- <td class="text-top">
- Standard text<br>
- > Blockquoted text<br>
- > that spans multiple lines<br>
- </td>
- <td class="markdown text-top">
- <p>Standard text</p>
- <blockquote>Blockquoted text<br>
- that spans multiple lines<br></blockquote>
- </td>
- </tr>
- </tbody>
-</table>
diff --git a/server/sonar-web/src/main/js/apps/metrics/components/MetricsAppContainer.js b/server/sonar-web/src/main/js/apps/metrics/components/MetricsAppContainer.js
new file mode 100644
index 00000000000..765ead2248a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/metrics/components/MetricsAppContainer.js
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import init from '../init';
+
+export default class MetricsAppContainer extends React.Component {
+ componentDidMount () {
+ init(this.refs.container);
+ }
+
+ render () {
+ return <div ref="container"/>;
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/metrics/app.js b/server/sonar-web/src/main/js/apps/metrics/init.js
index 542a5073d17..06f12f34ff2 100644
--- a/server/sonar-web/src/main/js/apps/metrics/app.js
+++ b/server/sonar-web/src/main/js/apps/metrics/init.js
@@ -26,11 +26,9 @@ import ListView from './list-view';
import ListFooterView from './list-footer-view';
const App = new Marionette.Application();
-const init = function () {
- const options = window.sonarqube;
-
+const init = function (el) {
// Layout
- this.layout = new Layout({ el: options.el });
+ this.layout = new Layout({ el });
this.layout.render();
// Collection
@@ -72,11 +70,13 @@ App.requestTypes = function () {
});
};
-App.on('start', function () {
+App.on('start', function (el) {
$.when(App.requestDomains(), App.requestTypes()).done(function () {
- init.call(App);
+ init.call(App, el);
});
});
-window.sonarqube.appStarted.then(options => App.start(options));
+export default function (el) {
+ App.start(el);
+}
diff --git a/server/sonar-web/src/main/js/apps/metrics/routes.js b/server/sonar-web/src/main/js/apps/metrics/routes.js
new file mode 100644
index 00000000000..84955baa23e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/metrics/routes.js
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import MetricsAppContainer from './components/MetricsAppContainer';
+
+export default (
+ <IndexRoute component={MetricsAppContainer}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/permissions/global/app.js b/server/sonar-web/src/main/js/apps/overview/components/AppContainer.js
index db8e2981d9c..85d09db946d 100644
--- a/server/sonar-web/src/main/js/apps/permissions/global/app.js
+++ b/server/sonar-web/src/main/js/apps/overview/components/AppContainer.js
@@ -18,18 +18,26 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import { render } from 'react-dom';
-import { Provider } from 'react-redux';
-import App from './components/App';
-import configureStore from '../../../components/store/configureStore';
-import rootReducer from '../shared/store/rootReducer';
+import App from './App';
-window.sonarqube.appStarted.then(options => {
- const el = document.querySelector(options.el);
- const store = configureStore(rootReducer);
- render((
- <Provider store={store}>
- <App/>
- </Provider>
- ), el);
-});
+export default class AppContainer extends React.Component {
+ state = {};
+
+ componentDidMount () {
+ window.sonarqube.appStarted.then(options => {
+ this.setState({ component: options.component });
+ });
+ }
+
+ render () {
+ if (!this.state.component) {
+ return null;
+ }
+
+ const component = { ...this.state.component, ...window.sonarqube.overview.component };
+
+ return (
+ <App component={component}/>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/routes.js b/server/sonar-web/src/main/js/apps/overview/routes.js
new file mode 100644
index 00000000000..6fac11a62ab
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/routes.js
@@ -0,0 +1,28 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute, Route } from 'react-router';
+import AppContainer from './components/AppContainer';
+
+export default [
+ <IndexRoute key="index" component={AppContainer}/>,
+ <Route key="1" path="index" component={AppContainer}/>,
+ <Route key="2" path="index/:projectKey" component={AppContainer}/>
+];
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/ActionsCell.js b/server/sonar-web/src/main/js/apps/permission-templates/components/ActionsCell.js
index bd538f0a2e0..d4d5b55c456 100644
--- a/server/sonar-web/src/main/js/apps/permission-templates/components/ActionsCell.js
+++ b/server/sonar-web/src/main/js/apps/permission-templates/components/ActionsCell.js
@@ -152,7 +152,7 @@ export default class ActionsCell extends React.Component {
{!this.props.fromDetails && (
<li>
- <Link to={{ pathname: '/', query: { id: t.id } }}>
+ <Link to={{ pathname: '/permission_templates', query: { id: t.id } }}>
{this.renderDropdownIcon(<i className="icon-edit"/>)}
Edit Permissions
</Link>
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/AppContainer.js b/server/sonar-web/src/main/js/apps/permission-templates/components/AppContainer.js
new file mode 100644
index 00000000000..b6f4134f066
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/permission-templates/components/AppContainer.js
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import App from './App';
+
+export default class AppContainer extends React.Component {
+ state = {};
+
+ componentDidMount () {
+ window.sonarqube.appStarted.then(options => {
+ this.setState({ rootQualifiers: options.rootQualifiers });
+ });
+ }
+
+ render () {
+ if (!this.state.rootQualifiers) {
+ return null;
+ }
+
+ return (
+ <App {...this.props} topQualifiers={this.state.rootQualifiers}/>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/NameCell.js b/server/sonar-web/src/main/js/apps/permission-templates/components/NameCell.js
index 8517610eb10..0e9a8b2e6be 100644
--- a/server/sonar-web/src/main/js/apps/permission-templates/components/NameCell.js
+++ b/server/sonar-web/src/main/js/apps/permission-templates/components/NameCell.js
@@ -33,7 +33,7 @@ export default class NameCell extends React.Component {
return (
<td>
- <Link to={{ pathname: '/', query: { id: t.id } }}>
+ <Link to={{ pathname: '/permission_templates', query: { id: t.id } }}>
<strong className="js-name">{t.name}</strong>
</Link>
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/TemplateHeader.js b/server/sonar-web/src/main/js/apps/permission-templates/components/TemplateHeader.js
index a92388d1f40..57dd6349760 100644
--- a/server/sonar-web/src/main/js/apps/permission-templates/components/TemplateHeader.js
+++ b/server/sonar-web/src/main/js/apps/permission-templates/components/TemplateHeader.js
@@ -36,7 +36,7 @@ export default class TemplateHeader extends React.Component {
return (
<header id="project-permissions-header" className="page-header">
<div className="note spacer-bottom">
- <Link to="/" className="text-muted">
+ <Link to="/permission_templates" className="text-muted">
{translate('permission_templates.page')}
</Link>
</div>
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/routes.js b/server/sonar-web/src/main/js/apps/permission-templates/routes.js
new file mode 100644
index 00000000000..799d82546f9
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/permission-templates/routes.js
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import AppContainer from './components/AppContainer';
+
+export default (
+ <IndexRoute component={AppContainer}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.js b/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.js
index bb7b24fd24b..56343415027 100644
--- a/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.js
+++ b/server/sonar-web/src/main/js/apps/permissions/global/components/AllHoldersList.js
@@ -22,23 +22,23 @@ import { connect } from 'react-redux';
import SearchForm from '../../shared/components/SearchForm';
import HoldersList from '../../shared/components/HoldersList';
import {
- loadHolders,
- grantToUser,
- revokeFromUser,
- grantToGroup,
- revokeFromGroup,
- updateFilter,
- updateQuery,
- selectPermission
+ loadHolders,
+ grantToUser,
+ revokeFromUser,
+ grantToGroup,
+ revokeFromGroup,
+ updateFilter,
+ updateQuery,
+ selectPermission
} from '../store/actions';
-import {
- getUsers,
- getGroups,
- getQuery,
- getFilter,
- getSelectedPermission
-} from '../../shared/store/rootReducer';
import { translate } from '../../../../helpers/l10n';
+import {
+ getPermissionsAppUsers,
+ getPermissionsAppGroups,
+ getPermissionsAppQuery,
+ getPermissionsAppFilter,
+ getPermissionsAppSelectedPermission
+} from '../../../../app/store/rootReducer';
const PERMISSIONS_ORDER = [
'admin',
@@ -102,11 +102,11 @@ class AllHoldersList extends React.Component {
}
const mapStateToProps = state => ({
- users: getUsers(state),
- groups: getGroups(state),
- query: getQuery(state),
- filter: getFilter(state),
- selectedPermission: getSelectedPermission(state)
+ users: getPermissionsAppUsers(state),
+ groups: getPermissionsAppGroups(state),
+ query: getPermissionsAppQuery(state),
+ filter: getPermissionsAppFilter(state),
+ selectedPermission: getPermissionsAppSelectedPermission(state)
});
const mapDispatchToProps = dispatch => ({
diff --git a/server/sonar-web/src/main/js/apps/permissions/global/components/PageHeader.js b/server/sonar-web/src/main/js/apps/permissions/global/components/PageHeader.js
index 23b750a2dd2..299de992836 100644
--- a/server/sonar-web/src/main/js/apps/permissions/global/components/PageHeader.js
+++ b/server/sonar-web/src/main/js/apps/permissions/global/components/PageHeader.js
@@ -21,7 +21,7 @@ import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../../helpers/l10n';
import { loadHolders } from '../store/actions';
-import { isLoading } from '../../shared/store/rootReducer';
+import { isPermissionsAppLoading } from '../../../../app/store/rootReducer';
class PageHeader extends React.Component {
static propTypes = {
@@ -53,7 +53,7 @@ class PageHeader extends React.Component {
}
const mapStateToProps = state => ({
- loading: isLoading(state)
+ loading: isPermissionsAppLoading(state)
});
const mapDispatchToProps = dispatch => ({
diff --git a/server/sonar-web/src/main/js/apps/permissions/global/store/actions.js b/server/sonar-web/src/main/js/apps/permissions/global/store/actions.js
index 3a7d1fa158d..207a0cf7e0a 100644
--- a/server/sonar-web/src/main/js/apps/permissions/global/store/actions.js
+++ b/server/sonar-web/src/main/js/apps/permissions/global/store/actions.js
@@ -19,19 +19,30 @@
*/
import * as api from '../../../../api/permissions';
import { parseError } from '../../../code/utils';
-import { raiseError } from '../../shared/store/actions';
import {
- getQuery,
- getFilter,
- getSelectedPermission
-} from '../../shared/store/rootReducer';
+ raiseError,
+ REQUEST_HOLDERS,
+ RECEIVE_HOLDERS_SUCCESS,
+ UPDATE_QUERY,
+ UPDATE_FILTER,
+ SELECT_PERMISSION,
+ GRANT_PERMISSION_TO_USER,
+ REVOKE_PERMISSION_TO_USER,
+ GRANT_PERMISSION_TO_GROUP,
+ REVOKE_PERMISSION_FROM_GROUP
+} from '../../shared/store/actions';
+import {
+ getPermissionsAppQuery,
+ getPermissionsAppFilter,
+ getPermissionsAppSelectedPermission
+} from '../../../../app/store/rootReducer';
export const loadHolders = () => (dispatch, getState) => {
- const query = getQuery(getState());
- const filter = getFilter(getState());
- const selectedPermission = getSelectedPermission(getState());
+ const query = getPermissionsAppQuery(getState());
+ const filter = getPermissionsAppFilter(getState());
+ const selectedPermission = getPermissionsAppSelectedPermission(getState());
- dispatch({ type: 'REQUEST_HOLDERS', query });
+ dispatch({ type: REQUEST_HOLDERS, query });
const requests = [];
@@ -49,7 +60,7 @@ export const loadHolders = () => (dispatch, getState) => {
return Promise.all(requests).then(responses => (
dispatch({
- type: 'RECEIVE_HOLDERS_SUCCESS',
+ type: RECEIVE_HOLDERS_SUCCESS,
users: responses[0],
groups: responses[1],
query
@@ -60,30 +71,30 @@ export const loadHolders = () => (dispatch, getState) => {
};
export const updateQuery = (query = '') => dispatch => {
- dispatch({ type: 'UPDATE_QUERY', query });
+ dispatch({ type: UPDATE_QUERY, query });
if (query.length === 0 || query.length > 2) {
dispatch(loadHolders());
}
};
export const updateFilter = filter => dispatch => {
- dispatch({ type: 'UPDATE_FILTER', filter });
+ dispatch({ type: UPDATE_FILTER, filter });
dispatch(loadHolders());
};
export const selectPermission = permission => (dispatch, getState) => {
- const selectedPermission = getSelectedPermission(getState());
+ const selectedPermission = getPermissionsAppSelectedPermission(getState());
if (selectedPermission !== permission) {
- dispatch({ type: 'SELECT_PERMISSION', permission });
+ dispatch({ type: SELECT_PERMISSION, permission });
} else {
- dispatch({ type: 'SELECT_PERMISSION', permission: null });
+ dispatch({ type: SELECT_PERMISSION, permission: null });
}
dispatch(loadHolders());
};
export const grantToUser = (login, permission) => dispatch => {
api.grantPermissionToUser(null, login, permission).then(() => {
- dispatch({ type: 'GRANT_PERMISSION_TO_USER', login, permission });
+ dispatch({ type: GRANT_PERMISSION_TO_USER, login, permission });
}).catch(e => {
return parseError(e).then(message => dispatch(raiseError(message)));
});
@@ -91,7 +102,7 @@ export const grantToUser = (login, permission) => dispatch => {
export const revokeFromUser = (login, permission) => dispatch => {
api.revokePermissionFromUser(null, login, permission).then(() => {
- dispatch({ type: 'REVOKE_PERMISSION_TO_USER', login, permission });
+ dispatch({ type: REVOKE_PERMISSION_TO_USER, login, permission });
}).catch(e => {
return parseError(e).then(message => dispatch(raiseError(message)));
});
@@ -100,7 +111,7 @@ export const revokeFromUser = (login, permission) => dispatch => {
export const grantToGroup = (groupName, permission) => dispatch => {
api.grantPermissionToGroup(null, groupName, permission).then(() => {
dispatch({
- type: 'GRANT_PERMISSION_TO_GROUP',
+ type: GRANT_PERMISSION_TO_GROUP,
groupName,
permission
});
@@ -112,7 +123,7 @@ export const grantToGroup = (groupName, permission) => dispatch => {
export const revokeFromGroup = (groupName, permission) => dispatch => {
api.revokePermissionFromGroup(null, groupName, permission).then(() => {
dispatch({
- type: 'REVOKE_PERMISSION_FROM_GROUP',
+ type: REVOKE_PERMISSION_FROM_GROUP,
groupName,
permission
});
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/AllHoldersList.js b/server/sonar-web/src/main/js/apps/permissions/project/components/AllHoldersList.js
index 6dcbe728084..63b041b2fcf 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/AllHoldersList.js
+++ b/server/sonar-web/src/main/js/apps/permissions/project/components/AllHoldersList.js
@@ -22,24 +22,24 @@ import { connect } from 'react-redux';
import SearchForm from '../../shared/components/SearchForm';
import HoldersList from '../../shared/components/HoldersList';
import {
- loadHolders,
- grantToUser,
- revokeFromUser,
- grantToGroup,
- revokeFromGroup,
- updateQuery,
- updateFilter,
- selectPermission
+ loadHolders,
+ grantToUser,
+ revokeFromUser,
+ grantToGroup,
+ revokeFromGroup,
+ updateQuery,
+ updateFilter,
+ selectPermission
} from '../store/actions';
-import {
- getUsers,
- getGroups,
- getQuery,
- getFilter,
- getSelectedPermission
-} from '../../shared/store/rootReducer';
import { translate } from '../../../../helpers/l10n';
import { PERMISSIONS_ORDER_BY_QUALIFIER } from '../constants';
+import {
+ getPermissionsAppUsers,
+ getPermissionsAppGroups,
+ getPermissionsAppQuery,
+ getPermissionsAppFilter,
+ getPermissionsAppSelectedPermission
+} from '../../../../app/store/rootReducer';
class AllHoldersList extends React.Component {
static propTypes = {
@@ -128,11 +128,11 @@ class AllHoldersList extends React.Component {
}
const mapStateToProps = state => ({
- users: getUsers(state),
- groups: getGroups(state),
- query: getQuery(state),
- filter: getFilter(state),
- selectedPermission: getSelectedPermission(state)
+ users: getPermissionsAppUsers(state),
+ groups: getPermissionsAppGroups(state),
+ query: getPermissionsAppQuery(state),
+ filter: getPermissionsAppFilter(state),
+ selectedPermission: getPermissionsAppSelectedPermission(state)
});
const mapDispatchToProps = dispatch => ({
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/App.js b/server/sonar-web/src/main/js/apps/permissions/project/components/App.js
index d8bc447fa08..ba2b4e44e2e 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/App.js
+++ b/server/sonar-web/src/main/js/apps/permissions/project/components/App.js
@@ -27,15 +27,19 @@ import '../../styles.css';
export default class App extends React.Component {
static propTypes = {
- project: React.PropTypes.object.isRequired
+ component: React.PropTypes.object
};
render () {
+ if (!this.props.component) {
+ return null;
+ }
+
return (
<div className="page page-limited">
- <PageHeader project={this.props.project}/>
+ <PageHeader project={this.props.component}/>
<PageError/>
- <AllHoldersList project={this.props.project}/>
+ <AllHoldersList project={this.props.component}/>
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.js b/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.js
index db60031625d..14fcf947ee9 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.js
+++ b/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.js
@@ -22,7 +22,7 @@ import { connect } from 'react-redux';
import { translate } from '../../../../helpers/l10n';
import ApplyTemplateView from '../views/ApplyTemplateView';
import { loadHolders } from '../store/actions';
-import { isLoading } from '../../shared/store/rootReducer';
+import { isPermissionsAppLoading } from '../../../../app/store/rootReducer';
class PageHeader extends React.Component {
static propTypes = {
@@ -76,7 +76,7 @@ class PageHeader extends React.Component {
}
const mapStateToProps = state => ({
- loading: isLoading(state)
+ loading: isPermissionsAppLoading(state)
});
const mapDispatchToProps = dispatch => ({
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/store/actions.js b/server/sonar-web/src/main/js/apps/permissions/project/store/actions.js
index 5011dc075ad..b705876a6a2 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/store/actions.js
+++ b/server/sonar-web/src/main/js/apps/permissions/project/store/actions.js
@@ -19,19 +19,30 @@
*/
import * as api from '../../../../api/permissions';
import { parseError } from '../../../code/utils';
-import { raiseError } from '../../shared/store/actions';
import {
- getQuery,
- getFilter,
- getSelectedPermission
-} from '../../shared/store/rootReducer';
+ raiseError,
+ REQUEST_HOLDERS,
+ RECEIVE_HOLDERS_SUCCESS,
+ UPDATE_QUERY,
+ UPDATE_FILTER,
+ SELECT_PERMISSION,
+ GRANT_PERMISSION_TO_USER,
+ REVOKE_PERMISSION_TO_USER,
+ GRANT_PERMISSION_TO_GROUP,
+ REVOKE_PERMISSION_FROM_GROUP
+} from '../../shared/store/actions';
+import {
+ getPermissionsAppQuery,
+ getPermissionsAppFilter,
+ getPermissionsAppSelectedPermission
+} from '../../../../app/store/rootReducer';
export const loadHolders = projectKey => (dispatch, getState) => {
- const query = getQuery(getState());
- const filter = getFilter(getState());
- const selectedPermission = getSelectedPermission(getState());
+ const query = getPermissionsAppQuery(getState());
+ const filter = getPermissionsAppFilter(getState());
+ const selectedPermission = getPermissionsAppSelectedPermission(getState());
- dispatch({ type: 'REQUEST_HOLDERS', query });
+ dispatch({ type: REQUEST_HOLDERS, query });
const requests = [];
@@ -51,7 +62,7 @@ export const loadHolders = projectKey => (dispatch, getState) => {
return Promise.all(requests).then(responses => (
dispatch({
- type: 'RECEIVE_HOLDERS_SUCCESS',
+ type: RECEIVE_HOLDERS_SUCCESS,
users: responses[0],
groups: responses[1],
query
@@ -62,30 +73,30 @@ export const loadHolders = projectKey => (dispatch, getState) => {
};
export const updateQuery = (projectKey, query = '') => dispatch => {
- dispatch({ type: 'UPDATE_QUERY', query });
+ dispatch({ type: UPDATE_QUERY, query });
if (query.length === 0 || query.length > 2) {
dispatch(loadHolders(projectKey));
}
};
export const updateFilter = (projectKey, filter) => dispatch => {
- dispatch({ type: 'UPDATE_FILTER', filter });
+ dispatch({ type: UPDATE_FILTER, filter });
dispatch(loadHolders(projectKey));
};
export const selectPermission = (projectKey, permission) => (dispatch, getState) => {
- const selectedPermission = getSelectedPermission(getState());
+ const selectedPermission = getPermissionsAppSelectedPermission(getState());
if (selectedPermission !== permission) {
- dispatch({ type: 'SELECT_PERMISSION', permission });
+ dispatch({ type: SELECT_PERMISSION, permission });
} else {
- dispatch({ type: 'SELECT_PERMISSION', permission: null });
+ dispatch({ type: SELECT_PERMISSION, permission: null });
}
dispatch(loadHolders(projectKey));
};
export const grantToUser = (projectKey, login, permission) => dispatch => {
api.grantPermissionToUser(projectKey, login, permission).then(() => {
- dispatch({ type: 'GRANT_PERMISSION_TO_USER', login, permission });
+ dispatch({ type: GRANT_PERMISSION_TO_USER, login, permission });
}).catch(e => {
return parseError(e).then(message => dispatch(raiseError(message)));
});
@@ -93,7 +104,7 @@ export const grantToUser = (projectKey, login, permission) => dispatch => {
export const revokeFromUser = (projectKey, login, permission) => dispatch => {
api.revokePermissionFromUser(projectKey, login, permission).then(() => {
- dispatch({ type: 'REVOKE_PERMISSION_TO_USER', login, permission });
+ dispatch({ type: REVOKE_PERMISSION_TO_USER, login, permission });
}).catch(e => {
return parseError(e).then(message => dispatch(raiseError(message)));
});
@@ -102,7 +113,7 @@ export const revokeFromUser = (projectKey, login, permission) => dispatch => {
export const grantToGroup = (projectKey, groupName, permission) => dispatch => {
api.grantPermissionToGroup(projectKey, groupName, permission).then(() => {
dispatch({
- type: 'GRANT_PERMISSION_TO_GROUP',
+ type: GRANT_PERMISSION_TO_GROUP,
groupName,
permission
});
@@ -114,7 +125,7 @@ export const grantToGroup = (projectKey, groupName, permission) => dispatch => {
export const revokeFromGroup = (projectKey, groupName, permission) => dispatch => {
api.revokePermissionFromGroup(projectKey, groupName, permission).then(() => {
dispatch({
- type: 'REVOKE_PERMISSION_FROM_GROUP',
+ type: REVOKE_PERMISSION_FROM_GROUP,
groupName,
permission
});
diff --git a/server/sonar-web/src/main/js/apps/permissions/routes.js b/server/sonar-web/src/main/js/apps/permissions/routes.js
new file mode 100644
index 00000000000..a273a2914b6
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/permissions/routes.js
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import GlobalPermissionsApp from './global/components/App';
+import ProjectPermissionsApp from './project/components/App';
+
+export const globalPermissionsRoutes = (
+ <IndexRoute component={GlobalPermissionsApp}/>
+);
+
+export const projectPermissionsRoutes = (
+ <IndexRoute component={ProjectPermissionsApp}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.js b/server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.js
index 3449153a921..289a6c196a0 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.js
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/components/PageError.js
@@ -19,7 +19,7 @@
*/
import React from 'react';
import { connect } from 'react-redux';
-import { getError } from '../store/rootReducer';
+import { getPermissionsAppError } from '../../../../app/store/rootReducer';
class PageError extends React.Component {
static propTypes = {
@@ -42,7 +42,7 @@ class PageError extends React.Component {
}
const mapStateToProps = state => ({
- message: getError(state)
+ message: getPermissionsAppError(state)
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/actions.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/actions.js
index be7cee4a4b7..ceed4f2f9ec 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/store/actions.js
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/actions.js
@@ -17,7 +17,18 @@
* 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 RECEIVE_HOLDERS_SUCCESS = 'permissions/RECEIVE_HOLDERS_SUCCESS';
+export const GRANT_PERMISSION_TO_GROUP = 'permissions/GRANT_PERMISSION_TO_GROUP';
+export const REVOKE_PERMISSION_FROM_GROUP = 'permissions/REVOKE_PERMISSION_FROM_GROUP';
+export const GRANT_PERMISSION_TO_USER = 'permissions/GRANT_PERMISSION_TO_USER';
+export const REVOKE_PERMISSION_TO_USER = 'permissions/REVOKE_PERMISSION_TO_USER';
+export const UPDATE_FILTER = 'permissions/UPDATE_FILTER';
+export const UPDATE_QUERY = 'permissions/UPDATE_QUERY';
+export const SELECT_PERMISSION = 'permissions/SELECT_PERMISSION';
+export const REQUEST_HOLDERS = 'permissions/REQUEST_HOLDERS';
+export const ERROR = 'permissions/ERROR';
+
export const raiseError = message => ({
- type: 'ERROR',
+ type: ERROR,
message
});
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/error.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/error.js
index 6fe0ec764c3..b56a9ee6cbf 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/store/error.js
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/error.js
@@ -17,15 +17,24 @@
* 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_HOLDERS_SUCCESS,
+ GRANT_PERMISSION_TO_USER,
+ REVOKE_PERMISSION_TO_USER,
+ GRANT_PERMISSION_TO_GROUP,
+ REVOKE_PERMISSION_FROM_GROUP,
+ ERROR
+} from './actions';
+
const error = (state = null, action = {}) => {
switch (action.type) {
- case 'RECEIVE_HOLDERS_SUCCESS':
- case 'GRANT_PERMISSION_TO_USER':
- case 'REVOKE_PERMISSION_TO_USER':
- case 'GRANT_PERMISSION_TO_GROUP':
- case 'REVOKE_PERMISSION_FROM_GROUP':
+ case RECEIVE_HOLDERS_SUCCESS:
+ case GRANT_PERMISSION_TO_USER:
+ case REVOKE_PERMISSION_TO_USER:
+ case GRANT_PERMISSION_TO_GROUP:
+ case REVOKE_PERMISSION_FROM_GROUP:
return null;
- case 'ERROR':
+ case ERROR:
return action.message;
default:
return state;
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/filter.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/filter.js
index 6934582b425..65fa36db24d 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/store/filter.js
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/filter.js
@@ -17,9 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { UPDATE_FILTER } from './actions';
+
const filter = (state = 'all', action = {}) => {
switch (action.type) {
- case 'UPDATE_FILTER':
+ case UPDATE_FILTER:
return action.filter;
default:
return state;
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/byName.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/byName.js
index c1475aa6763..a015820d0df 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/byName.js
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/byName.js
@@ -18,16 +18,17 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import keyBy from 'lodash/keyBy';
+import { RECEIVE_HOLDERS_SUCCESS, GRANT_PERMISSION_TO_GROUP, REVOKE_PERMISSION_FROM_GROUP } from '../actions';
const byName = (state = {}, action = {}) => {
- if (action.type === 'RECEIVE_HOLDERS_SUCCESS') {
+ if (action.type === RECEIVE_HOLDERS_SUCCESS) {
const newGroups = keyBy(action.groups, 'name');
return { ...state, ...newGroups };
- } else if (action.type === 'GRANT_PERMISSION_TO_GROUP') {
+ } else if (action.type === GRANT_PERMISSION_TO_GROUP) {
const newGroup = { ...state[action.groupName] };
newGroup.permissions = [...newGroup.permissions, action.permission];
return { ...state, [action.groupName]: newGroup };
- } else if (action.type === 'REVOKE_PERMISSION_FROM_GROUP') {
+ } else if (action.type === REVOKE_PERMISSION_FROM_GROUP) {
const newGroup = { ...state[action.groupName] };
newGroup.permissions = newGroup.permissions
.filter(p => p !== action.permission);
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/names.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/names.js
index 8451a26999e..4dbf7b34c8d 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/names.js
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/groups/names.js
@@ -17,8 +17,10 @@
* 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_HOLDERS_SUCCESS } from '../actions';
+
const names = (state = [], action = {}) => {
- if (action.type === 'RECEIVE_HOLDERS_SUCCESS') {
+ if (action.type === RECEIVE_HOLDERS_SUCCESS) {
return action.groups.map(group => group.name);
} else {
return state;
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/loading.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/loading.js
index b7ff6d172bc..87d7ee4d900 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/store/loading.js
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/loading.js
@@ -17,11 +17,13 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { REQUEST_HOLDERS, RECEIVE_HOLDERS_SUCCESS } from './actions';
+
const loading = (state = false, action = {}) => {
switch (action.type) {
- case 'REQUEST_HOLDERS':
+ case REQUEST_HOLDERS:
return true;
- case 'RECEIVE_HOLDERS_SUCCESS':
+ case RECEIVE_HOLDERS_SUCCESS:
return false;
default:
return state;
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/query.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/query.js
index 49a755a3fee..b8dbc36a794 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/store/query.js
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/query.js
@@ -17,10 +17,12 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { UPDATE_QUERY, REQUEST_HOLDERS } from './actions';
+
const query = (state = '', action = {}) => {
switch (action.type) {
- case 'UPDATE_QUERY':
- case 'REQUEST_HOLDERS':
+ case UPDATE_QUERY:
+ case REQUEST_HOLDERS:
return action.query;
default:
return state;
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/selectedPermission.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/selectedPermission.js
index c4e951745d7..b44531e3c12 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/store/selectedPermission.js
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/selectedPermission.js
@@ -17,9 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { SELECT_PERMISSION } from './actions';
+
const selectedPermission = (state = null, action = {}) => {
switch (action.type) {
- case 'SELECT_PERMISSION':
+ case SELECT_PERMISSION:
return action.permission;
default:
return state;
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/users/byLogin.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/users/byLogin.js
index a571966cd92..fd3d21db256 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/store/users/byLogin.js
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/users/byLogin.js
@@ -18,16 +18,17 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import keyBy from 'lodash/keyBy';
+import { RECEIVE_HOLDERS_SUCCESS, GRANT_PERMISSION_TO_USER, REVOKE_PERMISSION_TO_USER } from '../actions';
const byLogin = (state = {}, action = {}) => {
- if (action.type === 'RECEIVE_HOLDERS_SUCCESS') {
+ if (action.type === RECEIVE_HOLDERS_SUCCESS) {
const newUsers = keyBy(action.users, 'login');
return { ...state, ...newUsers };
- } else if (action.type === 'GRANT_PERMISSION_TO_USER') {
+ } else if (action.type === GRANT_PERMISSION_TO_USER) {
const newUser = { ...state[action.login] };
newUser.permissions = [...newUser.permissions, action.permission];
return { ...state, [action.login]: newUser };
- } else if (action.type === 'REVOKE_PERMISSION_TO_USER') {
+ } else if (action.type === REVOKE_PERMISSION_TO_USER) {
const newUser = { ...state[action.login] };
newUser.permissions = newUser.permissions
.filter(p => p !== action.permission);
diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/store/users/logins.js b/server/sonar-web/src/main/js/apps/permissions/shared/store/users/logins.js
index b0bc1e31ca0..ad32bdc8573 100644
--- a/server/sonar-web/src/main/js/apps/permissions/shared/store/users/logins.js
+++ b/server/sonar-web/src/main/js/apps/permissions/shared/store/users/logins.js
@@ -17,8 +17,10 @@
* 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_HOLDERS_SUCCESS } from '../actions';
+
const logins = (state = [], action = {}) => {
- if (action.type === 'RECEIVE_HOLDERS_SUCCESS') {
+ if (action.type === RECEIVE_HOLDERS_SUCCESS) {
return action.users.map(user => user.login);
} else {
return state;
diff --git a/server/sonar-web/src/main/js/apps/project-admin/app.js b/server/sonar-web/src/main/js/apps/project-admin/app.js
deleted file mode 100644
index 903ed046cb9..00000000000
--- a/server/sonar-web/src/main/js/apps/project-admin/app.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { render } from 'react-dom';
-import { Provider } from 'react-redux';
-import { Router, Route, useRouterHistory } from 'react-router';
-import { createHistory } from 'history';
-import Deletion from './deletion/Deletion';
-import QualityProfiles from './quality-profiles/QualityProfiles';
-import QualityGate from './quality-gate/QualityGate';
-import Links from './links/Links';
-import Key from './key/Key';
-import rootReducer from './store/rootReducer';
-import configureStore from '../../components/store/configureStore';
-
-window.sonarqube.appStarted.then(options => {
- const el = document.querySelector(options.el);
-
- const history = useRouterHistory(createHistory)({
- basename: window.baseUrl + '/project'
- });
-
- const store = configureStore(rootReducer);
-
- const withComponent = ComposedComponent => props =>
- <ComposedComponent {...props} component={options.component}/>;
-
- render((
- <Provider store={store}>
- <Router history={history}>
- <Route
- path="/deletion"
- component={withComponent(Deletion)}/>
- <Route
- path="/quality_profiles"
- component={withComponent(QualityProfiles)}/>
- <Route
- path="/quality_gate"
- component={withComponent(QualityGate)}/>
- <Route
- path="/links"
- component={withComponent(Links)}/>
- <Route
- path="/key"
- component={withComponent(Key)}/>
- </Router>
- </Provider>
- ), el);
-});
diff --git a/server/sonar-web/src/main/js/apps/project-admin/components/GlobalMessagesContainer.js b/server/sonar-web/src/main/js/apps/project-admin/components/GlobalMessagesContainer.js
index f64ef91664b..130192047b7 100644
--- a/server/sonar-web/src/main/js/apps/project-admin/components/GlobalMessagesContainer.js
+++ b/server/sonar-web/src/main/js/apps/project-admin/components/GlobalMessagesContainer.js
@@ -19,10 +19,10 @@
*/
import { connect } from 'react-redux';
import GlobalMessages from '../../../components/controls/GlobalMessages';
-import { getGlobalMessages } from '../store/rootReducer';
+import { getProjectAdminGlobalMessages } from '../../../app/store/rootReducer';
const mapStateToProps = state => ({
- messages: getGlobalMessages(state)
+ messages: getProjectAdminGlobalMessages(state)
});
export default connect(mapStateToProps)(GlobalMessages);
diff --git a/server/sonar-web/src/main/js/apps/project-admin/deletion/Deletion.js b/server/sonar-web/src/main/js/apps/project-admin/deletion/Deletion.js
index 67563891ade..52e4fbc1774 100644
--- a/server/sonar-web/src/main/js/apps/project-admin/deletion/Deletion.js
+++ b/server/sonar-web/src/main/js/apps/project-admin/deletion/Deletion.js
@@ -23,10 +23,14 @@ import Form from './Form';
export default class Deletion extends React.Component {
static propTypes = {
- component: React.PropTypes.object.isRequired
+ component: React.PropTypes.object
};
render () {
+ if (!this.props.component) {
+ return null;
+ }
+
return (
<div className="page page-limited">
<Header/>
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
index 315dc4b17f2..4bc8050a464 100644
--- 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
@@ -30,7 +30,7 @@ import {
closeAllGlobalMessages
} from '../../../components/store/globalMessages';
import { reloadUpdateKeyPage } from './utils';
-import RecentHistory from '../../../main/nav/component/RecentHistory';
+import RecentHistory from '../../../app/components/nav/component/RecentHistory';
class BulkUpdate extends React.Component {
static propTypes = {
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
index 019cde640df..f4bff8b4a59 100644
--- 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
@@ -25,7 +25,6 @@ import UpdateForm from './UpdateForm';
import BulkUpdate from './BulkUpdate';
import FineGrainedUpdate from './FineGrainedUpdate';
import GlobalMessagesContainer from '../components/GlobalMessagesContainer';
-import { getProjectModules } from '../store/rootReducer';
import { fetchProjectModules, changeKey } from '../store/actions';
import { translate } from '../../../helpers/l10n';
import {
@@ -35,7 +34,8 @@ import {
} from '../../../components/store/globalMessages';
import { parseError } from '../../code/utils';
import { reloadUpdateKeyPage } from './utils';
-import RecentHistory from '../../../main/nav/component/RecentHistory';
+import RecentHistory from '../../../app/components/nav/component/RecentHistory';
+import { getProjectAdminProjectModules } from '../../../app/store/rootReducer';
class Key extends React.Component {
static propTypes = {
@@ -152,7 +152,7 @@ class Key extends React.Component {
}
const mapStateToProps = (state, ownProps) => ({
- modules: getProjectModules(state, ownProps.component.key)
+ modules: getProjectAdminProjectModules(state, ownProps.component.key)
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/project-admin/links/Links.js b/server/sonar-web/src/main/js/apps/project-admin/links/Links.js
index 88602532ea9..4494c52b5c9 100644
--- a/server/sonar-web/src/main/js/apps/project-admin/links/Links.js
+++ b/server/sonar-web/src/main/js/apps/project-admin/links/Links.js
@@ -23,12 +23,12 @@ import { connect } from 'react-redux';
import Header from './Header';
import Table from './Table';
import DeletionModal from './views/DeletionModal';
-import { getProjectLinks } from '../store/rootReducer';
import {
fetchProjectLinks,
deleteProjectLink,
createProjectLink
} from '../store/actions';
+import { getProjectAdminProjectLinks } from '../../../app/store/rootReducer';
class Links extends React.Component {
static propTypes = {
@@ -73,7 +73,7 @@ class Links extends React.Component {
}
const mapStateToProps = (state, ownProps) => ({
- links: getProjectLinks(state, ownProps.component.key)
+ links: getProjectAdminProjectLinks(state, ownProps.component.key)
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/project-admin/quality-gate/QualityGate.js b/server/sonar-web/src/main/js/apps/project-admin/quality-gate/QualityGate.js
index e80c5b72284..0921f1f2060 100644
--- a/server/sonar-web/src/main/js/apps/project-admin/quality-gate/QualityGate.js
+++ b/server/sonar-web/src/main/js/apps/project-admin/quality-gate/QualityGate.js
@@ -23,8 +23,8 @@ import shallowCompare from 'react-addons-shallow-compare';
import Header from './Header';
import Form from './Form';
import GlobalMessagesContainer from '../components/GlobalMessagesContainer';
-import { getAllGates, getProjectGate } from '../store/rootReducer';
import { fetchProjectGate, setProjectGate } from '../store/actions';
+import { getProjectAdminAllGates, getProjectAdminProjectGate } from '../../../app/store/rootReducer';
class QualityGate extends React.Component {
static propTypes = {
@@ -60,8 +60,8 @@ class QualityGate extends React.Component {
}
const mapStateToProps = (state, ownProps) => ({
- allGates: getAllGates(state),
- gate: getProjectGate(state, ownProps.component.key)
+ allGates: getProjectAdminAllGates(state),
+ gate: getProjectAdminProjectGate(state, ownProps.component.key)
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/project-admin/quality-profiles/QualityProfiles.js b/server/sonar-web/src/main/js/apps/project-admin/quality-profiles/QualityProfiles.js
index de20aa1ad8d..9bfdab5c533 100644
--- a/server/sonar-web/src/main/js/apps/project-admin/quality-profiles/QualityProfiles.js
+++ b/server/sonar-web/src/main/js/apps/project-admin/quality-profiles/QualityProfiles.js
@@ -24,7 +24,7 @@ import Header from './Header';
import Table from './Table';
import GlobalMessagesContainer from '../components/GlobalMessagesContainer';
import { fetchProjectProfiles, setProjectProfile } from '../store/actions';
-import { getProjectProfiles, getAllProfiles } from '../store/rootReducer';
+import { getProjectAdminAllProfiles, getProjectAdminProjectProfiles } from '../../../app/store/rootReducer';
class QualityProfiles extends React.Component {
static propTypes = {
@@ -68,8 +68,8 @@ class QualityProfiles extends React.Component {
}
const mapStateToProps = (state, ownProps) => ({
- allProfiles: getAllProfiles(state),
- profiles: getProjectProfiles(state, ownProps.component.key)
+ allProfiles: getProjectAdminAllProfiles(state),
+ profiles: getProjectAdminProjectProfiles(state, ownProps.component.key)
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/projects-admin/app.js b/server/sonar-web/src/main/js/apps/project-admin/routes.js
index 7c68d2c4b6e..fda733c0002 100644
--- a/server/sonar-web/src/main/js/apps/projects-admin/app.js
+++ b/server/sonar-web/src/main/js/apps/project-admin/routes.js
@@ -18,16 +18,17 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import ReactDOM from 'react-dom';
-import Main from './main';
-import { getCurrentUser } from '../../api/users';
+import { Route } from 'react-router';
+import Deletion from './deletion/Deletion';
+import QualityProfiles from './quality-profiles/QualityProfiles';
+import QualityGate from './quality-gate/QualityGate';
+import Links from './links/Links';
+import Key from './key/Key';
-window.sonarqube.appStarted.then(options => {
- getCurrentUser().then(user => {
- const el = document.querySelector(options.el);
- const hasProvisionPermission = user.permissions.global.indexOf('provisioning') !== -1;
- const topLevelQualifiers = options.rootQualifiers;
- ReactDOM.render(<Main hasProvisionPermission={hasProvisionPermission}
- topLevelQualifiers={topLevelQualifiers}/>, el);
- });
-});
+export default [
+ <Route key="deletion" path="deletion" component={Deletion}/>,
+ <Route key="quality_profiles" path="quality_profiles" component={QualityProfiles}/>,
+ <Route key="quality_gate" path="quality_gate" component={QualityGate}/>,
+ <Route key="links" path="links" component={Links}/>,
+ <Route key="key" path="key" component={Key}/>
+];
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
index 18eb9917862..b5c3c1a5f21 100644
--- 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
@@ -18,7 +18,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { getQualityProfiles, associateProject, dissociateProject } from '../../../api/quality-profiles';
-import { getProfileByKey } from './rootReducer';
import {
fetchQualityGates,
getGateForProject,
@@ -29,14 +28,15 @@ import { getProjectLinks, createLink } from '../../../api/projectLinks';
import { getTree, changeKey as changeKeyApi } from '../../../api/components';
import { addGlobalSuccessMessage } from '../../../components/store/globalMessages';
import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { getProjectAdminProfileByKey } from '../../../app/store/rootReducer';
-export const RECEIVE_PROFILES = 'RECEIVE_PROFILES';
+export const RECEIVE_PROFILES = 'projectAdmin/RECEIVE_PROFILES';
export const receiveProfiles = profiles => ({
type: RECEIVE_PROFILES,
profiles
});
-export const RECEIVE_PROJECT_PROFILES = 'RECEIVE_PROJECT_PROFILES';
+export const RECEIVE_PROJECT_PROFILES = 'projectAdmin/RECEIVE_PROJECT_PROFILES';
export const receiveProjectProfiles = (projectKey, profiles) => ({
type: RECEIVE_PROJECT_PROFILES,
projectKey,
@@ -54,7 +54,7 @@ export const fetchProjectProfiles = projectKey => dispatch => {
});
};
-export const SET_PROJECT_PROFILE = 'SET_PROJECT_PROFILE';
+export const SET_PROJECT_PROFILE = 'projectAdmin/SET_PROJECT_PROFILE';
const setProjectProfileAction = (projectKey, oldProfileKey, newProfileKey) => ({
type: SET_PROJECT_PROFILE,
projectKey,
@@ -65,7 +65,7 @@ const setProjectProfileAction = (projectKey, oldProfileKey, newProfileKey) => ({
export const setProjectProfile = (projectKey, oldKey, newKey) =>
(dispatch, getState) => {
const state = getState();
- const newProfile = getProfileByKey(state, newKey);
+ const newProfile = getProjectAdminProfileByKey(state, newKey);
const request = newProfile.isDefault ?
dissociateProject(oldKey, projectKey) :
associateProject(newKey, projectKey);
@@ -79,13 +79,13 @@ export const setProjectProfile = (projectKey, oldKey, newKey) =>
});
};
-export const RECEIVE_GATES = 'RECEIVE_GATES';
+export const RECEIVE_GATES = 'projectAdmin/RECEIVE_GATES';
export const receiveGates = gates => ({
type: RECEIVE_GATES,
gates
});
-export const RECEIVE_PROJECT_GATE = 'RECEIVE_PROJECT_GATE';
+export const RECEIVE_PROJECT_GATE = 'projectAdmin/RECEIVE_PROJECT_GATE';
export const receiveProjectGate = (projectKey, gate) => ({
type: RECEIVE_PROJECT_GATE,
projectKey,
@@ -103,7 +103,7 @@ export const fetchProjectGate = projectKey => dispatch => {
});
};
-export const SET_PROJECT_GATE = 'SET_PROJECT_GATE';
+export const SET_PROJECT_GATE = 'projectAdmin/SET_PROJECT_GATE';
const setProjectGateAction = (projectKey, gateId) => ({
type: SET_PROJECT_GATE,
projectKey,
@@ -122,7 +122,7 @@ export const setProjectGate = (projectKey, oldId, newId) => dispatch => {
});
};
-export const RECEIVE_PROJECT_LINKS = 'RECEIVE_PROJECT_LINKS';
+export const RECEIVE_PROJECT_LINKS = 'projectAdmin/RECEIVE_PROJECT_LINKS';
export const receiveProjectLinks = (projectKey, links) => ({
type: RECEIVE_PROJECT_LINKS,
projectKey,
@@ -135,7 +135,7 @@ export const fetchProjectLinks = projectKey => dispatch => {
});
};
-export const ADD_PROJECT_LINK = 'ADD_PROJECT_LINK';
+export const ADD_PROJECT_LINK = 'projectAdmin/ADD_PROJECT_LINK';
const addProjectLink = (projectKey, link) => ({
type: ADD_PROJECT_LINK,
projectKey,
@@ -148,14 +148,14 @@ export const createProjectLink = (projectKey, name, url) => dispatch => {
});
};
-export const DELETE_PROJECT_LINK = 'DELETE_PROJECT_LINK';
+export const DELETE_PROJECT_LINK = 'projectAdmin/DELETE_PROJECT_LINK';
export const deleteProjectLink = (projectKey, linkId) => ({
type: DELETE_PROJECT_LINK,
projectKey,
linkId
});
-export const RECEIVE_PROJECT_MODULES = 'RECEIVE_PROJECT_MODULES';
+export const RECEIVE_PROJECT_MODULES = 'projectAdmin/RECEIVE_PROJECT_MODULES';
const receiveProjectModules = (projectKey, modules) => ({
type: RECEIVE_PROJECT_MODULES,
projectKey,
@@ -169,7 +169,7 @@ export const fetchProjectModules = projectKey => dispatch => {
});
};
-export const CHANGE_KEY = 'CHANGE_KEY';
+export const CHANGE_KEY = 'projectAdmin/CHANGE_KEY';
const changeKeyAction = (key, newKey) => ({
type: CHANGE_KEY,
key,
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/app.js b/server/sonar-web/src/main/js/apps/projects-admin/AppContainer.js
index 849bd897cb7..e87d63f8ec6 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/app.js
+++ b/server/sonar-web/src/main/js/apps/projects-admin/AppContainer.js
@@ -17,27 +17,39 @@
* 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 { connect } from 'react-redux';
import React from 'react';
-import ReactDOM from 'react-dom';
-import { Router, Route, Redirect, useRouterHistory } from 'react-router';
-import { createHistory } from 'history';
+import Main from './main';
+import { getCurrentUser } from '../../app/store/rootReducer';
-import BackgroundTasksApp from './components/BackgroundTasksApp';
+class AppContainer extends React.Component {
+ state = {};
-window.sonarqube.appStarted.then(options => {
- const el = document.querySelector(options.el);
+ componentDidMount () {
+ window.sonarqube.appStarted.then(options => {
+ this.setState({ rootQualifiers: options.rootQualifiers });
+ });
+ }
- const history = useRouterHistory(createHistory)({
- basename: window.baseUrl + (options.component ? '/project/background_tasks' : '/background_tasks')
- });
+ render () {
+ if (!this.props.user || !this.state.rootQualifiers) {
+ return null;
+ }
- const App = props => <BackgroundTasksApp {...props} component={options.component}/>;
+ const hasProvisionPermission = this.props.user.permissions.global.indexOf('provisioning') !== -1;
- ReactDOM.render((
- <Router history={history}>
- <Redirect from="/index" to="/"/>
- <Route path="/" component={App}/>
- </Router>
- ), el);
+ return (
+ <Main
+ hasProvisionPermission={hasProvisionPermission}
+ topLevelQualifiers={this.state.rootQualifiers}/>
+ );
+ }
+}
+
+const mapStateToProps = state => ({
+ user: getCurrentUser(state)
});
+
+export default connect(
+ mapStateToProps
+)(AppContainer);
diff --git a/server/sonar-web/src/main/js/apps/projects-admin/routes.js b/server/sonar-web/src/main/js/apps/projects-admin/routes.js
new file mode 100644
index 00000000000..5b25254fb7f
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projects-admin/routes.js
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import AppContainer from './AppContainer';
+
+export default(
+ <IndexRoute component={AppContainer}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/projects/routes.js b/server/sonar-web/src/main/js/apps/projects/routes.js
index 114e82ca197..017baac85be 100644
--- a/server/sonar-web/src/main/js/apps/projects/routes.js
+++ b/server/sonar-web/src/main/js/apps/projects/routes.js
@@ -24,7 +24,7 @@ import AllProjectsContainer from './components/AllProjectsContainer';
import FavoriteProjectsContainer from './components/FavoriteProjectsContainer';
export default (
- <Route path="projects" component={App}>
+ <Route component={App}>
<IndexRoute component={AllProjectsContainer}/>
<Route path="favorite" component={FavoriteProjectsContainer}/>
</Route>
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/routes.js b/server/sonar-web/src/main/js/apps/quality-gates/routes.js
index 8f471c3930b..1a05f4e4657 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/routes.js
+++ b/server/sonar-web/src/main/js/apps/quality-gates/routes.js
@@ -24,7 +24,7 @@ import Intro from './components/Intro';
import DetailsContainer from './containers/DetailsContainer';
export default (
- <Route path="quality_gates" component={QualityGatesAppContainer}>
+ <Route component={QualityGatesAppContainer}>
<Redirect from="/quality_gates/index" to="/quality_gates/"/>
<IndexRoute component={Intro}/>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/routes.js b/server/sonar-web/src/main/js/apps/quality-profiles/routes.js
index b5729b5643b..3530edc7a91 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/routes.js
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/routes.js
@@ -27,7 +27,7 @@ import ChangelogContainer from './changelog/ChangelogContainer';
import ComparisonContainer from './compare/ComparisonContainer';
export default (
- <Route path="profiles" component={AppContainer}>
+ <Route component={AppContainer}>
<Redirect from="/profiles/index" to="/profiles/"/>
<IndexRoute component={HomeContainer}/>
diff --git a/server/sonar-web/src/main/js/apps/settings/app.js b/server/sonar-web/src/main/js/apps/settings/app.js
deleted file mode 100644
index 15040500397..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/app.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { render } from 'react-dom';
-import { Provider } from 'react-redux';
-import { Router, Route, Redirect, useRouterHistory } from 'react-router';
-import { createHistory } from 'history';
-import App from './components/App';
-import LicensesApp from './licenses/LicensesApp';
-import EncryptionAppContainer from './encryption/EncryptionAppContainer';
-import ServerIdAppContainer from './serverId/ServerIdAppContainer';
-import rootReducer from './store/rootReducer';
-import configureStore from '../../components/store/configureStore';
-
-window.sonarqube.appStarted.then(options => {
- const el = document.querySelector(options.el);
-
- const controller = options.component ? '/project/settings' : '/settings';
- const history = useRouterHistory(createHistory)({
- basename: window.baseUrl + controller
- });
-
- const store = configureStore(rootReducer);
-
- const withComponent = ComposedComponent => props =>
- <ComposedComponent {...props} component={options.component}/>;
-
- render((
- <Provider store={store}>
- <Router history={history}>
- <Redirect from="/index" to="/"/>
- <Route path="/" component={withComponent(App)}/>
- <Route path="/licenses" component={LicensesApp}/>
- <Route path="/encryption" component={EncryptionAppContainer}/>
- <Route path="/server_id" component={ServerIdAppContainer}/>
- </Router>
- </Provider>
- ), el);
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js b/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js
index 285f9e769e7..96fccd0abfe 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js
@@ -21,7 +21,7 @@
import React from 'react';
import { connect } from 'react-redux';
import CategoriesList from './CategoriesList';
-import { getAllCategories } from '../store/rootReducer';
+import { getSettingsAppAllCategories } from '../../../app/store/rootReducer';
class AllCategoriesList extends React.Component {
render () {
@@ -30,7 +30,7 @@ class AllCategoriesList extends React.Component {
}
const mapStateToProps = state => ({
- categories: getAllCategories(state)
+ categories: getSettingsAppAllCategories(state)
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/settings/components/App.js b/server/sonar-web/src/main/js/apps/settings/components/App.js
index 9f2c99ecb6b..902e4bf4602 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/App.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/App.js
@@ -27,7 +27,7 @@ import AllCategoriesList from './AllCategoriesList';
import GlobalMessagesContainer from './GlobalMessagesContainer';
import WildcardsHelp from './WildcardsHelp';
import { fetchSettings } from '../store/actions';
-import { getDefaultCategory } from '../store/rootReducer';
+import { getSettingsAppDefaultCategory } from '../../../app/store/rootReducer';
import '../styles.css';
type Props = {
@@ -103,7 +103,7 @@ class App extends React.Component {
}
const mapStateToProps = state => ({
- defaultCategory: getDefaultCategory(state)
+ defaultCategory: getSettingsAppDefaultCategory(state)
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/settings/components/AppContainer.js b/server/sonar-web/src/main/js/apps/settings/components/AppContainer.js
new file mode 100644
index 00000000000..e4cd869edf9
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/AppContainer.js
@@ -0,0 +1,40 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import App from './App';
+
+export default class AppContainer extends React.Component {
+ state = {};
+
+ componentDidMount () {
+ window.sonarqube.appStarted.then(options =>
+ this.setState({ ready: true, component: options.component }));
+ }
+
+ render () {
+ if (!this.state.ready) {
+ return null;
+ }
+
+ return (
+ <App {...this.props} component={this.state.component}/>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js b/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js
index 5fb235d1da6..03b8f66ba75 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js
@@ -37,7 +37,7 @@ type Props = {
};
export default class CategoriesList extends React.Component {
- props: Props;
+ rops: Props;
shouldComponentUpdate (nextProps: Props, nextState: ?{}) {
return shallowCompare(this, nextProps, nextState);
@@ -56,8 +56,10 @@ export default class CategoriesList extends React.Component {
const className = category.key.toLowerCase() === this.props.selectedCategory.toLowerCase() ? 'active' : '';
+ const pathname = this.props.component ? '/project/settings' : '/settings';
+
return (
- <IndexLink to={{ pathname: '/', query }} className={className} title={category.name}>
+ <IndexLink to={{ pathname, query }} className={className} title={category.name}>
{category.name}
</IndexLink>
);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.js b/server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.js
index 8d7bf30fc1d..510cffb443a 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.js
@@ -21,7 +21,7 @@
import React from 'react';
import { connect } from 'react-redux';
import SubCategoryDefinitionsList from './SubCategoryDefinitionsList';
-import { getSettingsForCategory } from '../store/rootReducer';
+import { getSettingsAppSettingsForCategory } from '../../../app/store/rootReducer';
class CategoryDefinitionsList extends React.Component {
@@ -31,7 +31,7 @@ class CategoryDefinitionsList extends React.Component {
}
const mapStateToProps = (state, ownProps) => ({
- settings: getSettingsForCategory(state, ownProps.category)
+ settings: getSettingsAppSettingsForCategory(state, ownProps.category)
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/settings/components/Definition.js b/server/sonar-web/src/main/js/apps/settings/components/Definition.js
index 065b6b447f4..0aa95078681 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/Definition.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/Definition.js
@@ -28,10 +28,14 @@ import DefinitionChanges from './DefinitionChanges';
import { getPropertyName, getPropertyDescription, getSettingValue, isDefaultOrInherited } from '../utils';
import { translateWithParameters, translate } from '../../../helpers/l10n';
import { resetValue, saveValue } from '../store/actions';
-import { isLoading, getValidationMessage, getChangedValue } from '../store/rootReducer';
import { failValidation, passValidation } from '../store/settingsPage/validationMessages/actions';
import { cancelChange, changeValue } from '../store/settingsPage/changedValues/actions';
import { TYPE_PASSWORD } from '../constants';
+import {
+ getSettingsAppChangedValue,
+ isSettingsAppLoading,
+ getSettingsAppValidationMessage
+} from '../../../app/store/rootReducer';
class Definition extends React.Component {
mounted: boolean;
@@ -186,9 +190,9 @@ class Definition extends React.Component {
}
const mapStateToProps = (state, ownProps) => ({
- changedValue: getChangedValue(state, ownProps.setting.definition.key),
- loading: isLoading(state, ownProps.setting.definition.key),
- validationMessage: getValidationMessage(state, ownProps.setting.definition.key)
+ changedValue: getSettingsAppChangedValue(state, ownProps.setting.definition.key),
+ loading: isSettingsAppLoading(state, ownProps.setting.definition.key),
+ validationMessage: getSettingsAppValidationMessage(state, ownProps.setting.definition.key)
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/settings/components/GlobalMessagesContainer.js b/server/sonar-web/src/main/js/apps/settings/components/GlobalMessagesContainer.js
index da821b7d65f..9c9af651c6a 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/GlobalMessagesContainer.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/GlobalMessagesContainer.js
@@ -20,10 +20,10 @@
// @flow
import { connect } from 'react-redux';
import GlobalMessages from '../../../components/controls/GlobalMessages';
-import { getGlobalMessages } from '../store/rootReducer';
+import { getSettingsAppGlobalMessages } from '../../../app/store/rootReducer';
const mapStateToProps = state => ({
- messages: getGlobalMessages(state)
+ messages: getSettingsAppGlobalMessages(state)
});
export default connect(mapStateToProps)(GlobalMessages);
diff --git a/server/sonar-web/src/main/js/apps/settings/encryption/EncryptionAppContainer.js b/server/sonar-web/src/main/js/apps/settings/encryption/EncryptionAppContainer.js
index 42bd05c788d..0dd8e051b67 100644
--- a/server/sonar-web/src/main/js/apps/settings/encryption/EncryptionAppContainer.js
+++ b/server/sonar-web/src/main/js/apps/settings/encryption/EncryptionAppContainer.js
@@ -20,9 +20,9 @@
import { connect } from 'react-redux';
import EncryptionApp from './EncryptionApp';
import { checkSecretKey, generateSecretKey, encryptValue, startGeneration } from '../store/encryptionPage/actions';
-import { getEncryptionState } from '../store/rootReducer';
+import { getSettingsAppEncryptionState } from '../../../app/store/rootReducer';
export default connect(
- state => getEncryptionState(state),
+ state => getSettingsAppEncryptionState(state),
{ checkSecretKey, generateSecretKey, encryptValue, startGeneration }
)(EncryptionApp);
diff --git a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRowContainer.js b/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRowContainer.js
index af004df569f..0b8fefd5c39 100644
--- a/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRowContainer.js
+++ b/server/sonar-web/src/main/js/apps/settings/licenses/LicenseRowContainer.js
@@ -19,11 +19,11 @@
*/
import { connect } from 'react-redux';
import LicenseRow from './LicenseRow';
-import { getLicenseByKey } from '../store/rootReducer';
import { setLicense } from '../store/licenses/actions';
+import { getSettingsAppLicenseByKey } from '../../../app/store/rootReducer';
const mapStateToProps = (state, ownProps) => ({
- license: getLicenseByKey(state, ownProps.licenseKey)
+ license: getSettingsAppLicenseByKey(state, ownProps.licenseKey)
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/settings/licenses/LicensesListContainer.js b/server/sonar-web/src/main/js/apps/settings/licenses/LicensesListContainer.js
index bd692b7e390..ca19e0a2b41 100644
--- a/server/sonar-web/src/main/js/apps/settings/licenses/LicensesListContainer.js
+++ b/server/sonar-web/src/main/js/apps/settings/licenses/LicensesListContainer.js
@@ -20,10 +20,10 @@
import { connect } from 'react-redux';
import LicensesList from './LicensesList';
import { fetchLicenses } from '../store/licenses/actions';
-import { getAllLicenseKeys } from '../store/rootReducer';
+import { getSettingsAppAllLicenseKeys } from '../../../app/store/rootReducer';
const mapStateToProps = state => ({
- licenses: getAllLicenseKeys(state)
+ licenses: getSettingsAppAllLicenseKeys(state)
});
export default connect(
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/app.js b/server/sonar-web/src/main/js/apps/settings/routes.js
index 036918421e7..1982da9b7aa 100644
--- a/server/sonar-web/src/main/js/apps/permission-templates/app.js
+++ b/server/sonar-web/src/main/js/apps/settings/routes.js
@@ -18,27 +18,16 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import { render } from 'react-dom';
-import { Router, Route, useRouterHistory } from 'react-router';
-import { createHistory } from 'history';
-import App from './components/App';
+import { IndexRoute, Route, Redirect } from 'react-router';
+import AppContainer from './components/AppContainer';
+import LicensesApp from './licenses/LicensesApp';
+import EncryptionAppContainer from './encryption/EncryptionAppContainer';
+import ServerIdAppContainer from './serverId/ServerIdAppContainer';
-window.sonarqube.appStarted.then(options => {
- const el = document.querySelector(options.el);
-
- const history = useRouterHistory(createHistory)({
- basename: window.baseUrl + '/permission_templates'
- });
-
- const EnhancedApp = props => (
- <App
- {...props}
- topQualifiers={options.rootQualifiers}/>
- );
-
- render((
- <Router history={history}>
- <Route path="/" component={EnhancedApp}/>
- </Router>
- ), el);
-});
+export default [
+ <Redirect key="1" from="/settings/index" to="/settings"/>,
+ <IndexRoute key="2" component={AppContainer}/>,
+ <Route key="3" path="licenses" component={LicensesApp}/>,
+ <Route key="4" path="encryption" component={EncryptionAppContainer}/>,
+ <Route key="5" path="server_id" component={ServerIdAppContainer}/>
+];
diff --git a/server/sonar-web/src/main/js/apps/settings/store/actions.js b/server/sonar-web/src/main/js/apps/settings/store/actions.js
index df6ed194049..79f4d15ed9c 100644
--- a/server/sonar-web/src/main/js/apps/settings/store/actions.js
+++ b/server/sonar-web/src/main/js/apps/settings/store/actions.js
@@ -25,9 +25,9 @@ import { parseError } from '../../code/utils';
import { addGlobalErrorMessage, closeAllGlobalMessages } from '../../../components/store/globalMessages';
import { passValidation, failValidation } from './settingsPage/validationMessages/actions';
import { cancelChange } from './settingsPage/changedValues/actions';
-import { getDefinition, getChangedValue } from './rootReducer';
import { isEmptyValue } from '../utils';
import { translate } from '../../../helpers/l10n';
+import { getSettingsAppDefinition, getSettingsAppChangedValue } from '../../../app/store/rootReducer';
export const fetchSettings = componentKey => dispatch => {
return getDefinitions(componentKey)
@@ -48,8 +48,8 @@ export const saveValue = (key, componentKey) => (dispatch, getState) => {
dispatch(startLoading(key));
const state = getState();
- const definition = getDefinition(state, key);
- const value = getChangedValue(state, key);
+ const definition = getSettingsAppDefinition(state, key);
+ const value = getSettingsAppChangedValue(state, key);
if (isEmptyValue(definition, value)) {
dispatch(failValidation(key, translate('settings.state.value_cant_be_empty')));
diff --git a/server/sonar-web/src/main/js/apps/system/app.js b/server/sonar-web/src/main/js/apps/system/routes.js
index 652fd6d06bc..9d257927d7f 100644
--- a/server/sonar-web/src/main/js/apps/system/app.js
+++ b/server/sonar-web/src/main/js/apps/system/routes.js
@@ -18,11 +18,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import ReactDOM from 'react-dom';
+import { IndexRoute, Redirect } from 'react-router';
import Main from './main';
-window.sonarqube.appStarted.then(options => {
- const el = document.querySelector(options.el);
- ReactDOM.render(<Main/>, el);
-});
-
+export default [
+ <Redirect key="redirect" from="/system/index" to="/system"/>,
+ <IndexRoute key="index" component={Main}/>
+];
diff --git a/server/sonar-web/src/main/js/apps/update-center/components/UpdateCenterAppContainer.js b/server/sonar-web/src/main/js/apps/update-center/components/UpdateCenterAppContainer.js
new file mode 100644
index 00000000000..4e40999fe81
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/update-center/components/UpdateCenterAppContainer.js
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import init from '../init';
+
+export default class UpdateCenterAppContainer extends React.Component {
+ componentDidMount () {
+ init(this.refs.container);
+ }
+
+ render () {
+ return <div ref="container"/>;
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/update-center/app.js b/server/sonar-web/src/main/js/apps/update-center/init.js
index 3cf3adc9d38..3c509e36232 100644
--- a/server/sonar-web/src/main/js/apps/update-center/app.js
+++ b/server/sonar-web/src/main/js/apps/update-center/init.js
@@ -29,16 +29,14 @@ import Router from './router';
import Plugins from './plugins';
const App = new Marionette.Application();
-const init = function () {
- const options = window.sonarqube;
-
+const init = function (el) {
// State
this.state = new Backbone.Model({
updateCenterActive: window.SS.updateCenterActive
});
// Layout
- this.layout = new Layout({ el: options.el });
+ this.layout = new Layout({ el });
this.layout.render();
// Plugins
@@ -70,13 +68,14 @@ const init = function () {
// Go
Backbone.history.start({
pushState: true,
- root: options.urlRoot
+ root: window.baseUrl + '/updatecenter'
});
};
-App.on('start', function () {
- init.call(App);
+App.on('start', function (el) {
+ init.call(App, el);
});
-window.sonarqube.appStarted.then(options => App.start(options));
-
+export default function (el) {
+ App.start(el);
+}
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/app.js b/server/sonar-web/src/main/js/apps/update-center/routes.js
index 1646df7ef24..308a3fa8538 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/app.js
+++ b/server/sonar-web/src/main/js/apps/update-center/routes.js
@@ -18,18 +18,13 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import { render } from 'react-dom';
-import { Provider } from 'react-redux';
-import App from './components/App';
-import configureStore from '../../../components/store/configureStore';
-import rootReducer from '../shared/store/rootReducer';
+import { IndexRoute, Route } from 'react-router';
+import UpdateCenterAppContainer from './components/UpdateCenterAppContainer';
-window.sonarqube.appStarted.then(options => {
- const el = document.querySelector(options.el);
- const store = configureStore(rootReducer);
- render((
- <Provider store={store}>
- <App project={options.component}/>
- </Provider>
- ), el);
-});
+export default [
+ <IndexRoute key="index" component={UpdateCenterAppContainer}/>,
+ <Route key="installed" path="installed" component={UpdateCenterAppContainer}/>,
+ <Route key="updates" path="updates" component={UpdateCenterAppContainer}/>,
+ <Route key="available" path="available" component={UpdateCenterAppContainer}/>,
+ <Route key="system" path="system" component={UpdateCenterAppContainer}/>
+];
diff --git a/server/sonar-web/src/main/js/apps/users/components/UsersAppContainer.js b/server/sonar-web/src/main/js/apps/users/components/UsersAppContainer.js
new file mode 100644
index 00000000000..8442a308327
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/users/components/UsersAppContainer.js
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import init from '../init';
+
+export default class UsersAppContainer extends React.Component {
+ componentDidMount () {
+ init(this.refs.container);
+ }
+
+ render () {
+ return <div ref="container"/>;
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/users/app.js b/server/sonar-web/src/main/js/apps/users/init.js
index 14ea47e63e3..cd1dc8a6568 100644
--- a/server/sonar-web/src/main/js/apps/users/app.js
+++ b/server/sonar-web/src/main/js/apps/users/init.js
@@ -29,11 +29,9 @@ import { getIdentityProviders } from '../../api/users';
const App = new Marionette.Application();
-const init = function (providers) {
- const options = window.sonarqube;
-
+const init = function (el, providers) {
// Layout
- this.layout = new Layout({ el: options.el });
+ this.layout = new Layout({ el });
this.layout.render();
// Collection
@@ -59,9 +57,10 @@ const init = function (providers) {
this.users.fetch();
};
-App.on('start', function () {
- getIdentityProviders().then(r => init.call(App, r.identityProviders));
+App.on('start', function (el) {
+ getIdentityProviders().then(r => init.call(App, el, r.identityProviders));
});
-window.sonarqube.appStarted.then(options => App.start(options));
-
+export default function (el) {
+ App.start(el);
+}
diff --git a/server/sonar-web/src/main/js/apps/users/routes.js b/server/sonar-web/src/main/js/apps/users/routes.js
new file mode 100644
index 00000000000..b727131f339
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/users/routes.js
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute } from 'react-router';
+import UsersAppContainer from './components/UsersAppContainer';
+
+export default (
+ <IndexRoute component={UsersAppContainer}/>
+);
diff --git a/server/sonar-web/src/main/js/apps/web-api/app.js b/server/sonar-web/src/main/js/apps/web-api/app.js
deleted file mode 100644
index 0ff00d28a30..00000000000
--- a/server/sonar-web/src/main/js/apps/web-api/app.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { render } from 'react-dom';
-import { Router, Route, Redirect, useRouterHistory } from 'react-router';
-import { createHistory } from 'history';
-
-import WebApiApp from './components/WebApiApp';
-import './styles/web-api.css';
-
-window.sonarqube.appStarted.then(options => {
- const el = document.querySelector(options.el);
-
- const history = useRouterHistory(createHistory)({
- basename: window.sonarqube.urlRoot
- });
-
- render((
- <Router history={history}>
- <Redirect from="/index" to="/"/>
- <Route path="/**" component={WebApiApp}/>
- </Router>
- ), el);
-});
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Action.js b/server/sonar-web/src/main/js/apps/web-api/components/Action.js
index 2c3cc0dcfa2..cfe3a6df465 100644
--- a/server/sonar-web/src/main/js/apps/web-api/components/Action.js
+++ b/server/sonar-web/src/main/js/apps/web-api/components/Action.js
@@ -60,7 +60,7 @@ export default class Action extends React.Component {
<TooltipsContainer>
<header className="web-api-action-header">
<Link
- to={{ pathname: '/' + actionKey }}
+ to={{ pathname: '/web_api/' + actionKey }}
className="spacer-right icon-link"/>
<h3 className="web-api-action-title">
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Menu.js b/server/sonar-web/src/main/js/apps/web-api/components/Menu.js
index af81e50fb45..198fd6cc5f3 100644
--- a/server/sonar-web/src/main/js/apps/web-api/components/Menu.js
+++ b/server/sonar-web/src/main/js/apps/web-api/components/Menu.js
@@ -50,7 +50,7 @@ export default function Menu ({ domains, showInternal, showOnlyDeprecated, searc
<Link
key={domain.path}
className={classNames('list-group-item', { 'active': isDomainPathActive(domain.path, splat) })}
- to={domain.path}>
+ to={'/web_api/' + domain.path}>
<h3 className="list-group-item-heading">
{domain.path}
{domain.internal && (
diff --git a/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js b/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js
index 51c56ab4839..ab5dfebbf23 100644
--- a/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js
+++ b/server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.js
@@ -24,6 +24,7 @@ import Menu from './Menu';
import Search from './Search';
import Domain from './Domain';
import { getActionKey, isDomainPathActive } from '../utils';
+import '../styles/web-api.css';
export default class WebApiApp extends React.Component {
state = {
@@ -59,7 +60,7 @@ export default class WebApiApp extends React.Component {
}
scrollToAction () {
- const { splat } = this.props.params;
+ const splat = this.props.params.splat || '';
this.scrollToElement(splat);
}
@@ -77,7 +78,7 @@ export default class WebApiApp extends React.Component {
}
toggleInternalInitially () {
- const { splat } = this.props.params;
+ const splat = this.props.params.splat || '';
const { domains, showInternal } = this.state;
if (!showInternal) {
@@ -100,7 +101,7 @@ export default class WebApiApp extends React.Component {
}
handleToggleInternal () {
- const { splat } = this.props.params;
+ const splat = this.props.params.splat || '';
const { router } = this.context;
const { domains } = this.state;
const domain = domains.find(domain => isDomainPathActive(domain.path, splat));
@@ -118,7 +119,7 @@ export default class WebApiApp extends React.Component {
}
render () {
- const { splat } = this.props.params;
+ const splat = this.props.params.splat || '';
const { domains, showInternal, showOnlyDeprecated, searchQuery } = this.state;
const domain = domains.find(domain => isDomainPathActive(domain.path, splat));
@@ -127,7 +128,7 @@ export default class WebApiApp extends React.Component {
<div className="search-navigator sticky">
<div className="search-navigator-side search-navigator-side-light" style={{ top: 30 }}>
<div className="web-api-page-header">
- <Link to="/">
+ <Link to="/web_api/">
<h1>Web API</h1>
</Link>
</div>
diff --git a/server/sonar-web/src/main/js/apps/web-api/routes.js b/server/sonar-web/src/main/js/apps/web-api/routes.js
new file mode 100644
index 00000000000..18daa8ccd71
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/web-api/routes.js
@@ -0,0 +1,27 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import { IndexRoute, Route } from 'react-router';
+import WebApiApp from './components/WebApiApp';
+
+export default [
+ <IndexRoute key="index" component={WebApiApp}/>,
+ <Route key="splat" path="**" component={WebApiApp}/>
+];